開発環境 Microsoft Visual Studio Express 2013 for Windows Desktop
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 Visual C#/コンソール アプリケーション
プロジェクト名 kcsapiLog

Program.cs
/*
 * プロジェクト参照
 * ・アセンブリ/フレームワーク
 *  ・System.Web
 * ・参照
 *  ・DynamicJson.dll
 *  ・FiddlerCore4.dll
 */
 
using Codeplex.Data;
using Fiddler;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
 
namespace kcsapiLog
{
    class Program
    {
        static readonly string[] formation = { null, "単縦陣", "複縦陣", "輪形陣", "梯形陣", "単横陣" };
        static readonly string[] intercept = { null, "同航戦", "反航戦", "T字戦(有利)", "T字戦(不利)" };
 
        static dynamic api_deck;    // 艦隊
        static Dictionary<int, dynamic> mst_ship = new Dictionary<int, dynamic>();    // 艦マスタ
        static Dictionary<int, dynamic> mst_slot = new Dictionary<int, dynamic>();    // 装備マスタ
        static Dictionary<int, dynamic> lst_ship = new Dictionary<int, dynamic>();    // 保有艦リスト
        static Dictionary<int, int> lst_slot = new Dictionary<int, int>();    // 装備保有リスト
        static Dictionary<string, string> map_deck = new Dictionary<string, string>();
        static string map_id;
 
        static void Main(string[] args)
        {
            ParseApiStart2();
            ParseApiPort();
 
            FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
            Console.CancelKeyPress += Console_CancelKeyPress;
            Disp("Starting {0}...", FiddlerApplication.GetVersionString());
            FiddlerApplication.Startup(0, true, true);
            Disp("Hit CTRL+C to end session.");
 
            try
            {
                bool bDone = false;
                do
                {
                    ConsoleKeyInfo cki = Console.ReadKey();
                    Console.WriteLine();
                    switch (cki.KeyChar)
                    {
                        case '1': DispDeck(1); break;
                        case '2': DispDeck(2); break;
                        case '3': DispDeck(3); break;
                        case '4': DispDeck(4); break;
                        case 'n': DispNDock(); break;
                        case 'q':
                            bDone = true;
                            break;
                    }
                } while (!bDone);
            }
            catch (Exception e)
            {
                Disp(e.ToString());
            }
 
            DoQuit();
        }
 
        static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            DoQuit();
        }
 
        private static void DoQuit()
        {
            DispColor(ConsoleColor.Yellow, "Shutting down...");
            FiddlerApplication.Shutdown();
            Thread.Sleep(500);
        }
 
        private static void Disp(string format, params object[] arg)
        {
            DispColor(ConsoleColor.Gray, format, arg);
        }
 
        private static void DispColor(ConsoleColor color, string format, params object[] arg)
        {
            Console.ForegroundColor = color;
            Console.WriteLine(format, arg);
            Console.ResetColor();
        }
 
        static void FiddlerApplication_AfterSessionComplete(Session oSession)
        {
            string[] url = oSession.fullUrl.Split('/');
            if (5 <= url.Length && url[3] == "kcsapi")
            {
                if (oSession.oResponse.MIMEType == "text/plain")
                {
                    string req = oSession.GetRequestBodyAsString();
                    string res = oSession.GetResponseBodyAsString();
 
                    string dir = string.Join("/", url, 4, url.Length - 4);
                    DispColor(ConsoleColor.DarkGreen, dir);
                    string fname = "";
                    switch (dir)
                    {
                        case "api_start2":
                            fname = "api_start2";
                            break;
                        case "api_port/port":
                            fname = "api_port";
                            break;
                        case "api_get_member/slot_item":
                            fname = "slot_item";
                            break;
                    }
                    if (fname != "")
                    {
                        using (StreamWriter sw = new StreamWriter(fname + ".js"))
                        {
                            sw.Write(res);
                        }
                    }
 
                    using (StreamWriter sw = new StreamWriter("Response.log", true))    // append
                    {
                        sw.WriteLine(oSession.fullUrl + "\t" + req + "\t" + res);
                    }
 
                    NameValueCollection nvc = HttpUtility.ParseQueryString(req);
                    dynamic json = svdata2json(res);
                    dynamic data = json.api_data() ? json.api_data : null;
                    switch (url[4])
                    {
                        case "api_get_member":
                            switch (url[5])
                            {
                                case "mapinfo":
                                    GetMember_Mapinfo(data);
                                    break;
                                case "mapcell":
                                    Disp("出撃開始");
                                    break;
                                case "ndock":
                                    Disp("入渠");
                                    break;
                                case "practice":
                                    GetMember_Practice(data);
                                    break;
                                case "ship2":
                                    api_deck = json.api_data_deck;
                                    CreateLstShip(data);
                                    break;
                                case "slot_item":
                                    GetMember_SlotItem(data);
                                    break;
                            }
                            break;
                        case "api_port":
                            switch (url[5])
                            {
                                case "port":
                                    ParseApiPort(json);
                                    break;
                            }
                            break;
                        case "api_req_battle_midnight":
                            switch (url[5])
                            {
                                case "battle":
                                    Disp("夜戦");
                                    break;
                                case "sp_midnight":
                                    ReqBattleMidnight_SpMidnight(data);
                                    break;
                            }
                            break;
                        case "api_req_hokyu":
                            switch (url[5])
                            {
                                case "charge":
                                    ReqHokyu_Charge(data);
                                    break;
                            }
                            break;
                        case "api_req_kousyou":
                            switch (url[5])
                            {
                                case "createitem":
                                    ReqKousyou_Createitem(nvc, data);
                                    break;
                            }
                            break;
                        case "api_req_map":
                            switch (url[5])
                            {
                                case "next":
                                    ReqMap(data);
                                    break;
                                case "start":
                                    ReqMap(data);
                                    break;
                            }
                            break;
                        case "api_req_member":
                            switch (url[5])
                            {
                                case "get_practice_enemyinfo":
                                    ReqMember_GetPracticeEnemyinfo(data);
                                    break;
                            }
                            break;
                        case "api_req_practice":
                            switch (url[5])
                            {
                                case "battle":
                                    ReqPractice_Battle(data);
                                    break;
                                case "battle_result":
                                    ReqPractice_BattleResult(data);
                                    break;
                                case "midnight_battle":
                                    ReqPractice_MidnightBattle(data);
                                    break;
                            }
                            break;
                        case "api_req_sortie":
                            switch (url[5])
                            {
                                case "battle":
                                    ReqSortie_Battle(data);
                                    break;
                                case "battleresult":
                                    ReqSortie_Battleresult(data);
                                    break;
                            }
                            break;
                    }
                }
            }
        }
 
        // 各種マスタ
        private static void ParseApiStart2()
        {
            dynamic json = ReadJson("api_start2.js");
 
            dynamic data = json.api_data;
            foreach (dynamic ship in data.api_mst_ship)
            {
                mst_ship[(int)ship.api_id] = ship;
            }
            foreach (dynamic slot in data.api_mst_slotitem)
            {
                mst_slot[(int)slot.api_id] = slot;
            }
        }
 
        // 母港情報
        private static void ParseApiPort(dynamic json = null)
        {
            if (json == null)
            {
                json = ReadJson("api_port.js");
            }
 
            dynamic data = json.api_data;
            api_deck = data.api_deck_port;
            CreateLstShip(data.api_ship);
        }
 
        // JSONファイル読み込み
        private static dynamic ReadJson(string path)
        {
            string svdata;
            using (StreamReader sr = new StreamReader(path))
            {
                svdata = sr.ReadToEnd();
            }
            return svdata2json(svdata);
        }
 
        private static dynamic svdata2json(string svdata)
        {
            string res = Regex.Replace(svdata, @"\\u(?<code>[0-9A-Fa-f]{4})",
                (Match m) => ((char)Convert.ToInt32(m.Groups["code"].Value, 16)).ToString());
            return DynamicJson.Parse(res.Substring(7));
        }
 
//==============================================================================
 
        private static void GetMember_Mapinfo(dynamic data)
        {
            Disp("出撃");
            foreach (dynamic map in data)
            {
                if (map.api_eventmap() && (int)map.api_cleared == 0)
                {
                    int max_maphp = (int)map.api_eventmap.api_max_maphp;
                    int now_maphp = (int)map.api_eventmap.api_now_maphp;
                    Disp("map:{0} {1}/{2} {3}%", (int)map.api_id,
                        now_maphp, max_maphp, 100 * now_maphp / max_maphp);
                }
            }
        }
 
        private static void GetMember_Practice(dynamic data)
        {
            Disp("演習");
            foreach (dynamic d in data)
            {
                Disp("{0}「{1}」", d.api_enemy_name, d.api_enemy_comment);
            }
        }
 
        // 装備アイテム
        private static void GetMember_SlotItem(dynamic data)
        {
            lst_slot.Clear();
            foreach (dynamic d in data)
            {
                lst_slot[(int)d.api_id] = (int)d.api_slotitem_id;
            }
            Disp("装備アイテム保有数 {0}", lst_slot.Count);
        }
 
        private static void ReqBattleMidnight_SpMidnight(dynamic data)
        {
            MidnightBattle(data);
        }
 
        private static void ReqHokyu_Charge(dynamic data)
        {
            Disp("補給");
            Disp("ボーキサイト消費:{0}", (int)data.api_use_bou);
        }
 
        private static void ReqKousyou_Createitem(NameValueCollection nvc, dynamic data)
        {
            Disp("開発開始");
 
            string str = "失敗";
            if (data.api_slot_item())
            {
                str = mst_slot[(int)data.api_slot_item.api_slotitem_id].api_name;
            }
 
            var mat = new string[4];
            for (var i = 0; i < mat.Length; i++)
            {
                mat[i] = nvc["api_item" + (i + 1)];
            }
            Disp("{0} {1}", string.Join("/", mat), str);
        }
 
        private static void ReqMap(dynamic data)
        {
            map_id = string.Format("{0}-{1}-{2}",
                (int)data.api_maparea_id, (int)data.api_mapinfo_no, (int)data.api_no);
            Disp("{0} 羅針盤:{1}", map_id, data.api_rashin_flg);
 
            if (data.api_itemget())
            {
                dynamic item = data.api_itemget;
                Disp("item:{0} {1}", (int)item.api_id, (int)item.api_getcount);
            }
        }
 
        private static void ReqMember_GetPracticeEnemyinfo(dynamic data)
        {
            Disp("艦隊名:{0}", data.api_deckname);
            foreach (dynamic ship in data.api_deck.api_ships)
            {
                int id = (int)ship.api_ship_id;
                if (id < 0) break;
                Disp("lv{0} {1}", (int)ship.api_level, GetShipName(id));
            }
        }
 
        private static void ReqPractice_Battle(dynamic data)
        {
            Battle(data);
        }
 
        private static void ReqPractice_BattleResult(dynamic data)
        {
            BattleResult(data);
        }
 
        private static void ReqPractice_MidnightBattle(dynamic data)
        {
            MidnightBattle(data);
        }
 
        private static void ReqSortie_Battle(dynamic data)
        {
            Battle(data);
        }
 
        private static void ReqSortie_Battleresult(dynamic data)
        {
            BattleResult(data);
 
            Disp("艦保有数 {0} 隻", lst_ship.Count);
            string ship_type = "";
            string ship_name = "";
            if (data.api_get_ship())
            {
                dynamic ship = data.api_get_ship;
                ship_type = ship.api_ship_type;
                ship_name = ship.api_ship_name;
            }
 
            string line = string.Join(",",
                DateTime.Now.ToString(), map_id, data.api_win_rank, ship_type, ship_name);
            Disp(line);
            using (StreamWriter sw = new StreamWriter("get_ship.csv", true, Encoding.Default))
            {
                sw.WriteLine(line);
            }
        }
 
        private static void Battle(dynamic data)
        {
            int[] ship_ke = data.api_ship_ke;
            for (int i = 1; i < ship_ke.Length; i++)
            {
                int id = ship_ke[i];
                if (id < 0) continue;
 
                dynamic mship = mst_ship[id];
                Disp("{0} lv{1} hp{2} {3} {4}", i, (int)data.api_ship_lv[i], (int)data.api_maxhps[6 + i],
                    mship.api_name, mship.api_yomi);
            }
 
            dynamic form = data.api_formation;
            Disp("自:{0} 敵:{1} {2}",
                formation[(int)form[0]], formation[(int)form[1]], intercept[(int)form[2]]);
            Disp("艦隊:{0} 夜戦:{1}", (int)data.api_dock_id, (int)data.api_midnight_flag);
            /*
            api_kouku	航空
             api_stage1	
              api_disp_seiku
              api_f_count	味方制空値
              api_f_lostcount
             api_stage3
              api_edam	敵ダメージ
 
            api_opening_atack	開幕雷撃
             api_edam	敵ダメージ
             api_frai	味方攻撃対象
             */
        }
 
        private static void MidnightBattle(dynamic data)
        {
            dynamic hougeki = data.api_hougeki;
            for (int i = 1; i < ((int[])hougeki.api_at_list).Length; i++)
            {
                Disp("at{0} sp{1}",
                    (int)hougeki.api_at_list[i], (int)hougeki.api_sp_list[i]);
            }
            // at_list 攻撃番号配列
            // cl_list クリティカル
            // damage  ダメージ
            // df_list 防御番号
            // si_list 攻撃装備id slot item
            // sp_list 特殊攻撃 1:連撃 3:カットイン雷撃
        }
 
        private static void BattleResult(dynamic data)
        {
            Disp("敵艦隊名:{0}", data.api_enemy_info.api_deck_name);
            Disp("win_rank:{0} mvp:{1}", data.api_win_rank, (int)data.api_mvp);
            Disp("基本経験値:{0} 提督経験値:{1}", (int)data.api_get_base_exp, (int)data.api_get_exp);
            // api_dests  撃沈数
            // api_destsf 旗艦撃沈
        }
 
//==============================================================================
 
        // 保有艦リスト
        private static void CreateLstShip(dynamic api_ship)
        {
            Disp("保有艦リスト更新 {0}", DateTime.Now);
            lst_ship.Clear();
            foreach (dynamic ship in api_ship)
            {
                lst_ship[(int)ship.api_id] = ship;
            }
            Disp("艦保有数 {0} 隻", lst_ship.Count);
            DispDeck(1);
        }
 
        // 艦名の取得
        private static string GetShipName(int ship_id)
        {
            dynamic mship = mst_ship[ship_id];
            return mship.api_name;
        }
 
        // 艦隊の表示
        private static void DispDeck(int id)
        {
            foreach (dynamic i in api_deck[id - 1].api_ship)
            {
                int ship_uid = (int)i;
                if (ship_uid < 0) break;
 
                dynamic ship = lst_ship[ship_uid];
                dynamic mship = mst_ship[(int)ship.api_ship_id];
                Disp("lv{0}.{1:D2} co{2} 燃{4}/弾{5} hp{3}% {6}",
                    (int)ship.api_lv, (int)ship.api_exp[2], (int)ship.api_cond,
                    100 * (int)ship.api_nowhp / (int)ship.api_maxhp,
                    Math.Round(10 * ship.api_fuel / mship.api_fuel_max),
                    Math.Round(10 * ship.api_bull / mship.api_bull_max),
                    mship.api_name);
            }
        }
 
        // 入渠ドックの表示
        private static void DispNDock()
        {
            var list = new List<Tuple<int, string>>();
            foreach (var kvp in lst_ship)
            {
                dynamic ship = kvp.Value;
                int hp = (int)ship.api_maxhp - (int)ship.api_nowhp;
                if (0 < hp)
                {
                    int sec = (int)ship.api_ndock_time / 1000;
                    int nowhp = (int)ship.api_nowhp;
                    int maxhp = (int)ship.api_maxhp;
                    TimeSpan ts = new TimeSpan(0, 0, sec);
                    list.Add(Tuple.Create(sec, string.Format("{0} {1} {2}/{3} {4}", ts.ToString("g"),
                        maxhp - nowhp, nowhp, maxhp, GetShipName((int)ship.api_ship_id))));
                }
            }
            list.Sort((Tuple<int, string> t1, Tuple<int, string> t2) => t2.Item1 - t1.Item1);
            foreach (var t in list)
            {
                Disp(t.Item2);
            }
        }
    }
}
 
最終更新:2014年05月23日 04:27