晴兰的秘密社团 https://seiran.mist.so Ruby与RGSS研究 Tue, 15 Jan 2019 10:09:01 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.9.5 RML v2.0 发布 https://seiran.mist.so/rml/rml.html https://seiran.mist.so/rml/rml.html#respond Thu, 10 Jan 2019 21:13:59 +0000 http://seiran.mist.so/?p=201 项目地址:https://github.com/RGSS3/PML

下载地址:https://github.com/RGSS3/PML/archive/v2.0.zip

支援地址:https://afdian.net/@seiran

 

2.0和1.x相比
最主要的是调用方式变更
所有命令的格式是
./rml2 command args
比如./rml2 run -code “msgbox 1”

然后新建一个模板变得容易,例如你可以复制Templates目录下一份RMVXA的文件夹,粘贴并更名为XAS,用VA打开它并且真的塞一个XAS工程进去,然后你就可以直接用./rml2 run -Gen XAS ….
来执行了

Ruby方面,已经更新到Ruby2.6。

即将进行一波基于工程的操作,下面是即将开展的计划,连rmk这个命令名字也是暂定的:

 

# 新建一个Project1文件夹,用XAS工程模板去初始化他:
rmk new Project1 -Gen XAS

# 进入Project1文件夹
cd Project1

# 运行
rmk run 
# 调试
rmk debug
# 假设有两个调试插件分别叫F5HP,F6MP,在这次调试进程中使用:
rmk debug F5HP,F6MP
# 打包
rmk package
# 新建一个ScriptEvent(假设我们有个生成器叫脚本事件,用脚本的方式描述一个地图事件)
rmk gen ScriptEvent se1
# 在Map001使用
rmk use Map001 se1

 

]]>
https://seiran.mist.so/rml/rml.html/feed 0
我的shell会算矩阵,你的呢 https://seiran.mist.so/uncategorized/%e6%88%91%e7%9a%84shell%e4%bc%9a%e7%ae%97%e7%9f%a9%e9%98%b5%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%91%a2.html https://seiran.mist.so/uncategorized/%e6%88%91%e7%9a%84shell%e4%bc%9a%e7%ae%97%e7%9f%a9%e9%98%b5%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%91%a2.html#respond Fri, 16 Mar 2018 07:37:13 +0000 http://seiran.mist.so/?p=196

$ [1\;2\;3].*[4 5 6] | sed 's/;/\n/g'
[4 5 6
 8 10 12
 12 15 18]

实现:

我今天知道有个函数名叫command_not_found_handle于是写了下面代码

$ command_not_found_handle(){
>   /f/julia/bin/julia -e "print($1 $2 $3 $4 $5 $6 $7 $8 $9)"
> }

 

]]>
https://seiran.mist.so/uncategorized/%e6%88%91%e7%9a%84shell%e4%bc%9a%e7%ae%97%e7%9f%a9%e9%98%b5%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%91%a2.html/feed 0
lean and mean https://seiran.mist.so/uncategorized/lean-and-mean.html https://seiran.mist.so/uncategorized/lean-and-mean.html#respond Mon, 26 Jun 2017 15:47:48 +0000 http://seiran.mist.so/?p=193

<body>
<script>
    let $ = parent => (tagName, attr, fn) => {
       if(tagName){
            let node = Object.assign(document.createElement(tagName), attr);
            fn && fn($(node));
            (parent || document.body).appendChild(node);
       }else{
            fn(parent);
       }
    };


    let $E    = ev => fn => p => p.addEventListener(ev, fn);
    let click = $E('click');

    $()("div", {style: 'color: red;'}, $ => {
        $("ul", {style: 'text-decoration: underline;'}, $ => {
            for(let i = 0; i < 10; ++i){
                $("li", {innerText: i}, $ => {
                     $(null, null, click(_ => alert(i)))
                });
            }
        });
    });




</script>
</body>

 

]]>
https://seiran.mist.so/uncategorized/lean-and-mean.html/feed 0
嵌入CRuby脚本引擎的一个历史遗留问题和解决方案 https://seiran.mist.so/uncategorized/embed-cruby.html https://seiran.mist.so/uncategorized/embed-cruby.html#comments Sun, 26 Feb 2017 22:25:46 +0000 http://seiran.mist.so/?p=181 最近又需要嵌入CRuby,又遇到了这个问题,

主要是当使用net/http等socket相关的库时,会提示找不到read_nonblock方法。

这个问题的解决方案很简单,补充一个定义即可

class IO
  def read_nonblock(size, buf = nil, exception)
     __read_nonblock(size, buf, exception)
  end
end

但是使用ruby或者irb时就没有这个问题,为什么呢

(这也不是操作系统相关的问题,虽然我用的是windows)

irb下通过IO.instance_method(:read_nonblock).source_location可以发现这个方法的定义在一个叫”<internal:prelude>”的文件中定义,显然是内部自己的奇怪操作。

这个定义可以通过ruby_init_options函数来初始化,然而。

然而经过搜索发现这个函数一直有人提出,将它导出作为feature,结果从1.9到2.4都没有实行,这个函数直到现在,现成编译的版本从未导出符号。

所以,现在初始化ruby解释器,如果不想从源码修改去掉函数的static存储类关键字这里开始,一个比较合适的写法是:

int argc = 0;
char **argv = 0;
static char* args[] = {(char *)"ruby",
  #ifdef WIN32
     (char *)"nul"
  #else
     (char *)"/dev/null"
  #endif
};
ruby_sysinit(&argc, &argv);
ruby_init();
ruby_init_loadpath();
ruby_process_options(2, &args); //假装有个ruby程序执行了一个程序,从而隐含调用prelude定义

 

 

]]>
https://seiran.mist.so/uncategorized/embed-cruby.html/feed 1
Ruby自学顾问系列 https://seiran.mist.so/%e8%87%aa%e5%ad%a6%e9%a1%be%e9%97%ae/self-promoting.html https://seiran.mist.so/%e8%87%aa%e5%ad%a6%e9%a1%be%e9%97%ae/self-promoting.html#respond Mon, 14 Nov 2016 07:40:45 +0000 http://seiran.mist.so/?p=177 321321321

]]>
https://seiran.mist.so/%e8%87%aa%e5%ad%a6%e9%a1%be%e9%97%ae/self-promoting.html/feed 0
一种简单啰嗦的强行point-free的方法 https://seiran.mist.so/uncategorized/force-stupid-point-free-2.html https://seiran.mist.so/uncategorized/force-stupid-point-free-2.html#respond Wed, 10 Aug 2016 08:25:15 +0000 http://seiran.mist.so/?p=170 最近做codewars上的Haskell的水题的时候(难题我也不会),基本上是尽量用一种point-free的风格(https://en.wikipedia.org/wiki/Tacit_programming)去写的。我个人理解也就是函数的实现不写出参数,只通过curry和组合等来实现,例如:

-- let add a b = a + b
let add = (+)

-- let factorial n = product [1..n]
let factorial = product . enumFromTo 1

-- let isPalindrome str = reverse str == str
let isPalindrome = reverse >>= (==)

-- 下面几个的point-free style作为练习
-- let k f x      = f
-- let g x y f    = f x y
-- let triple f x = f x x x

另外这里也不认可出现用lambda形式代入参数如:

let g = \x y f -> f x y
--这也不是本文讨论的

这里用一个生成的方法来实现一个比较通用的方案,其实应该也可以用haskell的point-free风格代码来实现这套代码而不是生成,这里用Ruby生成。

注意到:

let f x y = a (b x y)

也可以写成

let f x y = ((a.) . b) x y
-- 即
let f = (a.) . b

每次多一个参数就会是最里面多一个

... (a .) .   ...
... (  ((a .) .) . (a .)) . ...

等等的结构,也就是组合前面是一个(a .)的形式

 

另外,如果我们把tuple视为栈

> let f = (3, (2, 1))
> let push = (,)
 push 4 f -- (4, (3, (2, 1)))
> let pop = snd
 pop f -- (2, 1)
> let modify = first
 modify (+1) f -- (4, (2, 1))
> let apply = (uncurry ($) . (first *** id))
> let g = ((+1), (2, 3))
apply g -- (3, 3)
另外实现几个从forth拿过来的栈运算
>let vdup = modify (fst >>= (,))
复制栈顶 (a, b) -> b
vdup f -- (3, (3, (2, 1))
>let vswap = modify ((fst . snd) &&& (fst &&& (snd . snd)))
交换栈顶二个元素 (a, (b, c)) -> (b, (a, c))
vswap f -- (2, (3, 1))
>let vover = modify ((fst . snd) &&& id)
over运算, 把栈顶的下一个元素复制一份压在顶上,(a, (b, c)) -> (b, (a, (b, c)))
vover f -- (2, (3, (2, 1)))

等等可以把forth的栈操作都实现出来

于是这样就可以实现一组DSL(https://github.com/Artoria/pf-builder)了,比如海伦公式的实现

heron a b c = let s = (a + b + c) / 2 in s * (s – a) * (s – b) * (s – c)

下面的思路是通过build生成函数体

首先把三个参数a b c转成[c, b, a]

然后应用 (/2) . sum得到s

然后把s变成(s-), map到[c, b, a]上,变成[s-c, s-b, s-a], 然后对他它用product, 并且乘上这个积和s

就是结果

puts Builder.new{
  push_arg
  modify "(: [])"
  push_arg
  push_const "(:)"
  apply
  apply
  push_arg
  push_const "(:)"
  apply
  apply

  modify_dup "(/2) . sum"
  vover
  vover
  modify "(-)"
  push_const "map"
  apply 
  apply
  modify "product"
  push_const "(*)"
  apply
  apply
  modify "sqrt"
}.finish!

得到的结果,反正就是不能看了:

((((((((((((((((((((((((((( fst . (first (sqrt))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((*)))) . (first (product))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) (map))) . (first ((-)))) . ((fst . snd) &&& id)) . ((fst . snd) &&& id)) . (first ((/2) . sum))) . (fst >>= (,))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((:)))) .) . flip (,)) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((:)))) .) . flip (,)) . (first ((: [])))) .) . flip (,)) undefined)

另外,因为point-free的函数也是函数,可以嵌套

比如fib n = foldr (\_ (x, y) -> (y, x+y)) (1, 0) [1..n]

puts Builder.new {
  push_arg
  modify "enumFromTo 1" 
  push_const "(1, 0)"
  push_const Builder.new{
    push_arg 
    vpop
    push_arg
    modify "snd &&& (liftA2 (+) fst snd)"
  }.finish!
  push_const "foldr"
  apply
  apply
  apply
  modify "snd"
}.finish!

得到的结果

((((((((((( fst . (first (snd))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) (foldr))) . ((,) (((((((( fst . (first (snd &&& (liftA2 (+) fst snd)))) .) . flip (,)) . snd) .) . flip (,)) undefined)))) . ((,) ((1, 0)))) . (first (enumFromTo 1))) .) . flip (,)) undefined)

 

 

]]>
https://seiran.mist.so/uncategorized/force-stupid-point-free-2.html/feed 0
简单的Ruby直接到机器码的生成器(X86) RPGMaker兼容 https://seiran.mist.so/uncategorized/simple-ruby-mc-gen.html https://seiran.mist.so/uncategorized/simple-ruby-mc-gen.html#comments Fri, 06 May 2016 19:45:44 +0000 http://seiran.mist.so/?p=164 毕竟Bellard大牛的OTCC里面就是到处飞机器码,并且,他是一边解析词法符号一边就直接产生了,真是棒棒的不按套路却又无比正经的写法

=begin
Author: 晴兰@66RPG UID=131313
LICENSE: CC-BY-SA 3.0 [url]http://creativecommons.org/licenses/by-sa/3.0/deed.zh[/url]
Purpose: Simple Machine Code Generator. Limited operation supported
=end

CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L'

def prolog(num_of_var = nil)
  [0x55, 0x8b, 0xec].pack("C*") + (num_of_var ? [0x83, 0354, num_of_var * 4].pack("C*") : "")
end

def epilog
  [0xc9, 0xc2, 0x10].pack("CCS")
end

def render(list, num_of_var = nil)
 prolog(num_of_var) + render_rec(list) + epilog
end

def check_var(list)
  return -4 * list[1]  if list[0] == :var
  raise "lvalue required for #{list.inspect}"
end

def render_rec(list)  
  case list.first
    when :lit
      [0xb8, list[1]].pack("CL")
    when :arg
      [0x8b, 0105, 4 + list[1] * 4].pack("C*")
    when :do
      list[1..-1].map{|x| render_rec(x)}.join
    when :var
      [0x8b, 0105, -4 * list[1] ].pack("C*")
    when :assign
      id = check_var(list[1])
      render_rec(list[2]) + [0x89, 0105, id].pack("C*")
    when :+, :-, :&, :^, :|
      render_rec(list[2]) + "\x50" + render_rec(list[1]) + 
      [0132, "+|ab&-^".index(list.first.to_s) << 3 | 3, 0302].pack("C*")
    when :<, :>, :'==', :'!=', :>=, :<=
      v = list.first.to_s
      l = v.length
      f = v.ord rescue v[0]
      u = "0000G+000000<HF>".index((f + (l > 1 ? 10 : 0)).chr)
      render_rec(list[2]) + "\x50" + render_rec(list[1]) + 
      [0132, 073, 0302, 0x0f, 0x90 + u, 0300, 0x81, 0340, 0xff, 0x00, 0x00, 0x00].pack("C*")
    when :nil; ""
    when :if
      cond, thenpart, elsepart = list[1..-1].map{|x| render_rec(x)}
      thenpart += [0xe9, elsepart.length].pack("CL")
      cond     += [0x85, 0300, 0x75, 0x05, 0xe9, thenpart.length].pack("CCCCCL")
      cond     + thenpart + elsepart
    when :for
      init, cond, incr, body = list[1..-1].map{|x| render_rec(x)}
      addbyte = [0x85, 0300, 0x75, 0x05, 0xe9, body.size + incr.size + 5].pack("CCCCCL")
      fbody = body + incr + 
              [0xe9, -(body.size + incr.size + cond.size + addbyte.size + 5)].pack("CL")
      init + cond + addbyte + fbody
  end
end

x = render(
 [:do,
   [:assign, [:var, 1], [:lit, 0]], 
   [:for, 
       [:assign, [:var, 2], [:lit, 1]],
       [:<, [:var, 2], [:lit, 101]],
       [:assign, [:var, 2], [:+, [:var, 2], [:lit, 1]]],
       [:assign, [:var, 1], [:+, [:var, 1], [:var, 2]]]
   ],
   [:var, 1]
 ], 2
)

=begin
 int var1 = 0;
 for(int var2 = 1; var2 < 101; var2+=1)
    var1 += var2;
 return var1
=end

p CallWindowProc.call x, 0, 0, 0, 0  #=>5050

 

]]>
https://seiran.mist.so/uncategorized/simple-ruby-mc-gen.html/feed 1
利用set_trace_func方法来判断一个方法是否被alias过 https://seiran.mist.so/ruby/%e5%88%a9%e7%94%a8set_trace_func%e6%96%b9%e6%b3%95%e6%9d%a5%e5%88%a4%e6%96%ad%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%e6%98%af%e5%90%a6%e8%a2%abalias%e8%bf%87.html https://seiran.mist.so/ruby/%e5%88%a9%e7%94%a8set_trace_func%e6%96%b9%e6%b3%95%e6%9d%a5%e5%88%a4%e6%96%ad%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%e6%98%af%e5%90%a6%e8%a2%abalias%e8%bf%87.html#comments Mon, 25 Aug 2014 19:13:06 +0000 http://seiran.mist.so/?p=147 其实就是囧叔跟我说的利用irb的help相同的技巧,在set_trace_func下调用,在合适的binding中取得信息并且直接用throw…catch来跳出(实际并不执行方法体),

详细方法见代码注释:

def custom_trace(sym, &b)
  u = method(sym)                            #得到方法
  v = u.arity < 0 ? [] : [0] * u.arity       #伪造方法参数
  x = lambda{u.call(*v)}                     #x.call将要调用这个方法,但是实际上不会真的调用
  set_trace_func Proc.new
  ret = catch(:gogogo) do                         #捕捉gogogo并且返回新的方法名                          
    x.call                                  #执行上述方法
  end
  set_trace_func nil#取消跟踪
  ret
end

def aliased?(sym)
  sym != custom_trace(sym) do |*e|
    next unless e[0] == "call"       #定位是call
    throw :gogogo, e[-3]             #退出, e[-3]就是当时的方法名
  end
end

def a u 
  puts "Hello"
end
alias b a

p aliased? :b #=> true
p aliased? :a #=> false

顺便,在Ruby1.8的Method没有定义source_location的情况下取得方法定义的位置的方法,以及取得参数名的方法。

def source_location(sym)
  custom_trace(sym) do |*e|
    next unless e[0] == "call"      
    throw :gogogo, eval("[__FILE__, __LINE__]", e[-2])
  end
end

def parameters(sym)
    custom_trace(sym) do |*e|
    next unless e[0] == "call"      
    throw :gogogo, eval("local_variables", e[-2]) 
=begin
  第一行就出现的本地变量是一般就是参数
  除非有意写成def add(a,b); s = 3
  这个方法除了返回"a" "b"还会返回"s"
=end
  end
end

 

 

]]>
https://seiran.mist.so/ruby/%e5%88%a9%e7%94%a8set_trace_func%e6%96%b9%e6%b3%95%e6%9d%a5%e5%88%a4%e6%96%ad%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%e6%98%af%e5%90%a6%e8%a2%abalias%e8%bf%87.html/feed 2
在RM中使用gem和bundle https://seiran.mist.so/rgss/%e5%9c%a8rm%e4%b8%ad%e4%bd%bf%e7%94%a8gem%e5%92%8cbundle.html https://seiran.mist.so/rgss/%e5%9c%a8rm%e4%b8%ad%e4%bd%bf%e7%94%a8gem%e5%92%8cbundle.html#respond Mon, 25 Aug 2014 17:28:10 +0000 http://seiran.mist.so/?p=136 其实很多东西跟普通ruby使用gem和bundle是一样的,但是RM没有自带rubygems,因此有两种思路,一种是给RM嵌入一个rubygems,一种是利用另一个Ruby(也就是实际运行bundle的ruby.exe等)来发现require需要的文件和依赖关系。

下面以第二种思路为例,例子任务是使用iniparse这个gem来帮助RM里面读Game.ini。

注意:RPGMaker系列本身不支持载入.so文件,因此能用到的gems只能是纯Ruby形式的源文件组成的代码,这个文章与这个限制无关,也无意绕过这个限制。只是提供了另一种管理脚本插件的思路:借用rubygems。产生的gem目录也可以最后放在加密的rgssad(rgss2a/rgss3a)文件里面并用某种手段当做本地目录读出来,从而保证了加密保护游戏程序的语义,当然这里也不讨论对gem目录的加密和解包具体方法。

1. 首先像正常使用bundle一样在Game.exe目录下建立一个gemfile:

source 'http://ruby.taobao.org'

gem 'iniparse'

2. 用bundle在工程目录安装所需的gems:

用cmd在工程目录下运行下列代码。

bundle install --path gems

3. 在RM的脚本编辑器中插入一段辅助代码,让require可以自动去找到我们指定的gem:

def rb(code, args = nil)
  open "run.rb", "w" do |f|
    f.write "
      class Output
        def <<(obj)
          puts [Marshal.dump(obj)].pack('M')
        end
      end
      $output = Output.new
    "
    f.write code
  end
  system "ruby run.rb #{args}> list.txt"
  Marshal.load File.read('list.txt').unpack("M").first
end

module Kernel
 alias oreq require
 $:.concat rb %{ $output << $: }
 def require(a)
   u = rb %{$output << Gem.find_files(ARGV[0])}, a
   u.select(&FileTest.method(:file?)).any?{|req|oreq req}
 end

 Object::RUBY_VERSION = rb %{$output << RUBY_VERSION} 
 require 'rubygems'
 alias require oreq
end

 

4. 这个时候在脚本编辑器之后可以插入使用的代码了,这里我们用的是RGSS3(RPG Maker VX Ace)的代码例子:

require 'iniparse'
msgbox IniParse.parse(File.read('Game.ini'))["Game"]["Scripts"]

5. 最后,运行的方式是在cmd下运行下列代码,你也可以建立快捷方式:

bundle exec "Game.exe console"

 

]]>
https://seiran.mist.so/rgss/%e5%9c%a8rm%e4%b8%ad%e4%bd%bf%e7%94%a8gem%e5%92%8cbundle.html/feed 0
RGSS3Facets 0.02 https://seiran.mist.so/rgss/rgss3facets.html https://seiran.mist.so/rgss/rgss3facets.html#comments Sun, 23 Feb 2014 07:43:53 +0000 http://seiran.mist.so/?p=128 0.02

Class:
#基于类的通用cache系统,比如
x = Bitmap.cache(“Graphics/Parallaxes/Mountain4”) #你懂的
y = Bitmap.cache(“Graphics/Parallaxes/Mountain4”)
# x.object_id == y.object_id应该成立,同一个位图
#Bitmap.clear_cache #你懂的
#也可以是自定义对象
class A
def initialize(a, b)
@a, @b = a, b
end
end
x = A.cache(3, 5)
y = A.cache(3, 5)
#应该是同一个对象

# RGSS3Facets::CachePolicy 奇怪的东西:
Bitmap.cache_policy = RGSS3Facets::CachePolicy::Default #Cache在内存中,以Hash的形式记录,类似于默认脚本的Cache或者RPG::Cache
Bitmap.cache_policy = RGSS3Facets::CachePolicy::Marshal.new(Bitmap) #Cache不是在内存中而是以Marshal形式存到磁盘上
Bitmap.cache_policy = RGSS3Facets::CachePolicy::BareMarshal.new(Bitmap) #Cache不是在内存中而是以Marshal形式存到磁盘上,而且没有Marshal头,仅仅是直接调用了_dump和_load

Bitmap:
#Bitmap::MarshalPolicy bitmap的marshal方案可以是
Bitmap::MarshalPolicy = Bitmap::BitmapMarshalPolicy::Raw # [width, height, data].pack(“LLa*”)
Bitmap::MarshalPolicy = Bitmap::BitmapMarshalPolicy::RawCompress # [width, height, Zlib::Deflate.deflate(data)].pack(“LLa*”)
Bitmap::MarshalPolicy = Bitmap::BitmapMarshalPolicy::BitmapFile # Marshal内容相当于savebmp做的,也就是一个合法的bmp文件内容

Object:
load_script(name) #也就是eval read_data(name), TOPLEVEL_BINDING, “Load Script: #{name}”, 1

0.01

Object:
font.assign(:size=>5, :color=>Color.new(255,0,0,255)) # font.size=5; font.color = Color.new(255,0,0,255)
object.self # 返回本身,为了某些场合可以用&:self
object.deepcopy #=>某种深拷贝,也就是Marshal.load Marshal.dump object
object.template(“{{a}}, {{b}}”)#=>模板替换,也就相当于是”#{obj.a},#{obj.b}”,但模板内容可以是变量。
私有:
read_data(“Data/1.txt”) #=>读取Data/1.txt的内容,可以是加密包中的内容
write_data(“Data/1.txt”, “Hello”)#=>把Hello写到Data/1.txt,只能是磁盘上的,不会变更加密包
sugar(/\b类\b/){“class”} #=>宏替换,$RGSS_SCRIPTS.each{|x| x[3].gsub!(/\b类\b/){“class”}}
with(obj){}#=>obj.instance_eval{}
a = 5
ref{}[“a”]=3
a = ref{}[“a”]#=> 上下文变量的字符引用

Module:
Sprite_Base.each_object{|x| p x}#遍历Sprite_Base的实例
Vocab.each_constant{|value, name| p value, name}#遍历常量,以值和名的形式
MyModule.to_class #生成一个include了本模块的类(可以new了)
attr_constant :a, 5# 相当于def a(); 5; end

Proc:
lambda{|x| a}.call(a,b,c)可以写成lambda{|x| a}.update(a,b,c) lambda{|x| a}.fire(a,b,c)随便什么方法名都行
用method_missing实现的,不一定是call了

Range:
(1..5).clamp(a) # 如果a<1返回1 如果a>5返回5 否则返回a

Rect:
rect.each_slice(5, 5) do |r| … end # 将这个rect均匀分成5×5的部分,每一部分调用一下迭代器

Exception:
ex.raise # reraise ex
ex.translate(新的消息) # 返回一个和ex只有消息不同的异常对象,也就是ex.exception的别名

IO:
IO.binread(“1.txt”) #二进制读取1.txt
IO.binwrite(“1.txt”, “Hello”)#二进制写入1.txt

Symbol:
to_proc(这个功能VA本来就有)

String:
self.note.match_notes “<itemid = {{item}}>”, “<skillid = {{skill}}>”#如果self.note是一个”<itemid = 5> <skillid = 3>”的话,返回一个hash {“item”=>5, “skill”=>3}

Bitmap:
bitmap.repeat_blt(bitmap.rect, another_bitmap, another_bitmap.rect)#尽可能平铺绘制another_bitmap的rect部分的内容
bitmap.address:位图地址
bitmap.savebmp(“1.bmp”): 以bmp格式保存为1.bmp
bitmap.savepng(“1.png”):以png格式保存为1.png
bitmap.getBitmap(rect) : 返回rect部分构成的新位图
bitmap.split(:A=>[0,0,128,128], :B=>[0,128,128,128]):返回一个hash,其中hash[:A]= bitmap.getBitmap(Rect.new(0,0,128,128)),类推
bitmap.with_tone!(tone)
bitmap.with_tone(tone) #用指定的色调tone来处理本位图

(下面是还在测试和修正的内容)
Sprite:
sprite.image #返回sprite能看到的图形,没有考虑tone,wave系列,考虑了src_rect
Plane:
plane.image #返回plane能看到的图形,没有考虑tone,考虑了屏幕大小和循环的情况

 

# http://seiran.mist.so

# mixin in to Kernel (Object)
module RGSS3Facets
  module RGSS
    Sprite   = ::Sprite
    Bitmap   = ::Bitmap
    Rect     = ::Rect
    Plane    = ::Plane
    Viewport = ::Viewport
    Tilemap  = ::Tilemap
  end

  class CPtr
    RMM = Win32API.new("Kernel32", "RtlMoveMemory", "LLL", "L")
    SLEN = Win32API.new("Kernel32", "lstrlenA", "L", "L")
    WLEN = Win32API.new("Kernel32", "lstrlenW", "L", "L")
    def initialize(start, len = 0)
      @start, @len = start, len
    end
    def [](st, le = nil)
      if !le
        CPtr.new(self[st * 4, 4].unpack("L").first)
      else
        buf = ""*le
        RMM.call *[buf, @start+st, le].pack("pLL").unpack("L*")
        buf = buf.force_encoding("US-ASCII") if buf.respond_to?(:force_encoding)
        buf
      end
    end
    def +(a)
      CPtr.new(@start+a, @len)
    end
    def []=(st, le, str)
      RMM.call *[@start+st, str, [le,str.size].min].pack("LpL").unpack("L*")
    end
    def to_s(size = nil)
      a = SLEN.call(to_i) 
      size ||= a
      self[0, [size, a].min]
    end
    def to_ws(size = nil)
      a = WLEN.call(to_i) 
      size ||= a
      self[0, [size, a].min * 2]
    end
    def to_i
      @start
    end
  end

  module Object
    public 
    def assign(hash)
      hash.each{|k, v|send "#{k}=", v}
      self
    end

    def self
      self
    end

    def identity
      lambda{|x| x}
    end

    def send_rescue(*a, &b)
      send *a rescue b.call
    end

    # [1,2,3,4,5].select(&true) 
    # 真是一点用都没有啊。。。
    def to_proc
      proc{ self }
    end

    def deepcopy
      Marshal.dump Marshal.load self  
    end

    def template(str, lb = "{{", rb = "}}")
      regexp = Regexp.new(Regexp.escape(lb) + "(.*?)" + Regexp.escape(rb))
      str.gsub(regexp) do send $1 end
    end

    def grep_var(cond)
      instance_variables.select{|x| cond === x}.each{|y| yield(instance_variable_get(y), y)}
    end

    def call_each(method, *args)
      args.each{|x|
        send method, *args
      }
    end

    private
    def weaken(a = StandardError)
      yield
    rescue a => ex
       raise
    rescue Exception => ex
        raise StandardError, ex.message, ex.backtrace
    ensure
        $@.slice!(0, 2) if $@ 
    end

    class NoException < StandardError; end
    class CallerHint < NoException; end

    def hint(array)
      raise CallerHint, "No Exception", array
    end

    def reraise(ex)
       raise ex.class, ex.message, ex.backtrace
    end

    def using(*a)
      yield
      a.reverse.each(&:dispose)
    end

    def write_data(name, *content)
      File.open(name, 'wb') do |f| content.each do |x| f.write x end end
    end

    def load_script(name)
      eval read_data(name), TOPLEVEL_BINDING, "Load Script: #{name}", 1
    end

    def read_data(name)
       begin
        File.open(name, 'rb') do |f| f.read end
      rescue Exception
          x = Marshal.method(:load)
          y = class << Marshal; self; end
          y.send(:define_method, :load){|a, *b| a.respond_to?(:read) ? a.read : a.to_s}
          ret = load_data(name)
          y.send(:define_method, :load, x)
          ret
       end
    end

    def sugar(regexp)
      $RGSS_SCRIPTS.each{|x| x[3] = x[3].gsub(regexp){ yield($~) } }
    end

    def with(obj, &a)
      obj.instance_eval &a
    end

    class Ref
      def initialize(binding = nil)
        @binding = binding || TOPLEVEL_BINDING
      end
      def [](text)
        eval(text, @binding)
      end
      def []=(text, obj)
        eval "#{text} = ObjectSpace._id2ref(#{obj.object_id})", @binding
      end
    end

    def ref(&b)
      Ref.new(b && b.binding)
    end
  end

  module Module
    def each_object
      ObjectSpace.each_object(self).each{|obj|
        yield obj
      }
    end

    def each_constant
      if block_given?
       constants.each{|x|
         yield const_get(x), x
       }
      else
       Hash[constants.map{|x| [x, const_get(x)]}]
      end
    end

    def to_class
      Class === self ? self : begin
        @_avatar ||= begin
          this = self
          Class.new do include this end
        end
      end
    end

    def attr_constant(sym, c)
      define_method(sym, lambda{c})
    end

    alias def_constant_method  attr_constant 
  end

  class FacadeClass
     def initialize(obj, *a)
       @obj  = obj
       @args = a  
     end
     def new(*a, &b)
       v = @obj.new(*a, &b)
       @args.each{|x| v = x.new(v)}
       v
     end
  end

  module CachePolicy
    class Default
      def initialize
        @cache = {}
      end
      def set_or_get(k)
        if has?(k)
          get(k)
        else
          set(k, yield)
        end
      end
      def set(k, v)
        @cache[k] = v
      end
      def get(k, v)
        @cache[k]
      end
      def remove(k)
        @cache.delete k
      end
      def has?(k)
        @cache.include?(k)
      end
      def clear
        @cache.each{|k, v| yield v, k} if block_given?
        @cache.clear
      end
    end

    class Marshal
      def initialize(klass)
        @klass = klass
        @base = "Data/Cache/#{encode_name klass}/"
        Dir.mkdir @base rescue 1
      end

      def set_or_get(k)
        if has?(k)
          get(k)
        else
          set(k, v = yield)
          v
        end
      end

      def encode_name(k)
        [::Marshal.dump(k)].pack("m").tr("\n+/", "_%$")
      end

      def filename(k)
        @base+encode_name(k)
      end

      def set(k, v)
        write_data filename(k), ::Marshal.dump(v)
      end

      def get(k)
        ::Marshal.load read_data filename(k)
      end

      def has?(k)
        FileTest.exist?(filename(k))
      end

    end

    class BareMarshal < Marshal
      def set(k, v)
        write_data filename(k), v._dump(0)
      end

      def get(k)
        @klass._load read_data filename(k)
      end
    end
  end

  module Class
    def [](*a)
      RGSS3Facets::FacadeClass.new(self, *a)
    end

    def cache_policy
      @cache_policy ||= CachePolicy::Default.new
    end

    def cache_policy=(obj)
      @cache_policy = obj
    end

    def c_new(*a, &b)
      cache_policy.set_or_get([a, b]){ new(*a, &b) }
    end

    alias cache c_new

    def c_clear
      cache_policy.clear do |x| x.dispose if x.respond_to?(:dispose) && !x.send_rescue(:disposed?){false} end
    end

    alias clear_cache c_clear
  end

  module Proc
    def method_missing(sym, *a, &b)
      call(*a, &b)
    end
  end

  module Range
    def clamp(val)
      [[first, val].max, exclude_end? ? last.succ : last].min
    end
  end

  module Rect
    def to_a
      [x, y, width, height]
    end

    def each_slice(div_x = 1, div_y = 1)
      cx, cy = width / div_x, height / div_y
      a = RGSS::Rect.new(0, 0, cx, cy)
      ny = y
      div_y.times{
        nx = x
        div_x.times{
          a.set(nx, ny, cx, cy)
          yield a
          nx += cx
        }
        ny += cy
      }
    end
  end

  module Binding
    def [](text)
       eval(text, self)
    end
    def []=(text, obj)
      eval "#{text} = ObjectSpace._id2ref(#{obj.object_id})", self
    end
  end

  module Exception
    def raise
      reraise self
    end
=begin
See what the doc said,
 exception([error_message]) 
 引数を指定しない場合は self を返します。
 そうでなければ、自身のコピーを生成し、message 属性を error_message にして返します。
 raise は、実質的に、例外オブジェクトの exception メソッドの呼び出しです。

 If no argument is given, return self.
 Otherwise, return a copy of self, with the message property changed to error_message
 actually 'raise' calls an Exception object's exception method.

 Because method 'exception' is actually a method to replace error message.
here I just rename it to translate
=end
    def translate(msg = nil)
      exception(msg || self.message)
    end

  end

  module IO_extend
    def binread(file)
      open(file, 'rb') do |f|
        f.read
      end
    end
    def binwrite(file, content)
      open(file, 'wb') do |f|
        f.write content
      end
    end
  end

  module RegExp
    def sub(str, *a, &b)
      str.sub(self, *a, &b)
    end
    def gsub(str, *a, &b)
      str.gsub(self, *a, &b)
    end
  end

  module Symbol
    def to_proc
      lambda{|*a| a.shift.send self, *a}
    end
  end

  module Comparable
    def min_with(obj)
      self < obj ? self : obj
    end
    def max_with(obj)
      self > obj ? self : obj
    end
  end

  module String
    def match_note(expr)
      a = Regexp.new expr.gsub(/\{\{(\S+)\}\}/){
        "(?<#$1>.*?)"
      }
      self =~ a
      $~
    end

    def match_notes(*args)
      ret = {}
      args.each{|x|
        v = match_note(x)
        v.names.each do |k|
          ret[k] = v[k]
        end
      }
      ret
    end
  end

  module Bitmap
    def repeat_blt_rect(dst, bm, src)
      y = dst.y
      ye = dst.y + dst.height
      xe = dst.x + dst.width
      sw = src.width
      sh = src.height
      while y < ye
        x = dst.x
        while x < xe
          blt(x, y, bm, src)
          x += sw
        end
        y += sh
      end
    end

    def repeat_blt(*args)
      x,y,w,h,bm,rect = args
      if RGSS::Rect === x
        return repeat_blt_rect(*args)
      else
        return repeat_blt_rect(RGSS::Rect.new(x, y, w, h), bm, rect)
      end
    end

    def address
      CPtr.new(object_id*2)[4][2][4]
    end

    def getBitmap(rect = self.rect)
      x = RGSS::Bitmap.new(rect.width, rect.height)
      x.blt(0, 0, self, rect)
      x
    end

    def split(opt = {})
      ret = {}
      opt.each{|k, v|
        r = case v
          when Rect then v
          when Array then Rect.new(*v)
        end
        ret[k] = getBitmap(r)
      }
      ret
    end

    def savebmp(filename)
      write_data filename, 
        [0x4d42, (len = width*height*4), 0, 0, 54].pack("SLSSL"),
        CPtr.new(object_id*2)[4][2][2][0, 40],
        address[0, len]
    end

    def savepng(filename)
      write_data filename,
        (signature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"),

        [13].pack("N"),
        (header = ["IHDR", width, height, 8, 6, 0, 0, 0].pack("a4NNCCCCC")),
        [Zlib.crc32(header)].pack("N"),

        [width*height*4+height].pack("N"),
        (dat = "IDAT" << Zlib::Deflate.deflate(address[0, (cw = width* 4) * (ch = height)].instance_eval{
           ret = []
           (ch-1).downto(0){|x|
             ret << "" << self[x*cw, cw].unpack("L*").map{|x|
               (x & 0xFF0000) >> 16 | (x & 0xFF) << 16 | (x & 0xFF00FF00)
             }.pack("L*")
           }
           ret.join
        })),
        [Zlib.crc32(dat)].pack("N"),
        "\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"
    end

    def with_tone!(tone)
      address[0, width*height*4] = address[0, width*height*4].unpack("L*").map{|long|
        b, g, r, a = [long].pack("L").unpack("C*")
        grayfull = (r * 38 + g * 75 + b * 15) >> 7
        r = tone.red  + r + (grayfull - r) * tone.gray / 256  
        g = tone.green+ g + (grayfull - g) * tone.gray / 256
        b = tone.blue + b + (grayfull - b) * tone.gray / 256
        [b, g, r, a].pack("C*").unpack("L").first
      }.pack("L*")
      self
    end

    def with_tone(tone)
      clone.with_tone!
    end

  end

  module Sprite
    def image
      b = RGSS::Bitmap.new(src_rect.width, src_rect.height)
      b.blt(0, 0, bitmap, src_rect)
      b
    end

    def image=(bitmap)
      rect = bitmap.rect
      rect.width  = [rect.width, src_rect.width].min
      rect.height = [rect.height, src_rect.height].min
      self.bitmap.blt(rect.x, rect.y, bitmap, bitmap.rect)
    end
  end

  module Plane
    def image
      b = RGSS::Bitmap.new((Graphics.width  + bitmap.width - 1) / bitmap.width * bitmap.width, 
                     (Graphics.height + bitmap.height - 1) / bitmap.height * bitmap.height)
      a = b.rect.dup
      a.x = -self.ox
      a.y = -self.oy
      b.repeat_blt(a, self.bitmap, self.bitmap.rect)
      b
    end
  end

  module Font
    def marshal_dump
      ret = []
      [:name, :size, :bold, :italic, :outline, :shadow, :color, :out_color].each{|k|
        ret << [k, send(k)] if respond_to?(k)
      }
      ret
    end

    def marshal_load(obj)
      obj.each{|x|
        k, v = x
        self.send "#{k}=", v
      }
    end
  end

end

class Object
 include RGSS3Facets::Object
end

class Module
 include RGSS3Facets::Module
end

class Class
 include RGSS3Facets::Class
end

class Proc
 include RGSS3Facets::Proc
end

class Range
 include RGSS3Facets::Range
end

class Rect
 include RGSS3Facets::Rect  
end

class Binding
  include RGSS3Facets::Binding
end

class Exception
  include RGSS3Facets::Exception
end

class IO
  extend RGSS3Facets::IO_extend
end

class RegExp
  include RGSS3Facets::RegExp
end

class Symbol
  include RGSS3Facets::Symbol
end

class String
  include RGSS3Facets::String
end

class Sprite
  include RGSS3Facets::Sprite
end

class Plane
  include RGSS3Facets::Plane
end

class Bitmap
  include RGSS3Facets::Bitmap

  module BitmapMarshalPolicy
    class Raw
      def self._dump(obj)
        [obj.width, obj.height].pack("LL")+ obj.address[0, obj.width*obj.height*4]
      end

      def self._load(arg)
        w, h = arg.unpack("LL")
        bi = RGSS3Facets::RGSS::Bitmap.new(w, h)
        bi.address[0, w*h*4] = arg[8..-1]
        bi
      end
    end

    class RawCompress
      def self._dump(obj)
        [obj.width, obj.height].pack("LL")+ Zlib::Deflate.deflate(obj.address[0, obj.width*obj.height*4])
      end

      def self._load(arg)
        w, h = arg.unpack("LL")
        bi = RGSS3Facets::RGSS::Bitmap.new(w, h)
        bi.address[0, w*h*4] = Zlib::Inflate.inflate(arg[8..-1])
        bi
      end
    end

    class BitmapFile
      def self._dump(obj)
        [0x4d42, (len = obj.width*obj.height*4), 0, 0, 54].pack("SLSSL") <<
        RGSS3Facets::CPtr.new(obj.object_id*2)[4][2][2][0, 40] <<
        obj.address[0, len]
      end

      def self._load(arg)
        w, h = arg[18, 8].unpack("LL")
        obj = RGSS3Facets::RGSS::Bitmap.new(w, h)
        obj.address[0, w*h*4] = arg[54..-1]
        obj
      end
    end
  end

  MarshalPolicy = :Raw

  def _dump(limit)
    self.class::BitmapMarshalPolicy.const_get(self.class::MarshalPolicy)._dump(self)
  end

  def self._load(obj)
    self.class::BitmapMarshalPolicy.const_get(self.class::MarshalPolicy)._load(obj)
  end
end

class Font
  include RGSS3Facets::Font
end

module RGSS3Facets::Enumerable

  def partial_sum(start, *s)
    if block_given?
      inject([start], *s) do |a, b|
        a << yield(a[-1], b)
      end
    else
      v = s[0].to_proc
      inject([start]) do |a, b|
        a << v.call(a[-1], b)
      end
    end
  end
end

Class.each_object{|klass|
  klass.send :include, RGSS3Facets::Enumerable if klass.ancestors.include?(Enumerable)
}

#load_script "Data/utils/api.rb"
#load_script "Data/utils/gc.rb"

 

]]>
https://seiran.mist.so/rgss/rgss3facets.html/feed 5