An Enable / Disable script, your thoughts?

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
script boss ss.png

I counted 140+ scripts in my project. Obviously script compatibility debugging becomes an issue at some point. Or I commission a new script and then it bugs in my project because one of my own scripts may not be compatible.

Outcommenting over a 100 scripts every time that happens is such a waste of time and sadly Ace has no way to turn scripts on/off so I came up with a script to do that.

You have to add your script to the $scripts = [] array and you have to add these 2 lines:

if !$imported || ($imported[:nap_script_boss] && Script_Boss.script_enabled?:)nap_rnd_dialogue))# <your script here>end # Script BossI can not seem to find a way around adding those 2 lines because the scripts are loaded by the closed internal code of Ace. If someone knows a legal way around it, please enlighten me.

It seems rather complicated but it does save me a LOT of time. I can now disable entire batches of scripts and not worry about any crashes. I repeat this until the script works and then I know what script(s) caused the incompatibility. Or are there better solutions?

Full script:

#-----------------------------------------------------------------------------=beginWhy:I got so tired of [ctrl]+[q]'ing entire scripts or adding 'if true/false end'to them to enable/disable them. It get's worse when they have dependencies.About:When a script is enabled while one or more of it's dependencies are disabledthen this script will either enable all those depenencies or just disable thescript (and then all scripts that have that script as a dependency).Instructions:- Place this script on before any other script that is listed here.- Add a new entry to: $scripts = []- Add the 2 lines listed below around your script.Copy-Paste stuff:if !$imported || ($imported[:nap_script_boss] && Script_Boss.script_enabled?:)REPLACE_ME))# <your entire script goes here>end # Script BossLicense:- All rights reserved (for now). (Currently not released)=end#-----------------------------------------------------------------------------$imported ||= {}$imported[:nap_script_boss] = 2.00#===============================================================================# Script Reporting & Enable/Disable Preferences#===============================================================================module Script_Boss ON_MISSING_DEPENDENCY_ACTION = :disable # possible values: :enable, :disable REPORT_ENABLED_DEPENDENCIES = true REPORT_DISABLED_DEPENDENCIES = true REPORT_ENABLED_SCRIPTS = false REPORT_DISABLED_SCRIPTS = true # - Array of scripts that you need enabled. # - Everything else will be disabled. But dependencies will be enabled as well # of course. # - ALWAYS_ENABLED entries are still enabled. DISABLE_ALL_EXCEPT = [] # Disables the scripts by index. Excluding ALWAYS_ENABLED entries. # value: [min, max] DISABLE_RANGE = [] DISABLE_CATEGORIES = [] # Disables all scripts from these categories. ALWAYS_ENABLED entries are still enabled. ALWAYS_ENABLED = [:nap_ev_text, :set_win_size, :skip_title_scrn, :khas_lighting_v2, :route_helper, :event_finetuning] # list of keys that are always enabled no matter what. REPORT_SCRIPT_INDEX = -1 # -1 disables it. Set to a value to retrieve the name of the script for the specified value.end#===============================================================================# Class SBoss#===============================================================================class SBoss attr_reader :key, :category, :req_scripts attr_accessor :enabled def initialize(key, script_enabled, category, *req_scripts) raise if script_enabled.class == Array @key = key; @enabled = script_enabled; @category = category; @req_scripts = req_scripts end # Transforms the @req_scripts from keys into actual SBoss classes def translate_req_scripts return if @req_scripts.empty? translated = [] req_scripts.each { |k| req = $scripts.find{ |s| s.key == k} raise "ERROR: Required script '#{k}' for '#{@key}' not found while translating!" if req.nil? translated << req } @req_scripts = translated end def enable_req_scripts(key = nil) # If the dev doesn't want to enable the dependencies then disable the script that requires them instead. if Script_Boss::oN_MISSING_DEPENDENCY_ACTION == :disable req_scripts.each { |req| if !req.enabled @enabled = false print "■ Disabled: '#{@key}' because it requires '#{req.key}'.\n" if Script_Boss::REPORT_DISABLED_DEPENDENCIES return end } return end return if key == @key # return if it is starting to loop (found itself again) req_scripts.each { |req| if !req.enabled req.enabled = true print "■ Enabled: '#{req.key}' because '#{@key}' requires it.\n" if Script_Boss::REPORT_ENABLED_DEPENDENCIES end key = @key if key.nil? # If it's the first in the recursive-tree then set the value to the 'initial caller'. req.enable_req_scripts(key) } endend#===============================================================================# Script Settings#===============================================================================# Turning on/off scripts happens here.SKIP_TITLE = true$scripts = [ SBoss.new:)fix_passability, true, :bugfix), SBoss.new:)fix_f12, true, :bugfix), SBoss.new:)fix_text_cache, true, :bugfix), SBoss.new:)nap_inifile, true, :core), SBoss.new:)unlimited_resolution, true, :misc, :nap_inifile), SBoss.new:)set_win_size, true, :misc), SBoss.new:)fulscreen_pp, true, :misc), SBoss.new:)event, true, :core), SBoss.new:)event_hook, true, :core, :event), SBoss.new:)initialization, false, :core, :event_hook), SBoss.new:)perm_cache, false, :core, :event_hook, :nap_map_overlay), SBoss.new:)nap_map_overlay, false, :misc), SBoss.new:)generic_audio, false, :misc), SBoss.new:)nap_core, true, :core), SBoss.new:)point, true, :core), SBoss.new:)nap_npc_rnd, false, :misc), SBoss.new:)rectangle, true, :core, :point), SBoss.new:)sprite_ani, true, :core, :rectangle), SBoss.new:)settings_mgr, true, :core, :event_hook, :achievement), SBoss.new:)nap_image, true, :misc), SBoss.new:)magazines, true, :misc, :settings_mgr, :nap_core), SBoss.new:)alien_shooter, false, :minigame, :rectangle), SBoss.new:)telephone, true, :menu), # <snip> SBoss.new:)fps, true, :debug),] # Do not edit/remove this character#===============================================================================# Enable / Disable scripts based on preferences#===============================================================================module Script_Boss # Set script dependency class references $scripts.each { |s| s.translate_req_scripts } $scripts.each_with_index { |s, i| if !s.enabled s.enabled = true if ALWAYS_ENABLED.include?(s.key) next end if !DISABLE_ALL_EXCEPT.empty? s.enabled = false if !DISABLE_ALL_EXCEPT.include?(s.key) next end if !DISABLE_RANGE.empty? s.enabled = false if i.between?(DISABLE_RANGE[0], DISABLE_RANGE[1]) next end if !DISABLE_CATEGORIES.empty? s.enabled = false if DISABLE_CATEGORIES.include?(s.category) end } # Enable Dependencies $scripts.each { |s| s.enable_req_scripts if s.enabled } #============================================================================= # Report enabled/disabled dependencies (if applicable) #============================================================================= if REPORT_ENABLED_SCRIPTS || REPORT_DISABLED_SCRIPTS $scripts.each{ |s| if s.enabled print "* Enabled: '#{s.key}.\n" if REPORT_ENABLED_SCRIPTS elsif REPORT_DISABLED_SCRIPTS print "» Disabled: '#{s.key}.\n" end } end #============================================================================= # End Reporting #============================================================================= enabled = 0; disabled = 0 $scripts.each{ |s| s.enabled ? enabled += 1 : disabled += 1 } enabled_perc = (enabled / (enabled.to_f + disabled)).round(2) print "=============================================================================\n" print "[#{ ('■' * (enabled_perc * 10)).ljust(10) }] #{(enabled_perc * 100).to_i}% #{enabled} enabled and #{disabled} disabled scripts out of #{enabled + disabled} total.\n" print "=============================================================================\n" print "Script at index #{REPORT_SCRIPT_INDEX}: #{$scripts[REPORT_SCRIPT_INDEX].key} \n" if REPORT_SCRIPT_INDEX != -1 #============================================================================= # Script_Boss.script_enabled?(key) #============================================================================= def self.script_enabled?(script_symbol) script = $scripts.find { |s| s.key == script_symbol} raise "[Line:#{__LINE__}] Script not added to Script Boss array: #{script_symbol}" if script.nil? return script.enabled endend # module Script_Boss#===============================================================================# ■ End of Script ■#===============================================================================
I did notice that disabling the range as well as the counting for the enabled scripts are bugged lol. I forgot to include the 'dependency-disabled scripts' to the total count.
 
Last edited by a moderator:

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
Oh nice link. So there was one all that time... But non-commercial use only :( .

And how did he get that internal variable? It's not listed in the help files. Did he print out all global variables and classes or something to find that?

He also doesn't catch any dependencies. If I disable scripts 1-10 for example but script 11 uses methods from script #2 then it will crash. With a 100+ the dependencies can be rather complex and there will be lots of 'em.

If I would have more information about those internal variables/classes then I could improve my script.
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,202
First Language
Binary
Primarily Uses
RMMZ
Indeed.

I have no idea how that variable was found, I have tried printing various information before i the hope of finding something and discovered nothing of interest :/

Even thought it doesnt catch the dependent scripts, still another way to disable the scripts easily. Maybe it will help you to understand how to improve your own methods ^_^

Maye not though considering the 8 lines of code(or so) in that script
 

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
Yeah it's not hard.

<removed (was a stupid question I realize that now, sorry. He obviously used Ruby methods to find it out.)>

I am blind. I found a quote from a moderator at the other topic:

Neither of those breach the EULA. They are just scripts. Neither actually requires decompiling/recompiling or changing the exe.
So basically I could scan the memory for certain values and then use Ruby to change those memory values without changing the exe itself (since when is that forbidden anyway? Wasn't in the EULA). Changing what is in memory seems legit. It's risky but it's good news. But memory scanning as well as using Ruby methods to find out any of the internal code could be considered reverse engineering but whatever. Forget it. It seems accepted and I too will be using such methods now whenever I need them.
 
Last edited by a moderator:

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
Hate to burst your bubble on this one, but if you put

puts global_variablesliterally anywhere it will display a list that includes $RGSS_SCRIPTS. It's a basic method of the Kernel module. As such, I rather doubt TDS had need of any illegal methods to discover it - the name is rather self-explanatory, after all.
 

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
Thanks. That means that I can use that info as well then. :) That will improve my script.

script_idx = 145#puts $RGSS_SCRIPTS[script_idx].inspectputs $RGSS_SCRIPTS[script_idx][0] # some fixnumputs $RGSS_SCRIPTS[script_idx][1] # Script name in the Script Editor#puts $RGSS_SCRIPTS[script_idx][2] # I have no idea but it can't always be printed in the console, might crash because of the escape characters.puts $RGSS_SCRIPTS[script_idx][3] # The script's contents.Does anyone know what the items at index 0 & 2 mean? I figured out the others.

[0] in my case returned 5087790. What could that possible be...

[2] sometimes returns stuff like "x\x9C\x8DY\xC1r\u001C\xB7\u0011=KU\xFA\aX\". It looks like some form of encryption but it probably isn't. Or unicode strings... It's typeof: string. Yeah I believe that those are unicode strings.
 
Last edited by a moderator:

Galenmereth

Retired
Veteran
Joined
May 15, 2013
Messages
2,248
Reaction score
2,158
First Language
English
Primarily Uses
N/A
Check out the plugin system in my signature; commenting out one line in the ace script editor will mean no loaded scripts, and you can group scripts into folders and comment out loading scripts from within those, too. If it's a wanted request, I could add a "exclude scripts" option for debugging, too, to easily load everything except specified scripts.
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
[2], I believe, is a compiled version of the script, and is why you can't just edit it in an external editor and use a script to read it back into the correct slot. There may be way using standard methods to compile it (or maybe it does it when you hit 'apply' or when you save in the editor) - I never really got to experimenting with it that far.


Not sure what [0] is.
 

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
@Galenmereth

Looks great. So I add everything to PRIORITY_PLUGINS (because the order matters for most scripts). Ace should have been like this by default in some way imo. Because the build-in editor = bad.

Some questions:

- Can I replace default RM scripts with that as well? Like the "Main" script? Or do I have to make those edits still through the RM Script Editor?

- I didn't see any way to disable scripts without causing their dependencies to not crash.

- It still doesn't have encryption right? It supports the RM encryption but the scripts itself are just plain unencrypted text inside of it, if I understood it correctly.

@Shaz

It seems that by changing [3] to an empty string the script is not executed. Also

puts $RGSS_SCRIPTS[1][3] = "raise 'test'"Will raise an error 'test' so I don't really think that it is compiled code. You can change the script's contents dynamically. Binary usually looks a bit different and doesn't have series of  unicode strings (\u0000) or \x.

But it is possible. Some Ruby distributions are compiled. But I believe that the default Ruby distribution (including ours) is interpreted and not compiled.
 

Galenmereth

Retired
Veteran
Joined
May 15, 2013
Messages
2,248
Reaction score
2,158
First Language
English
Primarily Uses
N/A
@Galenmereth

Looks great. So I add everything to PRIORITY_PLUGINS (because the order matters for most scripts). Ace should have been like this by default in some way imo. Because the build-in editor = bad.

Some questions:

- Can I replace default RM scripts with that as well? Like the "Main" script? Or do I have to make those edits still through the RM Script Editor?

- I didn't see any way to disable scripts without causing their dependencies to not crash.

- It still doesn't have encryption right? It supports the RM encryption but the scripts itself are just plain unencrypted text inside of it, if I understood it correctly.
  1. Yes, you can replace default RM scripts with it, just like in the editor. For a "real world" example, you can check out the demo project for my easing script; it utilizes this plugin system to both provide completely new methods and classes, and extending Ace's Game_Picture class and other classes. It shows off the kind of folder structure you can use, too.
  2. One way to disable scripts right now is to comment out Plugins.load_files within bootstrap.rb files in subfolders, but that will exclude all the files in that subfolder. This is actually something I've wanted myself (a way to exclude certain scripts easily for debugging or testing), so I'm going to add this feature ASAP. I'll give you a heads up once it's done.
  3. It does support encryption. The way I set it up, it works like this: Upon testing your game, it rebuilds scripts.rb, a file where all the scripts are added in the correct sequence. All contents of /Data in RM projects get encrypted, but in encrypted mode, we no longer have access to the file finding and searching methods I use when building this file, so I then make the Plugin manager skip rebuilding scripts.rb and just go ahead and load it. Since you can tell it to load scripts with absolute paths in encrypted mode, this works fine. This means that in an encrypted game, your scripts are protected just like they are when entered into the built-in editor :)
The Plugin Framework scripts suffer a bit from lack of good documentation; while the code itself is relatively well documented, it's not exactly user friendly documentation. Since there's interest for it (and not just me using it), I'm going to take some time and write proper documentation for this as soon as I can. A plan I had for this all along was to make a very simple GUI application with drag and drop, to let people manage their scripts easily using this framework, but without needing to write anything. While this works very well for my current use, I find myself sometimes wishing it was even easier to manage my scripts; lazyness is the greatest of motivators ;) After the IGMC, that script manager GUI will be my new project.

In the meantime, feel free to ask me any questions you might have in the thread, and I'll make sure to reply in a timely manner.
 

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
With the new info I created a new script. It's much shorter and much easier to use:

script boss v3.png

Code:

Code:
#================================================================================beginWhy:I got so tired of [ctrl]+[q]'ing entire scripts or adding 'if true/false end'to them to enable/disable them. It get's worse when they have dependencies.About:- When a script is enabled while one or more of it's dependencies are disabled then this script will either enable all those depenencies or just disable the script (and then all scripts that have that script as a dependency).- It also has several features for quickly turning many scripts on/off- For advanced users only! It's aimed at scripters.Instructions:- Place this script on before any other script that is listed here.- Add a new entry to: $scripts = []- Add the line #sb:<script_id> [misc] on the FIRST LINE of your script.  Make sure to replace <script_id> with the symbol that you added to $scripts- Note that space between categories are allowed. But the delimiter must be a  comma.Copy-Paste stuff:#sb:script_id [misc]Terms of Use: - Attribution 3.0 Unported (CC BY 3.0)   [URL="http://creativecommons.org/licenses/by/3.0/%C2%A0-"]http://creativecommons.org/licenses/by/3.0/ -[/URL] Attribution is not required. This overrules what's stated in the above   license.=end$imported ||= {}$imported[:nap_script_boss] = 3.00#===============================================================================# Settings#===============================================================================module Script_Boss  SCRIPT_ID_PREFIX = '#sb:'  $scripts = { # <script_id> => [<enabled?>, <dependency1>, <dependency2>, <dependency etc> ]    :t1 => [true, :t3],    :t2 => [true],    :t3 => [true],    :t4 => [true],    :t5 => [false],  }  ON_MISSING_DEPENDENCY_ACTION = :enable # possible values: :enable, :disable  DISABLED_CATEGORIES = [] # Use symbols   # The scripts that are always enabled NO MATTER WHAT. Even if dependencies are  # missing.  ALWAYS_ENABLED = []   # [<start index>, <end index>]  # Use an empty array to disable  # Starts at 0.  # The first index is the first $scripts item.  DISABLE_RANGE = []  #=============================================================================  # Do not edit below this line  #=============================================================================  # Automated settings  #=============================================================================  PREFIX_LEN = SCRIPT_ID_PREFIX.length  DISABLED_CATEGORIES.map!(&:to_s) # Cast to strings  #=============================================================================  # Disable the scripts based on the settings  #=============================================================================  def self.calc_disabled_scripts    disable_idx = 0    $RGSS_SCRIPTS.each_with_index{ |s, script_idx|      next if s[3].length < PREFIX_LEN || s[3][0..(PREFIX_LEN - 1)] != SCRIPT_ID_PREFIX      first_line = s[3].each_line.take(1) # Get first line without going through the entire script      disable_idx += 1            id, categories = first_line[0].match(/#{SCRIPT_ID_PREFIX}(.*?)\[(.*?)\]/).captures      key = id.strip.to_sym      categories = categories.gsub(/\s+/, '').split(',')      # Check if $scripts has the key      raise "$scripts[#{key}] is missing for (#{$RGSS_SCRIPTS[script_idx][1]})" if !$scripts.has_key?(key)            # Skip if forced enabled      if ALWAYS_ENABLED.include?(key)        print "» #{key} Enabled (forced)\n"        next      end            # Disable based on $script variable      if !$scripts[key][0]        @processed_scripts[key] = [script_idx, "« #{id} Disabled by user\n"]        next      end            # Disable based on DISABLED_CATEGORIES      matching_cats = categories & DISABLED_CATEGORIES      if !matching_cats.empty?        @processed_scripts[key] = [script_idx, "« #{id} Disabled by categories: #{matching_cats.join(', ')}\n"]        next      end            # Disable based on DISABLE_RANGE      if !DISABLE_RANGE.empty? && disable_idx.between?(DISABLE_RANGE[0], DISABLE_RANGE[1])        @processed_scripts[key] = [script_idx, "« #{id} Disabled by range[#{DISABLE_RANGE[0]},#{DISABLE_RANGE[1]}]. Script index: #{disable_idx}\n"]        next      end            @processed_scripts[key] = [script_idx, nil] # nil means: do not disable this script    }  end   # Disable/Enable based on dependencies  def self.apply_dependencies    if ON_MISSING_DEPENDENCY_ACTION == :disable      begin        restart = false        $scripts.each { |script_id, v|          v[1..-1].each { |dependency|            if @processed_scripts[dependency][1] && !@processed_scripts[script_id][1]              @processed_scripts[script_id][1] = "« #{script_id.to_s} Disabled by dependency: #{dependency.to_s}\n"              restart = true # because script #1 could have a dependency on script #2 (which is enabled) but if script #2 has a dependency on #3 (which is disabled) then script #1 would be wrongfully enabled. The restart-loop prevents that.            end          }        }      end while restart    else # enable all dependencies and the dependency it's dependencies.      $scripts.each { |script_id, v|        v[1..-1].each { |dependency_key|          if @processed_scripts[dependency_key][1]            enable_dependencies_recursive(dependency_key, script_id) if @processed_scripts[dependency_key][1]          end        }      }    end  end # apply_dependencies   def self.enable_dependencies_recursive(key, parent)    @processed_scripts[key][1] = nil # enable dependency    print "» Enabled dependency #{key} because #{parent} required it\n"        $scripts[key][1..-1].each { |child_key| enable_dependencies_recursive(child_key, parent) }  end   # Actually disable the scripts now  def self.disable_scripts    @enabled_cnt = 0    @disabled_cnt = 0        @processed_scripts.each { |k, v|      if v[1]        $RGSS_SCRIPTS[v[0]][3] = '#' + v[1]        print v[1]        @disabled_cnt += 1      else        @enabled_cnt += 1      end    }        @enabled_perc = (@enabled_cnt / (@enabled_cnt.to_f + @disabled_cnt)).round(2)    @processed_scripts = nil  end   @processed_scripts = {} # script_id => [<script index>, <reason for deleting, or nil if active>]  calc_disabled_scripts  apply_dependencies  disable_scripts  print "=============================================================================\n"  print "[#{ ('█' * (@enabled_perc * 10)).ljust(10, '░') }] #{(@enabled_perc * 100).to_i}%   #{@enabled_cnt} enabled and #{@disabled_cnt} disabled out of #{@enabled_cnt + @disabled_cnt} scripts total.\n"  print "=============================================================================\n"  #=============================================================================end # module Script_Boss
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
Thanks. That means that I can use that info as well then. :) That will improve my script.

script_idx = 145#puts $RGSS_SCRIPTS[script_idx].inspectputs $RGSS_SCRIPTS[script_idx][0] # some fixnumputs $RGSS_SCRIPTS[script_idx][1] # Script name in the Script Editor#puts $RGSS_SCRIPTS[script_idx][2] # I have no idea but it can't always be printed in the console, might crash because of the escape characters.puts $RGSS_SCRIPTS[script_idx][3] # The script's contents.Does anyone know what the items at index 0 & 2 mean? I figured out the others.[0] in my case returned 5087790. What could that possible be...

[2] sometimes returns stuff like "x\x9C\x8DY\xC1r\u001C\xB7\u0011=KU\xFA\aX\". It looks like some form of encryption but it probably isn't. Or unicode strings... It's typeof: string. Yeah I believe that those are unicode strings.
That's just the script text itself, zlib compressed.

You can read it easily using

Code:
Zlib::Inflate.inflate(yourData)
Unless the format has changed, but I don't think the 4th element is the script text.
 
Last edited by a moderator:

Napoleon

Veteran
Veteran
Joined
Dec 29, 2012
Messages
869
Reaction score
97
First Language
Dutch
Primarily Uses
Yup that explains [2] indeed. But why do they keep compressed scripts in memory throughout the game? Why is it compressed at all?
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

How many parameters is 'too many'??
Yay, now back in action Happy Christmas time, coming back!






Back in action to develop the indie game that has been long overdue... Final Fallacy. A game that keeps on giving! The development never ends as the developer thinks to be the smart cookie by coming back and beginning by saying... "Oh bother, this indie game has been long overdue..." How could one resist such? No-one c
So I was playing with filters and this looked interesting...

Versus the normal look...

Kind of gives a very different feel. :LZSexcite:
To whom ever person or persons who re-did the DS/DS+ asset packs for MV (as in, they are all 48x48, and not just x2 the pixel scale) .... THANK-YOU!!!!!!!!! XwwwwX

Forum statistics

Threads
105,849
Messages
1,016,981
Members
137,563
Latest member
cexojow
Top