Advertisement
LeonMMS

ESIE-RGU

Jun 5th, 2025
580
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 16.26 KB | None | 0 0
  1.  
  2. =begin
  3. ================================================================================
  4. Easy Script Importer-Exporter                                       Version 4.0
  5. by KK20                                                             Jul 18 2018
  6. --------------------------------------------------------------------------------
  7.  
  8. [ Introduction ]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  9.   Ever wanted to export your RPG Maker scripts to .rb files, make changes to
  10.   them in another text editor, and then import them back into your project?
  11.   Look no further, fellow scripters. ESIE is easy to use!
  12.  
  13. [ Instructions ]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  14.   Place this script at the top of your script list to ensure it runs first.
  15.   Make any changes to the configuration variables below if desired.
  16.   Run your game and a message box will prompt success and close the game.
  17.  
  18.   If exporting, you can find the folder containing a bunch of .rb files in your
  19.   project folder. A new file called "!script_order.csv" will tell this script
  20.   in what order to import your script files back into RPG Maker. As such, you
  21.   can create new .rb files and include its filename into "!script_order.csv"
  22.   without ever having to open RPG Maker!
  23.  
  24.   If importing, please close your project (DO NOT SAVE IT) and re-open it.
  25.  
  26.   ** As of Version 4.0, subfolders are now possible!
  27.  
  28.   - Script names that start with the character defined in FOLDER_INDICATOR will
  29.     be subfolders within your exported scripts folder.
  30.   - You can specify the depth of subfolders by increasing the number
  31.     FOLDER_INDICATOR characters.
  32.   - Any scripts below the subfolder will be placed within it.
  33.   - A script name that only consists of FOLDER_INDICATOR characters indicates
  34.     "closing" that subfolder; scripts below will now be placed in the previous
  35.     (i.e. its parent's) subfolder.
  36.   - You may reuse a folder name multiple times. You can have subfolders named
  37.     after script authors and keep their scripts grouped together without
  38.     disrupting your script order (and potentially crashing your project).
  39.  
  40.   Here's an example assuming FOLDER_INDICATOR is set to '@' :
  41.  
  42.   Project Script List       Project Directory
  43.  
  44.                             Scripts_Export_Folder/
  45.   EarlyScript               ├ EarlyScript.rb
  46.   @Base Scripts             ├ Base Scripts/
  47.   @@Game Classes            │ ├ Game Classes/
  48.   Game_Temp                 │ │ ├ Game_Temp.rb
  49.   Game_System               │ │ └ Game_System.rb
  50.   @@Sprite Classes          │ └ Sprite Classes/
  51.   Sprite_Character          │   └ Sprite_Character
  52.   @Custom Scripts           ├ Custom Scripts/
  53.   MyScript                  │ └ MyScript.rb
  54.   @                         │
  55.   Main                      └ Main.rb
  56.  
  57. [ Compatibility ]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  58.   This script already has methods to ensure it will run properly on any RPG
  59.   Maker version. This script does not rely on nor makes changes to any existing
  60.   scripts, so it is 100% compatible with anything.
  61.  
  62. [ Credits ]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  63.   KK20 - made this script
  64.   GubiD - referenced his VXA Script Import/Export
  65.   FiXato and HIRATA Yasuyuki - referenced VX/VXA Script Exporter
  66.   ForeverZer0 - suggesting and using Win32API to read .ini file
  67.  
  68. ================================================================================
  69. =end
  70.  
  71. #******************************************************************************
  72. # B E G I N   C O N F I G U R A T I O N
  73. #******************************************************************************
  74. #------------------------------------------------------------------------------
  75. # Set the script's mode. Will export the scripts, import the scripts, or do
  76. # absolutely nothing.
  77. #       ACCEPTED VALUES:
  78. #       0 = Disable (pretends like this script doesn't even exist)
  79. #       1 = Export
  80. #       2 = Import
  81. #       3 = Playtest (import scripts from folder to playtest game; does not
  82. #                     replace or create a 'Scripts.r_data' file)
  83. #------------------------------------------------------------------------------
  84. IMPORT_EXPORT_MODE = 0
  85. #------------------------------------------------------------------------------
  86. # Folder name where scripts are imported from and exported to
  87. #------------------------------------------------------------------------------
  88. FOLDER_NAME = "Scripts"
  89. #------------------------------------------------------------------------------
  90. # Character positioned at the start of a script name to indicate a subfolder.
  91. # All scripts (or other subfolders) below it will be placed within this folder.
  92. # This must only be a one character string.
  93. #------------------------------------------------------------------------------
  94. FOLDER_INDICATOR = '▼'
  95. #------------------------------------------------------------------------------
  96. # This tag will be added to the end of a script name in the CSV file for any
  97. # scripts that do not have code in them. This tag will be removed when imported
  98. # back into the project. Note that this does not apply to scripts with no name.
  99. #------------------------------------------------------------------------------
  100. BLANK_SCRIPT_TAG = '~blank'
  101. #------------------------------------------------------------------------------
  102. # When exporting, if the folder FOLDER_NAME already exists, it will create
  103. # another folder of the same name along with an ID. This will make sure you do
  104. # not overwrite the changes you made to your scripts accidentally. If false,
  105. # it will erase all the files in the folder prior to exporting.
  106. # Useless for importing.
  107. #------------------------------------------------------------------------------
  108. MAKE_EXPORT_COPIES = false
  109. #------------------------------------------------------------------------------
  110. # Creates a duplicate of the Scripts.r_data file to ensure you don't break your
  111. # project. The duplicate will be placed in the Data folder as "Copy - Scripts".
  112. # Useless for exporting.
  113. #------------------------------------------------------------------------------
  114. CREATE_SCRIPTS_COPY = false
  115. #------------------------------------------------------------------------------
  116. # If true, converts any instances of tab characters (\t) into two spaces. This
  117. # is extremely helpful if writing code from an external editor and moving it
  118. # back into RPG Maker where tab characters are instantly treated as two spaces.
  119. #------------------------------------------------------------------------------
  120. TABS_TO_SPACES = true
  121. #******************************************************************************
  122. # E N D   C O N F I G U R A T I O N
  123. #******************************************************************************
  124. #------------------------------------------------------------------------------
  125. if IMPORT_EXPORT_MODE != 0
  126.  
  127.   RGSS = (RUBY_VERSION == "1.9.2" ? 3 : defined?(Hangup) ? 1 : 2)
  128.  
  129.   if RGSS == 3
  130.     def p(*args)
  131.       msgbox *args
  132.     end
  133.   end
  134.  
  135.   # From GubiD's script
  136.   # These characters cannot be used as folder/file names. Any of your script
  137.   # names that use the characters on the left will be replaced with the right.
  138.   INVALID_CHAR_REPLACE = {
  139.     '\\'=> '&',
  140.     '/' => '&',
  141.     ':' => ';',
  142.     '*' => '°',
  143.     '?' => '!',
  144.     '<' => '«',
  145.     '>' => '»',
  146.     '|' => '¦',
  147.     '"' => '\''
  148.   }
  149.  
  150.   unless FOLDER_INDICATOR.is_a?(String) && FOLDER_INDICATOR.size == 1
  151.     raise "FOLDER_INDICATOR needs to be 1 character long!"
  152.   end
  153.  
  154.   def mkdir_p(list)
  155.     path = ''
  156.     list.each do |dirname|
  157.       Dir.mkdir(path + dirname) unless File.exist?(path + dirname)
  158.       path += "#{dirname}/"
  159.     end
  160.   end
  161.  
  162.   def traceback_report
  163.     backtrace = $!.backtrace.clone
  164.     backtrace.each{ |bt|
  165.       bt.sub!(/{(\d+)}/) {"[#{$1}]#{$RGSS_SCRIPTS[$1.to_i][1]}"}
  166.     }
  167.     return $!.message + "\n\n" + backtrace.join("\n")
  168.   end
  169.  
  170.   def raise_traceback_error
  171.     if $!.message.size >= 900
  172.       File.open('traceback.log', 'w') { |f| f.write($!) }
  173.       raise 'Traceback is too big. Output in traceback.log'
  174.     else
  175.       raise
  176.     end
  177.   end
  178. #-[ B E G I N ]-----------------------------------------------------------------
  179.   # Get project's script file
  180.   #ini = Win32API.new('kernel32', 'GetPrivateProfileString','PPPPLP', 'L')
  181.   #ini = Fiddle::Function.new(
  182.   #  Fiddle::Handle.new('kernel32'),
  183.   #  [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP,
  184.   #  Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG, Fiddle::TYPE_VOIDP],
  185.   #  Fiddle::TYPE_LONG
  186.   #)
  187.   #scripts_filename = "\0" * 256
  188.   #ini.call('Game', 'Scripts', '', scripts_filename, 256, '.\\Game.ini')
  189.   #scripts_filename.delete!("\0")
  190.   scripts_filename = 'Data/Scripts.rvdata2'
  191.  
  192.   counter = 0
  193.   # Exporting?
  194.   if IMPORT_EXPORT_MODE == 1
  195.     folder_name = FOLDER_NAME
  196.     if File.exist?(FOLDER_NAME)
  197.       # Keep a history of exports? Or only one folder?
  198.       if MAKE_EXPORT_COPIES
  199.         i = 1
  200.         i += 1 while File.exist?("#{FOLDER_NAME}_#{i}")
  201.         Dir.mkdir("#{FOLDER_NAME}_#{i}")
  202.         folder_name = "#{FOLDER_NAME}_#{i}"
  203.       else
  204.         Dir['Scripts/*'].each { |file| File.delete(file) }
  205.       end
  206.     else
  207.       Dir.mkdir(FOLDER_NAME) unless File.exist?(FOLDER_NAME)
  208.     end
  209.     # Create script order list
  210.     script_order = File.open("#{folder_name}/!script_order.csv", 'w')
  211.     script_names = {}
  212.     folder_tree = [folder_name]
  213.     current_subfolder_level = 0
  214.     # Load the raw script data
  215.     scripts = load_data(scripts_filename)
  216.     scripts.each_index do |index|
  217.       # skip ESIE
  218.       next if index == 0
  219.       script = scripts[index]
  220.       id, name, code = script
  221.       next if id.nil?
  222.  
  223.       # if this is a subfolder script name
  224.       subfolder_level, subfolder_name = name.scan(/^(#{FOLDER_INDICATOR}+)(.*)/).flatten
  225.       if subfolder_level
  226.         # Replace invalid filename characters with valid characters
  227.         subfolder_level = subfolder_level.size
  228.         subfolder_name.split('').map{ |chr| INVALID_CHAR_REPLACE[chr] || chr }.join
  229.  
  230.         case subfolder_level <=> current_subfolder_level
  231.         when -1
  232.           (current_subfolder_level - subfolder_level).times do |n|
  233.             folder_tree.pop
  234.             current_subfolder_level -= 1
  235.           end
  236.           if subfolder_name.empty?
  237.             folder_tree.pop
  238.             current_subfolder_level -= 1
  239.           else
  240.             folder_tree[-1] = subfolder_name
  241.           end
  242.  
  243.         when 0
  244.           if subfolder_name.empty?
  245.             folder_tree.pop
  246.             current_subfolder_level -= 1
  247.           else
  248.             folder_tree[-1] = subfolder_name
  249.           end
  250.  
  251.         when 1
  252.           if subfolder_level - current_subfolder_level != 1
  253.             raise "Invalid sublevel for folder!\n" +
  254.                   "Expected: #{FOLDER_INDICATOR * (current_subfolder_level + 1)}#{subfolder_name}\n" +
  255.                   "Received: #{name}"
  256.           end
  257.           raise "Branching subfolder needs a name!" if subfolder_name.empty?
  258.           folder_tree << subfolder_name
  259.           current_subfolder_level += 1
  260.         end
  261.         mkdir_p(folder_tree)
  262.         script_order.write("#{name}\n")
  263.         # no need to continue further with this script, so go to next
  264.         next
  265.       end
  266.  
  267.       # Replace invalid filename characters with valid characters
  268.       name = name.split('').map{ |chr| INVALID_CHAR_REPLACE[chr] || chr }.join
  269.       # Convert script data to readable format
  270.       code = Zlib::Inflate.inflate(code)
  271.       code.gsub!(/\t/) {'  '} if TABS_TO_SPACES
  272.  
  273.       if code.empty?
  274.         name += BLANK_SCRIPT_TAG unless name.empty?
  275.         script_order.write("#{name}\n")
  276.         next
  277.       end
  278.  
  279.       name = 'no_script_name' if name.empty?
  280.       if script_names.key?(name)
  281.         script_names[name] += 1
  282.         name = "#{name}~@#{script_names[name]}"
  283.       else
  284.         script_names[name] = 0
  285.       end
  286.       # Output script to file
  287.       script_order.write("#{name}\n")
  288.       dir_path = folder_tree.join('/')
  289.       File.open("#{dir_path}/#{name}.rb", 'wb') { |f| f.write(code) }
  290.       counter += 1
  291.     end
  292.     script_order.close
  293.     p "#{counter} files successfully exported to folder '#{folder_name}'"
  294.     exit
  295.   end
  296.   # If importing or play-testing
  297.   if IMPORT_EXPORT_MODE >= 2
  298.     folder_tree = [FOLDER_NAME]
  299.     counter = 1
  300.     # If strictly importing, we want to replace the data directly in the scripts
  301.     # data file. Otherwise, just override the scripts global variable.
  302.     if IMPORT_EXPORT_MODE == 2
  303.       scripts_file = File.open(scripts_filename, 'rb')
  304.       import_obj = Marshal.load(scripts_file)
  305.     else
  306.       import_obj = $RGSS_SCRIPTS
  307.     end
  308.     # If strictly importing, create a copy of the scripts file in case something
  309.     # goes wrong with the import.
  310.     if IMPORT_EXPORT_MODE == 2 && CREATE_SCRIPTS_COPY
  311.       base_name = File.basename(scripts_filename)
  312.       dir_name = File.dirname(scripts_filename)
  313.       copy = File.open(dir_name + "/Copy - " + base_name, 'wb')
  314.       Marshal.dump(import_obj, copy)
  315.       copy.close
  316.     end
  317.     # Load each script file
  318.     File.open("#{FOLDER_NAME}/!script_order.csv", 'r') do |list|
  319.       list = list.read.split("\n")
  320.       list.each do |filename|
  321.         code = ''
  322.         script_name = filename.gsub(/(.*?)(?:~@\d+)?$/) {$1}
  323.         # Is this a subfolder?
  324.         level, subfolder = script_name.scan(/^(#{FOLDER_INDICATOR}+)(.*)/).flatten
  325.         if level
  326.           level = level.size
  327.           case level <=> (folder_tree.size - 1)
  328.           when -1
  329.             (folder_tree.size - 1 - level).times { |n| folder_tree.pop }
  330.             if subfolder.empty?
  331.               folder_tree.pop
  332.             else
  333.               folder_tree[-1] = subfolder
  334.             end
  335.           when 0
  336.             if subfolder.empty?
  337.               folder_tree.pop
  338.             else
  339.               folder_tree[-1] = subfolder
  340.             end
  341.           when 1
  342.             if level - (folder_tree.size - 1) != 1
  343.               raise "Invalid sublevel for folder!\n" +
  344.                     "Expected: #{FOLDER_INDICATOR * (folder_tree.size)}#{subfolder}\n" +
  345.                     "Received: #{script_name}"
  346.             end
  347.             raise "Branching subfolder needs a name!" if subfolder.empty?
  348.             folder_tree << subfolder
  349.           end
  350.  
  351.         elsif script_name.empty? || script_name[/#{BLANK_SCRIPT_TAG}$/]
  352.           script_name = script_name.chomp("#{BLANK_SCRIPT_TAG}")
  353.           code = ''
  354.         else # script file
  355.           dir_path = folder_tree.join('/')
  356.           code = File.open("#{dir_path}/#{filename}.rb", 'r') { |f| f.read }
  357.           code.gsub!(/\t/) {'  '} if TABS_TO_SPACES
  358.         end
  359.         # If strictly importing, compress script. Otherwise, keep script in
  360.         # readable format.
  361.         if IMPORT_EXPORT_MODE == 2
  362.           z = Zlib::Deflate.new(6)
  363.           data = z.deflate(code, Zlib::FINISH)
  364.         else
  365.           data = code
  366.         end
  367.         # If strictly importing, replaces entries in the scripts file data with
  368.         # the newly-compressed imported scripts. Otherwise, replace entries in
  369.         # $RGSS_SCRIPTS with imported scripts.
  370.         import_obj[counter] = [counter]
  371.         import_obj[counter][1] = script_name
  372.         import_obj[counter][IMPORT_EXPORT_MODE] = data
  373.         counter += 1
  374.       end
  375.     end
  376.     # Dump imported file data to a new Scripts file and close the program.
  377.     if IMPORT_EXPORT_MODE == 2
  378.       data = File.open(scripts_filename, 'wb')
  379.       Marshal.dump(import_obj[0, counter], data)
  380.       data.close
  381.       p "#{counter-1} files successfully imported. Please close your RPG Maker " +
  382.       "now without saving it. Re-open your project to find the scripts imported."
  383.       exit
  384.     else
  385.       # Run the project from here, eval-ing everything
  386.       ($RGSS_SCRIPTS.size - counter).times { |n| $RGSS_SCRIPTS.pop }
  387.       $RGSS_SCRIPTS.each_with_index do |script, i|
  388.         next if i == 0
  389.         begin
  390.           eval(script[3], nil, script[1])
  391.         rescue ScriptError
  392.           raise ScriptError.new($!.message)
  393.         rescue
  394.           $!.full_message.sub!($!.message, traceback_report)
  395.           raise_traceback_error
  396.         end
  397.       end
  398.       exit
  399.     end
  400.   end
  401. #------------------------------------------------------------------------------
  402. end # if IMPORT_EXPORT_MODE != 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement