| 赞 | 54 |
| VIP | |
| 好人卡 | |
| 积分 | 46 |
| 经验 | |
| 最后登录 | 2026-9-12 |
| 在线时间 | 1207 小时 |
- 梦石
- 0
- 星屑
- 4623
- 在线时间
- 1207 小时
- 注册时间
- 2016-4-7
- 回帖
- 944

|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 shitake 于 2018-4-6 00:54 编辑
众所周知,rm 新三作(此处借用晴兰的说法,RPG Maker 95、RPG Maker 2000、RPG Maker 2003 为旧三作,RMXP/RMVX/RMVA 为新三作)虽然有脚本支持,且编辑器也自带了脚本编辑器。但是,由于脚本被存在 Scripts.rvdata2 中。很难像开发普通的 ruby 程序一样开发(例如使用 JB 家的IDE之类的)。
即使如此,不少前辈也做过各种把脚本编写这一工作搬到外部的尝试。比如写完再手动粘回去之类的。期间我个人也搞出了 RM.dll 这种方法:https://rpg.blue/thread-380195-1-1.html
这种把脚本打包在一个文件的情况,在很多场景都会遇到。比如前端开发。不过人家有完整的工具流(以前的gulp,现在的webpack等)。最近看到⑨姐姐和黄鸡的工作,有动手重启了 RGUI 的坑。开发过程中顺手写了个按依赖对rm文件做合并的脚本。有了这个,无论是把脚本合并在一个文件再复制到 Scripts.rvdata2 中,或者直接由此来生成 Scripts.rvdata2 都行。
代码[pre lang="ruby" file="rm_pack.rb"]require 'fileutils'
module RmPack
class RmPack
class << self
# @return [Array<Proc>]
attr_reader :loaders
def use(loader)
@loaders = [] unless @loaders
@loaders << loader
end
end
attr_reader :excludes
attr_reader :source
attr_reader :output
def initialize
@visited = {}
@cont = []
@count = 0
@files = {}
end
def get_requires
until @cont.empty?
visit(@cont.shift, @visited, @cont)
end
end
def get_file_name(file)
"\n\n# File #{file.gsub(Dir::getwd + '/', '')}\n\n"
end
def get_file(file)
@files[file]
.gsub("# encoding:utf-8\n", '')
.strip
end
def init_loaders
RmPack.loaders.map! { |loader| loader.new(self) }
end
def create_file
FileUtils.mkdir_p(File.dirname(@output))
File.open(@output, 'w')
end
def pack(conf)
@source = conf[:source]
@excludes = conf[:excludes] || []
@output = conf[:output] || './out.rb'
@excludes.map!{|exclude| File.expand_path(exclude, File.dirname(@source)) }
init_loaders
@cont << @source
get_requires
file = create_file
file.write reorder(@source, @visited[@source]).map { |f|
file_str = get_file(f).strip
next '' if file_str == ''
@count += 1
puts f
get_file_name(f) + file_str
}.reduce(:concat).strip.gsub('', '')
puts "Finish! #{@count} files."
end
# @param [String] file
# @param [Hash] visited
# @param [Array] cont
def visit(file, visited, cont)
return if (visited.include? file)
visited[file] = []
File.open(file) do |f|
@files[file] = f.readlines.map { |str|
delete = false
RmPack.loaders.each do |loader|
if loader.match(str, f)
depends = loader.file
cont << depends unless cont.include? depends
visited[file] << depends
end
delete = delete || loader.delete
end
delete ? '' : str
}.reduce(:concat)
end
end
# @param [String] file
# @param [Array<String>] dependency
def reorder(file, dependency)
return [file] if dependency == []
dependency.map {|dep| reorder(dep, @visited[dep]) }.push(file).flatten.uniq
end
end
class RequireRelativeLoader
attr_reader :file
attr_reader :delete
def initialize(conf)
@excludes = conf.excludes
@file = ''
@match_exp = /require_relative[^\n]*/
@file_exp = /require_relative\s*'([^']*)'/
@mark_exp = /require_relative\s*'[^']*'\s*\#delete\s/
@delete = true
end
def add_suffix(str)
return str + '.rb' unless str.reverse =~ /^br\./
str
end
def match(str, f)
@delete = false
return false if str !~ @match_exp
@delete = true
return false if str =~ @mark_exp
return false if str !~ @file_exp
@file = File.expand_path(add_suffix($1), File.dirname(f))
return false if @excludes.include? @file
@file
end
end
RmPack.use(RequireRelativeLoader)
end
def rm_pack
RmPack::RmPack.new
end[/pre]
由于只是单纯的字符串操作,并没有实际对脚本做解释,所以对于动态的 require 是没法支持的。对于循环引用也需要手动消除,否则就会爆栈。另外,目前只写了 require_relative 所对应的 loader。所以也只对 require_relative有响应。
消除方法是在其中一方的 require_relative 后加上 #delete。例如
a.rb
[pre lang="ruby"]require_relative 'b'[/pre]
b.rb
[pre lang="ruby"]require_relative 'a' #delete[/pre]
在最后的文件中, a.rb 的内容将位于 b.rb 之后。
另外,一个约定是 require_relative 后跟的字符串用单引号。
用这个脚本,再加上 https://rpg.blue/thread-396263-1-1.html 这个,我们就可以很愉快的把脚本开发挪到 Ruby Mine/vs code/sublime text 等编辑器/集成开发环境上啦
一个使用这套方法的例子:https://github.com/molingyu/rgui
|
|