查看: 2156|回复: 1

[胡扯] RMVA的次世代式开发【雾

[复制链接]
梦石
0
星屑
4623
在线时间
1207 小时
注册时间
2016-4-7
回帖
944

开拓者

发表于 2018-4-6 00:43:59 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 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


附庸的附庸不是我的附庸,女儿的女儿还是我的女儿。CK2沉迷ing
梦石
0
星屑
9292
在线时间
2504 小时
注册时间
2011-5-20
回帖
14521

开拓者

发表于 2018-4-6 00:54:00 | 显示全部楼层
感觉现阶段脚本编辑器加一个自动补全和备选补全应该够了···
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部