2004/05/06

なんか、今更気がついたんですが、うちのプリの髪型+髪色が魔法実験の人のプリとまったく同じだったり。後発組なんでいくつもあるたまり場に出入りするいろんな人の髪型+髪色となるべくかぶらないようにしたはずですが、軽く鯖を超えるとめっちゃ近くに同じ髪型+髪色の人がいたとは…。

TWのはなしをながながと。

今日のTWのはなしは、正直おもしろくない話。

PostMessageとSendMessage

よつばでWM_DESTROYが拾えなかった件は、TWC-IIの人が書いてたとおり、キューに入らないから拾えないのでOKだと思います。Windowsメッセージって、

  • PostMessageでキューに入ってPeekMessage/GetMessageで取り出されるもの→WH_GETMESSAGEでフック
  • SendMessageでウィンドウに直接飛ばしてWndProcで処理されるもの→WH_CALLWNDPROCでフック

コレ書きながらMitsukiさんと話してたら、SendMessageでも別スレッド/プロセスあたりから投げつけるとキューに入るなんて指摘が来ました。→そういえばなんか昔書いたアプリでそれに心当たりがあるバグがあったような…(力業で別実装にした記憶が)。

の2種に大別されるんで、メッセージがPostされるのか直接Sendされるかでフック法が変わるってことで、どっちにしろ全メッセージを走査するにはフック2個引っかけなきゃダメです。

まぁ、SendされるメッセージかPostされるメッセージかはSpy++あたりで調べればいいかと思います。

身近な例では、TWのチャットラインアクティブ時にAlt+コマンドを有効にさせるための実装でTWのEDITをフックしてWM_SYSKEYDOWN/UPを親ウィンドウ(TW本体)に再送するというのをやったんですが、キーボード入力系はSendじゃなくてPostされるものなので、いくらSendMessageで再送してもダメなようですよ。というのに最近twexの人がはまってました。まぁ、そのサンプルコード書いたのは私なわけで、当然わたしもサンプルコード書いたときにはまったんですが。

キルカウンタ

で、そのTWC-IIの人の話の続きでキルカウンタなんて話題が出てましたが、まぁとりあえずそういうのは先人に学べってことなんでいろいろ考えてみましたが、とりあえず基本的にROのキルカウンタはパケットではなくてメモリ監視をベースに実装されてきた経緯があります(あんまりROのツールのこと知らないけど、ROHPとかはパケットベースで監視してるのかしら→ROHPにキルカウンタがついてたかどうかの記憶さえ怪しい)。

てなわけで、本当はメモリ参照でやっつけるのが楽なんですが、そもそもTWはシステム上入手EXPが自レベルと敵レベルの兼ね合いで同じ敵で変動しちゃいますから、単純に入手EXPで敵判別はムリです。まぁ、そもそもあのよく分からないチーム公平システムとかでは、何がどうなってるのかメモリだけで読むのは、困難というよりは、ムリです。

となるとパケ監視からカウントする必要がありますが、これはどうなんだろう…。まだマジメにしらべてないんで何ともいえませんが、普通にゲームを実装するなら敵を倒したときのパケットに最低限乗せてくるべき情報は、敵IDぐらいなもので(まぁ、一般的なオブジェクト消滅パケなら消滅要因として敵が倒されたって情報も乗ってこないとダメですが)、そのパケ検知だけだと全然情報が足りません。

まぁ、ここでその敵倒したパケットに倒したプレイヤーIDとか、敵の種類情報(ゼリッピ、とか)、その辺のデータが乗ってくるとキルカウントしやすいですが、対外部ツール耐性という点では乗ってきてなさそうな…。ということを考えると、最悪のコストがかかるケースでは画面内に入ってきた/出ていった敵について敵個体IDとモンスター種類の対応表を保持して、自キャラがダメージを与えた敵IDをピックアップした上でその敵IDの消滅を検知してモンスター種類を逆引きしてカウント、ということになりますか。

一応、自キャラがダメージ与えた敵ID調べるのは楽そうな気がしますが、地面指定スキル(カウンタースピアとか)とかはちゃんとSendまでフックして自分のスキル発動検知して調べないとダメじゃないかなぁ、とか。ROはどうなんだろうなぁ…スキルオブジェクトに発生者情報がついてたようなついてなかったような

で、ここで考え得るのはパケット+メモリの両方を読んでみるっていう手段ですが、これも結局寄与とか公平とかのシステムを使ってしまうと狂いそうですね。ROとちがってパケットにレベルが乗ってこないので、レベルとの兼ね合いとかで取得経験値が変わってくる公平のシステム(いや、オレもよく知らないけどさ)の上でキルカウントするのは、まぁまず無理でしょう。というか、誰もやらないでしょう。

TWのウィンドウモードの話

一応調べたの私なんでこれも書いておきますか。

TWをウィンドウモードで起動すると、まず間違いなく画面が歪むと思います。これは、TWのクライアントがクライアントエリアに対して縦38px、横18pxだけ上乗せしたサイズに決め打ちでウィンドウフレームを作ってしまうという謎アルゴリズムでやってるので、まぁ、Krのほうはどうだか知りませんけどまず普通の日本の環境ではこのサイズでうまく歪まないTWをプレイするというのは、ありえないといっていいでしょう。

てなわけで、これを補正するにはTWのウィンドウを見つけたらWindowRectをしらべて、とりあえずそこから縦38px、横18pxを引いたサイズをClientRectとして、これを用いてAdjustWindowRectExあたりを呼び出してWindowRectを再設定するのが一番楽な補正方法でしょう。

しかしながら、コレをそのままツールに実装すると、TW起動したまんまでそのウィンドウサイズ補正するツールを何度も再起動すると、補正済みのTWウィンドウをさらに補正しようとする(結果、ウィンドウが小さくなっていく…)ということになってしまうので、縦38px、横18pxを引いた辞典で算出したClientRectが800x600か1024x768になっているかどうかをチェックする必要が出てきます。もしこのサイズになっていれば、今のWindowRectが18x38だけ広がってる歪みウィンドウなので、補正の必要がある、ということですね。

ついでに書いておきますと、ここでTWを直接起動させてInphase.iniからクライアントエリア指定にすると、SVGAとXGAの決め打ちチェックができなくなるので、こういう場合はInphase.iniをツール側で読み込んでチェックするか、ツールのiniにTWをどのサイズで起動するかを指定しておく必要がありますね。今のところこの機能が乗っててちゃんと公開されてるTWのツールはautoherbだけですが、autoherbではTWのClientRectサイズをツールのiniで指定するアプローチになっているようです。うちの手元のサンプルコードではツール側指定無しにいけるようにInphase.iniを自力で読むコードになってますけど。

TWをウィンドウモードで起動して外部ツールからスクリーンショットをとって「あぁ、なんか画面歪んでる…、なんでやねんっ」という人、この辺がその理由になっております。

ってことで、また。

うされもん @acidlemonについて

|'-')/ acidlemonです。鎌倉市在住で、鎌倉で働く普通のITエンジニアです。

30年弱住んだ北海道を離れ、鎌倉でまったりぽわぽわしています。

外部サイト情報

  • twitter
  • github
  • facebook
  • instagram
  • work on kayac