设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3572|回复: 7
打印 上一主题 下一主题

[原创发布] 自带脚本编辑器太难用了,要是可以导出用notepad++编辑的话

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1680
在线时间
91 小时
注册时间
2019-5-16
帖子
45
跳转到指定楼层
1
发表于 2019-6-5 03:33:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 Aephiex 于 2019-6-6 23:50 编辑

我不是很清楚每个脚本自带的那一串数字的功能。我已经用自己写的脚本管理模块多次导出导入,那一串谜之数字全部变成了nil,而游戏并未出现任何功能问题。所以我觉得可以发出来分享一下。

为避免可能的风险,建议每次执行脚本导入之前备份 "Data/Scripts.rvdata2" 。

此外,进行脚本导入期间,如果你的 RMVA 是开着的, "Data/Scripts.rvdata2" 的变化不会立刻反映到 RMVA 里,需要关掉 RMVA 再重新打开工程才能看到脚本的变化。否则的话,导入过的脚本可能会被 RMVA 的缓存覆盖。

  1. #!!! skip_if_destructive
  2. #==============================================================================
  3. # ◆ 脚本管理模块 by Aephiex
  4. #------------------------------------------------------------------------------
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #------------------------------------------------------------------------------
  10. #
  11. #  使用说明:
  12. #  ◎ 创建 script_manager.txt ,在里面写入指令,再运行 Game.exe 来触发。
  13. #     脚本管理模块将会抢在游戏开始之前执行任务。
  14. #     该文件不能有任何多余字符!
  15. #  ◎ 可用指令如下
  16. #     export ->
  17. #       • 导出脚本到 Scripts\ ,然后关闭游戏。
  18. #         脚本将以 002 [Vocab].rb 的格式决定文件名,并单独储存在每个文件中。
  19. #         不适宜出现在文件名中的特殊符号会被自动替换。
  20. #       • 脚本的原本标题和排列顺序储存在 000 Mapping.txt 中,
  21. #         格式为:"Vocab->002 [Vocab].rb"
  22. #         没有指定文件名的行是一个只有标题、没有内容的脚本,
  23. #         而空行是一个既没有标题又没有内容的脚本。
  24. #       • 000 Mapping.txt 是脚本导入的依据。
  25. #         可以通过调换行顺序来调换脚本顺序,也可以通过增删行来增删脚本。
  26. #         新文件名哪怕是 "新建 文本文档.txt" 都可以。
  27. #         不符合格式将会使这一行导入失败。
  28. #       • 顺便一提,> 也是敏感字符之一,所以脚本标题不会影响到 000 Mapping.txt 的格式。
  29. #     import ->
  30. #       • 从 Scripts\ 导入脚本,然后关闭游戏。
  31. #     blink ->
  32. #       • 先执行导入,再执行导出以刷新 Scripts\ 的内容。然后关闭游戏。
  33. #     destructive_import ->
  34. #       • 执行破坏性的导入。然后关闭游戏。
  35. #         文件的开头写着 "#!!! skip_if_destructive" 的脚本会被跳过。
  36. #         符合特定格式的代码块会被移除。
  37. #         符合特定格式的代码块会被指定的其他代码块替换。
  38. #       • Scripts\ 会被删除。
  39. #       • 适合在制作发行包之前运行一次。由于是破坏性的,请勿在主分支中运行。
  40. #       • 顺便一提,虽然此脚本是阿帕奇协议V2.0,
  41. #         但执行过破坏性导入以后,此脚本即消失,所以……
  42. #     exit ->
  43. #       • 什么也不做,直接关闭游戏。
  44. #
  45. #==============================================================================

  46. # * 特定格式

  47. #!!! remove_if_destructive
  48. # 我是要被删除的代码块
  49. #!!! end_remove_if_destructive

  50. #!!! replace_if_destructive
  51. # 我是要被取代的代码块
  52. #!!! with
  53. #~ # 我是要取代它的代码块
  54. #!!! end_replace_if_destructive

  55. module ScriptManager
  56.   #--------------------------------------------------------------------------
  57.   # ¤ 运行
  58.   #--------------------------------------------------------------------------
  59.   def self.run
  60.     return if !File.exists?("script_manager.txt")
  61.     mode = self.read("script_manager.txt")
  62.     case mode
  63.     when "export"
  64.       self.export
  65.       self.write("script_manager.txt", "watch")
  66.       exit
  67.     when "import"
  68.       self.import
  69.       self.write("script_manager.txt", "do nothing")
  70.       exit
  71.     when "blink"
  72.       self.import
  73.       self.export
  74.       self.write("script_manager.txt", "watch")
  75.       exit
  76.     when "watch"
  77.       t = File.mtime("Data/Scripts.rvdata2")
  78.       flag = false
  79.       if File.exist?("Scripts")
  80.         Files.list("Scripts").each do |path|
  81.           m = File.mtime(path)
  82.           if m > t
  83.             self.import
  84.             self.export
  85.             exit
  86.           elsif m < t
  87.             flag = true
  88.           end
  89.         end
  90.       end
  91.       if flag
  92.         self.export
  93.         exit
  94.       end
  95.     when "destructive_import"
  96.       self.import(true)
  97.       File.delete("script_manager.txt")
  98.       self.deleteDirectory("Scripts")
  99.       exit
  100.     when "exit"
  101.       exit
  102.     end
  103.   end
  104.   #--------------------------------------------------------------------------
  105.   # ¤ 导出
  106.   #--------------------------------------------------------------------------
  107.   def self.export
  108.     self.deleteDirectory("Scripts")
  109.     self.ensureDirectory("Scripts")
  110.     p "extracting script..."
  111.     script_mapper = []
  112.     load_data("Data/Scripts.rvdata2").each_with_index do |(num, title, contents), i|
  113.       contents = self.decrypt(contents)
  114.       if contents.empty?
  115.         script_mapper.push(title.empty? ? "" : "#{title}->")
  116.         next
  117.       end
  118.       filename = sprintf("%03d [%s].rb", i, title)
  119.       filename.gsub!("/", "/")
  120.       filename.gsub!("\\", "﹨")
  121.       filename.gsub!(":", ":")
  122.       filename.gsub!("*", "﹡")
  123.       filename.gsub!("\"", """)
  124.       filename.gsub!("<", "<")
  125.       filename.gsub!(">", ">")
  126.       filename.gsub!("|", "|")
  127.       filename.gsub!("?", "?")
  128.       contents.gsub!(/\r\n/, "\n")
  129.       self.write("Scripts/#{filename}", contents)
  130.       script_mapper.push("#{title}->#{filename}")
  131.       p filename
  132.     end
  133.     self.write("Scripts/000 Mapping.txt", script_mapper.join("\n"))
  134.     t = Time.new
  135.     File.utime(t, t, "Data/Scripts.rvdata2")
  136.     File.utime(t, t, "Scripts/")
  137.     p "extraction complete."
  138.   end
  139.   #--------------------------------------------------------------------------
  140.   # ¤ 导入
  141.   #--------------------------------------------------------------------------
  142.   def self.import(destructively = false)
  143.     self.ensureDirectory("Scripts")
  144.     p "loading script..."
  145.     scripts = []
  146.     mapper_info = self.read("Scripts/000 Mapping.txt")
  147.     script_mapper = mapper_info.split("\n")
  148.     script_mapper.push("") if mapper_info.slice(-1, 1) == "\n"
  149.     script_mapper.each do |entry|
  150.       title = ""
  151.       contents = ""
  152.       if !entry.empty?
  153.         if entry =~ /^(.*)->(.*)$/
  154.           title = $1
  155.           contents = $2.empty? ? "" : self.read("Scripts/#{$2}")
  156.           if destructively
  157.             next if contents =~ /^#!!! skip_if_destructive/
  158.             contents.gsub!(/#!!! remove_if_destructive\n.*?#!!! end_remove_if_destructive\n?/m, "")
  159.             contents.gsub!(/#!!! replace_if_destructive\n.*?#!!! with\n(.*?)#!!! end_replace_if_destructive\n?/m) { $1.gsub(/^#~/, "") }
  160.           end
  161.           p title
  162.         else
  163.           title = "<ERROR>"
  164.           contents = "# Error loading this script:\n# #{entry}"
  165.         end
  166.       end
  167.       scripts.push([nil, title, self.encrypt(contents)])
  168.     end
  169.     save_data(scripts, "Data/Scripts.rvdata2")
  170.     p "script loaded."
  171.   end
  172.   #--------------------------------------------------------------------------
  173.   # ¤ 读文件
  174.   #--------------------------------------------------------------------------
  175.   def self.read(path)
  176.     File.open(path, 'r:utf-8') {|f| return f.read() }
  177.   end
  178.   #--------------------------------------------------------------------------
  179.   # ¤ 写文件
  180.   #--------------------------------------------------------------------------
  181.   def self.write(path, contents)
  182.     File.open(path, 'w:utf-8') {|f| f.write(contents) }
  183.   end
  184.   #--------------------------------------------------------------------------
  185.   # ¤ 如果文件夹不存在则创建
  186.   #--------------------------------------------------------------------------
  187.   def self.ensureDirectory(path)
  188.     Dir.mkdir(path) if !File.exist?(path)
  189.   end
  190.   #--------------------------------------------------------------------------
  191.   # ¤ 删除文件夹和所有内容
  192.   #--------------------------------------------------------------------------
  193.   def self.deleteDirectory(path)
  194.     return if !File.exist?(path)
  195.     if File.directory?(path)
  196.       self.list(path).each {|title| self.deleteDirectory(title) }
  197.       Dir.rmdir(path)
  198.     else
  199.       File.delete(path)
  200.     end
  201.   end
  202.   #--------------------------------------------------------------------------
  203.   # ¤ 列出直属某文件夹的所有文件名
  204.   #--------------------------------------------------------------------------
  205.   def self.list(directory, filter = nil)
  206.     directory += "/" if directory.slice(-1, 1) != "/"
  207.     directory += "*"
  208.     array = Dir.glob(directory)
  209.     array.reject! {|str| !str =~ filter } if filter.is_a?(Regexp)
  210.     return array
  211.   end
  212.   #--------------------------------------------------------------------------
  213.   # ¤ 压缩文本
  214.   #--------------------------------------------------------------------------
  215.   def self.encrypt(string)
  216.     return Zlib::Deflate.deflate(string)
  217.   end
  218.   #--------------------------------------------------------------------------
  219.   # ¤ 解压文本
  220.   #--------------------------------------------------------------------------
  221.   def self.decrypt(string)
  222.     return Zlib::Inflate.inflate(string).force_encoding("UTF-8")
  223.   end
  224. end

  225. ScriptManager.run
复制代码


---------- 2019/6/6 ----------
• 增加了 watch 指令。会自动检查脚本的最后修改时间,如果有任何脚本文件的最后修改时间晚于 "Data/Scripts.rvdata2" 则自动 blink;否则,如果有任何脚本文件的最后修改时间早于 "Data/Scripts.rvdata2" 则自动导出。每次导出文件,都会将脚本文件和 "Data/Scripts.rvdata2" 的最后修改时间设为完全相同,且只在所有文件的最后修改时间都完全相同的情况下,watch 模式的脚本管理模块才会不进行任何动作。

Lv4.逐梦者

梦石
0
星屑
9617
在线时间
566 小时
注册时间
2017-9-28
帖子
208
2
发表于 2019-6-5 10:24:49 | 只看该作者
本帖最后由 hyrious 于 2019-6-5 10:31 编辑

好久以前我也写过一个(x

其实对于脚本工作,你可以在脚本编辑器【插件脚本】处写一句
  1. require 'Scripts/main'
复制代码
这样游戏文件夹下 Scripts 目录下的 main.rb 就被“插入”到游戏里了,而且不用重启编辑器,外置脚本里可以继续 require 引入别的文件。

一个更有操作性的例子参考喵 5 的这个帖子

当然使用外置脚本后就有一系列要注意的地方,比如

  • 脚本正文有中文等非 ASCII 字符时,使用 UTF-8 编码并在脚本开头加上 # coding: utf-8
  • 热加载?调试?(广告 1/1)
  • 是不是可以实现 MV 的【插件管理器】


进而,你可能注意到了 RM 编辑器本身由于会缓存项目状态,所以开着编辑器的情况下改任何数据库文件都是无效的,而且一些游戏作者会扩展数据库(普通的【备注】已经满足不了他们了),此时……重写一个编辑器就好了!(x


总之,脚本真好玩.jpg
喵喵喵
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1680
在线时间
91 小时
注册时间
2019-5-16
帖子
45
3
 楼主| 发表于 2019-6-5 16:49:36 | 只看该作者
本帖最后由 Aephiex 于 2019-6-5 17:06 编辑
hyrious 发表于 2019-6-5 10:24
好久以前我也写过一个(x

其实对于脚本工作,你可以在脚本编辑器【插件脚本】处写一句


原来还能这样…… Data/Scripts.rvdata2 里面只剩下一句 require 和游戏开始,剩余的脚本全部放在外面管理。游戏发布的时候再统一装进去。听起来好方便。emmm

之前试着论坛搜索“导出脚本”,倒是搜到了前者,但是我希望有以下特性,所以最后还是自己写了:
• 导出的文件会被 Windows 自动按照在编辑器里的顺序排列,比如说,用数字编号作为文件名开头
• 方便地新增、删除、排序脚本,且不丢失脚本标题等信息。
而后者则没有搜到……emmm
如果搜到的话我可能就不会自己写了。

我也想扩展数据库内容,因为编辑器真的好难用!不管是哪里都好难用!但是那样的话要针对每个不同的 RPG::XXX 对象写个文本化和解析文本的东西……
我想过用 json,但是 ruby 自带的 json 在 v1.9.2 以后才是标准库,而 rmva 的 ruby 是 v1.9.1,只正好差了一个小版本……
而正因为 ruby 自带的 json 在 v1.9.2 以后成为了标准库,谷歌搜索 "ruby parse json" 之类的关键字找到的全都是建议你使用标准库。
某一次我看到一个标题叫:「如何使用纯 ruby 实现 json 解析?」我兴高采烈地点了进去,结果里面的最高赞回答是:「ruby 自带的 json 在 v1.9.2 以后成为了标准库,所以使用 ruby 自带的 json 是“纯 ruby”。」
自己写 json 解析器……我,我,我才懒得。

点评

看到楼下m5的回答了……已抄走(  发表于 2019-6-6 14:44
json有okjson和json_purl,我稍微修改了一下okjson以适应rm系列:https://gitlab.com/gxm/rgsos/tree/master/Base_Scripts  发表于 2019-6-6 14:42
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (暗夜天使)

只有笨蛋才会看到

梦石
1
星屑
20915
在线时间
9331 小时
注册时间
2012-6-19
帖子
7105

开拓者短篇九导演组冠军

4
发表于 2019-6-5 19:39:12 | 只看该作者
Aephiex 发表于 2019-6-5 16:49
原来还能这样…… Data/Scripts.rvdata2 里面只剩下一句 require 和游戏开始,剩余的脚本全部放在外面管 ...

https://github.com/RGSS3/SJSON
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1680
在线时间
91 小时
注册时间
2019-5-16
帖子
45
5
 楼主| 发表于 2019-6-6 08:08:04 | 只看该作者
喵呜喵5 发表于 2019-6-5 19:39
https://github.com/RGSS3/SJSON

谢谢!
要是我早点来贵坛的话能少走不少弯路吧……
回复 支持 反对

使用道具 举报

Lv3.寻梦者

小睡

梦石
0
星屑
2061
在线时间
508 小时
注册时间
2010-8-1
帖子
1378
6
发表于 2019-6-6 11:58:12 | 只看该作者
Aephiex 发表于 2019-6-5 16:49
原来还能这样…… Data/Scripts.rvdata2 里面只剩下一句 require 和游戏开始,剩余的脚本全部放在外面管 ...

如果有谁去改写rgss3让它支持更高版本的ruby就好了…可惜…官方是不可能的了……
欢迎来到6R RTP Maker!加入RTP行走图制作组的行列吧!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-20 17:25

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表