艦娘所有一覧をExcel VBAから作ろう(開発が完了しました編)

艦娘所有一覧をExcel VBAから作ろう(開発開始!!編) – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5112

の続きです。

艦娘所有一覧
http://dunkel.halfmoon.jp/kancolle/index.html

image

艦娘所有一覧に、諜報員でCSVファイルを吐き出した後、Excel VBA で投稿をします。直接投稿すればいいのですが…まあ、Excel VBAで試したかったというところで。

■諜報員でパース

艦これ諜報員が動いている状態で「図鑑表示」から、艦船図鑑の1,2,3をクリックします。このときのレスポンス(/api_get_member/book2)を調べて、所有している艦船を収集します。たぶん、他でもできそうな気もするんですが…ひとまずこれで。

image

諜報員を右クリックして「オプション」を選択した後に「艦娘所有一覧」でOKを押すと、CSVをデスクトップに出力します。ファイルは面倒なので決め打ち。

image

こんな感じで図鑑番号が取れます。

public List<Ship> ParseBook2( string json )
{
    var reader = JsonReaderWriterFactory.CreateJsonReader(
        Encoding.UTF8.GetBytes(json),
        XmlDictionaryReaderQuotas.Max);
    var el = XElement.Load(reader);
    var doc = ExDocument.Load(el);

    var lst = doc * "api_id" != "-1";
    var res = new List<Ship>();
    foreach (var it in lst)
    {
        var pa = it.Parent;
        var ship = new Ship() {
            id = pa / "api_id",
            index_no = pa / "api_index_no",
            ship_id = pa / "api_table_id",
            name = pa / "api_name"
        };
        res.Add(ship);
    }
    return res;
}

JSONをパースしているところの抜粋はこんな感じで。JsonReaderWriterFactory から XElement を使って ExDocument を作るという流れです。ExDoc は、なんとなくイイ感じに XML が扱える自作ライブラリです。XPath でもいいのですが、試行錯誤がやりやすいかなと。

■艦娘所有一覧に投稿する。

このCSVファイルを同梱してある「艦娘所有一覧へ投稿.xlsm」に貼り付けて投稿します。所有一覧のページは、マウスでぽちぽちクリックするのですが、これならば一発で投稿完了…つーか、ぽちぽちクリックしている方が楽しくていい感じがするのですが、まあ、このあたりはプログラマの性ということで。

Private Const url = "http://dunkel.halfmoon.jp/kancolle/index.html"
Public Sub 艦娘所有一覧を投稿()
    Dim ie As New InternetExplorer
    ie.navigate url
    ie.Visible = True
    ' 完了待ち
    While ie.Busy = True Or ie.readyState < READYSTATE_COMPLETE
        DoEvents
    Wend
    ' optionタグを取得
    Dim doc As HTMLDocument
    Set doc = ie.document
    Dim coll As IHTMLElementCollection
    Set coll = doc.getElementsByTagName("option")
    Dim dic As New Dictionary
    Dim el As IHTMLOptionElement
    For Each el In coll
        dic.Add 0 + el.Value, el
    Next

    ' 図鑑のcellとマッチングさせる
    Dim i
    For i = 2 To 1000
        Dim 図鑑番号
        図鑑番号 = Sheet1.Cells(i, 2)
        If 図鑑番号 = "" Then Exit For
        If dic.Exists(図鑑番号) Then
            Set el = dic(図鑑番号)
            el.Selected = True
        End If
    Next
    ' サブミット
    doc.forms(0).submit
End Sub

Excel VBA の全文はこんな感じです。さっくりと短い感じになっています。これは、yuki(siro) さん のソースがきれい≒操作しやすい、ってのもありますね。option タグが並んで、jQuery で操作しているので、そのあたりを拾い集めればOKです。艦これ諜報員じゃなくても、使えるように別ツールにしてあるので、適当に活用して頂ければと。

■サンプルコード

サンプルコードはこちら http://sdrv.ms/19xmMD0

そのうち、データベース艦これ! にも対応したい。でも、これって母数が不明(失敗は投稿しないだろうから)なので、相対的に特定の艦娘がでやすい、という見方が正しいかも。

カテゴリー: C#, 艦これ | 艦娘所有一覧をExcel VBAから作ろう(開発が完了しました編) はコメントを受け付けていません

艦娘所有一覧をExcel VBAから作ろう(開発開始!!編)

艦娘所有一覧
http://dunkel.halfmoon.jp/kancolle/index.html

image

というのができたそうなので、Excel VBAから(!!!)投稿させてみます。単にちまちま選択するのが面倒なのと…「Excel VBAへのいざない」を書いた後なので、その余力からです。

■Fiddlerで図鑑表示(books)を取得

艦これで「図鑑表示」をすると、/api_get_member/book2 の JSON を取得します。この中に図鑑で表示されている艦娘が取得できます。ええと、図鑑表示の場合、轟沈した艦娘も入っているので、「艦娘所有」ってことにはならないのですが(こっちのは別のAPIがあるので)、多分、図鑑のほうですよね、多分。

{
“api_id”:102,
“api_index_no”:4,
“api_state”:[1,1,0,0,0],
“api_table_id”:87,
“api_name”:”日向”,
“api_yomi”:”ひゅうが”,
“api_stype”:9,
“api_ctype”:2,
“api_cnum”:2,
“api_taik”:74,
“api_souk”:70,
“api_kaih”:22,
“api_houg”:74,
“api_raig”:0,
“api_tyku”:28,
“api_tais”:0,
“api_leng”:3,
“api_sinfo”:”伊勢型戦艦2番艦、日向。<br>ああ、そうだ、あの伊勢と一緒に航空戦艦になったんだ。<br>もともとは、私の砲塔の事故もあるんだけどな。<br>呉で朽ち果てる迄、戦うつもりだ。”
},

色々詳細なデータは取れるのですが、艦娘所有一覧に欲しいのは、上の4つです。

  • api_id : まだ所有したことがない場合は –1 になります。
  • api_index_no : 図鑑の番号です。多分、艦娘所有一覧の順番に一致します。
  • api_table_id : 艦娘の番号です。サーバーのmp3とかswfに使います。
  • api_name : 艦娘の名前ですね。

薀蓄の apai_sinfo の部分は秘密なので、この4つを CSV に出力して Excel 形式に読みませれば OK ですね。

■艦娘所有一覧のソース

さらっとソースを見て Excel VBA からの方針を立てます。

image

普通に submit しているだけなので簡単そうです。option タグの value を設定して、submit すれば ok です。これぐらいであれば、Excel VBA + InternetExplorer オブジェクトを使わなくても十分なのですが、まあ「Excel VBAのいざない」の余力ということで。

続きは割り込みの後で。

カテゴリー: 艦これ | 艦娘所有一覧をExcel VBAから作ろう(開発開始!!編) はコメントを受け付けていません

艦これ 秘書官改め諜報員 ver0.3

艦これ 諜報員 – Moonmile Solutions Blog
http://www.moonmile.net/blog/tools/kchisyo

上記にバイナリ版があります。サンプルソースはこちら。http://sdrv.ms/1fJ0q2X

終了方法を右クリックメニューで付けただけなので、基本は ver0.2と変わっていません。

■ship2 の解析

艦隊における艦娘の ID は、api_get_member/ship2 で以下のように取れる。

“api_data_deck”:
[
{
“api_member_id”:41898,
“api_id”:1,
“api_name”:”第1艦隊”,
“api_name_id”:””,
“api_mission”:[0,0,0,0],
“api_flagship”:”0″,
“api_ship”:[83,71,226,278,250,252]
},

この api_ship のところが、艦娘のユニークIDですね。艦娘は同じ艦種を複数持てるので、これを同じ ship2 の中で探していくと、「83」というのが、ship_id の「221」ということが分かります。これが「榛名改」です。

{
“api_id”:83,
“api_sortno”:311,
“api_ship_id”:211,
“api_lv”:47,
“api_exp”:111978,
“api_nowhp”:75,
“api_maxhp”:75,
“api_leng”:3,
“api_slot”:[246,108,247,248,-1],
“api_onslot”:[3,3,3,3,0],
“api_kyouka”:[14,0,32,19],
“api_backs”:5,
“api_fuel”:90,
“api_bull”:120,
“api_slotnum”:4,
“api_ndock_time”:0,
“api_ndock_item”:[0,0],
“api_srate”:3,
“api_cond”:84,
“api_karyoku”:[129,94],
“api_raisou”:[0,0],
“api_taiku”:[75,79],
“api_soukou”:[86,89],
“api_kaihi”:[51,69],
“api_taisen”:[0,0],
“api_sakuteki”:[31,49],
“api_lucky”:[20,69],
“api_locked”:1
},

ship_id がどの艦種を示しているかというと、これは起動時に読み込まれる api_get_master/ship の中に書いてあります。このファイルは結構でかい(400Kぐらいある)ので、いちいち検索するよりは、まあ、ship_id はそうそう変わらないので(アップデートの時は変わるんでしょうが)、これを保持しておいて、艦娘の画像を出したりできますね。色々なパラメータがあるので、これを取り出して戦況を有利に勧めることはできそうですが…まあ、だいたいはブラウザで見えるので、これ自体はあまり意味ないかも。回避能力とか運とかを見比べるぐらいですかね。

カテゴリー: 艦これ | 艦これ 秘書官改め諜報員 ver0.3 はコメントを受け付けていません

情報の濃度勾配と非不変性の話

https://twitter.com/PaxilAddict/status/375349331076710401

本当は昨日の夜にざっくりと説明しようと思ったのですが、忘れてたので昼に30分ほど。

経済の仕組みとして商社/物流の場合には「濃度勾配」=「安く仕入れて高く売る」のが基本なので、そのあたりの言及は別として(彼のほうが詳しいだろうし)、具体的に「情報」の話に絞ります。

で、議論を始める前に「情報とはなんぞや?」というのを定義しないといけないのだけど、情報工学的に言えば「とある現象が整理された状態」を情報とみなしています。この「整理された状態」ってのが曲者で、観察者の主観が入っています。なので、現象そのものは「情報」とはみなさないのですよ。昨今のビックデータみたいなのは「現象そのもの」ではないか?と思われるでしょうが、とある現象から生データを保存している状態で「整理した状態」であるし、またデータベースの作りの状態で「整理された状態」であり、厳密に言えば現象そのものではありません。なので、「現象そのもの」を扱うのは非常に難しいのではありますが…実は、現象そのもの自体を観察することはできないので、このあたりは不要な議論だったりします。

ええ、みなさんご存じの通りッ!!!、量子力学の範疇では位置とエネルギー(運動量)は同時に特定できません。マクロ的な視点で言えば、その位置にありその運動ありという2視点で特定できるように見えますが、実はミクロ視点の誤差においては確実ではありません。まあ、そこまで数値を突き詰めることがないので「誤差」だったりするのですが、それこそが、不確定性の部分と確率の部分になるのですよ。なので、微小な範囲で不確定であるものが、全体においてどのように影響するか。それは「誤差」以上に影響するのか?という問題があって、一見、目に見える物理法則は量子力学を含んでいないように見えますが、頭の中で考える電磁的なパイプ(名を失念)に電気が流れるとき(電子が伝播するとき)には、量子力学的な不確定さが発揮されます。これゆえに、この微小な電子信号で左右される思考自体も、不確定さの範疇になります。つまり、Aの現象を同じ条件下で受け取ったとしても、反応は、AかもしれずBかもしれず、ということです。ひとつの電子量で判断を行う場合には、量子力的な揺らぎを大きく含みますが、大抵の場合はそれなりに大きな電子量が使われるので、アナログ的にどちらかの確率が高くになります。このあたりファインマンの光の直線性に関する考察を読むとわかるのですが、因果関係が逆転しているように見えてきます。未来があって過去が決定する、というような感じですね。

話が大幅にずれてきていますが、元に戻すと「現象そのもの」は「情報」としてイコールにならない、という前提があります。あるいは、情報を「現象そのもの」として捉えようとしても、それは無理、ということですね。もう少し数学的に言えば、1+2=3の場合、「1+2」と「3」は数値的にはイコールですが、復元するときの情報量が違います。これは情報の圧縮とか不可逆性とかにも関係しますが、現象自体はそのまま未来に残すことはできないので、「1+2」のなかの「+」という演算子を、結果が「3」であることに集約させてしまいます。これはこれで便利なのですが、時として「+」が必要な時がありますよね。一体、何と何を足したら「3」になったのか?ということが問われるシーンがあります。これらのシーンに対しては未来に位置しているにも関わらず、過去に対して「+」を要求するという時間の逆行があります。時間の流れが不変(実は、ファインマンによって、逆行することが証明されているけど…というか、逆行の再定義というところか)と考えるならば、「3」という結果からは「1+2」という原因の部分は類推できません。しかし、物事は「3」で十分だし、もともと類推できないのだから、「1+2」という原因自体が不要、ということです。そんな訳で、時間が進むに従って、原因は次々と捨てられていき、新しい原因が次々と作られているということになります。

さて、この時間の逆行や原因が捨てられる、という視点は、ひとりの観察者の視点ですね。なので、複数の観察者が同じ現象を観察したときには、それぞれの視点により「情報」を蓄積します。同じ現象(と思われるもの。これが同じであるとは証明できない)に対して、同じ情報を得られる場合は、同じ現象から類推している、という結論が得られます。演繹法ですね。ですが、ここで気を付けたいのは、AとBという二人の観察者が、同じ現象を見て「情報」を得たとしても、それぞれの情報はの違いは「それぞれの情報を突き合わせたとき」にしか違いがわかりません。これは、情報を比較するという情報自体が、情報を比較という現象そのものとは違うという意味です。通常、情報自体は光の速度で伝播しますが(光の速度以上にならないのは、物理的な影響の最速が光だから、というためです…が、量子力学的に時間の逆行と不確定性を含めると、光よりも早く伝播する可能性はあります)、これをAとBが持つ「情報」自体が、物理的に離れていれば同時には無関係になる、影響しえないという「光の円錐」あるいは「情報/影響の円錐」になります。この円錐同士が重なるときだけ、それぞれの情報は交差します。逆に言えば、それ以外のところでは、全く影響しないし、他の情報を得ること自体が無意味である、という結論になります。

情報の円錐が重ならなければ情報として有効でない、ということと、数々の過去の原因が捨てられてつ新しい原因が作られ、それの切り取りが「情報」である、ということを合わせると、情報自体が「非不変」であることがわかります。また、円錐の重なりが観察者それぞれ(情報の受給者それぞれ)に与えられるので、何かの情報を得る人と何かの情報を得ない人が存在し、そこには濃度勾配があることがわかります。まあ、証明しなくても「情弱」という言われ方もするし、英語が読めなければ英語論文から情報を得る機会はすくなくなるだろうし、逆に言えば日本語ができなければ日本の情報を得る機会は少ないってことです。

で、先のビックデータのように情報は必ず「媒体」に依存します。データベースのテーブル構造もそうだし、記憶領域の制約もあります。第一にモデルを作ったときに、情報を整理するときに重要な要素が欠損しているかもしれません。もちろん、欠損していないようにテーブルは作る訳ですが、欠損するテーブルを敢えて作ることもできますよね。つまりは、未来は完全に予知できないのです。仮に欠損してしまったデータを「事象そのもの」として判断をし、なんらかの基準で「情報」を取り出したときに、それらの「情報」は本来の事実を表しているかどうか?の判断は難しいところです。多少の欠損ならば、確率的に大まかな予想があたっているかもしれませんが、微小領域では間違っているかもしれません。複雑系の畳み込み理論ってことです。畳み込まれたものは元に戻せませんし、逆に微小な範囲が大きな次の現象に影響を与えることがあります。これは先の脳内の量子力学的な性質と同じです。

こうなると「情報」の曖昧さ、正確性が問題になるのですが、大域においては問題は少ないのです。大抵の動きはニュートンの物理法則で事足りるように、人の動きと考えの大域においては似たようなものです。それを行動原理と言ったり行動経済学と言ったりします。大抵の場合「情報」を何等かの判断のものとにするために必要とされているので、「正しい情報」と「膨大な情報」を人は欲します…が、先に言った通り、情報の正確性というのは判断がつかないものです。これを回避するひとつの手段としては、観察者を複数持ち、複数の観察者から得られる情報を総合して、自らの情報として捉えることです。できれば、それぞれの情報供給元は、おのおの情報の円錐の外にある人がよいでしょう。これらの複数の情報から、ひとつの確率の高いもの次に確率の高いものをピックアップします。そのあたりは「非効率」なので、人はひとつの情報元を自分の情報として据え置きます。これは、生物手学的に「効率的」な方法なので、命にかかわらないこと(あるいは、趣味なのでどーでもいいようなこと)はそれはそれでいいのですが、まあ、お金や生命に関わることは、別視点を用意したほうがいいですよね。それを「情報収集のためのアンテナ」と呼ぶこともあるのですが、先に示した通り情報の円錐内にあるものだけを集めてもダメです、ってことです。

逆に言えば、情報源を少なめにする(厳選する)と、情報を整理する側(=自分の頭)に余裕ができるので生活が楽になります。いやいや、ジャーナリストという情報の海を泳ぐ方もいらっしゃるので、職業的には不可能な場合もあるのでアレですが、私の場合 TV を観なくなってからかなり情報の流入は制限されて、他の余裕ができています。とはいえ、

ドコモからのお知らせ : 本日の一部報道について | お知らせ | NTTドコモ

image

えええ?それってどういうこと?いやいや、私、ドコモユーザーでもないし、どーでもいいのですが、他の方の反応が気になるところです。

カテゴリー: 雑談 | 情報の濃度勾配と非不変性の話 はコメントを受け付けていません

UpdateLayeredWindowを使って縁取りも鮮やかに(祥鳳撃沈編)

艦これ秘書官 ver.0.1 – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5077

の縁取りは、フォームに TransparencyKey を設定する方法で縁取りがあまりきれいではありません。これは、元画像にアルファチャンネル(透明度)が設定しているためでそこのところにフォームの色が重なっているので…ってな感じです。this.TransparencyKey = this.BackColor と設定すればお手軽に透過ができるのですが、今となってはいまいち綺麗ではないかなと。Region を使っても似たことができるのですが、不定形の場合大変なのと Region 自体の数が多いとスタックオーバーフローで落ちる、という欠陥があります。このあたりの話はまた別の記事にでも。

■レイヤーウィンドウを使って縁取りをきれいにする

UpdateLayeredWindow 関数
http://msdn.microsoft.com/ja-jp/library/cc364847.aspx

のあたりを読んでも、さっぱりわからないので先達のサンプルを探します。

半通過ウィンドウの作り方講座
http://www.inasoft.org/wpt/ulw.html
[VB, C#] レイヤード ウィンドウを使用する
http://youryella.wankuma.com/Library/Extensions/Form/LayeredWindow.aspx

のソースを丸ごと持ってきてコピーして使っています。便利なレイヤーウィンドウのライブラリを作るのは大変なのですが、ひとまず、

  • 秘書艦の縁取りができればOK
  • 定期的に書き換える遠征と入渠の残り時間が表示できればOK

ということにしておきます。こんな感じに、榛名の切り取りと遠征/入渠の残り時間がうまく切り取れています。ソースを見るとわかるのですが、文字のところを含めて1秒間に1回 bitmap を書き換えるという荒業をしているので、パフォーマンス的にどうかなというわけなのですが…「ええ、榛名なら大丈夫でしょう」…というか、1コマ/秒ならば動画よりも少ないので大丈夫でしょう。

image

■Windows 8 のトーストを付ける

ついでに Windows 8 の場合はトースト≒通知機能を付けてみました。トースト自体は Windows 8 の機能ですが、それを利用するには WinRT API を使わないと駄目、というジレンマがあります。が、Outlook 2013 でも実装されているので普通に許容範囲ですね。

デスクトップアプリからWinRT APIを使用する – 酢ろぐ!
http://ch3cooh.hatenablog.jp/entry/20121204/1354596483
Windows Sending toast notifications from desktop apps sample in C#, C++ for Visual Studio 2012
http://code.msdn.microsoft.com/windowsdesktop/Sending-toast-notifications-71e230a2
Windows® API Code Pack for Microsoft® .NET Framework – Home
http://archive.msdn.microsoft.com/WindowsAPICodePack

から Toast の処理を丸ごと持ってきています。ややこしい AppUserModelId の設定もサンプルの中に入っているので、それも持ってきてあります。まあ、デスクトップアプリからスタート画面にピン止めをするので、スタート画面のアイコンが変なのですが(KcHisyo8のアイコン)…まあ、これは後で直しましょう。Windows 7 以前は、トーストの機能はないので、別プロジェクトにしてあります。

image

■サンプルコード

KcHisyo-v0.2-src.zip 艦これ秘書官 ver.0.2
http://sdrv.ms/1aaZDXK

からソースがダウンロードできます。バイナリのほうは、バージョン番号と終了方法を付けたら再びアップということで。いまのところ、終了方法はタスクバーから「閉じる」を選択しないとだめなので…ちょっとアレですね。

■祥鳳撃沈

そんな訳で、長らく愛用しておりました祥鳳さんが沖ノ島海域で撃沈です orz あまりレベル上げに専念していないので、ちと敷波さんといい気を付けないと。しかもクリアできていないし。

imageimage

プロジェクトでも、ひとり弱いと割りを喰うわけで、他が戦艦だとちょっと装甲の弱い祥鳳では無理ですね。TOC のレバレッジの考え方とか、構造力学の応力集中の考え方とか(切込みを丸くして応力を分散する方法とか)そういう物理原則が入ってくる(あるいはそんな感じがする)のが、面白いところです。このあたり、1チーム6艦船しかないという制限のなかで、どのような配艦をすれば良いのか?とか考えたりすると更に楽しめるかも。まあ、ゲームとしてはある程度レベル上げをしないとうまくいかないのですが「新人をどのように育てるのか?」っていう感じで。

# ううう、祥鳳は、数隻持っていたけど先日、まとめてた(祥鳳自身に近代改装した)ので1隻しかないのが仇に。というか、そういうシビアさ≒縛りもまた宜しということで。

カテゴリー: C#, WinRT, 艦これ | UpdateLayeredWindowを使って縁取りも鮮やかに(祥鳳撃沈編) はコメントを受け付けていません

艦これ秘書官 ver.0.1

艦これ 司令部室
http://nozomi.arege.jp/KanHQ/

に触発されて、遠征と入渠の残り時間だけ表示するツールを作ってみました。こんな風にデスクトップに貼りつきます…つーか、画像の縁取りがいい加減(プログラムがいい加減)なのは、サンプルということで。

20130904_03

ソースは http://sdrv.ms/15UAUWW からダウンロードしてください。Visual Studio 2012 でビルドしているので、そのあたりは適当に。バイナリは、もうちょっと整理してからにしましょう。

中身で何をやっているかというと、

  • FiddlerCoreを使ってIEのプロキシをフックする。
  • 遠征(deck_port)と入渠(ndock)のアドレスの時だけレスポンスをチェックして、JSONをパース
  • 定期的に遠征と入渠の時間を書き換え

ています。

JSONでパースするところは、JsonReaderWriterFactory.CreateJsonReader を使って XElemen に直した後に、自前の ExDoc を使って検索しています。ExDoc は遅延実行していないのですが…まあ、この程度ならばいいか、って感じでいい加減な作りです。ちょっと、仕事に使う予定なのでデバッグと必要なメソッドを調査も兼ねてってことで。ソースの解説は後ほど。

■今後の予定…は未定

  • 遠征や入渠が終わった後に、Win8 の通知がでるといいかな。
  • 秘書官の画像を「秘書艦」にあわせる、とか。
  • ひとまず、秘書官の透過をもうちょっときれいにしないと。
  • 「何か。」みたいに喋ったほうがいい?

本家のゲームは 艦隊これくしょん~艦これ~ DMM.com×角川ゲームスが贈る新鋭の大型戦略コンテンツ – オンラインゲーム – DMM.com

カテゴリー: 開発, EXDoc, 艦これ | 艦これ秘書官 ver.0.1 はコメントを受け付けていません

Fiddlerを使って艦これのバトルJSONを解析(敷波復活編)

ちょっと気になるツイートを見かけたのでそれ絡みで。

https://twitter.com/Sikushima/status/374120078976880640
「艦これ」から、ソーシャル系のサーバ構成を考える – SQLer 生島勘富 の日記
http://d.hatena.ne.jp/Sikushima/20130901/1378021345

艦これサーバーのトラブル云々には同意しかねるのですが、素直にMySQLのSQLで組んだほうが、下手にデータ構造を考えてAPIを作ったりするよりは断然早い、ところの同感です。更新系は兎も角、参照関係は断然RDBMSは早く作られているので、下手のO/RマッピングやるよりもSQL直で書いたほうが手早くかつ実行スピードがすばやくできます。ええ、SQL文を書ければ、の前提なのですが。

で、艦これの同時セッション絡みの部分、いくらか艦これをやっていて、いくらかFlashの通信部分を覗いてみると、さほどセッション/DBコネクション自体には負荷がかかっていないことが分かります。つーか、アクションRPGと違って、艦これの場合、サーバーとの通信が極端に少なくて、ガラ携のWEBゲームぐらい通信は少ない。なので、同時接続数(アクティブ数が30%だとしても3万人ぐらい)だとしても、DBコネクション等で輻輳しているところは更に1/100以下ぐらい、もっと少ないかもしれません。艦これの場合、Flashから各サーバーに送るのは、普通にRESTで送って、JSONで返ってきます。詳しく見ると cookie を使っていません。GET するときの URL に token が入っているのですが、多分ユーザIDへの紐づけかと。なので、非常にDBに負荷の少ない設計(意図的…ということにしておきましょう)になっています。ぷよぷよクエストとか、バウモンとか、レガリアを iPhone でやっていると、やたらに「ログイン中です…」が出るのですが、艦これの場合は全く出てきません。そういう意味では、パズドラも出てこないですね。優秀です。

このあたり、通常のソーシャルゲームにある、

  • ユーザーごとのチャット機能
  • 他ユーザーのデータを参照して、何かやる(仲間にするとか)する機能
  • リアルタイムに他ユーザーと何かやる機能

というのがごっそり抜けています。これは、各鎮守府サーバー(ログイン先のサーバー)間で通信が発生しない(発生できない)のと、まあ、そのあたりを設計しなかっった(意図的に…としておきます)ためです。なので、極端な話で言えば、ロードバランサーすら必要なくて(あるのかな?)、ひとつのサーバーで10万人程度受け持つ、という予算の中で組んで、開いてみたら思わずアクセスがあって、順々にサーバーを増やす、という作りになっているかと。と想像するわけですが、そのあたりは ツチノコブログ | DMM.comラボのインフラエンジニアブログ を参照して頂くということで。

なので、参照系のデータとしては艦船データやマップデータで、更新系は各ユーザーのHPやログインデータぐらいなもので、データベースへの輻輳の率を考えると、それほどシビアな形で使わないくてもうまくいのかな、と想像します。MySQL Clustor を使う位だから、それなりに負荷は掛かっているのでしょうが、同時コネクション数は、100程度あれば十分かも。

■戦闘の開始(battole)と結果(battleresult)

戦闘開始

svdata={
  "api_result":1,
  "api_result_msg":"成功",
  "api_data":{
    "api_dock_id":1,
    "api_ship_ke":[-1,509,509,502,502,502,-1],
    "api_ship_lv":[-1,1,1,1,1,1,-1],
    "api_nowhps":[-1,66,36,36,37,25,43,58,58,22,22,22,-1],
    "api_maxhps":[-1,75,40,36,37,25,63,58,58,22,22,22,-1],
    "api_midnight_flag":0,
    "api_eSlot":[[505,513,525,-1,-1],[505,513,525,-1,-1],[502,-1,-1,-1,-1],[502,-1,-1,-1,-1],[502,-1,-1,-1,-1],[-1,-1,-1,-1,-1]],
    "api_eKyouka":[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
    "api_fParam":[[82,0,50,81],[3,0,26,25],[32,19,19,28],[39,24,31,30],[24,43,31,17],[74,0,38,69]],
    "api_eParam":[[32,32,16,28],[32,32,16,28],[7,16,7,6],[7,16,7,6],[7,16,7,6],[0,0,0,0]],
    "api_search":[1,1],
    "api_formation":[3,2,1],
    "api_stage_flag":[1,1,1],
    "api_kouku":{
      "api_plane_from":[[2],[-1]],
      "api_stage1":{
        "api_f_count":58,
        "api_f_lostcount":0,
        "api_e_count":0,
        "api_e_lostcount":0,
        "api_disp_seiku":1
      },
      "api_stage2":{
        "api_f_count":46,
        "api_f_lostcount":0,
        "api_e_count":0,
        "api_e_lostcount":0
      },
      "api_stage3":{
        "api_frai_flag":[-1,0,0,0,0,0,0],
        "api_erai_flag":[-1,0,0,1,0,0,0],
        "api_fbak_flag":[-1,0,0,0,0,0,0],
        "api_ebak_flag":[-1,0,0,0,0,1,0],
        "api_fcl_flag":[-1,0,0,0,0,0,0],
        "api_ecl_flag":[-1,0,0,0,0,0,0],
        "api_fdam":[-1,0,0,0,0,0,0],
        "api_edam":[-1,0,0,25,0,0,0]
      }
    },
    "api_support_flag":0,
    "api_support_info":null,
    "api_opening_flag":0,
    "api_opening_atack":null,
    "api_hourai_flag":[1,1,0,0],
    "api_hougeki1":{
      "api_at_list":[-1,1,7,6,8,4,3,5,-1,-1,-1,-1,-1],
      "api_df_list":[-1,11,6,10,2,8,8,7,-1,-1,-1,-1,-1],
      "api_si_list":[-1,8,505,7,505,6,6,4,-1,-1,-1,-1,-1],
      "api_cl_list":[-1,1,2,1,1,1,1,1,-1,-1,-1,-1,-1],
      "api_damage":[-1,85,2,61,16,15,5,5,0,0,0,0,0]
    },
    "api_hougeki2":{
      "api_at_list":[-1,1,8,3,4,5,6,-1,-1,-1,-1,-1,-1],
      "api_df_list":[-1,7,2,8,8,8,8,-1,-1,-1,-1,-1,-1],
      "api_si_list":[-1,12,505,6,6,4,11,-1,-1,-1,-1,-1,-1],
      "api_cl_list":[-1,1,0,1,1,1,2,-1,-1,-1,-1,-1,-1],
      "api_damage":[-1,66,0,4,8,2,69,0,0,0,0,0,0]
    },
    "api_hougeki3":null,
    "api_raigeki":null
  }
}

戦闘開始のAPIを呼び出すと、いきなり戦闘結果が返ってきます。api_hougeki1 と api_hougeki2 のあたりがそれですね。サーバーにはユーザーの艦娘のデータが保持されているので、鎮守府サーバーで戦闘の計算を出して返してきます。なので、戦闘をしてズル…はできないと思います。api_hougeki1 などの結果で、クライアントの Flash でアニメーションをしています。ということは、このあたりのデータを解析すれば、戦闘シーンは復元可能ってことです。

戦闘結果

svdata={
  "api_result":1,
  "api_result_msg":"成功",
  "api_data":{
    "api_ship_id":[-1,509,509,502,502,502,-1],
    "api_win_rank":"S",
    "api_get_exp":60,
    "api_mvp":1,
    "api_member_lv":24,
    "api_member_exp":29431,
    "api_get_base_exp":120,
    "api_get_ship_exp":[-1,432,144,144,144,144,144],
    "api_get_exp_lvup":[[69933,70300,74100],[2471,2800],[2574,2800],[8773,9100],[9330,10500],[12372,13600]],
    "api_dests":5,
    "api_destsf":1,
    "api_lost_flag":[-1,0,0,0,0,0,0],
    "api_quest_name":"カムラン半島",
    "api_quest_level":3,
    "api_enemy_info":{
      "api_level":"",
      "api_rank":"",
      "api_deck_name":"敵前衛部隊"
    },
    "api_first_clear":0,
    "api_get_flag":[0,1,0],
    "api_get_ship":{
      "api_ship_id":32,
      "api_ship_type":"駆逐艦",
      "api_ship_name":"初雪",
      "api_ship_getmes":"初雪……です……よろしく。"
    },
    "api_get_eventflag":0
  }
}

戦闘のアニメーションが終わったら、戦闘結果≒経験値を取得します。この計算も既に鎮守府サーバーで行った結果を返してきて、結果のアニメーションを出します。新しい艦娘が出て来たときには、この JSON に書いてあります。ランクとか経験値が書いてあるので、先の戦闘前の戦闘結果(ってややこしい)と、経験値の結果をあわせると、自分の艦娘の戦歴が作成できます。

多分、サーバーのほうでは、この手の履歴は保持ってないと思うんですよね。なので、いつ、どんな風に戦闘を勝ち抜いてきたのか、という戦歴は、この方法でしか取れないと思います。

■敷波復活

そんな訳で、この通信キャプチャを遣っている間に「敷波さん」をGetッ!!! 英霊により復活であります。

image

まだ、Get したばっかりなので、レベル1ですが、ええ、「ブラ鎮」≒「鎮守府をぶらぶら歩くこと」(銀ぶらと同じですねッ!!! 決して、ブラック鎮守府ではありませぬー)して遠征に出れる位までには御育て致しましょう。

2014/03/11 追記
艦これのバトルJSONを再解析(祥鳳改小破編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5517

 

カテゴリー: 艦これ | Fiddlerを使って艦これのバトルJSONを解析(敷波復活編) はコメントを受け付けていません

Fiddlerを使って艦これの戦闘シーンをトラップ(敷波撃沈編)

FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦) – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5050

の続きで、昨日の晩3時間ぐらいやってました。メモ的にやったことを書くと、

  • IE10 の開発ツールを使って、サーバーアクセスをロギング
  • Fiddler を使ってロギング
  • FiddlerCore を使って自作ツールでロギング
  • Network Monitor を使ってロギング

って感じです。Fiddler自体は、「実践Fiddler」英語版をPDFで買ってチェック。

目的は、戦闘シーンを時系列でキャプチャできないかな?と思ったところです。艦娘の獲得シーンの画面キャプチャもそうなのですが、それぞれの戦闘シーンを記録しておくと、なんとなく感情移入がしやすいというか、ボードゲームの海戦シミュレーションをやったことがある方(って何時の話か?)は分かると思いますが、記録から映像が浮かぶってやつです。いくつかハッキングもどきもできそうな感じ(艦娘の画像取得とか)ですが、それはまた別の話(注意、悪用しないように)。

戦闘シーンをIEの開発ツールで「ネットワーク キャプチャ」をするとこんな風に取れます。battle で始まって、*.swf が艦娘の画像で、*.mp3 が艦娘の音声、最後に battleresult で戦闘結果がでます。battle と battleresult は JSON なので、艦船情報と戦闘の結果(HPとか大破とか)が取れそうです。リアルタイムに戦闘シーンが取れると思ったのですが…

image

で、これを fiddlerCore でキャプチャすれば言い訳ですから、IEのFiddlerで試してみます。

image

これを見るとわかるのですが、battle と battleresult の間がほとんど通信していませよね。あれ?変だなと思って IE のほうを見れば、ステータスが 304 な訳です。なるほど、HTTPステータス・コード – CyberLibrarian を見ればわかる通り、自前のキャシュを当てにせよ、ってわけですね。で、ここまで知っていたので、じゃあ、Fiddler って 304 を無視するんですかね?と思って調べていったのが私の間違いです。

実際、Fiddler には 304 を無視するカスタムルールがついているのですが、良く分からんけど、google への 304 はキャプチャできているけど、艦これの 304 はキャプチャできない。謎だー、ってことで、あれこれと fiddlerCore の CONFIG を探したりあれこれと調べました。

image

調べたおかげで、fiddler を使いこなせるかな、ぐらいにはなったのですが、まあ目的は「艦これの戦闘シーンのキャプチャ」なので、さて、どうするかというところ。

代案として、「IE でキャッシュを効かない」ようにして、毎回取るようにすれば、常に 200 になるから大丈夫とか、送信するときのヘッダを no-cache にしてしまえば…という誘惑もあるのですが、それはそれでサーバーに負担を掛けるし、第一毎度サーバーに取りに行ったのではスムースな戦闘シーンがダメになりそうですよね。

image

ちなみに、IE のオプションでキャッシュを使わないようにして試したのですが、Flash の場合は別ものみたいです。この「自動的に確認する」が曲者で、どのくらいの時間でサーバーに問い合わせをするのかが微妙なのです…というのに気付いたのは、実は後からで、ここで私が思い込んでいたのは、

  • 304 なのだから、毎度サーバーに If-Modified-Since で問い合わせをしているのだろう。

と想像したのが間違い。あれこれ2時間ほど network monitor を使って出た結論は、

  • IE の場合、If-Modified-Since を付けていても「自動的に確認する」にしておくと、時間内であれば IE 内でしれっと 304 を返す。

ってことです。詳細な動きは Fiddler PowerToy – 第 2 部: HTTP パフォーマンス あたりに書いてあります。クライアントアプリで Web API を使う時に高速化できるテクニック(逆に、最新データを取得するときに使うテクニック)としては常套手段みたいです。

そんな訳で、リアルタイムに戦闘シーンは取れなそうですね。IEを適当にフックすれば、サーバー問い合わせをしない 304 も取れそうな気がするのですが、ちょっとそれは大袈裟だし。どうせならば、ストア版のIEに艦これを出して、スナップ表示でリアルタイム実況なるものを考えていたのですが、ちょっと無理っぽい。バトル結果と艦娘一覧ぐらいが無難ですかね。

そんな訳で、出撃を何度も繰り返して経験値を貯めつつ、戦闘ログを取っていたわけで…駆逐艦敷波の憂き目に orz うっかり、大破の後、継続して出撃しておりました。

Amazon.co.jp: 聯合艦隊軍艦銘銘伝―全860余隻の栄光と悲劇: 片桐 大自: 本 によれば、名前は「万葉集」巻十一の「うぢ川のせぜのしきなみしくしくに」から。最後は海南東方において、米潜水艦「グローラー」の雷撃により撃沈、だそうです。敷波 (吹雪型駆逐艦) – Wikipedia もあわせて、無駄な知識をため込むのOKかと。

image

英霊として復活すべく、現在、鎮守府海域を探索中…。

カテゴリー: 開発 | Fiddlerを使って艦これの戦闘シーンをトラップ(敷波撃沈編) はコメントを受け付けていません

FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦)

まあ、端的に言えば「艦これ」 http://www.dmm.com/netgame/feature/kancolle.html なのですが、先日「艦これのAPIがLTに」ってのを見つけて、そのあと自前で IE を使って調べてみました。で、単純な JSON と Flash の圧縮 SWF ファイルになっているので、解析は楽そう。実際公開当時(6月頃)から色々解析はやられているみたいで、マクロとか諸々あるのですが、まぁ、それはさておき。

艦これ 司令部室
http://nozomi.arege.jp/KanHQ/

20130827_01

というので、FiddlerCore というのを知りました。Fiddler 自体、Network monitor の後継なのかな?程度の知識しかなくて、昔は winsock をトラップするには特殊なDLLを入れないといけなくて(それでも DLL を入れて組めばなんとかなったわけですが)、かなり躊躇していたのですが、どうやら Fiddler にはコア部分だけをアプリで使えるように FiddlerCore ってのがあるんですね。なるほど。

# F# で JSON のパーサーが作ってあるのはまた後日に。

Fiddler – The Free Web Debugging Proxy by Telerik
http://fiddler2.com/
FiddlerCore – Fiddler Proxy Engine for your .NET Applications
http://fiddler2.com/fiddlercore

ネットワークモニタとして使う場合は、Fiddler をアプリとしてインストールします。詳細は、↓なんかを参考いすると色々でてきます。

実はFiddlerがすごすぎたので、機能まとめ紹介 – digital matter
http://blog.loadlimits.info/2009/09/%E5%AE%9F%E3%81%AFfiddler%E3%81%8C%E3%81%99%E3%81%94%E3%81%99%E3%81%8E%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E6%A9%9F%E8%83%BD%E3%81%BE%E3%81%A8%E3%82%81%E7%B4%B9%E4%BB%8B/

それはそれでWEB開発のテストには便利なのですが、もうちょっと突っ込んでアプリに組み込んでみたいと思っていたわけです。普通にプロキシを使えばそれでいいのですが、他アプリのネットワークも覗いてみたいですね、という感じで。

Fiddlercore Demo – Fiddler
http://fiddler.wikidot.com/fiddlercore-demo

に組み込んだときのテストコードがあります。これだとちと、ややこしいのでコメントやらイベントの位置を直したのが以下です。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.OnNotification += FiddlerApplication_OnNotification;
        Fiddler.FiddlerApplication.Log.OnLogString += Log_OnLogString;
        Fiddler.FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
        Fiddler.FiddlerApplication.BeforeResponse += FiddlerApplication_BeforeResponse;
        Fiddler.FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
        Fiddler.CONFIG.IgnoreServerCertErrors = false;
    }

    void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
    {
        Console.WriteLine("Finished session:t" + oSession.fullUrl);
    }

    void FiddlerApplication_BeforeResponse(Fiddler.Session oSession)
    {
        Debug.WriteLine("{0}:HTTP {1} for {2}", oSession.id, oSession.responseCode, oSession.fullUrl);
    }

    void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
    {
        Debug.WriteLine("Before request for:t" + oSession.fullUrl);
        oSession.bBufferResponse = true;
    }

    void FiddlerApplication_OnNotification(object sender, Fiddler.NotificationEventArgs e)
    {
        Debug.WriteLine("** NotifyUser: " + e.NotifyString);
    }
    void Log_OnLogString(object sender, Fiddler.LogEventArgs e)
    {
        Debug.WriteLine("** LogString: " + e.LogString);
    }

    /// <summary>
    /// キャプチャ開始
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.Startup(8877, true, true);

    }

    /// <summary>
    /// キャプチャ終了
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        Debug.WriteLine("Shutting down...");
        Fiddler.FiddlerApplication.Shutdown();
    }
}

実行するとこんな感じになります。

Before request for:	http://t.jp.msn.com/
** LogString: Fiddler.Network.AutoProxy> AutoProxy Detection failed.
** LogString: AutoProxy failed. Disabling for this network.
1:HTTP 200 for http://t.jp.msn.com/
Finished session:	http://t.jp.msn.com/
Before request for:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Before request for:	http://c.msn.com/c.gif?udc=true&rid=FE68A2FD2C6040C69F537FF40F542212&rnd=1377519905169&rf=&tp=http%3A%2F%2Ft.jp.msn.com%2F&scr=1920x1080&di=258&pi=9961&ps=26623&lng=ja-jp
Before request for:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
2:HTTP 200 for http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
4:HTTP 204 for http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Finished session:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Finished session:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Before request for:	http://kaw.stb01.s-msn.com/i/50/1918772e1d6c3e65af249dfb71f252/_h145_w300_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/43/b1db42c168f3442eea6c660e454/_h145_w145_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/53/cadac0dbcd456cef11aec35e1bbe17/_h145_w145_m6_utrue_otrue_lfalse.jpg

手順としては、

  1. トラップするイベントを割り付けておく。
  2. Startup メソッドでプロキシ開始。
  3. データ自体は、AfterSessionComplete イベントの Session オブジェクトで取得。
  4. 終わりは Shutdown を呼び出す。

という流れです。
コードを見るとわかるのですが、Fiddler.FiddlerApplication クラスの static メソッドになっています。つまりは、OS にひとつしかない訳ですね。どうやら、wininet をトラップしているらしく、os 上で動くネットワークを完全にプロキシ

…はしていませんね。wiinet 経由のみ。自前 winsock やっていると駄目? 一応、うちのブラウザIE10でもFirefoxの最新では大丈夫でした。それで十分用途は足りるので。

■フィルタをどうするのか?

ブラウザを複数開いていると(タブでも同じ)、あちこちでアクセスするデータを拾ってきてしまいます。なので、目的のサイトへのアクセスだけをトラップしたい場合は、、AfterSessionComplete イベントの oSession.fullUrl プロパティで判別すると思います。このあたり、いま起動している艦これだけを対象にしたい場合は、横須賀サーバーのIPだけフィルタリングするとか、そういう工夫が必要です。いや、ブラウザのトラップしたいだけなれば、WebBrowser を貼り付けてプロキシ経由にしてしまえば良いのですが。ええ、プロキシに関してはそのうち試してみましょう。

■データをどうやって取得するのか?

レスポンス自体は、oSession.ResponseBody で byte[] で取得するか、oSession.GetResponseBodyAsString() で文字列として取得します。テキストなのかバイナリなのかは、oSession.oResponse.MIMEType でチェックすれば OK ですね。

具体的に動かすのは、横須賀サーバーの復旧待ちということで。

カテゴリー: C# | FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦) はコメントを受け付けていません

ソフトウェア開発委託基本契約書の不備の感想戦

ソフトウェア開発委託基本契約書の不備により、未払い200万円の被害を受ける – Moonmile Solutions Blog
未払金の続きは内容証明で – Moonmile Solutions Blog
未払金の結末 – Moonmile Solutions Blog

のまとめです。

■ソフトウェア開発委託基本契約書の見直し

まずは、未払いなりのトラブルが発生しないように、ソフトウェア開発委託基本契約書の見直しをします。今回の落ち度は、善意に基づき「トラブルが発生した場合の損害賠償の上限を、委託金とする」という条件を入れたのですが、これを外します。ただし、条件がない場合には青天井になって、相手の悪意により(瑕疵とか難癖とかがあるので)こちらの被害が甚大になってしまうので、ある程度の上限が必要です。

  • 支払いの遅延に関しては、年18%とする。
  • 支払いを遅延した場合は、委託金の50%を損害賠償金として支払う。

金額がもっと多い場合(1000万円とか)は、別途損害金の見直しは必要でしょう。個別契約書で変更するのがよいと思います。支払の遅延による年利は銀行からの借入の利率よりも高くしておきます。そうしないと、簡単に遅延されてしまいますからね。あと、損害賠償金を明記しておきます。これは、弁護士費用、裁判費用も込みで上乗せしておくという形ですね。ただし、自転車操業的にお金をまわしている場合は、手元のキャッシュが危うくなるので、この損害賠償金では危ないパターンがあります。もともと、遅延自体がリスクなので、リスク管理的に抑制効果として条項を加えておきます。

逆に、当方の瑕疵によるプロジェクト遅延に対しても損害賠償金を支払う義務が生じます。これは、プロジェクトの遅延をしないように努めること、遅延しそうになったら事前に相手に通知すること(損害賠償金を請求されないように)を行い、事前の合意を取ります。たいていの場合、お客マター(要件定義の遅れとか、要求の肥大化、お客の隠し玉などなど)が多いので、これでクリアできるでしょう。まあ、外注している場合は「できなかった」リスクもあるので、会社としてはフォローすべきかも。フリーランスでやる限りでは、これは大丈夫かと。

■相手の状況を調べる

ホームページがあれば、それで調べるし、社長の名前があれば必ず google で検索をします。あと、2チャンネルで噂になった詐欺師ではないかを調べます。

ただし、与信管理が必要なので、

を事前にやっておきます。帝国データバンクと東京商工リサーチは5,000円ぐらいで済みます。資本金と主要株主、取締役、従業員数が出るので、これを相手の営業なり担当なりの言葉とすり合わせればOKです。このあたりの方法は、孫子の兵法に詳しいです。

■実際に遅延が起こったら(難癖による支払遅延も含む)

で、実際にお客が支払わないよ、という自体が起こったときにはどうするかというと、

今回は、金額が比較的大きいことと、私が個人的に弁護士と知り合いということもあって、弁護士費用を出すことにしましたが(まあ、それ以外の方法を知らなかったというのもあるのですが)、一応、上記2つの方法があります。

下請法の場合は、勧告扱いで実際の取り立てはどうなのかわからないのですが、ホームページに会社名が晒されるし、信用にキズが付くので、支払ってくれるはずです。あと、資本金がそれなりに多ければ100万程度なら大丈夫でしょう。まあ、大抵は会社間ってことになりますね。

支払督促の場合は、裁判所が相手の会社の給与差押えなどをしてくれます。継続して取引がある会社だと困るんでしょうが、未払いが発生するような会社と取引は続けたくないわけで(下請メーカーだと別なんでしょうが)、フリーランスならばもっと優良なお客を掴みましょう(自戒をこめて)。裁判所が強制執行をしてくれるので楽です。そのための税金ですからね。支払督促状自体は、裁判所にPDFがあるし、自分が書ける範囲です。裁判所に出向く必要もありません(郵送でOKだそうです)。値段は5,000円位(通常の訴訟の半額)なので、10万円規模ならば使ってもいいかも。

まあ、どちらにせよ、きっちりと「契約書」が残っていないと駄目なので、メールベースなりPDFなりで、金額が書いてあるものが必要です。これは忘れずに。

あと、商取引的に「手形を切って貰う」という方法もあります。手形を使うと、相手の当座預金からの引き落としができるし、手形自体を信用金庫などに売ることもでるし、それなりに融通が利くのですが、IT業界で手形で取引しているところはないですよね?小切手とか手形を使うと、未払い=即銀行の焦げ付きになるわけで、大抵は期限までに支払ってくれるはずですが、簿記を勉強すると手形の未払金の例題が多いので、まあこのパターンも支払ってもらえないパターン(相手が倒産するパターンですが)が多いのかなと。モノ(在庫)が関わってくる工場とか流通とかはそのパターンが多いかも。

■弁護士費用はどのくらいなの?

弁護士にもよるのでしょうが、経験上、

  • 手付金が10万円程度
  • 日当が3万位(これは法律で決まっている)+諸経費
  • 成功報酬が10%ぐらい(これは弁護士によって異なる)

な感じでしょうか。弁護士も「仕事」でやっているので、それなりの金額が必要です。少額の取引の場合には弁護士費用だけで赤字になってしまうので、頼むことはできなでしょうが。逆に言えば、15万円程度で弁護士を雇うことができるってことです。悪徳弁護士もいるので注意は必要ですが(そういう場合には、弁護士会に連絡すれば、弁護士資格を剥奪することも可能です)、高学歴の方をこき使うというのも面白いかと。まあ、みなさん「先生」つけて余分のですが、私は「さん」づけです。つーか、「先生」ってのは蔑称ですから。

それぞれの地方には弁護士会があるので、そこに連絡するのもありかと。あと、弁護士費用は分割にしてくれるパターンも多いので、最初は相談だけというのもありです。

■泣き寝入りしない

先のブログのコメントやメールなどで頂いたのですが、結構、未払いの例は多いようです。ひどいですよね。私の場合、2,3日寝込んでしまったのは、同時に例の8.1事件があった訳でまた別件も含めてなので(実質的には、トリプルパンチを喰らった状態で、なにがなにやら)ちょっと特殊な環境ではありますが、「泣き寝入り」ないことが重要です。

ビジネス上「はじめてのお客さん」というのは避けられません。新規顧客開拓は必要だし、引き合いでビジネスをやるのは、交渉術のひとつですよね。なので、ガードを緩く見せて、実はガードを固く保つ(あるいは、ノーガード戦法?死にそうですがw)のが良いかと。

なので、フリーランスの場合トラブルに巻き込まれるのは確率的なものです。ブラックな会社に就職しているのと違うので(いや、法務的にトラブルってのもあるし、ブラックじゃなくてもトラブルはあるんですが)、お客を選ぶというのも重要ですよね。逆に「お客に選ばせる」という戦法もあります。

私としては、今回は「泣き寝入り」はしたくなかったので「いい加減にしろ」状態で、あれこれと手を打ってみました。探してみれば、それなりに手はあるわけで、最初は全額諦めなければいけない、という話を何度も聞かされたのですが、結果的には全額支払わせたわけですよね。まあ、偶然的な要素と将棋的な手法(意図的に使いました)が功を奏したと思う訳ですが、逆に言えば、それなりの手を使えば「泣き寝入り」をする必要はありません。「泣き寝入り」を勧める意見を聞く必要もありません。邪魔です。ええ、自分が「正しいことをやっている」のであれば、被害を蒙って泣き寝入りすることはあり得ませんってことです。まあ、そのあたりは「正義」かどうかは別として、高い税金を払っていることだし、役人に動いてもらいましょう、ってことで。

カテゴリー: 仕事 | 2件のコメント