FC2ブログ

    PD2BLA開発

    最近の進捗

    NGBTOを参考に書いてみた。
    参考にとはいいつつもやはり手さぐりなので数時間もクラッシュと戦ってしまった。
    BLTを導入してからもう半年も経つらしいが、今更logsフォルダの存在に気が付きデバッグがとても捗った。
    SteamLibrary\SteamApps\common\PAYDAY 2\mods\logs

    このフォルダには日付別にテキストファイルでBLTのログが出力される。
    このログはシステムメッセージやチャットなどからLuaファイルの読み込みとエラーなどがすべて記録される。

    それから、クラッシュ時のログでおなじみの
    C:\Users\ユーザ名\AppData\Local\PAYDAY 2\crashlog.txt


    あとは沢山のLuaのリファレンスと沢山のMODのソースを見ながらいじる・・・。
    しかし、実行するのにいちいちPD2を立ち上げなければならない、Luaを変更して再読み込みするためにはPD2を再起動しなければならないと面倒・・・。

    理解していないけれども一応思った通りの動きをするようにはなった。

    スキルとパークとプレイ中のジョブ名あたりも記録できるようにしたい。
    教えて先生。

    このMODを入れてから
    Application has crashed: access violation
    が増えた気がするのでしばらく様子見。

    mod/PD2BLAp/lua/BaseMod.lua

    if RequiredScript == "lib/network/base/networkpeer" then
    --設定
    if not _G.PD2BLAp then
    _G.PD2BLAp = _G.PD2BLAp or {}
    PD2BLAp.Colors = {"ff0000", "00ff04", "1a64f6"} -- RGB
    PD2BLAp.settings = {
    file_path = "mods/PD2BLAp/ConnectionIDList.txt",
    header_list = "Time,Unixtime,SteamID64,Name",
    }
    end


    --ファイルの存在
    function PD2BLAp:FileExists(path)
    local fh = io.open(path, "rb")
    if fh then fh:close() end
    return fh ~= nil
    end

    --デバッグメッセージ
    function PD2BLAp:Debug_Message(message, color, message2)
    if message2 then
    managers.mission._fading_debug_output:script().log(message2, Color(color))
    end
    managers.mission._fading_debug_output:script().log(message, Color(color))
    end

    --Hooks
    Hooks:Add("NetworkManagerOnPeerAdded", "PD2BLAp:PeerAdded", function(peer, peer_id)
    --まずファイルが存在するか確認する
    file_exist_flag = PD2BLAp:FileExists(PD2BLAp.settings.file_path)

    --1行目は項目タイトル
    --1行に1 ID情報を格納
    --ファイルが存在しない場合は新しくファイルを作る
    if file_exist_flag == false then
    f = io.output(PD2BLAp.settings.file_path)
    f:write(PD2BLAp.settings.header_list.."\n")
    f:close()
    else
    f = io.open(PD2BLAp.settings.file_path , "r")
    line = f:read()
    print(line)
    --読み込んだ1行目の項目が最新のものでなければ最新のものに置き換える
    if line ~= PD2BLAp.settings.header_list and line ~= PD2BLAp.settings.header_list.."b" then
    text_all = {} --ファイルの内容

    while true do
    text = f:read()
    table.insert(text_all , text)
    if text == nul then break end
    end
    f:close()

    --書き込み内容を保持しつつ、項目タイトルを更新する
    f = io.open(PD2BLAp.settings.file_path , "w")
    f:write(PD2BLAp.settings.header_list.."\n")
    for i=1, #text_all, 1 do
    f:write(text_all[i].."\n")
    print(text_all[i])
    end
    end

    f:close()
    end

    f = io.open(PD2BLAp.settings.file_path , "a+") --追記で開きなおす

    --書き込む文字列
    write_line = os.date()..","..os.time()..","..peer:user_id()..","..peer:name()

    --PD2BLAp:Debug_Message(write_line, PD2BLAp.Colors[2])

    f:write(write_line.."\n")
    f:close()

    end)
    end
    スポンサーサイト



    最近の進捗

    PD2BLAの進捗

    ランキング機能は相変わらず放置中、いろいろ考えてはいるのだけれど、実装するのに必要な知識が足りないことと、拡張性を持たせて実装したいので悩み中。

    今後バックグラウンドで自動判定することを考えると、Warning判定が出たときに何か音を鳴らすとかしてもいいかもしれない。

    細かい変更だけども、AchievementDetailのバーの位置を変更して常に全ての行が見えるようにした。
    バーと表が被っているのがのがデザイン的に不恰好だっただけ。
    ついでにスクリーンショットのメニューも追加。
    手軽に絞り込みできる機能をつける予定。(UnlockTime LIKE 'XXX'のXXXを自動的に挿入するような)

    76561198147063532_AchievementDetail_20160305162153.png


    あとはフレンドを一括でチェックする機能。
    ただし、こちらはSteamとPD2StatsAPIに連続アクセスするので没になるかも。
    一応最低でも1秒以内に連続アクセスすることは無いように配慮しているが、それでいいのか?
    SteamBan情報は数百のIDに対して1度で取得できるが、AchievementとPD2Statsは1IDに対して1度のアクセスが必要。

    PD2BLA1_15_0_0_1.jpg
    (今話題のこの方!ちなみにフレンドが被害にあったので間違いなく黒。
    この人が出現するとSWATは死ぬ、残らず死ぬ。)

    PD2でユーザが接続を要求したときにバックグラウンドで勝手に判定する機能を考え中。
    プロセス間通信にはいろいろ方法があるけれど、ログを後でも見られたほうがいいかなということでテキストファイルに出力していく形で実装しようかと。
    そうなると、PD2側にMODを導入してもらわないといけなくなるが、Luaの勉強にもなるしいいかなーと、書き始めたはいいもののぜんぜん知らない言語だとはかどらないはかどらない。

    でも、思い通りに動くと楽しいね!
    実行もコマンドラインですぐ、実行速度も速いし。

    ということで、とりあえずLuaでちょろっと書いてみた。
    C#ならもっとコンパクトに書けるのに、うーん。

    ファイルを開いて、閉じて、開いて、閉じて、開く!
    すごく無駄!
    どうすれば・・・。
    (あと、Syntaxのハイライトされない)


    --http://symfoware.blog68.fc2.com/blog-entry-454.html

    --http://lua.tips/index.php?Lua%20implements_func_io
    -- 対象のfilenameのファイルが存在するかどうか。
    -- 対象のファイルのフルパス。もしくは、カレントからの相対パス。
    --戻り値bool
    function io.file_exists(path)
    local fh = io.open(path, "rb")
    if fh then fh:close() end
    return fh ~= nil
    end

    br = "n" -- 改行
    header_list = "SteamID64,Name" --出力する項目タイトル

    --まずファイルが存在するか確認する
    file_path = "ConnectedList.txt"
    file_exist_flag = io.file_exists(file_path)

    --1行目は項目タイトル
    --1行に1 ID情報を格納

    --ファイルが存在しない場合は新しくファイルを作る
    if file_exist_flag == false then
    f = io.output(file_path)
    f:write(header_list..br)
    f:close()
    else
    f = io.open(file_path , "r")
    line = f:read()
    print(line)
    --読み込んだ1行目の項目が最新のものでなければ最新のものに置き換える
    if line ~= header_list and line ~= header_list..br then
    text_all = {} --ファイルの内容

    while true do
    text = f:read()
    table.insert(text_all , text)
    if text == nul then break end
    end
    f:close()

    --書き込み内容を保持しつつ、項目タイトルを更新する
    f = io.open(file_path , "w")
    f:write(header_list..br)
    for i=1, #text_all, 1 do
    f:write(text_all[i]..br)
    print(text_all[i])
    end
    end

    f:close()
    end

    f = io.open(file_path , "a+") --追記で開きなおす
    --ID情報の書き出し処理
    f:close()

    最近の進捗

    前回の記事で実績情報を他から得ようとしていたけれども、解除時間まで取得しようと思うと今の取得方法は外せないことが分かったのでショボーン

    http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=APPID&key=APIKEY&steamid=SteamID64

    でユーザの詳細な情報を取得するところまで作ったけれども、どうしたものやら。

    PD2Stats APIがまだ使えるのでそこで判定している条件はとりあえず実装しないが、もしかすると使えなくなったときのことを考えて条件を知っておきたい。

    ところで、PD2BLAのダウンロード数をまとめてみた。

    PD2BLA_Download_1_13_0_0.png

    公開時間が一番長いv1.0.0が一番ダウンロード数が多いのは当然として、EXEのダウンロード数がここまで多いというのは意外だった。

    二つリンクを貼るのが面倒でEXEを公開しなくなったが、あったほうがよかっただろうか?
    ZIPの二倍くらいダウンロードされているし需要高いのだろうか。
    個人的にEXEは怖いというイメージがあるのだが。

    readme.txtを読んでもブログの記事を検索してもv1.5.2とv1.5.4に関するものはなく、一瞬だけ公開した不具合の多いバージョンだったので一日で公開を停止したものの20件近くのダウンロードされている。
    新規さんよりも、バージョンを追いかけてくれている人が多いといことだろうか?

    アプリ内でバージョンアップ出来るようにしたv1.5.5の直後v1.6.2ではZIP利用者が増えているが、不具合も多くその後もZIP利用は伸び悩みしているが、
    直前のv1.4.2とv1.5.2ではZIPが多くダウンロードされている、謎だ。

    何はともあれ、v1.10.2からはダウンロード数も安定しているようで嬉しい。
    あまり利用者が増えてあれこれエラー報告されても困るし(報告されたことない)

    ##########

    ちなみに、PAYDAY2 セーブデータ手動バックアップ(batファイル)の方は2015/9/13公開で48回のダウンロード数。

    ##########




    PD2BLA内の実績関係の部分でCSVを作ろうかなと思っていたので、タイムリーな話題だ!

    最近の進捗

    実績の規定値情報を取得するAPIは何だったかなと思いながら、ぼんやりGetUserStatsForGame (v0002)を眺めていた所、
    skillの取得情報や武器の使用状況などPD2StatsやFBIFileで実現しているゲーム内情報をゲーム外から見るために必要な情報が含まれていることを発見した。

    が、それをWEBブラウザ上で視覚化する技術が無かった残念!
    HTMLとCSSとJSとPHPあたりが自由に使えるとかなり捗るのはわかっているもののなかなか・・・、デザインセンスもないしで。

    ちなみに、実績の規定値情報を取得するAPIはこちら。

    http://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v2/?key=APIKEY&appid=APPID

    ユーザの実績情報は

    http://steamcommunity.com/id/NAME/stats/APPID/achievements/?xml=1

    で取得しているけれど、ここを

    http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=APPID&key=APIKEY&steamid=SteamID64&format=xml

    で取得して、実績情報のついでにその他の情報まで取得して、更にデータサイズが小さくなって一石二鳥のようだ。

    ちなみに、スキル振りの状況や武器の使用状況は以下のようになっている。(覚書:長くなったので一番下に移動)

    ところで、グローバル実績との比較の情報はこちら

    http://api.steampowered.com/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v0002/?gameid=218620&format=xml

    で取得できるのだが、現状取得できないはず(情報がない実績の取得情報)があるのはチーターなのか、テスト用の実績なのかどちらだろう。
    この辺を使うと新実績が追加されてすぐにチートで実績を解除したチーターも排除できそう。


    現在のレベル
    <stat>
    <name>player_level</name>
    <value>100</value>
    </stat>

    スキルの振り方簡易(MM:1以上ならスキルツリーを解除済みでbasic,ace共に1でカウント)
    <stat>
    <name>skill_mastermind</name>
    <value>11</value>
    </stat>
    <stat>

    スキルの振り方詳細(MM:basic,aceの取得状況)
    <stat>
    <name>skill_mastermind_cable_guy</name>
    <value>1</value>
    </stat>
    <stat>
    <name>skill_mastermind_cable_guy_ace</name>
    <value>1</value>
    </stat>

    武器使用状況
    <stat>
    <name>weapon_used_new_m4</name>
    <value>208</value>
    </stat>

    武器キル数
    <stat>
    <name>weapon_kills_b92fs</name>
    <value>4154</value>
    </stat>

    装備品使用状況
    <stat>
    <name>gadget_used_ammo_bag</name>
    <value>1339</value>
    </stat>

    難易度挑戦回数(DWは内部的にはOVK145らしい)
    <stat>
    <name>difficulty_overkill</name>
    <value>165</value>
    </stat>
    <stat>
    <name>difficulty_overkill_145</name>
    <value>958</value>
    </stat>

    JOB挑戦回数?
    <stat>
    <name>level_four_stores</name>
    <value>67</value>
    </stat>

    JOB挑戦回数?
    <stat>
    <name>job_four_stores</name>
    <value>161</value>
    </stat>

    JOB成功回数
    <stat>
    <name>contract_four_stores_win</name>
    <value>63</value>
    </stat>
    <stat>
    <name>contract_four_stores_win_dropin</name>
    <value>11</value>
    </stat>
    <stat>
    <name>contract_four_stores_fail</name>
    <value>8</value>
    </stat>

    アーマー使用回数
    <stat>
    <name>armor_used_level_1</name>
    <value>2415</value>
    </stat>

    敵キル数
    <stat>
    <name>enemy_kills_swat</name>
    <value>12426</value>
    </stat>

    近接武器キル数
    <stat>
    <name>melee_kills_barbedwire</name>
    <value>1</value>
    </stat>

    マスク使用回数
    <stat>
    <name>mask_used_unicorn</name>
    <value>199</value>
    </stat>

    キャラクタ使用回数(ソコル君?)
    <stat>
    <name>character_used_russian</name>
    <value>244</value>
    </stat>

    最近の進捗

    いちいち魚拓を取るのも面倒な人向け機能"画面キャプチャ"意外ととてもお手軽に実装できる。

    ところで、画像の保存形式(bmp,png,jpegなど)と保存名はどうするのが一般的なのだろうか。
    とりあえずは、"現在の日時時間.png"でexeと同じ場所に出力するようにしているのだが、"SteamID64_時間.png"とかにしたほうがいいのだろうか。
    その辺をいじれるような機能の実装に挑戦する機会だろうか。
    文字列の置き換えだけで済みそうな予感だけれども、正規表現が不自由なので苦労しそうだ。

    PD2BLA1_13_0_2_20151103033553_2.png
    PD2BLA1_13_0_2_20151103035140_2.png

    ついでにSteamIDタブのテキストが見切れる不具合も
    修正。(多分気が付いている人すらいないくらいびみょうなところ)


    ところで、PD2Stats APIはFriendOnly設定のプレイヤーもWarning表示できるようで。
    そもそも、privacyStateがPrivateかFriendOnlyの場合はPD2Statsを取得しないようにプログラムしているはずなのになぜ取得しているのか全くわけがわからない。
    非同期処理の弊害かもしれない、要チェック。

    HTMLしか見ていなかったときは、PrivateかFriendOnly設定になっていると判定していても表示を伏せるようになっていたからわからなかったようで、その辺を考えてもAPIからの取得に切り替えたのはよかったなと。

    PD2BLA1_13_0_2_20151103034643.png

    Achievementの部分にラベルが被って表示がおかしくなっているのは気のせい