2007年 05月 10日

mac socks

Mac で svn/svk を socks 化する方法がない…… tsocks うごかないしなぁ

MacPorts インストールしなおしたらうごいた。
けど、DNS をやっぱりローカル解決しててだめだ。hosts かけばいいかなぁ

hosts に SSH サーバ先から見たレポジトリの IP 書いて sudo lookupd -flushcache したらいけた

2007年 05月 09日

Lua イテレータをコルーチンで実装する。

これはなんか Ruby と似た感じで実装できる。

local itr = coroutine.wrap(function ()
    local i = 1
    while true do
        coroutine.yield(i)
        i = i + 1
    end
end)


for i in itr do
    print(i)
    if i > 10 then break end
end

for in にはイテレータ関数を与える。coroutine.wrap はファンクションを与えるとコルーチン (thread) を生成してそれを resume する関数を返す。

yield の引数が呼び出し元に返って、in の前の変数に代入される。(多値かえして多重代入もできる)

2007年 05月 08日

Lua

os.execute ができるなら、cscript とか ruby ( cscript のが標準だからよさげ) よんでなんかするかはできそう。
スタンドアロンの Lua だと os.execute("dir /B > tmp") とかやると tmp に保存される。os.tmpname() と組みあわせればできそう。でも RO 組みこみの Lua がこれをいつまでやらせてくれるかは謎。

RO AI

2007年 05月 07日

Lua coroutine で「くるくる」を実装

http://lab.lowreal.net/trac/browser/c/ro/AI/Main.lua?rev=735#L347
してみた。コルーチンの使いかたがよくわかってなくて、callcc みたいに使ってるけど、なんか面白い使いかたないかなぁ。

「コマンドを予約」しておくと、次の AI ループ (RO がわから 140ms ごとによびだされる) のときにコマンドに対応した関数がよばれるようにしてある。http://lab.lowreal.net/trac/browser/c/ro/AI/Main.lua?rev=735#L34

で、

COMMAND[101] = "StepMotion"

でコマンドを定義して、self.resCmds:push({101}) でキューにつっこんでる。なんかダサい。

でもって onStepMotion がよばれるので、onStepMotion には coroutine を resume する関数をいれとく。coroutine.wrap をするとまさにその関数をつくってくれるのでそのまま代入。あとはループ中で条件判断をしつつ呼び出しを RO にかえしてあげて、処理を継続させてる。ループで書けるのはわかりやすいけど、コルーチン自体がわかりにくい感じだ。

Lua における「環境」

Lua では getfenv, setfenv (function env?) という関数を使って環境を取得したり、セットしたりできる。
これは JavaScript における「変数オブジェクト」にアクセスできるイメージかな

a = loadstring([[
function hoge ()
	print("hoge", fuga)
end
]])
local env = {}
-- copy env
for i, v in pairs(_G) do
	env[i] = v
end
setfenv(a, env)

a() -- セットした環境で実行する
env.hoge() -- hoge, nil
env.fuga = "fuga"
env.hoge() -- hoge, fuga

こうすると閉じたところで実行できる。サンドボックスみたいなのが作れそうなのでつくってみよう。

あるいは、

function foo (aaa, bbb)
    local localvariable = "aaa"
    for i, v in pairs(getfenv(1)) do
        print(i, v) -- この関数の変数とその値を列挙
    end
end
foo()

copy env って書いたけど、コピーされずに参照がそのままつっこまれてる。というか再帰的にテーブルをコピーしないとだめだ。

Lua

でも Lua は os.cd とかないから、ファイル書きこみとかされるとうまくいかないなぁ。io.open をフックしたらできるかな。

io._orig_open = io.open
io.open = function (filename, mode)
	return io._orig_open("/tmp/"..filename, mode)
end

でふつうにうまくいった。

Ragnarok Online Lua Shell

似非シェルを作ってみた。
http://lab.lowreal.net/test/RO_AI_shell.PNG
ファイルの読みかき以外はできないので、コマンドを送るようのファイルと、結果を書くファイルふたつを使って ruby プロセスと通信

e は生の eval みたいなもの。i は return をつけただけ。
でも Lua はグローバルで評価されてしまうっぽい。(setfenv は上位変数は見れない?)

でもこれ便利っぽい。うんこソースになってしまったけど実装してよかった

> i  Actor.players():map(function(i) return i.id end):join()
1111, 2222, 3333

とか見れるようになる。

2007年 05月 06日

Ragnarok Online のホムンクルス AI

Lua 云々はこれのためにやっていたやつです。
公式配布のもの (ROのインストールディレクトリの AI 以下) は最小限の機能が最小限の実装で書かれていて、そのままだと読みにくく、書きかえにくい。

なので、とりあえずデフォルトのAIの機能を移植するかたちで、書きやすように OOP 化しはじめてみた ( http://lab.lowreal.net/trac/browser/c/ro/AI/ )

デフォルトの Util.lua にある List テーブルがなぜかクラスではないので List.lua として分離し、ruby っぽいメソッドをいくつか追加した。

l = List.new(1, 2, 3)
l:join() --> "1, 2, 3"

l1 = List.new(4, 5, 6)
l2 = l + l1
l2:map(function (i)
    return i * i
end) --> 1, 4, 9, 16, 25, 36

クラスの実装は http://subtech.g.hatena.ne.jp/cho45/20070502/1178092846 のまま。


GetDistance 系はダサいので、Actor クラスを作ってラップしてある (Actor.lua)。Actor クラスはモンスターやホムやプレイヤーに対して使えるクラス。

a1 = Actor.new(id)
a2 = Actor.new(other_id)

a1:distanceFrom(a2) > 3
a1:isInSight(a2) --> a2 が 20 セル以内にいるとき true
a1:isInAttackSight(a2) --> a2 が攻撃可能な範囲にいるとき true (今は単に 1 セル以内)

a1:isStand() --> a1 が立っているとき true

これによって GetV を使わなくてすむはず。定数を何回も書くのがめんどいのでちょっと楽かなぁと思う。


Homun クラス (Homun.lua) は飼っているホムに使うクラス。Actor のサブクラスになっていて、Actor のメソッドはよべる。

h = Homun.new(myid)
h:owner() --> オーナーキャラ (つまり操作している自分のキャラ) を Actor インスタンスで取得
h:move(x, y) --> x, y に移動
h:attack(target) --> target を攻撃 (attack できる範囲にはいっていないと何もおきないと思う)

スキル使うのはこれから実装する (AIばっかり書いててまだスキルがとれてない)


RO からは AI.lua が呼びだされる。こいつにはデバッグメッセージの出力と、本体でエラーをはいたときに RO のほうに伝達しないようにしてる (RO に伝達すると、ダイアログが表示されまくって Alt-F4 するしかない。さすが! 重力クオリティ!) AI.lua は Main.lua をロードして、Main 関数を実行する。

Main.lua には Main 関数と HogeAI クラスと reload 関数が定義されてる。

Main 関数では HogeAI クラスをインスタンス化して、RO から呼びだしがくるたびに、インスタンス化した AI クラスの act メソッドを呼びだしている。CurrentAI とかいうグローバル変数に突っ込んでいるのは、そのうち切りかえとかできたらなぁとか考えているからだけど、実装できるか謎い。

HogeAI は今つくってる劣化デフォルトAI で、やってることはデフォルト AI とそんな違いはないはず (実装してないのがいくつかある)。デフォルト AI の処理をとりあえず移植したら DefaultAI クラスにでもして、それのサブクラスを作ったらいいかなぁとか思ったけど、まだやってなくてわからない。

Try と xpcall

xpcall とかいう関数ふたつとってエラーキャッチする関数をみのがしてた!!
Try をつかいつづけるか悩む