読者です 読者をやめる 読者になる 読者になる

Future Convergence PRJ.

主にプログラミング関連で調べたことのメモ(趣味プログラムなので動作は保証しません)

imgタグで画像が表示されない原因と対策

imgタグでパスがあっているのに画像が表示されないと思っていろいろ調べたところ、CMYK形式で保存されたjpgファイルだとブラウザによって表示できないことがあるらしい。確かに、IEで表示できなかった画像がChromeでは普通に表示できていた。
対策としてはRGB形式に変換すればいいらしいが、専門ソフトとか持ってないので、とりあえずペイントで開いて名前をつけて保存(上書きはだめ)を選択、ファイル名はもとのまま保存したら表示できるようになった。

floatプロパティは浮くって話

html/CSSのfloatプロパティについて。
floatは文字通り「浮く」ってことを理解したら、動作がしっくりくるようになった。

以下、図にfloatを設定したdiv要素の配置結果をまとめてみた。図の中で浮くっていうのは画面から飛び出すイメージで↑は見たままの方向に移動するイメージ。
f:id:CHappy:20150328024433p:plain

floatを使うと「floatで浮き上がった画面」と「残った画面」の2枚ができて、その2つを重ねるっていうイメージがいいのかな?重ね合わせるときに「残った画面」の隠れちゃう部分を表示するためにブロックレベル要素は下段にずらされるし、インライン要素はブロックの見えている部分に表示されるって感じだと思う。


サンプルソース
test.html

<!DOCTYPE html>
<thml lang="ja">
<head>
    <meta charset="utf-8">
    <title>FloatTest</title>
    <link rel="stylesheet" href="../common/css/test.css">
</head>
<body>
   <div id="boxA">boxA</div>
   <div id="boxB">boxB</div>
   <div id="boxC">boxC</div>
</body>
</html>

test.css

#boxA {
    width: 400px;
    background-color: #FF2255;
    float: left;
}

#boxB {
    width: 300px;
    background-color: #55FF22;
    float: left;
}

#boxC {
    width: 200px;
    background-color: #2255FF;
//    float: left;
}

第2回メドレーフェスティバルのボーダー推移

スクフェスの第2回メドレーフェスティバルのボーダーの時系列データまとめ。(今更ながら、忙しくてまとめてられなかった…)
スクフェス 自動ランキング取得(VB.NET)~パケット取得ver. - Future Convergence PRJ.で作ったアプリをタスクスケジューラで1時間毎に実行して取得。ところどころアプリが異常終了してデータが欠損してるけど原因がよく分からない。

日時 参加人数 20位 9000位 45000位 108000位 225000位 405000位 630000位 900000位
2015/01/20 16:42 125679 6687 2416 1055 301 0 0 0 0
2015/01/20 17:41 201516 14379 4036 1413 997 0 0 0 0
2015/01/20 18:40 279366 24237 5279 2009 1087 556 0 0 0
2015/01/20 19:40 346244 33137 6303 2283 1263 932 0 0 0
2015/01/20 20:40 402779 41860 7281 2741 1612 1026 0 0 0
2015/01/20 21:37 452443 50533 8572 3221 1958 1088 490 0 0
2015/01/20 22:39 496244 59284 9897 3758 2136 1315 707 0 0
2015/01/20 23:36 535418 68411 11015 4304 2418 1627 923 0 0
2015/01/21 00:36 568854 77509 12096 4824 2778 1880 1019 0 0
2015/01/21 01:37 588959 84990 12907 5247 3023 2039 1065 0 0
2015/01/21 02:37 600071 94012 13409 5470 3159 2093 1109 0 0
2015/01/21 03:39 605820 102254 13719 5609 3221 2139 1143 0 0
2015/01/21 04:39 609121 107178 13889 5706 3273 2174 1170 0 0
2015/01/21 05:39 611388 110372 14046 5790 3319 2199 1192 0 0
2015/01/21 06:37 613851 115615 14261 5892 3397 2247 1223 0 0
2015/01/21 07:38 618739 115900 14621 6123 3615 2404 1295 0 0
2015/01/21 08:38 625569 119104 15068 6410 3879 2636 1392 0 0
2015/01/21 09:37 630898 122720 15423 6587 4036 2767 1469 0 0
2015/01/21 10:37 635973 122720 15770 6761 4164 2868 1545 39 0
2015/01/21 11:37 640802 127218 16150 6953 4259 2981 1616 100 0
2015/01/21 12:37 646244 130722 16578 7179 4397 3096 1686 144 0
2015/01/21 13:37 653963 138031 17183 7511 4655 3246 1794 253 0
2015/01/21 14:37 658952 145997 17639 7737 4820 3368 1871 285 0
2015/01/21 15:37 663643 153384 18117 7974 4979 3487 1932 321 0
2015/01/21 16:37 669151 155999 18712 8269 5178 3650 2012 401 0
2015/01/21 17:37 675818 160938 19345 8585 5353 3818 2092 454 0
2015/01/21 18:37 682867 166499 20098 8946 5540 3990 2179 497 0
2015/01/21 19:37 690222 172969 20813 9316 5765 4160 2312 529 0
2015/01/21 20:37 698154 178120 21627 9705 5995 4311 2458 571 0
2015/01/21 21:36 706277 186186 22690 10150 6229 4500 2621 630 0
2015/01/21 22:36 714467 193657 24002 10606 6443 4700 2769 720 0
2015/01/21 23:36 722578 196796 25214 11110 6704 4923 2919 816 0
2015/01/22 00:36 729991 205203 25728 11570 6992 5145 3071 877 0
2015/01/22 01:36 734591 210035 26116 11945 7224 5299 3160 903 0
2015/01/22 02:36 737343 213526 26399 12193 7365 5402 3223 931 0
2015/01/22 03:37 738928 216807 26572 12344 7447 5470 3264 934 0
2015/01/22 04:37 739844 216807 26658 12444 7505 5513 3288 940 0
2015/01/22 05:37 740501 217202 26746 12514 7546 5546 3307 940 0
2015/01/22 06:37 741182 223138 26855 12601 7610 5597 3332 944 0
2015/01/22 07:37 742388 223705 27177 12793 7805 5735 3395 951 0
2015/01/22 08:37 744155 225530 27588 13065 8066 5941 3485 970 0
2015/01/22 09:37 745716 230850 27835 13239 8225 6070 3548 983 0
2015/01/22 10:37 747287 234800 28065 13403 8350 6176 3608 985 0
2015/01/22 11:37 748984 236568 28310 13578 8468 6271 3670 999 0
2015/01/22 12:37 750928 237118 28615 13780 8612 6381 3734 1017 0
2015/01/22 13:37 753716 240328 29117 14115 8862 6560 3832 1026 0
2015/01/22 14:37 755846 249804 29459 14325 9020 6678 3898 1031 0
2015/01/22 15:38 758009 251155 29773 14534 9170 6791 3963 1046 0
2015/01/22 16:37 760353 251557 30145 14793 9342 6932 4048 1050 0
2015/01/22 17:37 763373 260132 30571 15077 9529 7097 4144 1068 0
2015/01/22 18:38 766710 261199 31059 15378 9715 7262 4249 1098 0
2015/01/22 19:37 770339 265008 31519 15695 9927 7425 4371 1130 0
2015/01/22 20:37 774201 270549 32042 16029 10141 7591 4500 1176 0
2015/01/22 21:36 778442 274587 32622 16407 10352 7768 4634 1240 0
2015/01/22 22:36 782491 279923 33302 16832 10566 7963 4776 1309 0
2015/01/22 23:36 786544 283771 34042 17305 10809 8181 4926 1377 0
2015/01/23 00:36 790202 293279 34727 17734 11075 8383 5070 1443 0
2015/01/23 01:36 792694 294702 35219 18097 11307 8553 5172 1488 0
2015/01/23 03:36 795062 305632 35743 18492 11543 8734 5272 1535 0
2015/01/23 04:37 795603 312282 35874 18584 11599 8780 5295 1546 0
2015/01/23 05:37 795971 312282 36012 18655 11642 8814 5312 1553 0
2015/01/23 06:37 796346 315499 36119 18738 11708 8866 5333 1559 0
2015/01/23 07:37 796985 323662 36388 18931 11892 9004 5389 1573 0
2015/01/23 08:37 797946 326504 36724 19214 12157 9201 5469 1591 0
2015/01/23 09:37 798791 326504 37006 19393 12314 9322 5527 1608 0
2015/01/23 10:37 799719 328169 37245 19569 12439 9421 5577 1627 0
2015/01/23 11:37 800777 330835 37512 19740 12551 9512 5628 1639 0
2015/01/23 12:37 801906 333481 37760 19938 12687 9621 5689 1660 0
2015/01/23 13:37 803622 335664 38130 20223 12919 9795 5783 1687 0
2015/01/23 14:37 804928 335664 38433 20436 13073 9911 5847 1710 0
2015/01/23 15:37 806256 339006 38717 20643 13206 10022 5908 1727 0
2015/01/23 16:37 807802 339006 39029 20862 13375 10150 5985 1752 0
2015/01/23 17:37 809689 345412 39433 21120 13549 10298 6084 1785 0
2015/01/23 18:37 811873 352483 39861 21402 13724 10451 6187 1817 0
2015/01/23 19:37 814295 355623 40267 21677 13914 10601 6291 1855 0
2015/01/23 20:37 816904 359760 40645 21970 14101 10756 6397 1891 0
2015/01/23 21:37 819679 360995 41095 22286 14286 10909 6508 1932 0
2015/01/23 22:37 822510 364896 41719 22674 14501 11090 6626 1978 0
2015/01/23 23:36 825559 372563 42357 23125 14739 11287 6765 2028 0
2015/01/24 00:36 828330 381373 42952 23595 14990 11481 6903 2064 0
2015/01/24 01:36 830330 388141 43415 24043 15219 11645 7010 2088 0
2015/01/24 02:36 831653 397125 43740 24363 15373 11755 7077 2100 0
2015/01/24 03:36 832445 402976 43984 24572 15476 11829 7117 2113 0
2015/01/24 04:36 832939 405699 44151 24702 15546 11875 7143 2113 0
2015/01/24 05:37 833273 405699 44255 24789 15593 11909 7161 2119 0
2015/01/24 06:37 833569 405699 44352 24880 15644 11947 7179 2124 0
2015/01/24 07:37 834057 405924 44538 25018 15747 12022 7217 2133 0
2015/01/24 08:37 834934 407610 44806 25135 15922 12148 7276 2145 0
2015/01/24 09:36 836186 409893 45121 25300 16100 12277 7341 2162 0
2015/01/24 10:36 837678 418277 45412 25504 16281 12415 7418 2186 0
2015/01/24 11:37 839433 426072 45751 25714 16452 12555 7502 2211 0
2015/01/24 12:37 841311 434758 46143 25954 16635 12688 7591 2243 0
2015/01/24 13:37 843312 441083 46562 26205 16835 12842 7687 2277 0
2015/01/24 14:37 845296 446933 46966 26458 17022 12991 7787 2313 0
2015/01/24 15:36 847178 449279 47455 26706 17202 13127 7882 2350 0
2015/01/24 16:36 848987 458807 47848 26960 17375 13262 7974 2385 0
2015/01/24 17:40 850925 464297 48257 27191 17553 13401 8069 2423 0
2015/01/24 18:37 852869 469734 48654 27436 17725 13543 8162 2461 0
2015/01/24 19:37 855008 469734 49052 27691 17900 13680 8261 2502 0
2015/01/24 20:36 857023 474076 49498 27926 18074 13819 8357 2547 0
2015/01/24 21:36 859154 480579 50033 28202 18269 13965 8462 2594 0
2015/01/24 23:36 863556 497999 51056 28851 18681 14309 8700 2691 0
2015/01/25 00:36 865606 505313 51625 29196 18919 14497 8821 2734 0
2015/01/25 01:36 867155 506429 52063 29526 19146 14658 8927 2766 0
2015/01/25 02:36 868232 506429 52441 29755 19313 14774 9001 2788 0
2015/01/25 03:36 868898 510826 52728 29902 19429 14853 9045 2801 0
2015/01/25 04:36 869338 513592 52890 30013 19502 14905 9072 2811 0
2015/01/25 05:37 869638 513592 53012 30091 19559 14941 9090 2815 0
2015/01/25 06:37 869880 513592 53094 30154 19608 14974 9106 2820 0
2015/01/25 07:37 870202 513592 53221 30251 19694 15030 9135 2829 0
2015/01/25 08:37 870736 516834 53457 30402 19834 15123 9182 2840 0
2015/01/25 09:37 871595 516834 53769 30618 20012 15252 9249 2861 0
2015/01/25 10:37 872777 516834 54131 30872 20203 15401 9336 2889 0
2015/01/25 11:37 874219 523052 54523 31127 20395 15554 9425 2919 0
2015/01/25 12:37 875732 523263 54943 31375 20586 15697 9515 2951 0
2015/01/25 15:36 880325 529475 56071 32149 21139 16119 9788 3048 0
2015/01/25 16:36 881827 534678 56470 32405 21311 16257 9877 3078 0
2015/01/25 17:36 883292 543055 56805 32655 21471 16392 9972 3100 0
2015/01/25 18:37 884771 551930 57251 32888 21650 16537 10068 3131 0
2015/01/25 19:37 886291 558878 57671 33129 21819 16678 10161 3159 0
2015/01/25 20:37 887766 566550 58044 33391 22006 16821 10262 3186 0
2015/01/25 21:37 889374 575031 58619 33685 22196 16971 10362 3222 0
2015/01/25 22:36 890892 581006 59184 34020 22406 17138 10474 3260 0
2015/01/25 23:36 892483 581006 59831 34381 22645 17328 10589 3298 0
2015/01/26 00:37 894020 587882 60345 34787 22908 17529 10708 3339 0
2015/01/26 01:36 895138 594025 60826 35113 23133 17688 10798 3370 0
2015/01/26 02:36 895850 601594 61126 35357 23286 17792 10856 3389 0
2015/01/26 03:37 896286 609843 61279 35493 23371 17852 10890 3400 0
2015/01/26 04:37 896577 614503 61400 35601 23433 17891 10912 3407 0
2015/01/26 05:37 896763 620161 61479 35665 23480 17918 10926 3412 0
2015/01/26 06:37 896942 620161 61597 35736 23546 17959 10944 3417 0
2015/01/26 07:37 897171 622583 61861 35902 23723 18076 10989 3426 0
2015/01/26 08:37 897514 631019 62173 36152 23972 18240 11058 3440 0
2015/01/26 09:37 897861 634355 62408 36334 24115 18340 11106 3451 0
2015/01/26 10:37 898273 634355 62588 36488 24242 18427 11151 3464 0
2015/01/26 11:37 898789 634355 62805 36625 24361 18511 11196 3476 0
2015/01/26 12:37 899363 634355 63078 36825 24513 18612 11245 3490 0
2015/01/26 13:37 900102 634355 63438 37090 24760 18767 11321 3512 0
2015/01/26 14:36 900776 634355 63695 37272 24929 18867 11375 3530 0
2015/01/26 15:36 901383 634355 63933 37457 25043 18967 11428 3547 0
2015/01/26 16:36 902161 639647 64251 37673 25148 19091 11497 3569 0
2015/01/26 17:36 903081 639647 64585 37918 25268 19237 11578 3593 0
2015/01/26 18:36 904123 640155 65005 38165 25413 19392 11677 3626 0
2015/01/26 19:36 905253 647337 65388 38421 25577 19552 11772 3660 0
2015/01/26 20:36 906468 652620 65841 38713 25747 19708 11882 3695 32
2015/01/26 21:36 907796 656708 66320 39032 25928 19875 11997 3737 34
2015/01/26 22:36 909227 661811 66901 39396 26114 20055 12120 3777 36
2015/01/26 23:39 910665 664148 67525 39794 26312 20242 12248 3822 38
2015/01/27 00:38 911933 664148 68170 40163 26527 20441 12368 3863 39
2015/01/27 01:36 912855 669893 68734 40511 26721 20597 12459 3889 40
2015/01/27 02:36 913467 674726 69052 40724 26842 20702 12513 3907 42
2015/01/27 03:36 913883 680799 69267 40893 26920 20762 12543 3919 65
2015/01/27 04:36 914134 689811 69414 40983 26969 20798 12561 3926 66
2015/01/27 05:36 914336 691983 69549 41047 27007 20827 12577 3932 66
2015/01/27 06:36 914483 695470 69677 41140 27063 20870 12594 3935 66
2015/01/27 07:36 914737 695470 69978 41319 27217 20987 12638 3945 68
2015/01/27 08:36 915098 697335 70273 41565 27433 21151 12701 3959 68
2015/01/27 09:36 915429 700962 70435 41745 27570 21251 12743 3972 71
2015/01/27 10:36 915799 700962 70670 41916 27678 21337 12789 3984 72
2015/01/27 11:36 916250 700962 70865 42070 27779 21425 12831 3997 75
2015/01/27 12:36 916776 706175 71113 42268 27907 21527 12885 4012 76
2015/01/27 13:36 917497 709050 71416 42554 28111 21683 12965 4033 78
2015/01/27 14:36 918123 713391 71614 42748 28236 21788 13019 4050 81
2015/01/27 15:36 918767 713971 71915 42924 28353 21885 13073 4065 86
2015/01/27 16:36 919486 720127 72190 43141 28495 22002 13141 4085 93
2015/01/27 17:36 920322 724902 72446 43414 28652 22147 13223 4107 106
2015/01/27 18:36 921256 734919 72823 43672 28810 22302 13311 4135 114
2015/01/27 19:36 922272 742873 73185 43940 28984 22458 13403 4162 121
2015/01/27 20:36 923284 747486 73642 44200 29158 22613 13506 4188 126
2015/01/27 21:36 924447 748532 74076 44520 29335 22774 13618 4222 132
2015/01/27 22:36 925639 748532 74659 44921 29521 22948 13733 4257 137
2015/01/27 23:36 926865 749422 75248 45305 29745 23148 13860 4300 142
2015/01/28 00:40 928022 756757 75832 45729 29968 23344 13970 4339 151
2015/01/28 01:36 928901 760001 76291 46063 30159 23506 14052 4366 158
2015/01/28 02:36 929453 761221 76662 46297 30284 23611 14109 4383 161
2015/01/28 03:36 929814 767784 76869 46455 30358 23671 14141 4394 164
2015/01/28 04:36 930042 775638 76987 46543 30405 23706 14160 4400 165
2015/01/28 05:38 930181 779885 77094 46613 30445 23733 14174 4405 167
2015/01/28 06:36 930314 789568 77182 46701 30499 23777 14191 4411 168
2015/01/28 07:36 930538 797370 77447 46880 30664 23900 14239 4420 171
2015/01/28 08:36 930834 798843 77834 47123 30883 24062 14306 4437 173
2015/01/28 09:36 931126 798843 78045 47309 31016 24162 14350 4448 176
2015/01/28 11:37 931885 815052 78486 47624 31228 24338 14439 4475 185
2015/01/28 12:36 932350 815052 78689 47810 31360 24440 14493 4491 192
2015/01/28 13:36 933026 817061 79097 48117 31560 24606 14569 4511 199
2015/01/28 14:36 933605 818248 79319 48323 31692 24723 14627 4526 206
2015/01/28 15:36 934208 820355 79598 48504 31820 24832 14679 4540 216
2015/01/28 16:36 934912 820355 79956 48712 31965 24976 14746 4557 228
2015/01/28 17:36 935701 828372 80211 48971 32119 25045 14825 4578 239
2015/01/28 18:36 936577 828372 80478 49239 32285 25104 14915 4602 245
2015/01/28 19:36 937417 832375 80775 49523 32446 25166 15009 4629 250
2015/01/28 20:36 938335 839837 81108 49817 32618 25236 15112 4660 253
2015/01/28 21:36 939348 839837 81583 50131 32789 25308 15214 4695 258
2015/01/28 22:36 940501 847320 82010 50508 32986 25402 15325 4732 263
2015/01/28 23:41 941586 854866 82489 50939 33200 25502 15447 4768 269
2015/01/29 00:36 942643 858243 82987 51346 33431 25609 15568 4803 275
2015/01/29 01:36 943453 866043 83400 51735 33627 25693 15651 4827 278
2015/01/29 02:36 943957 866043 83756 52020 33747 25747 15700 4839 281
2015/01/29 03:36 944291 866043 83890 52165 33819 25783 15727 4848 281
2015/01/29 04:36 944470 867365 84012 52276 33869 25801 15746 4853 281
2015/01/29 05:36 944599 874874 84107 52341 33909 25816 15760 4858 283
2015/01/29 06:36 944725 874874 84226 52430 33967 25839 15779 4861 283
2015/01/29 07:36 944877 874874 84480 52609 34138 25906 15821 4869 284
2015/01/29 08:36 945124 878115 84777 52864 34352 25996 15891 4880 285
2015/01/29 09:36 945381 878115 84968 53053 34482 26050 15931 4889 286
2015/01/29 10:36 945668 879655 85125 53215 34589 26098 15971 4898 286
2015/01/29 11:36 946016 879655 85372 53393 34693 26149 16018 4910 288
2015/01/29 12:36 946439 879655 85574 53558 34824 26206 16069 4922 290
2015/01/29 13:36 946947 881233 85892 53868 35035 26290 16144 4942 294
2015/01/29 14:36 947464 887908 86080 54061 35163 26354 16197 4958 297
2015/01/29 15:36 947976 891190 86313 54270 35273 26413 16246 4974 301
2015/01/29 16:36 948560 891190 86521 54534 35401 26491 16307 4992 306
2015/01/29 17:36 949224 891190 86798 54778 35558 26579 16391 5013 311
2015/01/29 18:36 949997 891190 87068 55044 35725 26674 16477 5037 317
2015/01/29 19:36 950804 898625 87405 55298 35896 26774 16564 5063 324
2015/01/29 20:36 951687 904406 87799 55593 36065 26875 16663 5092 333
2015/01/29 21:36 952724 911880 88184 55931 36236 26985 16774 5127 345
2015/01/29 22:36 953730 920027 88753 56317 36424 27103 16896 5158 357
2015/01/29 23:36 954769 921053 89280 56776 36636 27227 17016 5190 370
2015/01/30 00:36 955679 925314 89783 57245 36857 27350 17127 5222 384
2015/01/30 01:36 956348 929465 90203 57666 37056 27440 17218 5242 393
2015/01/30 02:36 956783 929465 90541 57979 37179 27503 17276 5253 400
2015/01/30 03:36 957068 931431 90718 58185 37257 27538 17310 5262 404
2015/01/30 04:37 957253 938561 90838 58305 37300 27558 17332 5267 406
2015/01/30 05:36 957393 947238 90937 58390 37341 27574 17348 5270 407
2015/01/30 06:36 957506 952997 91046 58502 37399 27596 17369 5273 408
2015/01/30 07:36 957685 953908 91365 58745 37569 27655 17418 5281 410
2015/01/30 08:36 957943 956333 91681 59029 37782 27744 17491 5292 414
2015/01/30 09:36 958195 956333 91900 59250 37907 27795 17534 5298 417
2015/01/30 10:36 958480 957884 92088 59433 38008 27848 17576 5308 421
2015/01/30 11:36 958816 963646 92357 59649 38108 27900 17618 5317 426
2015/01/30 12:36 959233 970429 92603 59904 38227 27959 17662 5331 428
2015/01/30 13:36 959811 975226 92873 60227 38423 28051 17732 5348 428
2015/01/30 14:36 960332 976932 93153 60503 38569 28117 17792 5361 428
2015/01/30 15:36 960844 981164 93474 60769 38688 28178 17844 5375 436
2015/01/30 16:36 961471 987243 93725 61033 38829 28256 17916 5392 441
2015/01/30 17:36 962159 992786 94026 61321 38982 28347 17999 5411 449
2015/01/30 18:36 962979 996697 94482 61661 39140 28440 18098 5434 449
2015/01/30 19:36 963809 1000760 94842 62049 39311 28535 18191 5458 458
2015/01/30 20:36 964733 1004617 95248 62458 39475 28629 18289 5485 468
2015/01/30 21:36 965788 1004617 95731 62881 39650 28735 18407 5516 469
2015/01/30 22:37 966782 1006062 96297 63404 39836 28840 18524 5546 475
2015/01/30 23:36 967806 1014617 97078 64031 40053 28968 18668 5581 481
2015/01/31 00:36 968849 1016303 97915 64713 40276 29095 18805 5611 490
2015/01/31 01:36 969842 1016303 98743 65460 40477 29202 18931 5638 494
2015/01/31 02:36 970505 1016303 99421 66078 40628 29271 19008 5655 499
2015/01/31 03:36 970903 1016303 99835 66547 40724 29308 19061 5665 499
2015/01/31 04:36 971126 1024680 100167 66836 40780 29334 19088 5671 500
2015/01/31 05:36 971284 1034741 100341 67064 40816 29355 19109 5676 501
2015/01/31 06:36 971458 1044761 100568 67270 40876 29375 19140 5679 502
2015/01/31 07:36 971723 1055103 100908 67589 40986 29422 19184 5686 504
2015/01/31 08:36 972172 1055605 101459 68111 41152 29493 19258 5699 505
2015/01/31 09:36 972794 1055605 102083 68748 41332 29581 19349 5717 509
2015/01/31 10:36 973510 1059749 102888 69572 41510 29677 19452 5739 511
2015/01/31 12:36 975381 1077373 105049 71705 41918 29895 19697 5788 519
2015/01/31 13:36 976409 1083506 106627 73306 42190 30027 19846 5816 524
2015/01/31 14:36 977484 1088807 109111 75703 42545 30156 20038 5850 525
2015/01/31 16:38 970851 1088874 110989 77703 42743 30255 20138 5866 526

スクフェス 自動ランキング取得(VB.NET)~パケット取得ver.

スクフェスをPCでプレイする2~キーボードマッピングの追加 - Future Convergence PRJ.まで設定されていることを前提として、イベントの順位情報を自動で取得するプログラムのメモ。

[処理の流れ]
① パケット監視開始(非同期処理)
② BlueStacksからキーボード入力
③ パケットからデータ取得できればパケット監視終了、一定時間待ってもデータが得られなければパケット監視中断
④ 取得したデータ(③で中断した場合は空)からどの画面かを判別して次のキーボード入力内容決定
⑤ ランキングデータがすべて取得できたら終了、まだなら①に戻る


あとはこれをガシガシコーディングするだけなんだけど、デリゲートでの非同期処理は中断できないなど想定外の事態(無知なだけ)に遭遇してだいぶ時間がかかった。できあがったソースは以下の通り。長いし汚いけど、とりあえず動くからOK。使ってる技術は以下の記事を参照。
VB.NETでパケットキャプチャ2~HTTPリクエストボディ・レスポンスボディの取得 - Future Convergence PRJ.
VB.NETでJson形式のデータの取り扱い~Json.NETを使ってみる - Future Convergence PRJ.


SchoolIdolChaserMain.vb

Imports System.Text
Imports System.IO
Imports SchoolIdolChaser.SchoolIdleChaserConstant
Imports Newtonsoft.Json

Module SchoolIdolChaserMain

    'ランキングデータ
    Public Structure RankingData
        Public TotalCnt As Integer
        Public Ranking As Integer
        Public Score As Integer
        Public Sub New(ByVal x_TotalCnt As Integer, ByVal x_Ranking As Integer, ByVal x_Score As Integer)
            TotalCnt = x_TotalCnt
            Ranking = x_Ranking
            Score = x_Score
        End Sub
    End Structure

    'ネットワーク出力データ(パケットキャプチャ出力)
    Public Structure OutputData
        Public RequestMethod As String
        Public RequestBody As String
        Public ResponseStatus As String
        Public ResponseBody As String
        Public Sub New(ByVal x_RequestMethod As String, ByVal x_RequestBody As String, ByVal x_ResponseStatus As String, ByVal x_ResponseBody As String)
            RequestMethod = x_RequestMethod
            RequestBody = x_RequestBody
            ResponseStatus = x_ResponseStatus
            ResponseBody = x_ResponseBody
        End Sub
    End Structure

    '画面状態
    Public Structure DspStatus
        Public Reliability As Integer
        Public Status As Integer
        Public Sub New(ByVal x_Reliability As Integer, ByVal x_Status As Integer)
            Reliability = x_Reliability
            Status = x_Status
        End Sub
    End Structure

    '文字コード
    Private m_Enc As Encoding = Encoding.UTF8
    Private m_EncShiftJis As Encoding = Encoding.GetEncoding("shift-jis")

    '取得するランキング
    Private m_TargetList As Byte() = New Byte() {I_RANK_A, I_RANK_B, I_RANK_C, I_RANK_D, I_RANK_E, I_RANK_F, I_RANK_G, I_RANK_S}
    '画面状態が分からない時の入力(繰り返し)
    Private m_UnknownList As Byte() = New Byte() {I_NO, I_CLOSE, I_NO, I_OK, I_INVITE, I_HOME}

    '別スレッドのパケットキャプチャが終了したかどうかの判定フラグ
    Private m_IsThreadEnd As Boolean = False
    '別スレッドのパケットキャプチャからの戻り値として使用
    Private m_Output As OutputData = Nothing
    

    Sub Main()

        Using wsLog As New System.IO.StreamWriter(LOG_FILE, True, m_EncShiftJis)
            For tryCount As Integer = 1 To 3
                Try
                    '自プロセスをアクティブにする
                    Dim myPs As Process = Process.GetCurrentProcess
                    Interaction.AppActivate(myPs.Id)
                    Threading.Thread.Sleep(1000)

                    wsLog.WriteLine("{0} 処理スタート", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    Execute(wsLog)
                    Exit For
                Catch ex As Exception
                    wsLog.WriteLine("{0} 予期せぬ例外が発生[{1}回目]", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), tryCount)
                    wsLog.WriteLine(ex)
                    Threading.Thread.Sleep(180000)
                End Try
            Next
            wsLog.WriteLine("{0} 処理終了", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
        End Using

    End Sub

    ''' <summary>
    ''' このプログラムのメイン処理
    ''' キー入力した後のパケットキャプチャから状態を判別して次のキー入力を行う。
    ''' ランキングデータがすべて取得するか、キー入力数が最大になった場合に処理終了。
    ''' </summary>
    ''' <param name="wsLog"></param>
    ''' <remarks></remarks>
    Sub Execute(ByRef wsLog As System.IO.StreamWriter)

        Dim rankingDataList As New Dictionary(Of Byte, RankingData)
        Dim dsp As DspStatus = New DspStatus(RELIABILITY_HIGH - 1, S_HOME)
        Dim unknownCount As Integer = 0
        Dim totalCount As Integer = 1

        Dim input As Byte = I_HOME
        Dim output As OutputData = New OutputData("", "", "", "")

        Dim isEnd As Boolean = False

        While True

            wsLog.WriteLine("{0} インプット[{1}/{2}回目]", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), totalCount, MAX_COUNT)

            m_IsThreadEnd = False
            m_Output = New OutputData("", "", "", "")
            output = New OutputData("", "", "", "")

            'ネットワークからデータを取得するスレッドを開始
            Dim t As New Threading.Thread(New Threading.ThreadStart(AddressOf GetOutputData))
            t.IsBackground = True
            t.Start()

            'Blue Stacksのプロセスをアクティブにする
            Dim ps() As Process = Process.GetProcessesByName("HD-Frontend")
            If ps.Length > 0 Then
                ActiveWindow(ps(0).MainWindowHandle)
                Interaction.AppActivate(ps(0).Id)
            End If

            Threading.Thread.Sleep(1000)
            'キー入力
            InputAction(input)

            Console.Write("待機中")
            For timerCount As Integer = 0 To 4
                If m_IsThreadEnd Then
                    'Exit For
                End If
                Threading.Thread.Sleep(1000)
                Console.Write(".")
            Next

            If m_IsThreadEnd Then
                Console.WriteLine()
                Console.WriteLine("値取得完了")
                output = m_Output
            Else
                Console.WriteLine()
                Console.WriteLine("値取得中断")
                t.Abort()
            End If

            dsp = GetDspStatus(dsp, input, output)
            wsLog.WriteLine("{0} requestMethod={1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), output.RequestMethod)

            If dsp.Reliability > RELIABILITY_LOW Then
                '画面状態が判明している時

                If dsp.Status = S_HOME Then
                    'ホーム画面の時
                    wsLog.WriteLine("{0} ホーム画面", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    wsLog.Flush()
                    isEnd = True
                    For i As Integer = 0 To m_TargetList.Length - 1
                        isEnd = isEnd And rankingDataList.ContainsKey(m_TargetList(i))
                        If Not isEnd Then
                            Exit For
                        End If
                    Next
                    If isEnd Then
                        Exit While
                    Else
                        input = I_EVE
                    End If

                ElseIf dsp.Status = S_EVE Then
                    'イベント画面の時
                    wsLog.WriteLine("{0} イベント画面", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    wsLog.Flush()
                    input = I_RANKING

                ElseIf dsp.Status = S_RANKING Then
                    'ランキング画面の時
                    wsLog.WriteLine("{0} ランキング画面", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    wsLog.Flush()
                    If input = I_RANKING Then
                        rankingDataList(I_RANK_S) = GetRankingData(output)
                    Else
                        rankingDataList(input) = GetRankingData(output)
                    End If

                    input = I_HOME
                    For i As Integer = 0 To m_TargetList.Length - 1
                        If Not rankingDataList.ContainsKey(m_TargetList(i)) Then
                            InputAction(I_RANKING_SELECT)
                            Threading.Thread.Sleep(2000)
                            input = m_TargetList(i)
                            Exit For
                        End If
                    Next

                ElseIf dsp.Status = S_INVITE Then
                    '勧誘画面の時
                    wsLog.WriteLine("{0} 勧誘画面", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    wsLog.Flush()
                    input = I_HOME

                Else
                    wsLog.WriteLine("{0} 画面不明1", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    wsLog.Flush()
                    input = I_UNKNOWN

                End If

            Else
                '画面状態が不明な時
                wsLog.WriteLine("{0} 画面不明2", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
                wsLog.Flush()
                input = I_UNKNOWN

            End If

            If input = I_UNKNOWN Then
                input = m_UnknownList(unknownCount)
                unknownCount = unknownCount + 1
                If unknownCount >= m_UnknownList.Length Then
                    unknownCount = 0
                End If
            End If
            wsLog.WriteLine("{0} 次のインプット=[{1}]", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), input)

            If totalCount >= MAX_COUNT Then
                Exit While
            End If
            totalCount = totalCount + 1

        End While

        'ランキングデータを出力する
        Using wsRank As New System.IO.StreamWriter(RANKING_FILE, True, m_EncShiftJis)
            If isEnd Then
                wsRank.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17}", _
                                 DateTime.Now.ToString("yyyy/MM/dd HH:mm"), rankingDataList(I_RANK_S).TotalCnt, _
                                 rankingDataList(I_RANK_S).Score, rankingDataList(I_RANK_A).Score, rankingDataList(I_RANK_B).Score, _
                                 rankingDataList(I_RANK_C).Score, rankingDataList(I_RANK_D).Score, rankingDataList(I_RANK_E).Score, _
                                 rankingDataList(I_RANK_F).Score, rankingDataList(I_RANK_G).Score, _
                                 rankingDataList(I_RANK_S).Ranking, rankingDataList(I_RANK_A).Ranking, rankingDataList(I_RANK_B).Ranking, _
                                 rankingDataList(I_RANK_C).Ranking, rankingDataList(I_RANK_D).Ranking, rankingDataList(I_RANK_E).Ranking, _
                                 rankingDataList(I_RANK_F).Ranking, rankingDataList(I_RANK_G).Ranking)
            Else
                wsRank.WriteLine("{0},,,,,,,,,,,,,,,,,", DateTime.Now.ToString("yyyy/MM/dd HH:mm"))
            End If
            wsRank.Flush()
        End Using

    End Sub

    ''' <summary>
    ''' 画面の状態を返す
    ''' </summary>
    ''' <param name="currentStatus"></param>
    ''' <param name="input"></param>
    ''' <param name="output"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GetDspStatus(ByVal currentStatus As DspStatus, ByVal input As Byte, ByVal output As OutputData) As DspStatus

        Dim updatedStatus As DspStatus = New DspStatus(RELIABILITY_LOW, S_UNKNOWN)

        If output.RequestMethod.Contains(O_HOME) Then
            'ホーム画面確定の時
            updatedStatus.Reliability = RELIABILITY_HIGH
            updatedStatus.Status = S_HOME

        ElseIf output.RequestMethod.Contains(O_RANKING) Then
            'ランキング画面確定の時
            updatedStatus.Reliability = RELIABILITY_HIGH
            updatedStatus.Status = S_RANKING

        ElseIf output.RequestMethod.Contains(O_INVITE) Then
            '勧誘画面確定の時
            updatedStatus.Reliability = RELIABILITY_HIGH
            updatedStatus.Status = S_INVITE

        Else
            '通信から画面特定不可の時
            If currentStatus.Reliability > RELIABILITY_LOW Then
                If currentStatus.Status = S_HOME Then
                    'ホーム画面で
                    If input = I_HOME Then
                        'ホームボタンを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_HOME

                    ElseIf input = I_EVE Then
                        'イベントボタンを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_EVE
                    Else
                        'それ以外
                        updatedStatus.Reliability = RELIABILITY_LOW
                        updatedStatus.Status = S_UNKNOWN
                    End If

                ElseIf currentStatus.Status = S_EVE Then
                    'イベント画面で
                    If input = I_HOME Then
                        'ホームボタンを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_HOME

                    Else
                        'それ以外
                        updatedStatus.Reliability = RELIABILITY_LOW
                        updatedStatus.Status = S_UNKNOWN

                    End If

                ElseIf currentStatus.Status = S_RANKING Then
                    'ランキング画面で
                    If input = I_HOME Then
                        'ホームボタンを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_HOME

                    ElseIf input = I_BACK Then
                        '戻るを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_EVE

                    Else
                        'それ以外
                        updatedStatus.Reliability = RELIABILITY_LOW
                        updatedStatus.Status = S_UNKNOWN

                    End If

                ElseIf currentStatus.Status = S_INVITE Then
                    '勧誘画面で
                    If input = I_HOME Then
                        'ホームボタンを押した時
                        updatedStatus.Reliability = currentStatus.Reliability - 1
                        updatedStatus.Status = S_HOME

                    Else
                        'それ以外
                        updatedStatus.Reliability = RELIABILITY_LOW
                        updatedStatus.Status = S_UNKNOWN

                    End If

                Else
                    updatedStatus.Reliability = RELIABILITY_LOW
                    updatedStatus.Status = S_UNKNOWN

                End If

            End If

        End If

        Return updatedStatus

    End Function

    ''' <summary>
    ''' Json形式のデータからランキング情報を取得する
    ''' </summary>
    ''' <param name="output"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GetRankingData(ByVal output As OutputData) As RankingData

        Dim ranking As RankingData = New RankingData(-1, -1, -1)

        'Json文字列をJson形式データに復元する
        Dim jsonObj As Object = JsonConvert.DeserializeObject(output.ResponseBody)

        If jsonObj(JSON_STATUS_CODE) = "200" Then
            If jsonObj(JSON_RESPONSE_DATA) IsNot Nothing Then
                ranking.TotalCnt = jsonObj(JSON_RESPONSE_DATA)(JSON_TOTAL_CNT)
                For Each item In jsonObj(JSON_RESPONSE_DATA)(JSON_ITEMS)
                    ranking.Ranking = item(JSON_RANK)
                    ranking.Score = item(JSON_SCORE)
                Next
            End If
        End If

        Return ranking

    End Function

    ''' <summary>
    ''' バイトコードで指定したキーを押す
    ''' </summary>
    ''' <param name="input"></param>
    ''' <remarks></remarks>
    Private Sub InputAction(ByVal input As Byte)
        win32api.keybd_event(input, 0, 0, 0)
        win32api.keybd_event(input, 0, 2, 0)
    End Sub

    ''' <summary>
    ''' スクフェスサーバとのパケットデータを取得する
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub GetOutputData()

        Dim output As OutputData = New OutputData("", "", "", "")

        Dim isBuffered As Boolean = False
        Dim contentBuff As Byte() = Nothing
        Dim contentCounter As Integer = 0
        Dim contentSize As Integer = 0
        Dim isGzip As Boolean = False
        Dim isReqest As Boolean = False

        Dim socket As New Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Raw, Net.Sockets.ProtocolType.IP)
        socket.Bind(New Net.IPEndPoint(Net.IPAddress.Parse(MY_IP_ADDRESS), 0))
        socket.SetSocketOption(Net.Sockets.SocketOptionLevel.IP, Net.Sockets.SocketOptionName.AcceptConnection, True)
        socket.IOControl(Net.Sockets.IOControlCode.ReceiveAll, New Byte() {1, 0, 0, 0}, New Byte() {0, 0, 0, 0})

        While True

            Dim buff As Byte() = New Byte(4095) {}
            socket.Receive(buff)

            'IPパケットのサイズを取得
            Dim packetSize As Integer = buff(2) * 256 + buff(3)
            'プロトコル番号を取得
            Dim protocolNum As Integer = buff(9)
            '送信元IPを取得
            Dim srcIPAddress As String = String.Format("{0}.{1}.{2}.{3}", buff(12), buff(13), buff(14), buff(15))
            '送信先IPを取得
            Dim dstIPAddress As String = String.Format("{0}.{1}.{2}.{3}", buff(16), buff(17), buff(18), buff(19))

            'スクフェスサーバとのTCP通信のみ処理
            If (srcIPAddress = TARGET_IP_ADDRESS Or dstIPAddress = TARGET_IP_ADDRESS) And protocolNum = 6 Then

                'TCPの場合ヘッダ長を取得
                Dim tcpHeaderLength As Integer = Convert.ToInt32(Convert.ToString(buff(32), 2).PadLeft(8, "0").Substring(0, 4), 2) * 4
                'パケットの中身を文字列として取得
                Dim packetStr As String = m_Enc.GetString(buff, IP_HEADER_LENGTH + tcpHeaderLength, packetSize)

                If isBuffered Then
                    'バッファリング待機中の場合

                    For i As Integer = IP_HEADER_LENGTH + tcpHeaderLength To packetSize - 1
                        contentBuff(contentCounter) = buff(i)
                        contentCounter = contentCounter + 1

                        'ContentSizeを超えるデータ量だった場合は中断(パケット取り違えの場合)
                        If contentCounter >= contentBuff.Length Then
                            Exit For
                        End If
                    Next

                    'もしパケットにContent-Lengthが含まれていたらバッファリングは中断する
                    If packetStr.Contains("Content-Length:") Then
                        isBuffered = False
                    End If

                End If

                If Not isBuffered Then
                    'バッファリング待機なしの場合

                    'コンテンツバッファカウンターのクリア
                    contentCounter = 0
                    'Content-Lengthのクリア
                    contentSize = 0
                    'リクエストかレスポンスかの判定
                    isReqest = False


                    'リクエストヘッダー-メソッドの取得
                    Dim rGet As New RegularExpressions.Regex("(GET.+?\r\n)", RegularExpressions.RegexOptions.IgnoreCase Or RegularExpressions.RegexOptions.Singleline)
                    Dim mcGet As RegularExpressions.MatchCollection = rGet.Matches(packetStr)
                    For Each m As RegularExpressions.Match In mcGet
                        '正規表現に一致したグループの文字列を表示 
                        output.RequestMethod = m.Groups(1).Value.Replace(Chr(13), "").Replace(Chr(10), "")
                        isReqest = True
                        Exit For
                    Next

                    Dim rPost As New RegularExpressions.Regex("(POST.+?\r\n)", RegularExpressions.RegexOptions.IgnoreCase Or RegularExpressions.RegexOptions.Singleline)
                    Dim mcPost As RegularExpressions.MatchCollection = rPost.Matches(packetStr)
                    For Each m As RegularExpressions.Match In mcPost
                        '正規表現に一致したグループの文字列を表示 
                        output.RequestMethod = m.Groups(1).Value.Replace(Chr(13), "").Replace(Chr(10), "")
                        isReqest = True
                        Exit For
                    Next

                    'レスポンスヘッダ-ステータスの取得
                    Dim rStatus As New RegularExpressions.Regex("(HTTP/1.1 200 OK)", RegularExpressions.RegexOptions.IgnoreCase Or RegularExpressions.RegexOptions.Singleline)
                    Dim mcStatus As RegularExpressions.MatchCollection = rStatus.Matches(packetStr)
                    For Each m As RegularExpressions.Match In mcStatus
                        '正規表現に一致したグループの文字列を表示 
                        output.ResponseStatus = m.Groups(1).Value.Replace(Chr(13), "").Replace(Chr(10), "")
                        isReqest = False
                        Exit For
                    Next


                    'httpヘッダのContent-Lengthを取得
                    If packetStr.Contains("Content-Length:") Then
                        Dim rContentLength As New RegularExpressions.Regex("Content-Length: ([0-9]+)", RegularExpressions.RegexOptions.IgnoreCase Or RegularExpressions.RegexOptions.Singleline)
                        Dim mcrContentLength As System.Text.RegularExpressions.MatchCollection = rContentLength.Matches(packetStr)

                        For Each m As System.Text.RegularExpressions.Match In mcrContentLength
                            '正規表現に一致したグループの文字列を表示 
                            contentSize = m.Groups(1).Value
                            Exit For
                        Next
                    End If

                    If contentSize > 0 Then

                        'gzipかどうかの判別
                        isGzip = packetStr.Contains("Content-Encoding: gzip")

                        'Contentがスタートする場所を取得
                        Dim contentStart As Integer = packetSize
                        For i As Integer = 4 To packetSize - 1
                            If buff(i - 4) = 13 AndAlso buff(i - 3) = 10 AndAlso buff(i - 2) = 13 AndAlso buff(i - 1) = 10 Then
                                contentStart = i
                                Exit For
                            End If
                        Next

                        'Contentの取得
                        contentBuff = New Byte(contentSize - 1) {}
                        For i As Integer = contentStart To packetSize - 1
                            contentBuff(contentCounter) = buff(i)
                            contentCounter = contentCounter + 1
                        Next

                    End If

                End If

                If contentSize > 0 AndAlso contentBuff IsNot Nothing Then

                    If contentCounter >= contentSize - 1 Then
                        'コンテンツが全部取得できた
                        isBuffered = False

                        If isGzip Then
                            'GZIPファイルの書き出し
                            Using fs As New System.IO.FileStream(GZIP_TEMP_FILE, System.IO.FileMode.Create, System.IO.FileAccess.Write)
                                fs.Write(contentBuff, 0, contentBuff.Length)
                            End Using

                            'GZIPファイルの読み込み&解凍書き出し
                            Dim gzipFileStrm As New System.IO.FileStream(GZIP_TEMP_FILE, System.IO.FileMode.Open, System.IO.FileAccess.Read)
                            Using gzipStrm As New System.IO.Compression.GZipStream(gzipFileStrm, System.IO.Compression.CompressionMode.Decompress)
                                Using outFileStrm As New System.IO.FileStream(CONTENT_TEMP_FILE, System.IO.FileMode.Create, System.IO.FileAccess.Write)

                                    Dim gzipBuff(1024) As Byte
                                    While True
                                        '書庫から展開されたデータを読み込む
                                        Dim readSize As Integer = gzipStrm.Read(gzipBuff, 0, gzipBuff.Length)
                                        '最後まで読み込んだ時は、ループを抜ける
                                        If readSize = 0 Then
                                            Exit While
                                        End If '展開先のファイルに書き込む
                                        outFileStrm.Write(gzipBuff, 0, readSize)
                                    End While
                                End Using
                            End Using

                            '全読み込み
                            Using sr As New System.IO.StreamReader(CONTENT_TEMP_FILE, m_Enc)
                                If isReqest Then
                                    output.RequestBody = sr.ReadToEnd
                                Else
                                    output.ResponseBody = sr.ReadToEnd
                                End If

                            End Using

                            File.Delete(CONTENT_TEMP_FILE)
                            File.Delete(GZIP_TEMP_FILE)

                        Else
                            If isReqest Then
                                output.RequestBody = m_Enc.GetString(contentBuff, 0, contentSize)
                            Else
                                output.ResponseBody = m_Enc.GetString(contentBuff, 0, contentSize)
                            End If
                        End If

                    Else
                        'コンテンツが全部取得できていないので次のパケットを待つ
                        isBuffered = True
                    End If

                End If

                If isBuffered = False And output.RequestMethod <> "" And output.ResponseStatus <> "" Then
                    m_Output = output
                    m_IsThreadEnd = True
                    Exit While
                End If

            End If

        End While

    End Sub

    Private Sub ActiveWindow(ByVal hWnd As IntPtr)
        SwitchToThisWindow(hWnd, True)
    End Sub

    <Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Sub SwitchToThisWindow(ByVal hWnd As IntPtr, ByVal fAltTab As Boolean)
    End Sub

End Module

Class win32api
    Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
End Class


定数は以下のクラスで定義。スクフェスサーバのIPアドレスURIは伏せてあるので、動かしたいなら調べて設定する必要がある。

SchoolIdleChaserConstant.vb

Public Class SchoolIdleChaserConstant

    '#
    '# ユーザ設定にかかわる定数
    '#

    '自分のIPアドレス
    Public Const MY_IP_ADDRESS As String = "192.168.3.XXX"
    'スクフェスサーバのIPアドレス
    Public Const TARGET_IP_ADDRESS As String = "ここにスクフェスのサーバのIPアドレスを設定する"

    'ランキングファイルパス
    Public Const RANKING_FILE As String = "C:\test\ranking.txt"
    'ログファイルパス
    Public Const LOG_FILE As String = "C:\test\log.txt"
    'GZIPの一時ファイルパス
    Public Const GZIP_TEMP_FILE As String = "C:\test\gzip_temp.gz"
    'GZIP解凍の一時ファイルパス
    Public Const CONTENT_TEMP_FILE As String = "C:\test\content_temp.txt"


    '#
    '# システム固有の定数
    '#

    'キー入力の最大回数(超えた場合処理を終了)
    Public Const MAX_COUNT As Integer = 200

    'IPヘッダ長
    Public Const IP_HEADER_LENGTH As Integer = 20

    '画面状態の信頼度
    Public Const RELIABILITY_HIGH As Integer = 5
    Public Const RELIABILITY_LOW As Integer = 1

    'キーマッピング
    Public Const I_UNKNOWN As Byte = 0
    Public Const I_HOME As Byte = AscW("H")
    Public Const I_EVE As Byte = AscW("V")
    Public Const I_RANKING As Byte = AscW("R")
    Public Const I_RANKING_SELECT As Byte = AscW("J")
    Public Const I_RANK_S As Byte = AscW("S")
    Public Const I_RANK_A As Byte = AscW("A")
    Public Const I_RANK_B As Byte = AscW("B")
    Public Const I_RANK_C As Byte = AscW("C")
    Public Const I_RANK_D As Byte = AscW("D")
    Public Const I_RANK_E As Byte = AscW("E")
    Public Const I_RANK_F As Byte = AscW("F")
    Public Const I_RANK_G As Byte = AscW("G")
    Public Const I_BACK As Byte = AscW("Q")
    Public Const I_INVITE As Byte = AscW("I")
    Public Const I_OK As Byte = AscW("O")
    Public Const I_CLOSE As Byte = AscW("X")
    Public Const I_YES As Byte = AscW("Y")
    Public Const I_NO As Byte = AscW("N")

    '画面判別
    Public Const O_HOME As String = "ここにホーム画面のURIを設定する"
    Public Const O_RANKING As String = "ここにイベントのランキング画面のURIを設定する"
    Public Const O_INVITE As String = "ここに勧誘画面のURIを設定する"

    '画面状態
    Public Const S_UNKNOWN As Integer = 0
    Public Const S_HOME As Integer = 1
    Public Const S_EVE As Integer = 2
    Public Const S_RANKING As Integer = 3
    Public Const S_INVITE As Integer = 4

    'JSONパラメータ
    Public Const JSON_STATUS_CODE As String = "status_code"
    Public Const JSON_RESPONSE_DATA As String = "response_data"
    Public Const JSON_TOTAL_CNT As String = "total_cnt"
    Public Const JSON_ITEMS As String = "items"
    Public Const JSON_RANK As String = "rank"
    Public Const JSON_SCORE As String = "score"

End Class

スクフェス 自動ランキング取得(VB.NET)~画面キャプチャver.

スクフェスをPCでプレイする2~キーボードマッピングの追加 - Future Convergence PRJ.まで設定されていることを前提として、順位画面を自動でキャプチャするプログラムのメモ。


ソースは以下の通り。プログラムからキー入力して画面キャプチャ撮るだけの簡単なものなので、通信エラーなどのイレギュラーには一切対応できない。動かす前にBlue Stacksからスクフェスを起動してホーム画面まで行ってることが条件、起動してないと空振りします。このプログラムと同じ原理で、頑張れば一応は自動演奏させることも可能、大変だけど。

画像だとデータとして扱いにくいので、最終的にはパケットキャプチャから通信内容みて順位を取得する予定(⇒スクフェス 自動ランキング取得(VB.NET)~パケット取得ver. - Future Convergence PRJ.)。本当はBlue Stacksの操作を一切せず通信だけで順位取得したいけど、通信内容にブラックボックス部分があって無理っぽい。

Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Module LoveLiveEventRankCapture

    Private Const VK_HOME As Byte = AscW("H")
    Private Const VK_EVENT_PAGE As Byte = AscW("V")
    Private Const VK_RANK_PAGE As Byte = AscW("R")
    Private Const VK_RANK_CHANGE As Byte = AscW("J")
    Private Const VK_RANK_1 As Byte = AscW("S")
    Private Const VK_RANK_9000 As Byte = AscW("A")
    Private Const VK_RANK_45000 As Byte = AscW("B")

    Private Const CAPTURE_SAVE_DIR As String = "C:\test\"

    Sub Main()

        Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
        Dim grap As Graphics = Graphics.FromImage(bmp)

        '一度自身のプロセスをアクティブにする
        '(これしないとタスクスケジューラで起動時にBlueStacksをアクティブにしてもこのプロセスのコンソールが前にかぶさる)
        Dim myPs As Process = Process.GetCurrentProcess
        Interaction.AppActivate(myPs.Id)
        Threading.Thread.Sleep(1000)

        'Blue Stacksのプロセスをアクティブにする
        Dim ps() As Process = Process.GetProcessesByName("HD-Frontend")
        If ps.Length > 0 Then
            ActiveWindow(ps(0).MainWindowHandle)
            Interaction.AppActivate(ps(0).Id)
        End If
        Threading.Thread.Sleep(5000)

        'ホームに移動
        TapKey(VK_HOME)
        Threading.Thread.Sleep(2000)
        'イベントページに移動
        TapKey(VK_EVENT_PAGE)
        Threading.Thread.Sleep(5000)
        'ランキングページに移動
        TapKey(VK_RANK_PAGE)
        Threading.Thread.Sleep(5000)
        '9000位のランキングに変更
        TapKey(VK_RANK_CHANGE)
        Threading.Thread.Sleep(5000)
        TapKey(VK_RANK_9000)
        Threading.Thread.Sleep(5000)
        '画面を保存する
        grap.CopyFromScreen(New Point(0, 0), New Point(0, 0), bmp.Size)
        bmp.Save(CAPTURE_SAVE_DIR & DateTime.Now.ToString("yyyyMMddhhmmss") & "_9000位.png", Imaging.ImageFormat.Png)
        '45000位のランキングに変更
        TapKey(VK_RANK_CHANGE)
        Threading.Thread.Sleep(5000)
        TapKey(VK_RANK_45000)
        Threading.Thread.Sleep(5000)
        '画面を保存する
        grap.CopyFromScreen(New Point(0, 0), New Point(0, 0), bmp.Size)
        bmp.Save(CAPTURE_SAVE_DIR & DateTime.Now.ToString("yyyyMMddhhmmss") & "_45000位.png", Imaging.ImageFormat.Png)
        Threading.Thread.Sleep(5000)

        grap.Dispose()

    End Sub

    'キーボードを押して離す
    Sub TapKey(ByVal key As Byte)
        win32api.keybd_event(key, 0, 0, 0)
        win32api.keybd_event(key, 0, 2, 0)
    End Sub

    Private Sub ActiveWindow(ByVal hWnd As IntPtr)
        SwitchToThisWindow(hWnd, True)
    End Sub

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Sub SwitchToThisWindow(ByVal hWnd As IntPtr, ByVal fAltTab As Boolean)
    End Sub

End Module

Class win32api
    Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
End Class

VB.NETでJson形式のデータの取り扱い~Json.NETを使ってみる

VB.NETJson.NETを使ったJson形式データ取扱いのメモ。
Json.NET を使用して JSON 文字列を VB.net で使用する( 逆シリアライズ ) : logical errorを参考にしてます。


[準備]
Json.NETのダウンロード⇒Json.NET - Home
②ダウンロードしたファイルを解凍する
③解凍したフォルダの中のbinの下に.NETフレームワークのバージョンごとにフォルダがあるので、適切なバージョンのフォルダを選択する(4.0ならNet40のフォルダを選択)。自分のPCにインストールされている.NETフレームワークは「コントロールパネル」の「プログラムと機能」の一覧にあるので確認できる。下位互換あったはずなので、インストールされているより下位のバージョンを選べば問題ないはず(詳しくないので適当だけど)。
④3で選択したフォルダの中に「Newtonsoft.Json.dll」ってのがあるから、そいつをプロジェクトの参照に追加してやる。参照の追加メニューバーの「プロジェクト」の中の「(プロジェクト名)のプロパティ」から行う。
f:id:CHappy:20150105151732j:plain


[実装]
まず今回読み込むJson形式のファイルはこれ。

{
  "main_data":
  {
    "user_count":5,
    "items":[
              {"user_id":0001,"level":11},
              {"user_id":0002,"level":21},
              {"user_id":0003,"level":13},
              {"user_id":0004,"level":9},
              {"user_id":0005,"level":98}
            ]
  },
  "status_code":200
}


これを読み込むソースが以下になる。2パターンあるようで私的にはパターン1の方が好み。

Imports System.Text
Imports Newtonsoft.Json

Module JsonTest

    Sub Main()

        Dim enc As Encoding = Encoding.UTF8
        Dim jsonStr As String = ""
        Dim jsonFilePath As String = "C:\test\JsonTest"

        'ファイルからJson文字列を読み込む
        Using sr As New System.IO.StreamReader(jsonFilePath, enc)
            jsonStr = sr.ReadToEnd()
        End Using

        'Json文字列をJson形式データに復元する
        Dim jsonObj As Object = JsonConvert.DeserializeObject(jsonStr)


        '値の参照パターン1
        Console.WriteLine("値の参照パターン1")

        '1階層のデータ
        Console.WriteLine("status_code={0}", jsonObj("status_code"))

        If jsonObj("main_data") IsNot Nothing Then

            '2階層のデータ
            Console.WriteLine("user_count={0}", jsonObj("main_data")("user_count"))

            '2階層のデータで配列の場合
            For Each item In jsonObj("main_data")("items")
                Console.WriteLine("user_id={0} level={1}", item("user_id"), item("level"))
            Next

            '2階層配列データのうち1つ表示
            Console.WriteLine("(配列1つ表示)user_id={0}", jsonObj("main_data")("items")(0)("user_id"))

        End If

        Console.WriteLine()

        '値の参照パターン2
        Console.WriteLine("値の参照パターン2")

        '1階層のデータ
        Console.WriteLine("status_code={0}", jsonObj.SelectToken("status_code"))

        If jsonObj.selectToken("main_data") IsNot Nothing Then

            '2階層のデータ
            Console.WriteLine("user_count={0}", jsonObj.SelectToken("main_data.user_count"))

            '2階層のデータで配列の場合
            Dim i As Integer = 0
            While True
                If jsonObj.SelectToken("main_data.items[" & i & "].user_id") Is Nothing Then
                    Exit While
                End If
                Console.WriteLine("user_id={0} level={1}", jsonObj.SelectToken("main_data.items[" & i & "].user_id"), jsonObj.SelectToken("main_data.items[" & i & "].level"))
                i = i + 1
            End While

            '2階層配列データのうち1つ表示
            Console.WriteLine("(配列1つ表示)user_id={0}", jsonObj.SelectToken("main_data.items[0].user_id"))
  
        End If

        Console.ReadLine()

    End Sub

End Module


実行結果は以下の通り。

値の参照パターン1
status_code=200
user_count=5
user_id=1 level=11
user_id=2 level=21
user_id=3 level=13
user_id=4 level=9
user_id=5 level=98
(配列1つ表示)user_id=1

値の参照パターン2
status_code=200
user_count=5
user_id=1 level=11
user_id=2 level=21
user_id=3 level=13
user_id=4 level=9
user_id=5 level=98
(配列1つ表示)user_id=1

スクフェスをPCでプレイする2~キーボードマッピングの追加

スクフェスをPCでプレイする - Future Convergence PRJ.の続きというか補足みたいなもの。Blue Stacksの使用が前提なので、使ってない人は読んでも意味ないです。

前の記事のライブ時のボタンはそのままでキーボードの割当を増やしてみた。ライブをやりたかったらキーボードの「L」を押せば、曲の選択画面に行ける。ライブ画面での曲の切り替えは左が「2」で右が「0」でできる。通常と特別の切り替えは「Z」。曲の難易度選択には対応してない。もし対応したければ自分で調べて割当てることも可能。

やり方は簡単で、「キー = Tap (横%,縦%)」の書式でファイルに追加してあげればよい。横と縦の%は、画面のキャプチャをとってペイントでピクセル数から計算すれば、ほぼ合う。小さいボタンだと微調整も必要になるけど…
これからイベントランキングチェックに使おうと思ってるんで、ランキング絡みのボタンは充実してます…


C:\ProgramData\BlueStacks\UserData\InputMapper\klb.android.lovelive.cfg:

[keys]
#ライブ時タップボタン
 2 = Tap (10,25)
 3 = Tap (15,50)
 4 = Tap (20,70)
 5 = Tap (35,80)
 Space = Tap (50,90)
 7 = Tap (65,80)
 8 = Tap (80,70)
 9 = Tap (85,50)
 0 = Tap (89,25)
#ダウンロード確認時などのOKボタン
 O = Tap (50,77)
#お知らせなどの右上の×ボタン/LP回復ボタン
 X = Tap (91,6)
#ホームボタン
 H = Tap (7,95)
#ストーリーボタン
 T = Tap (20,95)
#部員ボタン
 M = Tap (34,95)
#ライブボタン
 L = Tap (50,95)
#勧誘ボタン
 I = Tap (66,95)
#ショップボタン
 U = Tap (79,95)
#その他ボタン
 K = Tap (92,95)
#イベントページ/特待生勧誘
 V = Tap (73,72)
#イベントページのルール説明
 P = Tap (71,76)
#イベントページのイベントランキング
 R = Tap (82,76)
#イベントページの報酬詳細
 W = Tap (93,76)
#イベントランキングページの左上のBackボタン
 Q = Tap (9,4)
#イベントランキングページの順位変更のDDL
 J = Tap (82,4)
#DDL-1位
 S = Tap (82,12)
#DDL-自分の順位
 Z = Tap (82,21)
#DDL-9000位
 A = Tap (82,32)
#DDL-45000位
 B = Tap (82,41)
#DDL-108000位
 C = Tap (82,51)
#DDL-225000位
 D = Tap (82,61)
#DDL-405000位
 E = Tap (82,70)
#DDL-630000位
 F = Tap (82,80)
#DDL-900000位
 G = Tap (82,90)
#LP回復などの選択時のキャンセルボタン
 N = Tap (32,76)
#LP回復などの選択時のOKボタン
 Y = Tap (69,76)