diff --git a/deps/GSL b/deps/GSL new file mode 160000 index 00000000..ebf04983 --- /dev/null +++ b/deps/GSL @@ -0,0 +1 @@ +Subproject commit ebf0498363c53f0d3c403b0548212c147e3747fe diff --git a/deps/WinToast b/deps/WinToast new file mode 160000 index 00000000..5e441fd0 --- /dev/null +++ b/deps/WinToast @@ -0,0 +1 @@ +Subproject commit 5e441fd03543b999edb663caf8df7be37c0d575c diff --git a/deps/asmjit b/deps/asmjit new file mode 160000 index 00000000..2a706fd2 --- /dev/null +++ b/deps/asmjit @@ -0,0 +1 @@ +Subproject commit 2a706fd2ba355808cada31ac1eed8ce28caa6b37 diff --git a/deps/discord-rpc b/deps/discord-rpc new file mode 160000 index 00000000..963aa9f3 --- /dev/null +++ b/deps/discord-rpc @@ -0,0 +1 @@ +Subproject commit 963aa9f3e5ce81a4682c6ca3d136cddda614db33 diff --git a/deps/extra/udis86/libudis86/itab.c b/deps/extra/udis86/libudis86/itab.c new file mode 100644 index 00000000..953f3e52 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.c @@ -0,0 +1,5946 @@ +/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ +#include "decode.h" + +#define GROUP(n) (0x8000 | (n)) +#define INVALID 0 + + +const uint16_t ud_itab__0[] = { + /* 0 */ 15, 16, 17, 18, + /* 4 */ 19, 20, GROUP(1), GROUP(2), + /* 8 */ 964, 965, 966, 967, + /* c */ 968, 969, GROUP(3), GROUP(4), + /* 10 */ 5, 6, 7, 8, + /* 14 */ 9, 10, GROUP(284), GROUP(285), + /* 18 */ 1336, 1337, 1338, 1339, + /* 1c */ 1340, 1341, GROUP(286), GROUP(287), + /* 20 */ 49, 50, 51, 52, + /* 24 */ 53, 54, INVALID, GROUP(288), + /* 28 */ 1407, 1408, 1409, 1410, + /* 2c */ 1411, 1412, INVALID, GROUP(289), + /* 30 */ 1487, 1488, 1489, 1490, + /* 34 */ 1491, 1492, INVALID, GROUP(290), + /* 38 */ 100, 101, 102, 103, + /* 3c */ 104, 105, INVALID, GROUP(291), + /* 40 */ 699, 700, 701, 702, + /* 44 */ 703, 704, 705, 706, + /* 48 */ 175, 176, 177, 178, + /* 4c */ 179, 180, 181, 182, + /* 50 */ 1246, 1247, 1248, 1249, + /* 54 */ 1250, 1251, 1252, 1253, + /* 58 */ 1101, 1102, 1103, 1104, + /* 5c */ 1105, 1106, 1107, 1108, + /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ 1254, 697, 1256, 698, + /* 6c */ 709, GROUP(300), 982, GROUP(301), + /* 70 */ 726, 728, 730, 732, + /* 74 */ 734, 736, 738, 740, + /* 78 */ 742, 744, 746, 748, + /* 7c */ 750, 752, 754, 756, + /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313), + /* 84 */ 1433, 1434, 1475, 1476, + /* 88 */ 828, 829, 830, 831, + /* 8c */ 832, 770, 833, GROUP(314), + /* 90 */ 1477, 1478, 1479, 1480, + /* 94 */ 1481, 1482, 1483, 1484, + /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1470, + /* 9c */ GROUP(318), GROUP(322), 1310, 766, + /* a0 */ 834, 835, 836, 837, + /* a4 */ 922, GROUP(326), 114, GROUP(327), + /* a8 */ 1435, 1436, 1402, GROUP(328), + /* ac */ 790, GROUP(329), 1346, GROUP(330), + /* b0 */ 838, 839, 840, 841, + /* b4 */ 842, 843, 844, 845, + /* b8 */ 846, 847, 848, 849, + /* bc */ 850, 851, 852, 853, + /* c0 */ GROUP(331), GROUP(332), 1301, 1302, + /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406), + /* c8 */ 200, 776, 1303, 1304, + /* cc */ 713, 714, GROUP(407), GROUP(408), + /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412), + /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1486, + /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425), + /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437), + /* e0 */ 794, 795, 796, GROUP(440), + /* e4 */ 690, 691, 978, 979, + /* e8 */ 72, 763, GROUP(441), 765, + /* ec */ 692, 693, 980, 981, + /* f0 */ 789, 712, 1299, 1300, + /* f4 */ 687, 83, GROUP(442), GROUP(443), + /* f8 */ 77, 1395, 81, 1398, + /* fc */ 78, 1396, GROUP(444), GROUP(445), +}; + +static const uint16_t ud_itab__1[] = { + /* 0 */ 1240, INVALID, +}; + +static const uint16_t ud_itab__2[] = { + /* 0 */ 1096, INVALID, +}; + +static const uint16_t ud_itab__3[] = { + /* 0 */ 1241, INVALID, +}; + +static const uint16_t ud_itab__4[] = { + /* 0 */ GROUP(5), GROUP(6), 767, 797, + /* 4 */ INVALID, 1426, 82, 1431, + /* 8 */ 716, 1471, INVALID, 1444, + /* c */ INVALID, GROUP(27), 430, GROUP(28), + /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34), + /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40), + /* 18 */ GROUP(41), 955, 956, 957, + /* 1c */ 958, 959, 960, 961, + /* 20 */ 854, 855, 856, 857, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45), + /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49), + /* 30 */ 1472, 1297, 1295, 1296, + /* 34 */ GROUP(50), GROUP(52), INVALID, 1514, + /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 84, 85, 86, 87, + /* 44 */ 88, 89, 90, 91, + /* 48 */ 92, 93, 94, 95, + /* 4c */ 96, 97, 98, 99, + /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146), + /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150), + /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154), + /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158), + /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162), + /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166), + /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170), + /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176), + /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186), + /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199, + /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID, + /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201), + /* 80 */ 727, 729, 731, 733, + /* 84 */ 735, 737, 739, 741, + /* 88 */ 743, 745, 747, 749, + /* 8c */ 751, 753, 755, 757, + /* 90 */ 1350, 1351, 1352, 1353, + /* 94 */ 1354, 1355, 1356, 1357, + /* 98 */ 1358, 1359, 1360, 1361, + /* 9c */ 1362, 1363, 1364, 1365, + /* a0 */ 1245, 1100, 131, 1670, + /* a4 */ 1375, 1376, GROUP(202), GROUP(207), + /* a8 */ 1244, 1099, 1305, 1675, + /* ac */ 1377, 1378, GROUP(215), 694, + /* b0 */ 122, 123, 775, 1673, + /* b4 */ 772, 773, 940, 941, + /* b8 */ GROUP(221), INVALID, GROUP(222), 1671, + /* bc */ 1659, 1660, 930, 931, + /* c0 */ 1473, 1474, GROUP(223), 904, + /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227), + /* c8 */ 1661, 1662, 1663, 1664, + /* cc */ 1665, 1666, 1667, 1668, + /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239), + /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243), + /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247), + /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251), + /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255), + /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259), + /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263), + /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267), + /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271), + /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275), + /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280), + /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID, +}; + +static const uint16_t ud_itab__5[] = { + /* 0 */ 1384, 1406, 786, 798, + /* 4 */ 1453, 1454, INVALID, INVALID, +}; + +static const uint16_t ud_itab__6[] = { + /* 0 */ GROUP(7), GROUP(8), +}; + +static const uint16_t ud_itab__7[] = { + /* 0 */ 1374, 1383, 785, 774, + /* 4 */ 1385, INVALID, 787, 719, +}; + +static const uint16_t ud_itab__8[] = { + /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16), + /* 4 */ 1386, INVALID, 788, GROUP(25), +}; + +static const uint16_t ud_itab__9[] = { + /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12), + /* 4 */ GROUP(13), INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__10[] = { + /* 0 */ INVALID, 1455, INVALID, +}; + +static const uint16_t ud_itab__11[] = { + /* 0 */ INVALID, 1461, INVALID, +}; + +static const uint16_t ud_itab__12[] = { + /* 0 */ INVALID, 1462, INVALID, +}; + +static const uint16_t ud_itab__13[] = { + /* 0 */ INVALID, 1463, INVALID, +}; + +static const uint16_t ud_itab__14[] = { + /* 0 */ 824, 952, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__15[] = { + /* 0 */ 1485, 1508, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__16[] = { + /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20), + /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24), +}; + +static const uint16_t ud_itab__17[] = { + /* 0 */ 1466, INVALID, INVALID, +}; + +static const uint16_t ud_itab__18[] = { + /* 0 */ 1467, INVALID, INVALID, +}; + +static const uint16_t ud_itab__19[] = { + /* 0 */ 1468, INVALID, INVALID, +}; + +static const uint16_t ud_itab__20[] = { + /* 0 */ 1469, INVALID, INVALID, +}; + +static const uint16_t ud_itab__21[] = { + /* 0 */ 1397, INVALID, INVALID, +}; + +static const uint16_t ud_itab__22[] = { + /* 0 */ 80, INVALID, INVALID, +}; + +static const uint16_t ud_itab__23[] = { + /* 0 */ 1399, INVALID, INVALID, +}; + +static const uint16_t ud_itab__24[] = { + /* 0 */ 720, INVALID, INVALID, +}; + +static const uint16_t ud_itab__25[] = { + /* 0 */ 1425, GROUP(26), INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__26[] = { + /* 0 */ 1298, INVALID, INVALID, +}; + +static const uint16_t ud_itab__27[] = { + /* 0 */ 1119, 1120, 1121, 1122, + /* 4 */ 1123, 1124, 1125, 1126, +}; + +static const uint16_t ud_itab__28[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ 1216, 1217, INVALID, INVALID, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ 1218, 1219, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, 1220, INVALID, + /* 8c */ INVALID, INVALID, 1221, INVALID, + /* 90 */ 1222, INVALID, INVALID, INVALID, + /* 94 */ 1223, INVALID, 1224, 1225, + /* 98 */ INVALID, INVALID, 1226, INVALID, + /* 9c */ INVALID, INVALID, 1227, INVALID, + /* a0 */ 1228, INVALID, INVALID, INVALID, + /* a4 */ 1229, INVALID, 1230, 1231, + /* a8 */ INVALID, INVALID, 1232, INVALID, + /* ac */ INVALID, INVALID, 1233, INVALID, + /* b0 */ 1234, INVALID, INVALID, INVALID, + /* b4 */ 1235, INVALID, 1236, 1237, + /* b8 */ INVALID, INVALID, INVALID, 1238, + /* bc */ INVALID, INVALID, INVALID, 1239, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__29[] = { + /* 0 */ 936, 925, 928, 932, +}; + +static const uint16_t ud_itab__30[] = { + /* 0 */ 938, 926, 929, 934, +}; + +static const uint16_t ud_itab__31[] = { + /* 0 */ GROUP(32), GROUP(33), +}; + +static const uint16_t ud_itab__32[] = { + /* 0 */ 892, 1563, 1571, 888, +}; + +static const uint16_t ud_itab__33[] = { + /* 0 */ 896, 1561, 1569, INVALID, +}; + +static const uint16_t ud_itab__34[] = { + /* 0 */ 894, INVALID, INVALID, 890, +}; + +static const uint16_t ud_itab__35[] = { + /* 0 */ 1449, INVALID, INVALID, 1451, +}; + +static const uint16_t ud_itab__36[] = { + /* 0 */ 1447, INVALID, INVALID, 1445, +}; + +static const uint16_t ud_itab__37[] = { + /* 0 */ GROUP(38), GROUP(39), +}; + +static const uint16_t ud_itab__38[] = { + /* 0 */ 882, INVALID, 1567, 878, +}; + +static const uint16_t ud_itab__39[] = { + /* 0 */ 886, INVALID, 1565, INVALID, +}; + +static const uint16_t ud_itab__40[] = { + /* 0 */ 884, INVALID, INVALID, 880, +}; + +static const uint16_t ud_itab__41[] = { + /* 0 */ 1127, 1128, 1129, 1130, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__42[] = { + /* 0 */ 862, INVALID, INVALID, 858, +}; + +static const uint16_t ud_itab__43[] = { + /* 0 */ 864, INVALID, INVALID, 860, +}; + +static const uint16_t ud_itab__44[] = { + /* 0 */ 141, 152, 154, 142, +}; + +static const uint16_t ud_itab__45[] = { + /* 0 */ 907, INVALID, INVALID, 905, +}; + +static const uint16_t ud_itab__46[] = { + /* 0 */ 165, 166, 168, 162, +}; + +static const uint16_t ud_itab__47[] = { + /* 0 */ 147, 148, 158, 138, +}; + +static const uint16_t ud_itab__48[] = { + /* 0 */ 1442, INVALID, INVALID, 1440, +}; + +static const uint16_t ud_itab__49[] = { + /* 0 */ 129, INVALID, INVALID, 127, +}; + +static const uint16_t ud_itab__50[] = { + /* 0 */ 1427, GROUP(51), +}; + +static const uint16_t ud_itab__51[] = { + /* 0 */ INVALID, 1428, INVALID, +}; + +static const uint16_t ud_itab__52[] = { + /* 0 */ 1429, GROUP(53), +}; + +static const uint16_t ud_itab__53[] = { + /* 0 */ INVALID, 1430, INVALID, +}; + +static const uint16_t ud_itab__54[] = { + /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64), + /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90), + /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72), + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(73), INVALID, INVALID, INVALID, + /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID, + /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84), + /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID, + /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74), + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94), + /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97), + /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101), + /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105), + /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, GROUP(109), + /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__55[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(56), +}; + +static const uint16_t ud_itab__56[] = { + /* 0 */ GROUP(57), GROUP(58), +}; + +static const uint16_t ud_itab__57[] = { + /* 0 */ INVALID, 717, INVALID, +}; + +static const uint16_t ud_itab__58[] = { + /* 0 */ INVALID, 718, INVALID, +}; + +static const uint16_t ud_itab__59[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(60), +}; + +static const uint16_t ud_itab__60[] = { + /* 0 */ GROUP(61), GROUP(62), +}; + +static const uint16_t ud_itab__61[] = { + /* 0 */ INVALID, 721, INVALID, +}; + +static const uint16_t ud_itab__62[] = { + /* 0 */ INVALID, 722, INVALID, +}; + +static const uint16_t ud_itab__63[] = { + /* 0 */ 1588, INVALID, INVALID, 1589, +}; + +static const uint16_t ud_itab__64[] = { + /* 0 */ 1591, INVALID, INVALID, 1592, +}; + +static const uint16_t ud_itab__65[] = { + /* 0 */ 1594, INVALID, INVALID, 1595, +}; + +static const uint16_t ud_itab__66[] = { + /* 0 */ 1597, INVALID, INVALID, 1598, +}; + +static const uint16_t ud_itab__67[] = { + /* 0 */ 1582, INVALID, INVALID, 1583, +}; + +static const uint16_t ud_itab__68[] = { + /* 0 */ 1585, INVALID, INVALID, 1586, +}; + +static const uint16_t ud_itab__69[] = { + /* 0 */ 1606, INVALID, INVALID, 1607, +}; + +static const uint16_t ud_itab__70[] = { + /* 0 */ 1612, INVALID, INVALID, 1613, +}; + +static const uint16_t ud_itab__71[] = { + /* 0 */ 1609, INVALID, INVALID, 1610, +}; + +static const uint16_t ud_itab__72[] = { + /* 0 */ 1615, INVALID, INVALID, 1616, +}; + +static const uint16_t ud_itab__73[] = { + /* 0 */ INVALID, INVALID, INVALID, 1621, +}; + +static const uint16_t ud_itab__74[] = { + /* 0 */ INVALID, INVALID, INVALID, 1683, +}; + +static const uint16_t ud_itab__75[] = { + /* 0 */ INVALID, INVALID, INVALID, 1657, +}; + +static const uint16_t ud_itab__76[] = { + /* 0 */ INVALID, INVALID, INVALID, 1656, +}; + +static const uint16_t ud_itab__77[] = { + /* 0 */ INVALID, INVALID, INVALID, 1711, +}; + +static const uint16_t ud_itab__78[] = { + /* 0 */ 1573, INVALID, INVALID, 1574, +}; + +static const uint16_t ud_itab__79[] = { + /* 0 */ 1576, INVALID, INVALID, 1577, +}; + +static const uint16_t ud_itab__80[] = { + /* 0 */ 1579, INVALID, INVALID, 1580, +}; + +static const uint16_t ud_itab__81[] = { + /* 0 */ INVALID, INVALID, INVALID, 1685, +}; + +static const uint16_t ud_itab__82[] = { + /* 0 */ INVALID, INVALID, INVALID, 1687, +}; + +static const uint16_t ud_itab__83[] = { + /* 0 */ INVALID, INVALID, INVALID, 1689, +}; + +static const uint16_t ud_itab__84[] = { + /* 0 */ INVALID, INVALID, INVALID, 1691, +}; + +static const uint16_t ud_itab__85[] = { + /* 0 */ INVALID, INVALID, INVALID, 1693, +}; + +static const uint16_t ud_itab__86[] = { + /* 0 */ 1600, INVALID, INVALID, 1601, +}; + +static const uint16_t ud_itab__87[] = { + /* 0 */ INVALID, INVALID, INVALID, 1622, +}; + +static const uint16_t ud_itab__88[] = { + /* 0 */ INVALID, INVALID, INVALID, 1708, +}; + +static const uint16_t ud_itab__89[] = { + /* 0 */ INVALID, INVALID, INVALID, 1681, +}; + +static const uint16_t ud_itab__90[] = { + /* 0 */ 1603, INVALID, INVALID, 1604, +}; + +static const uint16_t ud_itab__91[] = { + /* 0 */ INVALID, INVALID, INVALID, 1696, +}; + +static const uint16_t ud_itab__92[] = { + /* 0 */ INVALID, INVALID, INVALID, 1698, +}; + +static const uint16_t ud_itab__93[] = { + /* 0 */ INVALID, INVALID, INVALID, 1700, +}; + +static const uint16_t ud_itab__94[] = { + /* 0 */ INVALID, INVALID, INVALID, 1702, +}; + +static const uint16_t ud_itab__95[] = { + /* 0 */ INVALID, INVALID, INVALID, 1704, +}; + +static const uint16_t ud_itab__96[] = { + /* 0 */ INVALID, INVALID, INVALID, 1706, +}; + +static const uint16_t ud_itab__97[] = { + /* 0 */ INVALID, INVALID, INVALID, 1717, +}; + +static const uint16_t ud_itab__98[] = { + /* 0 */ INVALID, INVALID, INVALID, 1624, +}; + +static const uint16_t ud_itab__99[] = { + /* 0 */ INVALID, INVALID, INVALID, 1626, +}; + +static const uint16_t ud_itab__100[] = { + /* 0 */ INVALID, INVALID, INVALID, 1628, +}; + +static const uint16_t ud_itab__101[] = { + /* 0 */ INVALID, INVALID, INVALID, 1630, +}; + +static const uint16_t ud_itab__102[] = { + /* 0 */ INVALID, INVALID, INVALID, 1632, +}; + +static const uint16_t ud_itab__103[] = { + /* 0 */ INVALID, INVALID, INVALID, 1634, +}; + +static const uint16_t ud_itab__104[] = { + /* 0 */ INVALID, INVALID, INVALID, 1638, +}; + +static const uint16_t ud_itab__105[] = { + /* 0 */ INVALID, INVALID, INVALID, 1636, +}; + +static const uint16_t ud_itab__106[] = { + /* 0 */ INVALID, INVALID, INVALID, 1640, +}; + +static const uint16_t ud_itab__107[] = { + /* 0 */ INVALID, INVALID, INVALID, 1642, +}; + +static const uint16_t ud_itab__108[] = { + /* 0 */ INVALID, INVALID, INVALID, 1695, +}; + +static const uint16_t ud_itab__109[] = { + /* 0 */ INVALID, INVALID, INVALID, 45, +}; + +static const uint16_t ud_itab__110[] = { + /* 0 */ INVALID, INVALID, INVALID, 41, +}; + +static const uint16_t ud_itab__111[] = { + /* 0 */ INVALID, INVALID, INVALID, 43, +}; + +static const uint16_t ud_itab__112[] = { + /* 0 */ INVALID, INVALID, INVALID, 37, +}; + +static const uint16_t ud_itab__113[] = { + /* 0 */ INVALID, INVALID, INVALID, 39, +}; + +static const uint16_t ud_itab__114[] = { + /* 0 */ 1723, 1725, INVALID, INVALID, +}; + +static const uint16_t ud_itab__115[] = { + /* 0 */ 1724, 1726, INVALID, INVALID, +}; + +static const uint16_t ud_itab__116[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120), + /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID, + /* 44 */ GROUP(137), INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, GROUP(138), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__117[] = { + /* 0 */ INVALID, INVALID, INVALID, 1644, +}; + +static const uint16_t ud_itab__118[] = { + /* 0 */ INVALID, INVALID, INVALID, 1646, +}; + +static const uint16_t ud_itab__119[] = { + /* 0 */ INVALID, INVALID, INVALID, 1648, +}; + +static const uint16_t ud_itab__120[] = { + /* 0 */ INVALID, INVALID, INVALID, 1650, +}; + +static const uint16_t ud_itab__121[] = { + /* 0 */ INVALID, INVALID, INVALID, 1654, +}; + +static const uint16_t ud_itab__122[] = { + /* 0 */ INVALID, INVALID, INVALID, 1652, +}; + +static const uint16_t ud_itab__123[] = { + /* 0 */ INVALID, INVALID, INVALID, 1677, +}; + +static const uint16_t ud_itab__124[] = { + /* 0 */ 1618, INVALID, INVALID, 1619, +}; + +static const uint16_t ud_itab__125[] = { + /* 0 */ INVALID, INVALID, INVALID, 1045, +}; + +static const uint16_t ud_itab__126[] = { + /* 0 */ INVALID, INVALID, INVALID, 1056, +}; + +static const uint16_t ud_itab__127[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(128), +}; + +static const uint16_t ud_itab__128[] = { + /* 0 */ 1047, 1049, 1051, +}; + +static const uint16_t ud_itab__129[] = { + /* 0 */ INVALID, INVALID, INVALID, 201, +}; + +static const uint16_t ud_itab__130[] = { + /* 0 */ INVALID, INVALID, INVALID, 1058, +}; + +static const uint16_t ud_itab__131[] = { + /* 0 */ INVALID, INVALID, INVALID, 1557, +}; + +static const uint16_t ud_itab__132[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(133), +}; + +static const uint16_t ud_itab__133[] = { + /* 0 */ 1062, 1063, 1064, +}; + +static const uint16_t ud_itab__134[] = { + /* 0 */ INVALID, INVALID, INVALID, 197, +}; + +static const uint16_t ud_itab__135[] = { + /* 0 */ INVALID, INVALID, INVALID, 195, +}; + +static const uint16_t ud_itab__136[] = { + /* 0 */ INVALID, INVALID, INVALID, 1679, +}; + +static const uint16_t ud_itab__137[] = { + /* 0 */ INVALID, INVALID, INVALID, 1512, +}; + +static const uint16_t ud_itab__138[] = { + /* 0 */ INVALID, INVALID, INVALID, 47, +}; + +static const uint16_t ud_itab__139[] = { + /* 0 */ INVALID, INVALID, INVALID, 1715, +}; + +static const uint16_t ud_itab__140[] = { + /* 0 */ INVALID, INVALID, INVALID, 1713, +}; + +static const uint16_t ud_itab__141[] = { + /* 0 */ INVALID, INVALID, INVALID, 1721, +}; + +static const uint16_t ud_itab__142[] = { + /* 0 */ INVALID, INVALID, INVALID, 1719, +}; + +static const uint16_t ud_itab__143[] = { + /* 0 */ 900, INVALID, INVALID, 898, +}; + +static const uint16_t ud_itab__144[] = { + /* 0 */ 1387, 1391, 1393, 1389, +}; + +static const uint16_t ud_itab__145[] = { + /* 0 */ 1306, INVALID, 1308, INVALID, +}; + +static const uint16_t ud_itab__146[] = { + /* 0 */ 1291, INVALID, 1293, INVALID, +}; + +static const uint16_t ud_itab__147[] = { + /* 0 */ 61, INVALID, INVALID, 59, +}; + +static const uint16_t ud_itab__148[] = { + /* 0 */ 65, INVALID, INVALID, 63, +}; + +static const uint16_t ud_itab__149[] = { + /* 0 */ 976, INVALID, INVALID, 974, +}; + +static const uint16_t ud_itab__150[] = { + /* 0 */ 1499, INVALID, INVALID, 1497, +}; + +static const uint16_t ud_itab__151[] = { + /* 0 */ 27, 29, 31, 25, +}; + +static const uint16_t ud_itab__152[] = { + /* 0 */ 946, 948, 950, 944, +}; + +static const uint16_t ud_itab__153[] = { + /* 0 */ 145, 150, 156, 139, +}; + +static const uint16_t ud_itab__154[] = { + /* 0 */ 134, INVALID, 163, 143, +}; + +static const uint16_t ud_itab__155[] = { + /* 0 */ 1419, 1421, 1423, 1417, +}; + +static const uint16_t ud_itab__156[] = { + /* 0 */ 818, 820, 822, 816, +}; + +static const uint16_t ud_itab__157[] = { + /* 0 */ 189, 191, 193, 187, +}; + +static const uint16_t ud_itab__158[] = { + /* 0 */ 802, 804, 806, 800, +}; + +static const uint16_t ud_itab__159[] = { + /* 0 */ 1209, INVALID, INVALID, 1207, +}; + +static const uint16_t ud_itab__160[] = { + /* 0 */ 1212, INVALID, INVALID, 1210, +}; + +static const uint16_t ud_itab__161[] = { + /* 0 */ 1215, INVALID, INVALID, 1213, +}; + +static const uint16_t ud_itab__162[] = { + /* 0 */ 987, INVALID, INVALID, 985, +}; + +static const uint16_t ud_itab__163[] = { + /* 0 */ 1038, INVALID, INVALID, 1036, +}; + +static const uint16_t ud_itab__164[] = { + /* 0 */ 1041, INVALID, INVALID, 1039, +}; + +static const uint16_t ud_itab__165[] = { + /* 0 */ 1044, INVALID, INVALID, 1042, +}; + +static const uint16_t ud_itab__166[] = { + /* 0 */ 993, INVALID, INVALID, 991, +}; + +static const uint16_t ud_itab__167[] = { + /* 0 */ 1200, INVALID, INVALID, 1198, +}; + +static const uint16_t ud_itab__168[] = { + /* 0 */ 1203, INVALID, INVALID, 1201, +}; + +static const uint16_t ud_itab__169[] = { + /* 0 */ 1206, INVALID, INVALID, 1204, +}; + +static const uint16_t ud_itab__170[] = { + /* 0 */ 990, INVALID, INVALID, 988, +}; + +static const uint16_t ud_itab__171[] = { + /* 0 */ INVALID, INVALID, INVALID, 1547, +}; + +static const uint16_t ud_itab__172[] = { + /* 0 */ INVALID, INVALID, INVALID, 1545, +}; + +static const uint16_t ud_itab__173[] = { + /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175), +}; + +static const uint16_t ud_itab__174[] = { + /* 0 */ 866, 867, 910, +}; + +static const uint16_t ud_itab__175[] = { + /* 0 */ 868, 870, 911, +}; + +static const uint16_t ud_itab__176[] = { + /* 0 */ 920, INVALID, 1522, 1517, +}; + +static const uint16_t ud_itab__177[] = { + /* 0 */ 1134, 1537, 1535, 1539, +}; + +static const uint16_t ud_itab__178[] = { + /* 0 */ INVALID, INVALID, GROUP(179), INVALID, + /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID, +}; + +static const uint16_t ud_itab__179[] = { + /* 0 */ 1159, INVALID, INVALID, 1163, +}; + +static const uint16_t ud_itab__180[] = { + /* 0 */ 1152, INVALID, INVALID, 1150, +}; + +static const uint16_t ud_itab__181[] = { + /* 0 */ 1138, INVALID, INVALID, 1137, +}; + +static const uint16_t ud_itab__182[] = { + /* 0 */ INVALID, INVALID, GROUP(183), INVALID, + /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID, +}; + +static const uint16_t ud_itab__183[] = { + /* 0 */ 1165, INVALID, INVALID, 1169, +}; + +static const uint16_t ud_itab__184[] = { + /* 0 */ 1153, INVALID, INVALID, 1157, +}; + +static const uint16_t ud_itab__185[] = { + /* 0 */ 1142, INVALID, INVALID, 1141, +}; + +static const uint16_t ud_itab__186[] = { + /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188), + /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190), +}; + +static const uint16_t ud_itab__187[] = { + /* 0 */ 1171, INVALID, INVALID, 1175, +}; + +static const uint16_t ud_itab__188[] = { + /* 0 */ INVALID, INVALID, INVALID, 1543, +}; + +static const uint16_t ud_itab__189[] = { + /* 0 */ 1146, INVALID, INVALID, 1145, +}; + +static const uint16_t ud_itab__190[] = { + /* 0 */ INVALID, INVALID, INVALID, 1541, +}; + +static const uint16_t ud_itab__191[] = { + /* 0 */ 1027, INVALID, INVALID, 1028, +}; + +static const uint16_t ud_itab__192[] = { + /* 0 */ 1030, INVALID, INVALID, 1031, +}; + +static const uint16_t ud_itab__193[] = { + /* 0 */ 1033, INVALID, INVALID, 1034, +}; + +static const uint16_t ud_itab__194[] = { + /* 0 */ INVALID, 1464, INVALID, +}; + +static const uint16_t ud_itab__195[] = { + /* 0 */ INVALID, 1465, INVALID, +}; + +static const uint16_t ud_itab__196[] = { + /* 0 */ INVALID, 1551, INVALID, 1549, +}; + +static const uint16_t ud_itab__197[] = { + /* 0 */ INVALID, 1555, INVALID, 1553, +}; + +static const uint16_t ud_itab__198[] = { + /* 0 */ GROUP(199), INVALID, 916, GROUP(200), +}; + +static const uint16_t ud_itab__199[] = { + /* 0 */ 872, 873, 913, +}; + +static const uint16_t ud_itab__200[] = { + /* 0 */ 874, 876, 914, +}; + +static const uint16_t ud_itab__201[] = { + /* 0 */ 921, INVALID, 1524, 1515, +}; + +static const uint16_t ud_itab__202[] = { + /* 0 */ INVALID, GROUP(203), +}; + +static const uint16_t ud_itab__203[] = { + /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__204[] = { + /* 0 */ 825, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__205[] = { + /* 0 */ 1509, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__206[] = { + /* 0 */ 1510, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__207[] = { + /* 0 */ INVALID, GROUP(208), +}; + +static const uint16_t ud_itab__208[] = { + /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212), + /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID, +}; + +static const uint16_t ud_itab__209[] = { + /* 0 */ 1511, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__210[] = { + /* 0 */ 1501, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__211[] = { + /* 0 */ 1502, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__212[] = { + /* 0 */ 1503, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__213[] = { + /* 0 */ 1504, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__214[] = { + /* 0 */ 1505, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__215[] = { + /* 0 */ GROUP(216), GROUP(217), +}; + +static const uint16_t ud_itab__216[] = { + /* 0 */ 683, 682, 768, 1400, + /* 4 */ 1507, 1506, INVALID, 79, +}; + +static const uint16_t ud_itab__217[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220), +}; + +static const uint16_t ud_itab__218[] = { + /* 0 */ 777, 778, 779, 780, + /* 4 */ 781, 782, 783, 784, +}; + +static const uint16_t ud_itab__219[] = { + /* 0 */ 808, 809, 810, 811, + /* 4 */ 812, 813, 814, 815, +}; + +static const uint16_t ud_itab__220[] = { + /* 0 */ 1366, 1367, 1368, 1369, + /* 4 */ 1370, 1371, 1372, 1373, +}; + +static const uint16_t ud_itab__221[] = { + /* 0 */ INVALID, INVALID, 1710, INVALID, +}; + +static const uint16_t ud_itab__222[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ 1669, 1676, 1674, 1672, +}; + +static const uint16_t ud_itab__223[] = { + /* 0 */ 112, 117, 120, 110, +}; + +static const uint16_t ud_itab__224[] = { + /* 0 */ 1059, INVALID, INVALID, 1060, +}; + +static const uint16_t ud_itab__225[] = { + /* 0 */ 1055, INVALID, INVALID, 1053, +}; + +static const uint16_t ud_itab__226[] = { + /* 0 */ 1381, INVALID, INVALID, 1379, +}; + +static const uint16_t ud_itab__227[] = { + /* 0 */ GROUP(228), GROUP(235), +}; + +static const uint16_t ud_itab__228[] = { + /* 0 */ INVALID, GROUP(229), INVALID, INVALID, + /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234), +}; + +static const uint16_t ud_itab__229[] = { + /* 0 */ 124, 125, 126, +}; + +static const uint16_t ud_itab__230[] = { + /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233), +}; + +static const uint16_t ud_itab__231[] = { + /* 0 */ INVALID, 1459, INVALID, +}; + +static const uint16_t ud_itab__232[] = { + /* 0 */ INVALID, 1458, INVALID, +}; + +static const uint16_t ud_itab__233[] = { + /* 0 */ INVALID, 1457, INVALID, +}; + +static const uint16_t ud_itab__234[] = { + /* 0 */ INVALID, 1460, INVALID, +}; + +static const uint16_t ud_itab__235[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, 1456, INVALID, +}; + +static const uint16_t ud_itab__236[] = { + /* 0 */ INVALID, 35, INVALID, 33, +}; + +static const uint16_t ud_itab__237[] = { + /* 0 */ 1160, INVALID, INVALID, 1161, +}; + +static const uint16_t ud_itab__238[] = { + /* 0 */ 1166, INVALID, INVALID, 1167, +}; + +static const uint16_t ud_itab__239[] = { + /* 0 */ 1172, INVALID, INVALID, 1173, +}; + +static const uint16_t ud_itab__240[] = { + /* 0 */ 1527, INVALID, INVALID, 1528, +}; + +static const uint16_t ud_itab__241[] = { + /* 0 */ 1093, INVALID, INVALID, 1094, +}; + +static const uint16_t ud_itab__242[] = { + /* 0 */ INVALID, 1521, 1526, 918, +}; + +static const uint16_t ud_itab__243[] = { + /* 0 */ 1086, INVALID, INVALID, 1084, +}; + +static const uint16_t ud_itab__244[] = { + /* 0 */ 1192, INVALID, INVALID, 1193, +}; + +static const uint16_t ud_itab__245[] = { + /* 0 */ 1195, INVALID, INVALID, 1196, +}; + +static const uint16_t ud_itab__246[] = { + /* 0 */ 1083, INVALID, INVALID, 1081, +}; + +static const uint16_t ud_itab__247[] = { + /* 0 */ 1017, INVALID, INVALID, 1015, +}; + +static const uint16_t ud_itab__248[] = { + /* 0 */ 1009, INVALID, INVALID, 1010, +}; + +static const uint16_t ud_itab__249[] = { + /* 0 */ 1012, INVALID, INVALID, 1013, +}; + +static const uint16_t ud_itab__250[] = { + /* 0 */ 1075, INVALID, INVALID, 1076, +}; + +static const uint16_t ud_itab__251[] = { + /* 0 */ 1020, INVALID, INVALID, 1018, +}; + +static const uint16_t ud_itab__252[] = { + /* 0 */ 1023, INVALID, INVALID, 1021, +}; + +static const uint16_t ud_itab__253[] = { + /* 0 */ 1147, INVALID, INVALID, 1148, +}; + +static const uint16_t ud_itab__254[] = { + /* 0 */ 1156, INVALID, INVALID, 1154, +}; + +static const uint16_t ud_itab__255[] = { + /* 0 */ 1026, INVALID, INVALID, 1024, +}; + +static const uint16_t ud_itab__256[] = { + /* 0 */ 1087, INVALID, INVALID, 1088, +}; + +static const uint16_t ud_itab__257[] = { + /* 0 */ 1092, INVALID, INVALID, 1090, +}; + +static const uint16_t ud_itab__258[] = { + /* 0 */ INVALID, 136, 132, 160, +}; + +static const uint16_t ud_itab__259[] = { + /* 0 */ 909, INVALID, INVALID, 902, +}; + +static const uint16_t ud_itab__260[] = { + /* 0 */ 1186, INVALID, INVALID, 1187, +}; + +static const uint16_t ud_itab__261[] = { + /* 0 */ 1189, INVALID, INVALID, 1190, +}; + +static const uint16_t ud_itab__262[] = { + /* 0 */ 1080, INVALID, INVALID, 1078, +}; + +static const uint16_t ud_itab__263[] = { + /* 0 */ 1118, INVALID, INVALID, 1116, +}; + +static const uint16_t ud_itab__264[] = { + /* 0 */ 1003, INVALID, INVALID, 1004, +}; + +static const uint16_t ud_itab__265[] = { + /* 0 */ 1006, INVALID, INVALID, 1007, +}; + +static const uint16_t ud_itab__266[] = { + /* 0 */ 1074, INVALID, INVALID, 1072, +}; + +static const uint16_t ud_itab__267[] = { + /* 0 */ 1266, INVALID, INVALID, 1264, +}; + +static const uint16_t ud_itab__268[] = { + /* 0 */ INVALID, 1559, INVALID, INVALID, +}; + +static const uint16_t ud_itab__269[] = { + /* 0 */ 1136, INVALID, INVALID, 1135, +}; + +static const uint16_t ud_itab__270[] = { + /* 0 */ 1140, INVALID, INVALID, 1139, +}; + +static const uint16_t ud_itab__271[] = { + /* 0 */ 1144, INVALID, INVALID, 1143, +}; + +static const uint16_t ud_itab__272[] = { + /* 0 */ 1533, INVALID, INVALID, 1534, +}; + +static const uint16_t ud_itab__273[] = { + /* 0 */ 1069, INVALID, INVALID, 1070, +}; + +static const uint16_t ud_itab__274[] = { + /* 0 */ 1133, INVALID, INVALID, 1131, +}; + +static const uint16_t ud_itab__275[] = { + /* 0 */ INVALID, GROUP(276), +}; + +static const uint16_t ud_itab__276[] = { + /* 0 */ 799, INVALID, INVALID, 1519, +}; + +static const uint16_t ud_itab__277[] = { + /* 0 */ 1179, INVALID, INVALID, 1177, +}; + +static const uint16_t ud_itab__278[] = { + /* 0 */ 1182, INVALID, INVALID, 1180, +}; + +static const uint16_t ud_itab__279[] = { + /* 0 */ 1183, INVALID, INVALID, 1184, +}; + +static const uint16_t ud_itab__280[] = { + /* 0 */ 1532, INVALID, INVALID, 1530, +}; + +static const uint16_t ud_itab__281[] = { + /* 0 */ 996, INVALID, INVALID, 994, +}; + +static const uint16_t ud_itab__282[] = { + /* 0 */ 997, INVALID, INVALID, 998, +}; + +static const uint16_t ud_itab__283[] = { + /* 0 */ 1000, INVALID, INVALID, 1001, +}; + +static const uint16_t ud_itab__284[] = { + /* 0 */ 1242, INVALID, +}; + +static const uint16_t ud_itab__285[] = { + /* 0 */ 1097, INVALID, +}; + +static const uint16_t ud_itab__286[] = { + /* 0 */ 1243, INVALID, +}; + +static const uint16_t ud_itab__287[] = { + /* 0 */ 1098, INVALID, +}; + +static const uint16_t ud_itab__288[] = { + /* 0 */ 173, INVALID, +}; + +static const uint16_t ud_itab__289[] = { + /* 0 */ 174, INVALID, +}; + +static const uint16_t ud_itab__290[] = { + /* 0 */ 1, INVALID, +}; + +static const uint16_t ud_itab__291[] = { + /* 0 */ 4, INVALID, +}; + +static const uint16_t ud_itab__292[] = { + /* 0 */ GROUP(293), GROUP(294), INVALID, +}; + +static const uint16_t ud_itab__293[] = { + /* 0 */ 1257, INVALID, +}; + +static const uint16_t ud_itab__294[] = { + /* 0 */ 1258, INVALID, +}; + +static const uint16_t ud_itab__295[] = { + /* 0 */ GROUP(296), GROUP(297), INVALID, +}; + +static const uint16_t ud_itab__296[] = { + /* 0 */ 1110, INVALID, +}; + +static const uint16_t ud_itab__297[] = { + /* 0 */ 1111, INVALID, +}; + +static const uint16_t ud_itab__298[] = { + /* 0 */ 1658, INVALID, +}; + +static const uint16_t ud_itab__299[] = { + /* 0 */ 67, 68, +}; + +static const uint16_t ud_itab__300[] = { + /* 0 */ 710, 711, INVALID, +}; + +static const uint16_t ud_itab__301[] = { + /* 0 */ 983, 984, INVALID, +}; + +static const uint16_t ud_itab__302[] = { + /* 0 */ 21, 970, 11, 1342, + /* 4 */ 55, 1413, 1493, 106, +}; + +static const uint16_t ud_itab__303[] = { + /* 0 */ 23, 971, 13, 1343, + /* 4 */ 57, 1414, 1494, 108, +}; + +static const uint16_t ud_itab__304[] = { + /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308), + /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312), +}; + +static const uint16_t ud_itab__305[] = { + /* 0 */ 22, INVALID, +}; + +static const uint16_t ud_itab__306[] = { + /* 0 */ 972, INVALID, +}; + +static const uint16_t ud_itab__307[] = { + /* 0 */ 12, INVALID, +}; + +static const uint16_t ud_itab__308[] = { + /* 0 */ 1344, INVALID, +}; + +static const uint16_t ud_itab__309[] = { + /* 0 */ 56, INVALID, +}; + +static const uint16_t ud_itab__310[] = { + /* 0 */ 1415, INVALID, +}; + +static const uint16_t ud_itab__311[] = { + /* 0 */ 1495, INVALID, +}; + +static const uint16_t ud_itab__312[] = { + /* 0 */ 107, INVALID, +}; + +static const uint16_t ud_itab__313[] = { + /* 0 */ 24, 973, 14, 1345, + /* 4 */ 58, 1416, 1496, 109, +}; + +static const uint16_t ud_itab__314[] = { + /* 0 */ 1109, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__315[] = { + /* 0 */ 74, 75, 76, +}; + +static const uint16_t ud_itab__316[] = { + /* 0 */ 170, 171, 172, +}; + +static const uint16_t ud_itab__317[] = { + /* 0 */ 73, INVALID, +}; + +static const uint16_t ud_itab__318[] = { + /* 0 */ GROUP(319), GROUP(320), GROUP(321), +}; + +static const uint16_t ud_itab__319[] = { + /* 0 */ 1259, 1260, +}; + +static const uint16_t ud_itab__320[] = { + /* 0 */ 1261, 1262, +}; + +static const uint16_t ud_itab__321[] = { + /* 0 */ INVALID, 1263, +}; + +static const uint16_t ud_itab__322[] = { + /* 0 */ GROUP(323), GROUP(324), GROUP(325), +}; + +static const uint16_t ud_itab__323[] = { + /* 0 */ 1112, INVALID, +}; + +static const uint16_t ud_itab__324[] = { + /* 0 */ 1113, 1114, +}; + +static const uint16_t ud_itab__325[] = { + /* 0 */ INVALID, 1115, +}; + +static const uint16_t ud_itab__326[] = { + /* 0 */ 923, 924, 927, +}; + +static const uint16_t ud_itab__327[] = { + /* 0 */ 115, 116, 119, +}; + +static const uint16_t ud_itab__328[] = { + /* 0 */ 1403, 1404, 1405, +}; + +static const uint16_t ud_itab__329[] = { + /* 0 */ 791, 792, 793, +}; + +static const uint16_t ud_itab__330[] = { + /* 0 */ 1347, 1348, 1349, +}; + +static const uint16_t ud_itab__331[] = { + /* 0 */ 1279, 1286, 1267, 1275, + /* 4 */ 1327, 1334, 1318, 1313, +}; + +static const uint16_t ud_itab__332[] = { + /* 0 */ 1284, 1287, 1268, 1274, + /* 4 */ 1323, 1330, 1319, 1315, +}; + +static const uint16_t ud_itab__333[] = { + /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__334[] = { + /* 0 */ 771, INVALID, +}; + +static const uint16_t ud_itab__335[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 937, 939, GROUP(336), 895, + /* 14 */ 1450, 1448, GROUP(337), 885, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 863, 865, INVALID, 908, + /* 2c */ INVALID, INVALID, 1443, 130, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 901, 1388, 1307, 1292, + /* 54 */ 62, 66, 977, 1500, + /* 58 */ 28, 947, 146, 135, + /* 5c */ 1420, 819, 190, 803, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, GROUP(340), + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, GROUP(338), INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 113, INVALID, + /* c4 */ INVALID, INVALID, 1382, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__336[] = { + /* 0 */ 893, 897, +}; + +static const uint16_t ud_itab__337[] = { + /* 0 */ 883, 887, +}; + +static const uint16_t ud_itab__338[] = { + /* 0 */ GROUP(339), INVALID, +}; + +static const uint16_t ud_itab__339[] = { + /* 0 */ INVALID, INVALID, INVALID, 1401, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__340[] = { + /* 0 */ 1742, 1743, +}; + +static const uint16_t ud_itab__341[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 933, 935, GROUP(342), 891, + /* 14 */ 1452, 1446, GROUP(343), 881, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 859, 861, INVALID, 906, + /* 2c */ INVALID, INVALID, 1441, 128, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 899, 1390, INVALID, INVALID, + /* 54 */ 60, 64, 975, 1498, + /* 58 */ 26, 945, 140, 144, + /* 5c */ 1418, 817, 188, 801, + /* 60 */ 1208, 1211, 1214, 986, + /* 64 */ 1037, 1040, 1043, 992, + /* 68 */ 1199, 1202, 1205, 989, + /* 6c */ 1548, 1546, GROUP(344), 1518, + /* 70 */ 1540, GROUP(345), GROUP(347), GROUP(349), + /* 74 */ 1029, 1032, 1035, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1550, 1554, GROUP(351), 1516, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 111, INVALID, + /* c4 */ 1061, 1054, 1380, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 34, 1162, 1168, 1174, + /* d4 */ 1529, 1095, 919, GROUP(352), + /* d8 */ 1194, 1197, 1082, 1016, + /* dc */ 1011, 1014, 1077, 1019, + /* e0 */ 1022, 1149, 1155, 1025, + /* e4 */ 1089, 1091, 161, 903, + /* e8 */ 1188, 1191, 1079, 1117, + /* ec */ 1005, 1008, 1073, 1265, + /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355), + /* f4 */ INVALID, 1071, 1132, GROUP(356), + /* f8 */ 1178, 1181, 1185, 1531, + /* fc */ 995, 999, 1002, INVALID, +}; + +static const uint16_t ud_itab__342[] = { + /* 0 */ 889, INVALID, +}; + +static const uint16_t ud_itab__343[] = { + /* 0 */ 879, INVALID, +}; + +static const uint16_t ud_itab__344[] = { + /* 0 */ 869, 871, 912, +}; + +static const uint16_t ud_itab__345[] = { + /* 0 */ INVALID, INVALID, 1164, INVALID, + /* 4 */ 1151, INVALID, GROUP(346), INVALID, +}; + +static const uint16_t ud_itab__346[] = { + /* 0 */ 1756, INVALID, +}; + +static const uint16_t ud_itab__347[] = { + /* 0 */ INVALID, INVALID, 1170, INVALID, + /* 4 */ 1158, INVALID, GROUP(348), INVALID, +}; + +static const uint16_t ud_itab__348[] = { + /* 0 */ 1758, INVALID, +}; + +static const uint16_t ud_itab__349[] = { + /* 0 */ INVALID, INVALID, 1176, 1544, + /* 4 */ INVALID, INVALID, GROUP(350), 1542, +}; + +static const uint16_t ud_itab__350[] = { + /* 0 */ 1760, INVALID, +}; + +static const uint16_t ud_itab__351[] = { + /* 0 */ 875, 877, 915, +}; + +static const uint16_t ud_itab__352[] = { + /* 0 */ 1085, INVALID, +}; + +static const uint16_t ud_itab__353[] = { + /* 0 */ 1755, INVALID, +}; + +static const uint16_t ud_itab__354[] = { + /* 0 */ 1757, INVALID, +}; + +static const uint16_t ud_itab__355[] = { + /* 0 */ 1759, INVALID, +}; + +static const uint16_t ud_itab__356[] = { + /* 0 */ INVALID, 1520, +}; + +static const uint16_t ud_itab__357[] = { + /* 0 */ 1584, 1587, 1590, 1593, + /* 4 */ 1596, 1599, 1602, 1605, + /* 8 */ 1608, 1614, 1611, 1617, + /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, 1712, + /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID, + /* 1c */ 1575, 1578, 1581, INVALID, + /* 20 */ 1686, 1688, 1690, 1692, + /* 24 */ 1694, INVALID, INVALID, INVALID, + /* 28 */ 1623, 1709, 1682, 1684, + /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368), + /* 30 */ 1697, 1699, 1701, 1703, + /* 34 */ 1705, 1707, INVALID, 1718, + /* 38 */ 1625, 1627, 1629, 1631, + /* 3c */ 1633, 1635, 1639, 1637, + /* 40 */ 1641, 1643, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, 46, + /* dc */ 42, 44, 38, 40, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__358[] = { + /* 0 */ 1737, INVALID, +}; + +static const uint16_t ud_itab__359[] = { + /* 0 */ 1735, INVALID, +}; + +static const uint16_t ud_itab__360[] = { + /* 0 */ 1740, INVALID, +}; + +static const uint16_t ud_itab__361[] = { + /* 0 */ 1741, INVALID, +}; + +static const uint16_t ud_itab__362[] = { + /* 0 */ 1727, INVALID, +}; + +static const uint16_t ud_itab__363[] = { + /* 0 */ GROUP(364), INVALID, +}; + +static const uint16_t ud_itab__364[] = { + /* 0 */ INVALID, 1728, +}; + +static const uint16_t ud_itab__365[] = { + /* 0 */ 1731, INVALID, +}; + +static const uint16_t ud_itab__366[] = { + /* 0 */ 1733, INVALID, +}; + +static const uint16_t ud_itab__367[] = { + /* 0 */ 1732, INVALID, +}; + +static const uint16_t ud_itab__368[] = { + /* 0 */ 1734, INVALID, +}; + +static const uint16_t ud_itab__369[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID, + /* 8 */ 1645, 1647, 1649, 1651, + /* c */ 1655, 1653, 1678, 1620, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(374), 1057, GROUP(375), 202, + /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(383), 1558, GROUP(385), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 198, 196, 1680, INVALID, + /* 44 */ 1513, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392), + /* 4c */ GROUP(393), INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ 1716, 1714, 1722, 1720, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, 48, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__370[] = { + /* 0 */ 1738, INVALID, +}; + +static const uint16_t ud_itab__371[] = { + /* 0 */ 1736, INVALID, +}; + +static const uint16_t ud_itab__372[] = { + /* 0 */ GROUP(373), INVALID, +}; + +static const uint16_t ud_itab__373[] = { + /* 0 */ INVALID, 1739, +}; + +static const uint16_t ud_itab__374[] = { + /* 0 */ 1046, INVALID, +}; + +static const uint16_t ud_itab__375[] = { + /* 0 */ GROUP(376), GROUP(377), GROUP(378), +}; + +static const uint16_t ud_itab__376[] = { + /* 0 */ 1048, INVALID, +}; + +static const uint16_t ud_itab__377[] = { + /* 0 */ 1050, INVALID, +}; + +static const uint16_t ud_itab__378[] = { + /* 0 */ INVALID, 1052, +}; + +static const uint16_t ud_itab__379[] = { + /* 0 */ GROUP(380), INVALID, +}; + +static const uint16_t ud_itab__380[] = { + /* 0 */ INVALID, 1730, +}; + +static const uint16_t ud_itab__381[] = { + /* 0 */ GROUP(382), INVALID, +}; + +static const uint16_t ud_itab__382[] = { + /* 0 */ INVALID, 1729, +}; + +static const uint16_t ud_itab__383[] = { + /* 0 */ GROUP(384), INVALID, +}; + +static const uint16_t ud_itab__384[] = { + /* 0 */ 1065, INVALID, +}; + +static const uint16_t ud_itab__385[] = { + /* 0 */ GROUP(386), GROUP(388), +}; + +static const uint16_t ud_itab__386[] = { + /* 0 */ GROUP(387), INVALID, +}; + +static const uint16_t ud_itab__387[] = { + /* 0 */ 1066, INVALID, +}; + +static const uint16_t ud_itab__388[] = { + /* 0 */ GROUP(389), GROUP(390), +}; + +static const uint16_t ud_itab__389[] = { + /* 0 */ 1067, INVALID, +}; + +static const uint16_t ud_itab__390[] = { + /* 0 */ 1068, INVALID, +}; + +static const uint16_t ud_itab__391[] = { + /* 0 */ 1745, INVALID, +}; + +static const uint16_t ud_itab__392[] = { + /* 0 */ 1744, INVALID, +}; + +static const uint16_t ud_itab__393[] = { + /* 0 */ 1754, INVALID, +}; + +static const uint16_t ud_itab__394[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID, + /* 14 */ INVALID, INVALID, GROUP(398), INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 155, INVALID, + /* 2c */ 169, 159, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1394, 1309, 1294, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 32, 951, 157, 164, + /* 5c */ 1424, 823, 194, 807, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, 1523, + /* 70 */ 1536, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, 917, 1525, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 121, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 133, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__395[] = { + /* 0 */ 1751, 1750, +}; + +static const uint16_t ud_itab__396[] = { + /* 0 */ 1753, 1752, +}; + +static const uint16_t ud_itab__397[] = { + /* 0 */ 1572, 1570, +}; + +static const uint16_t ud_itab__398[] = { + /* 0 */ 1568, 1566, +}; + +static const uint16_t ud_itab__399[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 153, INVALID, + /* 2c */ 167, 149, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1392, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 30, 949, 151, INVALID, + /* 5c */ 1422, 821, 192, 805, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ 1538, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1552, 1556, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 118, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 36, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 137, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ 1560, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__400[] = { + /* 0 */ 1749, 1748, +}; + +static const uint16_t ud_itab__401[] = { + /* 0 */ 1564, 1562, +}; + +static const uint16_t ud_itab__402[] = { + /* 0 */ 1747, 1746, +}; + +static const uint16_t ud_itab__403[] = { + /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__404[] = { + /* 0 */ 769, INVALID, +}; + +static const uint16_t ud_itab__405[] = { + /* 0 */ 826, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__406[] = { + /* 0 */ 827, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__407[] = { + /* 0 */ 715, INVALID, +}; + +static const uint16_t ud_itab__408[] = { + /* 0 */ 723, 724, 725, +}; + +static const uint16_t ud_itab__409[] = { + /* 0 */ 1280, 1285, 1269, 1273, + /* 4 */ 1326, 1333, 1320, 1314, +}; + +static const uint16_t ud_itab__410[] = { + /* 0 */ 1281, 1288, 1272, 1276, + /* 4 */ 1325, 1332, 1329, 1312, +}; + +static const uint16_t ud_itab__411[] = { + /* 0 */ 1282, 1289, 1270, 1277, + /* 4 */ 1324, 1331, 1321, 1316, +}; + +static const uint16_t ud_itab__412[] = { + /* 0 */ 1283, 1290, 1271, 1278, + /* 4 */ 1328, 1335, 1322, 1317, +}; + +static const uint16_t ud_itab__413[] = { + /* 0 */ 3, INVALID, +}; + +static const uint16_t ud_itab__414[] = { + /* 0 */ 2, INVALID, +}; + +static const uint16_t ud_itab__415[] = { + /* 0 */ 1311, INVALID, +}; + +static const uint16_t ud_itab__416[] = { + /* 0 */ GROUP(417), GROUP(418), +}; + +static const uint16_t ud_itab__417[] = { + /* 0 */ 206, 503, 307, 357, + /* 4 */ 587, 630, 387, 413, +}; + +static const uint16_t ud_itab__418[] = { + /* 0 */ 215, 216, 217, 218, + /* 4 */ 219, 220, 221, 222, + /* 8 */ 504, 505, 506, 507, + /* c */ 508, 509, 510, 511, + /* 10 */ 309, 310, 311, 312, + /* 14 */ 313, 314, 315, 316, + /* 18 */ 359, 360, 361, 362, + /* 1c */ 363, 364, 365, 366, + /* 20 */ 589, 590, 591, 592, + /* 24 */ 593, 594, 595, 596, + /* 28 */ 614, 615, 616, 617, + /* 2c */ 618, 619, 620, 621, + /* 30 */ 388, 389, 390, 391, + /* 34 */ 392, 393, 394, 395, + /* 38 */ 414, 415, 416, 417, + /* 3c */ 418, 419, 420, 421, +}; + +static const uint16_t ud_itab__419[] = { + /* 0 */ GROUP(420), GROUP(421), +}; + +static const uint16_t ud_itab__420[] = { + /* 0 */ 476, INVALID, 573, 540, + /* 4 */ 493, 492, 584, 583, +}; + +static const uint16_t ud_itab__421[] = { + /* 0 */ 477, 478, 479, 480, + /* 4 */ 481, 482, 483, 484, + /* 8 */ 658, 659, 660, 661, + /* c */ 662, 663, 664, 665, + /* 10 */ 522, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ 549, 550, 551, 552, + /* 1c */ 553, 554, 555, 556, + /* 20 */ 233, 204, INVALID, INVALID, + /* 24 */ 639, 657, INVALID, INVALID, + /* 28 */ 485, 486, 487, 488, + /* 2c */ 489, 490, 491, INVALID, + /* 30 */ 203, 685, 529, 526, + /* 34 */ 684, 528, 377, 454, + /* 38 */ 527, 686, 537, 536, + /* 3c */ 530, 534, 535, 376, +}; + +static const uint16_t ud_itab__422[] = { + /* 0 */ GROUP(423), GROUP(424), +}; + +static const uint16_t ud_itab__423[] = { + /* 0 */ 456, 520, 448, 450, + /* 4 */ 462, 464, 460, 458, +}; + +static const uint16_t ud_itab__424[] = { + /* 0 */ 235, 236, 237, 238, + /* 4 */ 239, 240, 241, 242, + /* 8 */ 243, 244, 245, 246, + /* c */ 247, 248, 249, 250, + /* 10 */ 251, 252, 253, 254, + /* 14 */ 255, 256, 257, 258, + /* 18 */ 259, 260, 261, 262, + /* 1c */ 263, 264, 265, 266, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, 656, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__425[] = { + /* 0 */ GROUP(426), GROUP(427), +}; + +static const uint16_t ud_itab__426[] = { + /* 0 */ 453, 471, 467, 470, + /* 4 */ INVALID, 474, INVALID, 538, +}; + +static const uint16_t ud_itab__427[] = { + /* 0 */ 267, 268, 269, 270, + /* 4 */ 271, 272, 273, 274, + /* 8 */ 275, 276, 277, 278, + /* c */ 279, 280, 281, 282, + /* 10 */ 283, 284, 285, 286, + /* 14 */ 287, 288, 289, 290, + /* 18 */ 291, 292, 293, 294, + /* 1c */ 295, 296, 297, 298, + /* 20 */ 524, 523, 234, 455, + /* 24 */ 525, 532, INVALID, INVALID, + /* 28 */ 299, 300, 301, 302, + /* 2c */ 303, 304, 305, 306, + /* 30 */ 333, 334, 335, 336, + /* 34 */ 337, 338, 339, 340, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__428[] = { + /* 0 */ GROUP(429), GROUP(430), +}; + +static const uint16_t ud_itab__429[] = { + /* 0 */ 205, 494, 308, 358, + /* 4 */ 588, 613, 378, 404, +}; + +static const uint16_t ud_itab__430[] = { + /* 0 */ 207, 208, 209, 210, + /* 4 */ 211, 212, 213, 214, + /* 8 */ 495, 496, 497, 498, + /* c */ 499, 500, 501, 502, + /* 10 */ 317, 318, 319, 320, + /* 14 */ 321, 322, 323, 324, + /* 18 */ 325, 326, 327, 328, + /* 1c */ 329, 330, 331, 332, + /* 20 */ 622, 623, 624, 625, + /* 24 */ 626, 627, 628, 629, + /* 28 */ 597, 598, 599, 600, + /* 2c */ 601, 602, 603, 604, + /* 30 */ 405, 406, 407, 408, + /* 34 */ 409, 410, 411, 412, + /* 38 */ 379, 380, 381, 382, + /* 3c */ 383, 384, 385, 386, +}; + +static const uint16_t ud_itab__431[] = { + /* 0 */ GROUP(432), GROUP(433), +}; + +static const uint16_t ud_itab__432[] = { + /* 0 */ 475, 472, 574, 539, + /* 4 */ 531, INVALID, 533, 585, +}; + +static const uint16_t ud_itab__433[] = { + /* 0 */ 431, 432, 433, 434, + /* 4 */ 435, 436, 437, 438, + /* 8 */ 666, 667, 668, 669, + /* c */ 670, 671, 672, 673, + /* 10 */ 575, 576, 577, 578, + /* 14 */ 579, 580, 581, 582, + /* 18 */ 541, 542, 543, 544, + /* 1c */ 545, 546, 547, 548, + /* 20 */ 640, 641, 642, 643, + /* 24 */ 644, 645, 646, 647, + /* 28 */ 648, 649, 650, 651, + /* 2c */ 652, 653, 654, 655, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__434[] = { + /* 0 */ GROUP(435), GROUP(436), +}; + +static const uint16_t ud_itab__435[] = { + /* 0 */ 457, 521, 447, 449, + /* 4 */ 463, 465, 461, 459, +}; + +static const uint16_t ud_itab__436[] = { + /* 0 */ 223, 224, 225, 226, + /* 4 */ 227, 228, 229, 230, + /* 8 */ 512, 513, 514, 515, + /* c */ 516, 517, 518, 519, + /* 10 */ 367, 368, 369, 370, + /* 14 */ 371, 372, 373, 374, + /* 18 */ INVALID, 375, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ 631, 632, 633, 634, + /* 24 */ 635, 636, 637, 638, + /* 28 */ 605, 606, 607, 608, + /* 2c */ 609, 610, 611, 612, + /* 30 */ 422, 423, 424, 425, + /* 34 */ 426, 427, 428, 429, + /* 38 */ 396, 397, 398, 399, + /* 3c */ 400, 401, 402, 403, +}; + +static const uint16_t ud_itab__437[] = { + /* 0 */ GROUP(438), GROUP(439), +}; + +static const uint16_t ud_itab__438[] = { + /* 0 */ 451, 473, 466, 468, + /* 4 */ 231, 452, 232, 469, +}; + +static const uint16_t ud_itab__439[] = { + /* 0 */ 439, 440, 441, 442, + /* 4 */ 443, 444, 445, 446, + /* 8 */ 674, 675, 676, 677, + /* c */ 678, 679, 680, 681, + /* 10 */ 557, 558, 559, 560, + /* 14 */ 561, 562, 563, 564, + /* 18 */ 565, 566, 567, 568, + /* 1c */ 569, 570, 571, 572, + /* 20 */ 586, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 341, 342, 343, 344, + /* 2c */ 345, 346, 347, 348, + /* 30 */ 349, 350, 351, 352, + /* 34 */ 353, 354, 355, 356, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__440[] = { + /* 0 */ 758, 759, 760, +}; + +static const uint16_t ud_itab__441[] = { + /* 0 */ 764, INVALID, +}; + +static const uint16_t ud_itab__442[] = { + /* 0 */ 1432, 1437, 962, 953, + /* 4 */ 942, 695, 186, 689, +}; + +static const uint16_t ud_itab__443[] = { + /* 0 */ 1438, 1439, 963, 954, + /* 4 */ 943, 696, 185, 688, +}; + +static const uint16_t ud_itab__444[] = { + /* 0 */ 708, 183, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__445[] = { + /* 0 */ 707, 184, GROUP(446), 71, + /* 4 */ 761, 762, 1255, INVALID, +}; + +static const uint16_t ud_itab__446[] = { + /* 0 */ 69, 70, +}; + + +struct ud_lookup_table_list_entry ud_lookup_table_list[] = { + /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" }, + /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, + /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, + /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" }, + /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" }, + /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" }, + /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" }, + /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" }, + /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" }, + /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" }, + /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" }, + /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" }, + /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" }, + /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" }, + /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" }, + /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" }, + /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" }, + /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" }, + /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" }, + /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" }, + /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" }, + /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" }, + /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" }, + /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" }, + /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" }, + /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" }, + /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" }, + /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" }, + /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" }, + /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" }, + /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" }, + /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" }, + /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" }, + /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" }, + /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" }, + /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" }, + /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" }, + /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" }, + /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" }, + /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" }, + /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" }, + /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" }, + /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" }, + /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" }, + /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" }, + /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" }, + /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" }, + /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" }, + /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" }, + /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" }, + /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" }, + /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" }, + /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" }, + /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" }, + /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" }, + /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" }, + /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" }, + /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" }, + /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" }, + /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" }, + /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" }, + /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" }, + /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" }, + /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" }, + /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" }, + /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" }, + /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" }, + /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" }, + /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" }, + /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" }, + /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" }, + /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" }, + /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" }, + /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" }, + /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" }, + /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" }, + /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" }, + /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" }, + /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" }, + /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" }, + /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" }, + /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" }, + /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" }, + /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" }, + /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" }, + /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" }, + /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" }, + /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" }, + /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" }, + /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" }, + /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" }, + /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" }, + /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" }, + /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" }, + /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" }, + /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" }, + /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" }, + /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" }, + /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" }, + /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" }, + /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" }, + /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" }, + /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" }, + /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" }, + /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" }, + /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" }, + /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" }, + /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" }, + /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" }, + /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" }, + /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" }, + /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" }, + /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" }, + /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" }, + /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" }, + /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" }, + /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" }, + /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" }, + /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" }, + /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" }, + /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" }, + /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" }, + /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" }, + /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" }, + /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" }, + /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" }, + /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" }, + /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" }, + /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" }, + /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" }, + /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" }, + /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" }, + /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" }, + /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" }, + /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" }, + /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" }, + /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" }, + /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" }, + /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" }, + /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" }, + /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" }, + /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" }, + /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" }, + /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" }, + /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" }, + /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" }, + /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" }, + /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" }, + /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" }, + /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" }, + /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" }, + /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" }, + /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" }, + /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" }, + /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" }, + /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" }, + /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" }, + /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" }, + /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" }, + /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" }, + /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" }, + /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" }, + /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" }, + /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" }, + /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" }, + /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" }, + /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" }, + /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" }, + /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" }, + /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" }, + /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" }, + /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" }, + /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" }, + /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" }, + /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" }, + /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" }, + /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" }, + /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" }, + /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" }, + /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" }, + /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" }, + /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" }, + /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" }, + /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" }, + /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" }, + /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" }, + /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" }, + /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" }, + /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" }, + /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" }, + /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" }, + /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" }, + /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" }, + /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" }, + /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" }, + /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" }, + /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" }, + /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" }, + /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" }, + /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" }, + /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" }, + /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" }, + /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" }, + /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" }, + /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" }, + /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" }, + /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" }, + /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" }, + /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" }, + /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" }, + /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" }, + /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" }, + /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" }, + /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" }, + /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" }, + /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" }, + /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" }, + /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" }, + /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" }, + /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" }, + /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" }, + /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" }, + /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" }, + /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" }, + /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" }, + /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" }, + /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" }, + /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" }, + /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" }, + /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" }, + /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" }, + /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" }, + /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" }, + /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" }, + /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" }, + /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" }, + /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" }, + /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" }, + /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" }, + /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" }, + /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" }, + /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" }, + /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" }, + /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" }, + /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" }, + /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" }, + /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" }, + /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" }, + /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" }, + /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" }, + /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" }, + /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" }, + /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" }, + /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" }, + /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" }, + /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" }, + /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" }, + /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" }, + /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" }, + /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" }, + /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" }, + /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" }, + /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" }, + /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" }, + /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" }, + /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" }, + /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" }, + /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" }, + /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" }, + /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" }, + /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" }, + /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" }, + /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" }, + /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" }, + /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" }, + /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" }, + /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" }, + /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" }, + /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" }, + /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" }, + /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" }, + /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" }, + /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" }, + /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" }, + /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" }, + /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" }, + /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" }, + /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" }, + /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" }, + /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" }, + /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" }, + /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" }, + /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" }, + /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" }, + /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" }, + /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" }, + /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" }, + /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" }, + /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" }, + /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" }, + /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" }, + /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" }, + /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" }, + /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" }, + /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" }, + /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" }, + /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" }, + /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" }, + /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" }, + /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" }, + /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" }, + /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" }, + /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" }, + /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" }, + /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" }, + /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" }, + /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" }, + /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" }, + /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" }, + /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" }, + /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" }, + /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" }, + /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" }, + /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" }, + /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" }, + /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" }, + /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" }, + /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" }, + /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" }, + /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" }, + /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" }, + /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" }, + /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" }, + /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" }, + /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" }, + /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" }, + /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" }, + /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" }, + /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" }, + /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" }, + /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" }, + /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" }, + /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" }, + /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" }, + /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" }, + /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" }, + /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" }, + /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" }, + /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" }, + /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" }, + /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" }, + /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" }, + /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" }, + /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" }, + /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" }, + /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" }, + /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" }, + /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" }, + /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" }, + /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" }, + /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" }, + /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" }, + /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" }, + /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" }, + /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" }, + /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" }, + /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" }, + /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" }, + /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" }, + /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" }, + /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" }, + /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" }, + /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" }, + /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" }, + /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" }, + /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" }, + /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" }, + /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" }, + /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" }, + /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" }, + /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" }, +}; + +/* itab entry operand definitions (for readability) */ +#define O_AL { OP_AL, SZ_B } +#define O_AX { OP_AX, SZ_W } +#define O_Av { OP_A, SZ_V } +#define O_C { OP_C, SZ_NA } +#define O_CL { OP_CL, SZ_B } +#define O_CS { OP_CS, SZ_NA } +#define O_CX { OP_CX, SZ_W } +#define O_D { OP_D, SZ_NA } +#define O_DL { OP_DL, SZ_B } +#define O_DS { OP_DS, SZ_NA } +#define O_DX { OP_DX, SZ_W } +#define O_E { OP_E, SZ_NA } +#define O_ES { OP_ES, SZ_NA } +#define O_Eb { OP_E, SZ_B } +#define O_Ed { OP_E, SZ_D } +#define O_Eq { OP_E, SZ_Q } +#define O_Ev { OP_E, SZ_V } +#define O_Ew { OP_E, SZ_W } +#define O_Ey { OP_E, SZ_Y } +#define O_Ez { OP_E, SZ_Z } +#define O_FS { OP_FS, SZ_NA } +#define O_Fv { OP_F, SZ_V } +#define O_G { OP_G, SZ_NA } +#define O_GS { OP_GS, SZ_NA } +#define O_Gb { OP_G, SZ_B } +#define O_Gd { OP_G, SZ_D } +#define O_Gq { OP_G, SZ_Q } +#define O_Gv { OP_G, SZ_V } +#define O_Gw { OP_G, SZ_W } +#define O_Gy { OP_G, SZ_Y } +#define O_Gz { OP_G, SZ_Z } +#define O_H { OP_H, SZ_X } +#define O_Hqq { OP_H, SZ_QQ } +#define O_Hx { OP_H, SZ_X } +#define O_I1 { OP_I1, SZ_NA } +#define O_I3 { OP_I3, SZ_NA } +#define O_Ib { OP_I, SZ_B } +#define O_Iv { OP_I, SZ_V } +#define O_Iw { OP_I, SZ_W } +#define O_Iz { OP_I, SZ_Z } +#define O_Jb { OP_J, SZ_B } +#define O_Jv { OP_J, SZ_V } +#define O_Jz { OP_J, SZ_Z } +#define O_L { OP_L, SZ_O } +#define O_Lx { OP_L, SZ_X } +#define O_M { OP_M, SZ_NA } +#define O_Mb { OP_M, SZ_B } +#define O_MbRd { OP_MR, SZ_BD } +#define O_MbRv { OP_MR, SZ_BV } +#define O_Md { OP_M, SZ_D } +#define O_MdRy { OP_MR, SZ_DY } +#define O_MdU { OP_MU, SZ_DO } +#define O_Mdq { OP_M, SZ_DQ } +#define O_Mo { OP_M, SZ_O } +#define O_Mq { OP_M, SZ_Q } +#define O_MqU { OP_MU, SZ_QO } +#define O_Ms { OP_M, SZ_W } +#define O_Mt { OP_M, SZ_T } +#define O_Mv { OP_M, SZ_V } +#define O_Mw { OP_M, SZ_W } +#define O_MwRd { OP_MR, SZ_WD } +#define O_MwRv { OP_MR, SZ_WV } +#define O_MwRy { OP_MR, SZ_WY } +#define O_MwU { OP_MU, SZ_WO } +#define O_N { OP_N, SZ_Q } +#define O_NONE { OP_NONE, SZ_NA } +#define O_Ob { OP_O, SZ_B } +#define O_Ov { OP_O, SZ_V } +#define O_Ow { OP_O, SZ_W } +#define O_P { OP_P, SZ_Q } +#define O_Q { OP_Q, SZ_Q } +#define O_R { OP_R, SZ_RDQ } +#define O_R0b { OP_R0, SZ_B } +#define O_R0v { OP_R0, SZ_V } +#define O_R0w { OP_R0, SZ_W } +#define O_R0y { OP_R0, SZ_Y } +#define O_R0z { OP_R0, SZ_Z } +#define O_R1b { OP_R1, SZ_B } +#define O_R1v { OP_R1, SZ_V } +#define O_R1w { OP_R1, SZ_W } +#define O_R1y { OP_R1, SZ_Y } +#define O_R1z { OP_R1, SZ_Z } +#define O_R2b { OP_R2, SZ_B } +#define O_R2v { OP_R2, SZ_V } +#define O_R2w { OP_R2, SZ_W } +#define O_R2y { OP_R2, SZ_Y } +#define O_R2z { OP_R2, SZ_Z } +#define O_R3b { OP_R3, SZ_B } +#define O_R3v { OP_R3, SZ_V } +#define O_R3w { OP_R3, SZ_W } +#define O_R3y { OP_R3, SZ_Y } +#define O_R3z { OP_R3, SZ_Z } +#define O_R4b { OP_R4, SZ_B } +#define O_R4v { OP_R4, SZ_V } +#define O_R4w { OP_R4, SZ_W } +#define O_R4y { OP_R4, SZ_Y } +#define O_R4z { OP_R4, SZ_Z } +#define O_R5b { OP_R5, SZ_B } +#define O_R5v { OP_R5, SZ_V } +#define O_R5w { OP_R5, SZ_W } +#define O_R5y { OP_R5, SZ_Y } +#define O_R5z { OP_R5, SZ_Z } +#define O_R6b { OP_R6, SZ_B } +#define O_R6v { OP_R6, SZ_V } +#define O_R6w { OP_R6, SZ_W } +#define O_R6y { OP_R6, SZ_Y } +#define O_R6z { OP_R6, SZ_Z } +#define O_R7b { OP_R7, SZ_B } +#define O_R7v { OP_R7, SZ_V } +#define O_R7w { OP_R7, SZ_W } +#define O_R7y { OP_R7, SZ_Y } +#define O_R7z { OP_R7, SZ_Z } +#define O_S { OP_S, SZ_W } +#define O_SS { OP_SS, SZ_NA } +#define O_ST0 { OP_ST0, SZ_NA } +#define O_ST1 { OP_ST1, SZ_NA } +#define O_ST2 { OP_ST2, SZ_NA } +#define O_ST3 { OP_ST3, SZ_NA } +#define O_ST4 { OP_ST4, SZ_NA } +#define O_ST5 { OP_ST5, SZ_NA } +#define O_ST6 { OP_ST6, SZ_NA } +#define O_ST7 { OP_ST7, SZ_NA } +#define O_U { OP_U, SZ_O } +#define O_Ux { OP_U, SZ_X } +#define O_V { OP_V, SZ_DQ } +#define O_Vdq { OP_V, SZ_DQ } +#define O_Vqq { OP_V, SZ_QQ } +#define O_Vsd { OP_V, SZ_Q } +#define O_Vx { OP_V, SZ_X } +#define O_W { OP_W, SZ_DQ } +#define O_Wdq { OP_W, SZ_DQ } +#define O_Wqq { OP_W, SZ_QQ } +#define O_Wsd { OP_W, SZ_Q } +#define O_Wx { OP_W, SZ_X } +#define O_eAX { OP_eAX, SZ_Z } +#define O_eCX { OP_eCX, SZ_Z } +#define O_eDX { OP_eDX, SZ_Z } +#define O_rAX { OP_rAX, SZ_V } +#define O_rCX { OP_rCX, SZ_V } +#define O_rDX { OP_rDX, SZ_V } +#define O_sIb { OP_sI, SZ_B } +#define O_sIv { OP_sI, SZ_V } +#define O_sIz { OP_sI, SZ_Z } + +struct ud_itab_entry ud_itab[] = { + /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso }, + /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg }, + /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 }, + /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0523 */ { UD_Ifndisi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0524 */ { UD_Ifneni, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0525 */ { UD_Ifnsetpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0526 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0527 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0528 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0529 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0530 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0531 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0532 */ { UD_Ifrstpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0533 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0534 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0535 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0536 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0537 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0538 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0539 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0540 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0541 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0542 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0543 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0544 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0545 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0546 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0547 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0548 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0549 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0550 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0551 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0552 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0553 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0554 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0555 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0556 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0557 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0558 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0559 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0560 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0561 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0562 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0563 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0564 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0565 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0566 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0567 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0568 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0569 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0570 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0571 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0572 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0573 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0574 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0575 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0576 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0577 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0578 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0579 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0580 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0581 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0582 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0583 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0584 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0585 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0586 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none }, + /* 0587 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0588 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0589 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0590 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0591 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0592 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0593 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0594 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0595 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0596 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0597 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0598 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0599 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0600 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0601 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0602 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0603 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0604 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0605 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0606 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0607 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0608 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0609 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0610 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0611 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0612 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0613 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0614 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0615 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0616 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0617 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0618 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0619 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0620 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0621 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0622 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0623 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0624 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0625 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0626 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0627 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0628 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0629 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0630 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0631 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0632 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0633 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0634 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0635 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0636 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0637 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0638 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0639 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0640 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0641 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0642 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0643 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0644 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0645 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0646 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0647 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0648 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0649 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0650 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0651 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0652 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0653 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0654 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0655 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0656 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0657 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0658 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0659 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0660 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0661 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0662 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0663 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0664 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0665 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0666 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0667 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0668 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0669 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0670 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0671 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0672 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0673 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0674 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0675 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0676 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0677 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0678 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0679 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0680 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0681 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0682 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0683 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0684 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0685 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0686 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0687 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0688 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0689 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0690 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0691 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso }, + /* 0692 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none }, + /* 0693 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso }, + /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0695 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0696 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0697 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0698 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0699 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0700 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0701 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0702 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0703 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0704 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0705 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0706 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0707 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0708 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0709 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0710 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0711 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0712 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0713 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0714 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0715 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0716 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0717 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0718 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0719 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0720 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0721 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0722 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0723 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0724 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0725 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0726 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0727 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0728 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0729 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0730 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0731 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0732 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0733 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0734 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0735 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0736 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0737 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0738 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0739 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0740 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0741 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0742 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0743 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0744 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0745 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0746 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0747 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0748 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0749 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0750 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0751 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0752 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0753 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0754 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0755 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0756 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0757 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0758 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0759 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0760 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0761 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0762 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0763 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0764 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0765 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 }, + /* 0766 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0767 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0768 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0769 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0770 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0771 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0772 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0773 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0774 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0775 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0776 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0781 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0782 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0783 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0784 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0785 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0786 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0787 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0788 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0789 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0790 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0791 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0792 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0793 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0794 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0795 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0796 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0797 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0798 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0799 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0800 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0801 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0802 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0803 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0804 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0805 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0806 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0807 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0812 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0813 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0814 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0815 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0816 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0817 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0818 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0819 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0820 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0821 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0822 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0823 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0824 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0825 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0826 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0827 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0828 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0829 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0830 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0831 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0832 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0833 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0834 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none }, + /* 0835 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0836 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none }, + /* 0837 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0838 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0839 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0840 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0841 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0842 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0843 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0844 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0845 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0846 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0847 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0848 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0849 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0850 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0851 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0852 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0853 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0854 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0855 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0856 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0857 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0858 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0859 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0860 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0861 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0862 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0863 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0864 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0865 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0866 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0867 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0868 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0869 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0870 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0871 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0872 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0873 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0874 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0875 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0876 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0877 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0878 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0879 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0880 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0881 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0882 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0883 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0884 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0885 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0886 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0887 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0888 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0889 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0890 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0891 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0892 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0893 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0894 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0895 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0896 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0897 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0898 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0899 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl }, + /* 0900 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0901 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0902 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0903 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0904 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0905 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0906 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0907 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0908 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0909 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0910 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0911 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0912 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0913 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0914 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0915 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0916 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0917 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0918 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0919 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0920 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0921 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0922 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0923 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0924 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0925 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0926 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0927 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0928 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0929 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0930 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0931 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0932 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0933 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0934 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0935 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0936 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0937 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0938 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0939 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0940 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0941 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0942 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0943 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0944 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0945 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0946 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0947 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0948 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0949 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0950 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0951 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0952 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0953 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0954 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0958 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0959 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0960 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0961 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0962 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0963 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0964 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0965 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0966 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0967 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0968 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0969 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0970 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0971 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0972 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0973 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0974 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0975 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0976 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0977 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0978 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none }, + /* 0979 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0980 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none }, + /* 0981 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0982 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0983 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0984 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0985 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0986 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0987 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0988 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0989 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0990 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0991 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0992 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0993 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0994 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0995 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0996 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0997 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0998 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0999 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1000 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1001 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1002 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1003 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1004 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1005 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1006 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1007 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1008 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1009 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1010 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1011 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1012 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1013 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1014 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1015 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1016 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1017 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1018 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1019 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1020 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1021 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1022 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1023 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1024 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1025 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1026 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1027 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1028 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1029 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1030 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1031 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1032 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1033 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1034 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1035 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1036 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1037 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1038 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1039 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1040 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1041 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1042 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1043 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1044 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1045 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1046 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1047 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1048 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1049 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1050 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1051 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1052 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1053 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1054 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1055 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1056 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1057 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1058 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1059 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1060 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1061 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1062 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1063 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1064 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1065 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1066 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1067 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1068 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1069 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1070 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1071 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1072 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1073 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1074 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1075 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1076 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1077 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1078 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1079 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1080 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1081 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1082 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1083 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1084 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1085 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1086 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1087 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1088 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1089 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1090 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1091 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1092 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1093 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1094 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1095 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1096 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1097 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1098 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1099 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1100 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1101 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1102 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1103 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1104 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1105 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1106 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1107 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1108 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1109 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1110 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1111 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1112 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1113 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1114 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1115 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1116 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1117 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1118 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1123 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1124 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1125 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1126 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1127 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1128 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1129 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1130 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1131 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1132 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1133 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1134 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1135 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1136 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1137 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1138 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1139 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1140 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1141 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1142 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1143 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1144 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1145 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1146 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1147 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1148 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1149 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1150 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1151 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1152 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1153 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1154 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1155 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1156 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1157 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1158 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1159 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1160 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1161 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1162 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1163 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1164 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1165 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1166 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1167 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1168 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1169 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1170 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1171 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1172 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1173 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1174 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1175 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1176 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1177 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1178 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1179 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1180 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1181 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1182 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1183 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1184 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1185 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1186 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1187 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1188 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1189 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1190 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1191 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1192 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1193 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1194 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1195 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1196 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1197 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1198 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1199 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1200 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1201 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1202 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1203 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1204 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1205 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1206 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1207 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1208 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1209 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1210 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1211 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1212 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1213 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1214 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1215 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1216 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1217 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1218 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1219 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1220 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1221 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1222 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1223 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1224 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1225 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1226 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1227 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1228 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1229 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1230 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1231 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1232 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1233 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1234 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1235 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1236 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1237 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1238 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1239 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1240 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1241 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1242 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1243 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1244 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1245 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1246 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1247 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1248 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1249 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1250 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1251 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1252 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1253 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1254 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1255 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1256 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1257 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1258 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1259 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1260 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1261 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1262 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1263 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1264 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1265 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1266 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1267 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1268 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1269 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1270 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1271 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1272 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1273 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1274 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1275 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1276 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1277 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1278 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1279 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1280 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1281 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1282 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1283 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1284 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1285 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1286 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1287 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1288 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1289 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1290 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1291 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1292 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1293 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1294 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1295 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1296 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1297 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1298 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1299 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1300 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1301 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1302 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1303 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1304 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1305 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1306 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1307 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1308 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1309 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1310 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1311 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1312 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1313 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1314 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1315 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1316 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1317 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1318 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1320 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1321 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1322 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1323 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1324 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1326 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1327 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1328 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1329 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1330 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1331 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1332 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1333 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1334 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1335 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1336 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1337 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1338 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1339 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1340 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1341 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1342 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1343 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1344 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1345 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1346 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz }, + /* 1347 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1348 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1349 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1350 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1351 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1352 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1353 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1354 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1355 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1356 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1357 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1358 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1359 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1360 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1361 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1362 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1363 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1364 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1365 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1370 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1371 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1372 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1373 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1374 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1375 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1376 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1377 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1378 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1379 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1380 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1381 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1382 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1383 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1384 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1385 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1386 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1387 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1388 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1389 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1390 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1391 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1392 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1393 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1394 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1395 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1396 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1397 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1398 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1399 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1400 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1401 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1402 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 1403 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1404 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1405 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1406 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1407 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1408 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1409 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1410 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1411 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1412 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1413 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1414 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1415 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1416 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1417 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1418 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1419 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1420 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1421 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1422 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1423 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1424 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1425 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1426 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1427 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1428 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1429 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1430 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1431 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1432 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1433 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1434 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1435 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1436 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1437 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1438 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1439 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1440 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1441 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1442 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1443 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1444 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1445 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1446 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1447 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1448 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1449 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1450 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1451 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1452 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1453 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1454 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1455 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1456 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1457 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1458 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1459 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1460 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1461 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1462 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1463 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1464 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1465 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1466 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1467 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1468 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1469 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1470 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1471 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1472 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1473 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 1474 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1475 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1476 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1477 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1478 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1479 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1480 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1481 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1482 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1483 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1484 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1485 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1486 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg }, + /* 1487 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1488 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1489 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1490 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1491 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1492 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1493 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1494 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1495 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1496 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1497 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1498 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1499 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1500 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1501 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1502 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1503 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1504 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1505 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1506 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1507 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1508 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1509 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1510 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1511 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1512 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1513 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1514 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1515 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1516 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1517 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1518 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1519 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1520 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1521 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb }, + /* 1522 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1523 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1524 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1525 */ { UD_Ivmovdqu, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1526 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr }, + /* 1527 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1528 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1529 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1530 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1531 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1532 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1533 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1534 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1535 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1536 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1537 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1538 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1539 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1540 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1541 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1542 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1543 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1544 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1545 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1546 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1547 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1548 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1549 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1550 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1551 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1552 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1553 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1554 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1555 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1556 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1557 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1558 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1559 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1560 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1561 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1562 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1563 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1564 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1565 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1566 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1567 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1568 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1569 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1570 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1571 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1572 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1573 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1574 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1575 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1576 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1577 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1578 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1579 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1580 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1581 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1582 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1583 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1584 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1585 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1586 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1587 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1588 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1589 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1590 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1591 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1592 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1593 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1594 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1595 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1596 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1597 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1598 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1599 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1600 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1601 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1602 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1603 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1604 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1605 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1606 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1607 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1608 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1609 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1610 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1611 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1612 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1613 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1614 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1615 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1616 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1617 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1618 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1619 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1620 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1621 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1622 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1623 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1624 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1625 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1626 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1627 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1628 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1629 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1630 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1631 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1632 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1633 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1634 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1635 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1636 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1637 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1638 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1639 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1640 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1641 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1642 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1643 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1644 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1645 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1646 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1647 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1648 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1649 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1650 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1651 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1652 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1653 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1654 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1655 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1656 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1657 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1658 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 1659 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1660 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1661 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1662 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1663 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1664 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1665 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1666 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1667 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1668 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1669 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1670 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1671 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1672 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1673 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1674 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1675 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1676 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1677 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1678 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1679 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1680 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1681 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1682 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1683 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1684 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1685 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1686 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1687 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1688 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1689 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1690 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1691 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1692 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1693 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1694 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1695 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1696 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1697 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1698 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1699 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1700 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1701 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1702 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1703 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1704 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1705 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1706 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1707 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1708 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1709 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1710 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1711 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1712 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1713 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1714 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1715 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1716 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1717 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1718 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1719 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1720 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1721 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1722 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1723 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1724 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1725 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1726 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1727 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1728 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1729 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1730 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1731 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1732 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1733 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1734 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1735 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1736 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1737 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1738 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1739 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1740 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1741 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1742 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1743 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1744 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1745 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1746 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1747 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1748 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1749 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1750 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1751 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1752 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1753 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1754 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1755 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1756 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1757 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1758 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1759 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1760 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + + +const char* ud_mnemonics_str[] = { + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "aesdec", + "aesdeclast", + "aesenc", + "aesenclast", + "aesimc", + "aeskeygenassist", + "and", + "andnpd", + "andnps", + "andpd", + "andps", + "arpl", + "blendpd", + "blendps", + "blendvpd", + "blendvps", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cdq", + "cdqe", + "clc", + "cld", + "clflush", + "clgi", + "cli", + "clts", + "cmc", + "cmova", + "cmovae", + "cmovb", + "cmovbe", + "cmovg", + "cmovge", + "cmovl", + "cmovle", + "cmovno", + "cmovnp", + "cmovns", + "cmovnz", + "cmovo", + "cmovp", + "cmovs", + "cmovz", + "cmp", + "cmppd", + "cmpps", + "cmpsb", + "cmpsd", + "cmpsq", + "cmpss", + "cmpsw", + "cmpxchg", + "cmpxchg16b", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cqo", + "crc32", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2pd", + "cvtpi2ps", + "cvtps2dq", + "cvtps2pd", + "cvtps2pi", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2sd", + "cvtsi2ss", + "cvtss2sd", + "cvtss2si", + "cvttpd2dq", + "cvttpd2pi", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvttss2si", + "cwd", + "cwde", + "daa", + "das", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "dppd", + "dpps", + "emms", + "enter", + "extractps", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcom2", + "fcomi", + "fcomip", + "fcomp", + "fcomp3", + "fcomp5", + "fcompp", + "fcos", + "fdecstp", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fndisi", + "fneni", + "fninit", + "fnop", + "fnsave", + "fnsetpm", + "fnstcw", + "fnstenv", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "frstpm", + "fscale", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstp1", + "fstp8", + "fstp9", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxch4", + "fxch7", + "fxrstor", + "fxsave", + "fxtract", + "fyl2x", + "fyl2xp1", + "getsec", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "idiv", + "imul", + "in", + "inc", + "insb", + "insd", + "insertps", + "insw", + "int", + "int1", + "int3", + "into", + "invd", + "invept", + "invlpg", + "invlpga", + "invvpid", + "iretd", + "iretq", + "iretw", + "ja", + "jae", + "jb", + "jbe", + "jcxz", + "jecxz", + "jg", + "jge", + "jl", + "jle", + "jmp", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jrcxz", + "js", + "jz", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "leave", + "les", + "lfence", + "lfs", + "lgdt", + "lgs", + "lidt", + "lldt", + "lmsw", + "lock", + "lodsb", + "lodsd", + "lodsq", + "lodsw", + "loop", + "loope", + "loopne", + "lsl", + "lss", + "ltr", + "maskmovdqu", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "montmul", + "mov", + "movapd", + "movaps", + "movbe", + "movd", + "movddup", + "movdq2q", + "movdqa", + "movdqu", + "movhlps", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movmskpd", + "movmskps", + "movntdq", + "movntdqa", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movq2dq", + "movsb", + "movsd", + "movshdup", + "movsldup", + "movsq", + "movss", + "movsw", + "movsx", + "movsxd", + "movupd", + "movups", + "movzx", + "mpsadbw", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsd", + "outsw", + "pabsb", + "pabsd", + "pabsw", + "packssdw", + "packsswb", + "packusdw", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "palignr", + "pand", + "pandn", + "pavgb", + "pavgusb", + "pavgw", + "pblendvb", + "pblendw", + "pclmulqdq", + "pcmpeqb", + "pcmpeqd", + "pcmpeqq", + "pcmpeqw", + "pcmpestri", + "pcmpestrm", + "pcmpgtb", + "pcmpgtd", + "pcmpgtq", + "pcmpgtw", + "pcmpistri", + "pcmpistrm", + "pextrb", + "pextrd", + "pextrq", + "pextrw", + "pf2id", + "pf2iw", + "pfacc", + "pfadd", + "pfcmpeq", + "pfcmpge", + "pfcmpgt", + "pfmax", + "pfmin", + "pfmul", + "pfnacc", + "pfpnacc", + "pfrcp", + "pfrcpit1", + "pfrcpit2", + "pfrsqit1", + "pfrsqrt", + "pfsub", + "pfsubr", + "phaddd", + "phaddsw", + "phaddw", + "phminposuw", + "phsubd", + "phsubsw", + "phsubw", + "pi2fd", + "pi2fw", + "pinsrb", + "pinsrd", + "pinsrq", + "pinsrw", + "pmaddubsw", + "pmaddwd", + "pmaxsb", + "pmaxsd", + "pmaxsw", + "pmaxub", + "pmaxud", + "pmaxuw", + "pminsb", + "pminsd", + "pminsw", + "pminub", + "pminud", + "pminuw", + "pmovmskb", + "pmovsxbd", + "pmovsxbq", + "pmovsxbw", + "pmovsxdq", + "pmovsxwd", + "pmovsxwq", + "pmovzxbd", + "pmovzxbq", + "pmovzxbw", + "pmovzxdq", + "pmovzxwd", + "pmovzxwq", + "pmuldq", + "pmulhrsw", + "pmulhrw", + "pmulhuw", + "pmulhw", + "pmulld", + "pmullw", + "pmuludq", + "pop", + "popa", + "popad", + "popcnt", + "popfd", + "popfq", + "popfw", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "psadbw", + "pshufb", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "psignb", + "psignd", + "psignw", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "pswapd", + "ptest", + "punpckhbw", + "punpckhdq", + "punpckhqdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklqdq", + "punpcklwd", + "push", + "pusha", + "pushad", + "pushfd", + "pushfq", + "pushfw", + "pxor", + "rcl", + "rcpps", + "rcpss", + "rcr", + "rdmsr", + "rdpmc", + "rdrand", + "rdtsc", + "rdtscp", + "rep", + "repne", + "ret", + "retf", + "rol", + "ror", + "roundpd", + "roundps", + "roundsd", + "roundss", + "rsm", + "rsqrtps", + "rsqrtss", + "sahf", + "salc", + "sar", + "sbb", + "scasb", + "scasd", + "scasq", + "scasw", + "seta", + "setae", + "setb", + "setbe", + "setg", + "setge", + "setl", + "setle", + "setno", + "setnp", + "setns", + "setnz", + "seto", + "setp", + "sets", + "setz", + "sfence", + "sgdt", + "shl", + "shld", + "shr", + "shrd", + "shufpd", + "shufps", + "sidt", + "skinit", + "sldt", + "smsw", + "sqrtpd", + "sqrtps", + "sqrtsd", + "sqrtss", + "stc", + "std", + "stgi", + "sti", + "stmxcsr", + "stosb", + "stosd", + "stosq", + "stosw", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "swapgs", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud2", + "unpckhpd", + "unpckhps", + "unpcklpd", + "unpcklps", + "vaddpd", + "vaddps", + "vaddsd", + "vaddss", + "vaddsubpd", + "vaddsubps", + "vaesdec", + "vaesdeclast", + "vaesenc", + "vaesenclast", + "vaesimc", + "vaeskeygenassist", + "vandnpd", + "vandnps", + "vandpd", + "vandps", + "vblendpd", + "vblendps", + "vblendvpd", + "vblendvps", + "vbroadcastsd", + "vbroadcastss", + "vcmppd", + "vcmpps", + "vcmpsd", + "vcmpss", + "vcomisd", + "vcomiss", + "vcvtdq2pd", + "vcvtdq2ps", + "vcvtpd2dq", + "vcvtpd2ps", + "vcvtps2dq", + "vcvtps2pd", + "vcvtsd2si", + "vcvtsd2ss", + "vcvtsi2sd", + "vcvtsi2ss", + "vcvtss2sd", + "vcvtss2si", + "vcvttpd2dq", + "vcvttps2dq", + "vcvttsd2si", + "vcvttss2si", + "vdivpd", + "vdivps", + "vdivsd", + "vdivss", + "vdppd", + "vdpps", + "verr", + "verw", + "vextractf128", + "vextractps", + "vhaddpd", + "vhaddps", + "vhsubpd", + "vhsubps", + "vinsertf128", + "vinsertps", + "vlddqu", + "vmaskmovdqu", + "vmaskmovpd", + "vmaskmovps", + "vmaxpd", + "vmaxps", + "vmaxsd", + "vmaxss", + "vmcall", + "vmclear", + "vminpd", + "vminps", + "vminsd", + "vminss", + "vmlaunch", + "vmload", + "vmmcall", + "vmovapd", + "vmovaps", + "vmovd", + "vmovddup", + "vmovdqa", + "vmovdqu", + "vmovhlps", + "vmovhpd", + "vmovhps", + "vmovlhps", + "vmovlpd", + "vmovlps", + "vmovmskpd", + "vmovmskps", + "vmovntdq", + "vmovntdqa", + "vmovntpd", + "vmovntps", + "vmovq", + "vmovsd", + "vmovshdup", + "vmovsldup", + "vmovss", + "vmovupd", + "vmovups", + "vmpsadbw", + "vmptrld", + "vmptrst", + "vmread", + "vmresume", + "vmrun", + "vmsave", + "vmulpd", + "vmulps", + "vmulsd", + "vmulss", + "vmwrite", + "vmxoff", + "vmxon", + "vorpd", + "vorps", + "vpabsb", + "vpabsd", + "vpabsw", + "vpackssdw", + "vpacksswb", + "vpackusdw", + "vpackuswb", + "vpaddb", + "vpaddd", + "vpaddq", + "vpaddsb", + "vpaddsw", + "vpaddusb", + "vpaddusw", + "vpaddw", + "vpalignr", + "vpand", + "vpandn", + "vpavgb", + "vpavgw", + "vpblendvb", + "vpblendw", + "vpclmulqdq", + "vpcmpeqb", + "vpcmpeqd", + "vpcmpeqq", + "vpcmpeqw", + "vpcmpestri", + "vpcmpestrm", + "vpcmpgtb", + "vpcmpgtd", + "vpcmpgtq", + "vpcmpgtw", + "vpcmpistri", + "vpcmpistrm", + "vperm2f128", + "vpermilpd", + "vpermilps", + "vpextrb", + "vpextrd", + "vpextrq", + "vpextrw", + "vphaddd", + "vphaddsw", + "vphaddw", + "vphminposuw", + "vphsubd", + "vphsubsw", + "vphsubw", + "vpinsrb", + "vpinsrd", + "vpinsrq", + "vpinsrw", + "vpmaddubsw", + "vpmaddwd", + "vpmaxsb", + "vpmaxsd", + "vpmaxsw", + "vpmaxub", + "vpmaxud", + "vpmaxuw", + "vpminsb", + "vpminsd", + "vpminsw", + "vpminub", + "vpminud", + "vpminuw", + "vpmovmskb", + "vpmovsxbd", + "vpmovsxbq", + "vpmovsxbw", + "vpmovsxwd", + "vpmovsxwq", + "vpmovzxbd", + "vpmovzxbq", + "vpmovzxbw", + "vpmovzxdq", + "vpmovzxwd", + "vpmovzxwq", + "vpmuldq", + "vpmulhrsw", + "vpmulhuw", + "vpmulhw", + "vpmulld", + "vpmullw", + "vpor", + "vpsadbw", + "vpshufb", + "vpshufd", + "vpshufhw", + "vpshuflw", + "vpsignb", + "vpsignd", + "vpsignw", + "vpslld", + "vpslldq", + "vpsllq", + "vpsllw", + "vpsrad", + "vpsraw", + "vpsrld", + "vpsrldq", + "vpsrlq", + "vpsrlw", + "vpsubb", + "vpsubd", + "vpsubq", + "vpsubsb", + "vpsubsw", + "vpsubusb", + "vpsubusw", + "vpsubw", + "vptest", + "vpunpckhbw", + "vpunpckhdq", + "vpunpckhqdq", + "vpunpckhwd", + "vpunpcklbw", + "vpunpckldq", + "vpunpcklqdq", + "vpunpcklwd", + "vpxor", + "vrcpps", + "vrcpss", + "vroundpd", + "vroundps", + "vroundsd", + "vroundss", + "vrsqrtps", + "vrsqrtss", + "vshufpd", + "vshufps", + "vsqrtpd", + "vsqrtps", + "vsqrtsd", + "vsqrtss", + "vstmxcsr", + "vsubpd", + "vsubps", + "vsubsd", + "vsubss", + "vtestpd", + "vtestps", + "vucomisd", + "vucomiss", + "vunpckhpd", + "vunpckhps", + "vunpcklpd", + "vunpcklps", + "vxorpd", + "vxorps", + "vzeroall", + "vzeroupper", + "wait", + "wbinvd", + "wrmsr", + "xadd", + "xchg", + "xcryptcbc", + "xcryptcfb", + "xcryptctr", + "xcryptecb", + "xcryptofb", + "xgetbv", + "xlatb", + "xor", + "xorpd", + "xorps", + "xrstor", + "xsave", + "xsetbv", + "xsha1", + "xsha256", + "xstore", + "invalid", + "3dnow", + "none", + "db", + "pause" +}; diff --git a/deps/extra/udis86/libudis86/itab.h b/deps/extra/udis86/libudis86/itab.h new file mode 100644 index 00000000..3d54c435 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.h @@ -0,0 +1,939 @@ +#ifndef UD_ITAB_H +#define UD_ITAB_H + +/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */ + +/* ud_table_type -- lookup table types (see decode.c) */ +enum ud_table_type { + UD_TAB__OPC_VEX, + UD_TAB__OPC_TABLE, + UD_TAB__OPC_X87, + UD_TAB__OPC_MOD, + UD_TAB__OPC_RM, + UD_TAB__OPC_OSIZE, + UD_TAB__OPC_MODE, + UD_TAB__OPC_VEX_L, + UD_TAB__OPC_3DNOW, + UD_TAB__OPC_REG, + UD_TAB__OPC_ASIZE, + UD_TAB__OPC_VEX_W, + UD_TAB__OPC_SSE, + UD_TAB__OPC_VENDOR +}; + +/* ud_mnemonic -- mnemonic constants */ +enum ud_mnemonic_code { + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iaesdec, + UD_Iaesdeclast, + UD_Iaesenc, + UD_Iaesenclast, + UD_Iaesimc, + UD_Iaeskeygenassist, + UD_Iand, + UD_Iandnpd, + UD_Iandnps, + UD_Iandpd, + UD_Iandps, + UD_Iarpl, + UD_Iblendpd, + UD_Iblendps, + UD_Iblendvpd, + UD_Iblendvps, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icdq, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmova, + UD_Icmovae, + UD_Icmovb, + UD_Icmovbe, + UD_Icmovg, + UD_Icmovge, + UD_Icmovl, + UD_Icmovle, + UD_Icmovno, + UD_Icmovnp, + UD_Icmovns, + UD_Icmovnz, + UD_Icmovo, + UD_Icmovp, + UD_Icmovs, + UD_Icmovz, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpsw, + UD_Icmpxchg, + UD_Icmpxchg16b, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icqo, + UD_Icrc32, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2pd, + UD_Icvtpi2ps, + UD_Icvtps2dq, + UD_Icvtps2pd, + UD_Icvtps2pi, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2sd, + UD_Icvtsi2ss, + UD_Icvtss2sd, + UD_Icvtss2si, + UD_Icvttpd2dq, + UD_Icvttpd2pi, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvttss2si, + UD_Icwd, + UD_Icwde, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Idppd, + UD_Idpps, + UD_Iemms, + UD_Ienter, + UD_Iextractps, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmovbe, + UD_Ifcmove, + UD_Ifcmovnb, + UD_Ifcmovnbe, + UD_Ifcmovne, + UD_Ifcmovnu, + UD_Ifcmovu, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomi, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp3, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ifiadd, + UD_Ificom, + UD_Ificomp, + UD_Ifidiv, + UD_Ifidivr, + UD_Ifild, + UD_Ifimul, + UD_Ifincstp, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifisub, + UD_Ifisubr, + UD_Ifld, + UD_Ifld1, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifldl2e, + UD_Ifldl2t, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldpi, + UD_Ifldz, + UD_Ifmul, + UD_Ifmulp, + UD_Ifndisi, + UD_Ifneni, + UD_Ifninit, + UD_Ifnop, + UD_Ifnsave, + UD_Ifnsetpm, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifrstpm, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifst, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomi, + UD_Ifucomip, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Igetsec, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iimul, + UD_Iin, + UD_Iinc, + UD_Iinsb, + UD_Iinsd, + UD_Iinsertps, + UD_Iinsw, + UD_Iint, + UD_Iint1, + UD_Iint3, + UD_Iinto, + UD_Iinvd, + UD_Iinvept, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iinvvpid, + UD_Iiretd, + UD_Iiretq, + UD_Iiretw, + UD_Ija, + UD_Ijae, + UD_Ijb, + UD_Ijbe, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijg, + UD_Ijge, + UD_Ijl, + UD_Ijle, + UD_Ijmp, + UD_Ijno, + UD_Ijnp, + UD_Ijns, + UD_Ijnz, + UD_Ijo, + UD_Ijp, + UD_Ijrcxz, + UD_Ijs, + UD_Ijz, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Ileave, + UD_Iles, + UD_Ilfence, + UD_Ilfs, + UD_Ilgdt, + UD_Ilgs, + UD_Ilidt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsd, + UD_Ilodsq, + UD_Ilodsw, + UD_Iloop, + UD_Iloope, + UD_Iloopne, + UD_Ilsl, + UD_Ilss, + UD_Iltr, + UD_Imaskmovdqu, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imontmul, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovbe, + UD_Imovd, + UD_Imovddup, + UD_Imovdq2q, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovhlps, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovntdqa, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsd, + UD_Imovshdup, + UD_Imovsldup, + UD_Imovsq, + UD_Imovss, + UD_Imovsw, + UD_Imovsx, + UD_Imovsxd, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Impsadbw, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsd, + UD_Ioutsw, + UD_Ipabsb, + UD_Ipabsd, + UD_Ipabsw, + UD_Ipackssdw, + UD_Ipacksswb, + UD_Ipackusdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddd, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipaddw, + UD_Ipalignr, + UD_Ipand, + UD_Ipandn, + UD_Ipavgb, + UD_Ipavgusb, + UD_Ipavgw, + UD_Ipblendvb, + UD_Ipblendw, + UD_Ipclmulqdq, + UD_Ipcmpeqb, + UD_Ipcmpeqd, + UD_Ipcmpeqq, + UD_Ipcmpeqw, + UD_Ipcmpestri, + UD_Ipcmpestrm, + UD_Ipcmpgtb, + UD_Ipcmpgtd, + UD_Ipcmpgtq, + UD_Ipcmpgtw, + UD_Ipcmpistri, + UD_Ipcmpistrm, + UD_Ipextrb, + UD_Ipextrd, + UD_Ipextrq, + UD_Ipextrw, + UD_Ipf2id, + UD_Ipf2iw, + UD_Ipfacc, + UD_Ipfadd, + UD_Ipfcmpeq, + UD_Ipfcmpge, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfmin, + UD_Ipfmul, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfrcp, + UD_Ipfrcpit1, + UD_Ipfrcpit2, + UD_Ipfrsqit1, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfsubr, + UD_Iphaddd, + UD_Iphaddsw, + UD_Iphaddw, + UD_Iphminposuw, + UD_Iphsubd, + UD_Iphsubsw, + UD_Iphsubw, + UD_Ipi2fd, + UD_Ipi2fw, + UD_Ipinsrb, + UD_Ipinsrd, + UD_Ipinsrq, + UD_Ipinsrw, + UD_Ipmaddubsw, + UD_Ipmaddwd, + UD_Ipmaxsb, + UD_Ipmaxsd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipmaxud, + UD_Ipmaxuw, + UD_Ipminsb, + UD_Ipminsd, + UD_Ipminsw, + UD_Ipminub, + UD_Ipminud, + UD_Ipminuw, + UD_Ipmovmskb, + UD_Ipmovsxbd, + UD_Ipmovsxbq, + UD_Ipmovsxbw, + UD_Ipmovsxdq, + UD_Ipmovsxwd, + UD_Ipmovsxwq, + UD_Ipmovzxbd, + UD_Ipmovzxbq, + UD_Ipmovzxbw, + UD_Ipmovzxdq, + UD_Ipmovzxwd, + UD_Ipmovzxwq, + UD_Ipmuldq, + UD_Ipmulhrsw, + UD_Ipmulhrw, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmulld, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopcnt, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipopfw, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufb, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipsignb, + UD_Ipsignd, + UD_Ipsignw, + UD_Ipslld, + UD_Ipslldq, + UD_Ipsllq, + UD_Ipsllw, + UD_Ipsrad, + UD_Ipsraw, + UD_Ipsrld, + UD_Ipsrldq, + UD_Ipsrlq, + UD_Ipsrlw, + UD_Ipsubb, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipsubw, + UD_Ipswapd, + UD_Iptest, + UD_Ipunpckhbw, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpckhwd, + UD_Ipunpcklbw, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipunpcklwd, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipushfw, + UD_Ipxor, + UD_Ircl, + UD_Ircpps, + UD_Ircpss, + UD_Ircr, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdrand, + UD_Irdtsc, + UD_Irdtscp, + UD_Irep, + UD_Irepne, + UD_Iret, + UD_Iretf, + UD_Irol, + UD_Iror, + UD_Iroundpd, + UD_Iroundps, + UD_Iroundsd, + UD_Iroundss, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isalc, + UD_Isar, + UD_Isbb, + UD_Iscasb, + UD_Iscasd, + UD_Iscasq, + UD_Iscasw, + UD_Iseta, + UD_Isetae, + UD_Isetb, + UD_Isetbe, + UD_Isetg, + UD_Isetge, + UD_Isetl, + UD_Isetle, + UD_Isetno, + UD_Isetnp, + UD_Isetns, + UD_Isetnz, + UD_Iseto, + UD_Isetp, + UD_Isets, + UD_Isetz, + UD_Isfence, + UD_Isgdt, + UD_Ishl, + UD_Ishld, + UD_Ishr, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Iskinit, + UD_Isldt, + UD_Ismsw, + UD_Isqrtpd, + UD_Isqrtps, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Istmxcsr, + UD_Istosb, + UD_Istosd, + UD_Istosq, + UD_Istosw, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklpd, + UD_Iunpcklps, + UD_Ivaddpd, + UD_Ivaddps, + UD_Ivaddsd, + UD_Ivaddss, + UD_Ivaddsubpd, + UD_Ivaddsubps, + UD_Ivaesdec, + UD_Ivaesdeclast, + UD_Ivaesenc, + UD_Ivaesenclast, + UD_Ivaesimc, + UD_Ivaeskeygenassist, + UD_Ivandnpd, + UD_Ivandnps, + UD_Ivandpd, + UD_Ivandps, + UD_Ivblendpd, + UD_Ivblendps, + UD_Ivblendvpd, + UD_Ivblendvps, + UD_Ivbroadcastsd, + UD_Ivbroadcastss, + UD_Ivcmppd, + UD_Ivcmpps, + UD_Ivcmpsd, + UD_Ivcmpss, + UD_Ivcomisd, + UD_Ivcomiss, + UD_Ivcvtdq2pd, + UD_Ivcvtdq2ps, + UD_Ivcvtpd2dq, + UD_Ivcvtpd2ps, + UD_Ivcvtps2dq, + UD_Ivcvtps2pd, + UD_Ivcvtsd2si, + UD_Ivcvtsd2ss, + UD_Ivcvtsi2sd, + UD_Ivcvtsi2ss, + UD_Ivcvtss2sd, + UD_Ivcvtss2si, + UD_Ivcvttpd2dq, + UD_Ivcvttps2dq, + UD_Ivcvttsd2si, + UD_Ivcvttss2si, + UD_Ivdivpd, + UD_Ivdivps, + UD_Ivdivsd, + UD_Ivdivss, + UD_Ivdppd, + UD_Ivdpps, + UD_Iverr, + UD_Iverw, + UD_Ivextractf128, + UD_Ivextractps, + UD_Ivhaddpd, + UD_Ivhaddps, + UD_Ivhsubpd, + UD_Ivhsubps, + UD_Ivinsertf128, + UD_Ivinsertps, + UD_Ivlddqu, + UD_Ivmaskmovdqu, + UD_Ivmaskmovpd, + UD_Ivmaskmovps, + UD_Ivmaxpd, + UD_Ivmaxps, + UD_Ivmaxsd, + UD_Ivmaxss, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivminpd, + UD_Ivminps, + UD_Ivminsd, + UD_Ivminss, + UD_Ivmlaunch, + UD_Ivmload, + UD_Ivmmcall, + UD_Ivmovapd, + UD_Ivmovaps, + UD_Ivmovd, + UD_Ivmovddup, + UD_Ivmovdqa, + UD_Ivmovdqu, + UD_Ivmovhlps, + UD_Ivmovhpd, + UD_Ivmovhps, + UD_Ivmovlhps, + UD_Ivmovlpd, + UD_Ivmovlps, + UD_Ivmovmskpd, + UD_Ivmovmskps, + UD_Ivmovntdq, + UD_Ivmovntdqa, + UD_Ivmovntpd, + UD_Ivmovntps, + UD_Ivmovq, + UD_Ivmovsd, + UD_Ivmovshdup, + UD_Ivmovsldup, + UD_Ivmovss, + UD_Ivmovupd, + UD_Ivmovups, + UD_Ivmpsadbw, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmread, + UD_Ivmresume, + UD_Ivmrun, + UD_Ivmsave, + UD_Ivmulpd, + UD_Ivmulps, + UD_Ivmulsd, + UD_Ivmulss, + UD_Ivmwrite, + UD_Ivmxoff, + UD_Ivmxon, + UD_Ivorpd, + UD_Ivorps, + UD_Ivpabsb, + UD_Ivpabsd, + UD_Ivpabsw, + UD_Ivpackssdw, + UD_Ivpacksswb, + UD_Ivpackusdw, + UD_Ivpackuswb, + UD_Ivpaddb, + UD_Ivpaddd, + UD_Ivpaddq, + UD_Ivpaddsb, + UD_Ivpaddsw, + UD_Ivpaddusb, + UD_Ivpaddusw, + UD_Ivpaddw, + UD_Ivpalignr, + UD_Ivpand, + UD_Ivpandn, + UD_Ivpavgb, + UD_Ivpavgw, + UD_Ivpblendvb, + UD_Ivpblendw, + UD_Ivpclmulqdq, + UD_Ivpcmpeqb, + UD_Ivpcmpeqd, + UD_Ivpcmpeqq, + UD_Ivpcmpeqw, + UD_Ivpcmpestri, + UD_Ivpcmpestrm, + UD_Ivpcmpgtb, + UD_Ivpcmpgtd, + UD_Ivpcmpgtq, + UD_Ivpcmpgtw, + UD_Ivpcmpistri, + UD_Ivpcmpistrm, + UD_Ivperm2f128, + UD_Ivpermilpd, + UD_Ivpermilps, + UD_Ivpextrb, + UD_Ivpextrd, + UD_Ivpextrq, + UD_Ivpextrw, + UD_Ivphaddd, + UD_Ivphaddsw, + UD_Ivphaddw, + UD_Ivphminposuw, + UD_Ivphsubd, + UD_Ivphsubsw, + UD_Ivphsubw, + UD_Ivpinsrb, + UD_Ivpinsrd, + UD_Ivpinsrq, + UD_Ivpinsrw, + UD_Ivpmaddubsw, + UD_Ivpmaddwd, + UD_Ivpmaxsb, + UD_Ivpmaxsd, + UD_Ivpmaxsw, + UD_Ivpmaxub, + UD_Ivpmaxud, + UD_Ivpmaxuw, + UD_Ivpminsb, + UD_Ivpminsd, + UD_Ivpminsw, + UD_Ivpminub, + UD_Ivpminud, + UD_Ivpminuw, + UD_Ivpmovmskb, + UD_Ivpmovsxbd, + UD_Ivpmovsxbq, + UD_Ivpmovsxbw, + UD_Ivpmovsxwd, + UD_Ivpmovsxwq, + UD_Ivpmovzxbd, + UD_Ivpmovzxbq, + UD_Ivpmovzxbw, + UD_Ivpmovzxdq, + UD_Ivpmovzxwd, + UD_Ivpmovzxwq, + UD_Ivpmuldq, + UD_Ivpmulhrsw, + UD_Ivpmulhuw, + UD_Ivpmulhw, + UD_Ivpmulld, + UD_Ivpmullw, + UD_Ivpor, + UD_Ivpsadbw, + UD_Ivpshufb, + UD_Ivpshufd, + UD_Ivpshufhw, + UD_Ivpshuflw, + UD_Ivpsignb, + UD_Ivpsignd, + UD_Ivpsignw, + UD_Ivpslld, + UD_Ivpslldq, + UD_Ivpsllq, + UD_Ivpsllw, + UD_Ivpsrad, + UD_Ivpsraw, + UD_Ivpsrld, + UD_Ivpsrldq, + UD_Ivpsrlq, + UD_Ivpsrlw, + UD_Ivpsubb, + UD_Ivpsubd, + UD_Ivpsubq, + UD_Ivpsubsb, + UD_Ivpsubsw, + UD_Ivpsubusb, + UD_Ivpsubusw, + UD_Ivpsubw, + UD_Ivptest, + UD_Ivpunpckhbw, + UD_Ivpunpckhdq, + UD_Ivpunpckhqdq, + UD_Ivpunpckhwd, + UD_Ivpunpcklbw, + UD_Ivpunpckldq, + UD_Ivpunpcklqdq, + UD_Ivpunpcklwd, + UD_Ivpxor, + UD_Ivrcpps, + UD_Ivrcpss, + UD_Ivroundpd, + UD_Ivroundps, + UD_Ivroundsd, + UD_Ivroundss, + UD_Ivrsqrtps, + UD_Ivrsqrtss, + UD_Ivshufpd, + UD_Ivshufps, + UD_Ivsqrtpd, + UD_Ivsqrtps, + UD_Ivsqrtsd, + UD_Ivsqrtss, + UD_Ivstmxcsr, + UD_Ivsubpd, + UD_Ivsubps, + UD_Ivsubsd, + UD_Ivsubss, + UD_Ivtestpd, + UD_Ivtestps, + UD_Ivucomisd, + UD_Ivucomiss, + UD_Ivunpckhpd, + UD_Ivunpckhps, + UD_Ivunpcklpd, + UD_Ivunpcklps, + UD_Ivxorpd, + UD_Ivxorps, + UD_Ivzeroall, + UD_Ivzeroupper, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixcryptcbc, + UD_Ixcryptcfb, + UD_Ixcryptctr, + UD_Ixcryptecb, + UD_Ixcryptofb, + UD_Ixgetbv, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Ixrstor, + UD_Ixsave, + UD_Ixsetbv, + UD_Ixsha1, + UD_Ixsha256, + UD_Ixstore, + UD_Iinvalid, + UD_I3dnow, + UD_Inone, + UD_Idb, + UD_Ipause, + UD_MAX_MNEMONIC_CODE +}; + +extern const char * ud_mnemonics_str[]; + +#endif /* UD_ITAB_H */ diff --git a/deps/libtomcrypt b/deps/libtomcrypt new file mode 160000 index 00000000..673f5ce2 --- /dev/null +++ b/deps/libtomcrypt @@ -0,0 +1 @@ +Subproject commit 673f5ce29015a9bba3c96792920a10601b5b0718 diff --git a/deps/libtommath b/deps/libtommath new file mode 160000 index 00000000..bea92706 --- /dev/null +++ b/deps/libtommath @@ -0,0 +1 @@ +Subproject commit bea9270646303baf683f4ba2ddf0d70721f0e55d diff --git a/deps/lua b/deps/lua new file mode 160000 index 00000000..5d708c3f --- /dev/null +++ b/deps/lua @@ -0,0 +1 @@ +Subproject commit 5d708c3f9cae12820e415d4f89c9eacbe2ab964b diff --git a/deps/minhook b/deps/minhook new file mode 160000 index 00000000..4a455528 --- /dev/null +++ b/deps/minhook @@ -0,0 +1 @@ +Subproject commit 4a455528f61b5a375b1f9d44e7d296d47f18bb18 diff --git a/deps/premake/asmjit.lua b/deps/premake/asmjit.lua new file mode 100644 index 00000000..ee932594 --- /dev/null +++ b/deps/premake/asmjit.lua @@ -0,0 +1,34 @@ +asmjit = { + source = path.join(dependencies.basePath, "asmjit"), +} + +function asmjit.import() + links { "asmjit" } + asmjit.includes() +end + +function asmjit.includes() + includedirs { + path.join(asmjit.source, "src") + } + + defines { + "ASMJIT_STATIC" + } +end + +function asmjit.project() + project "asmjit" + language "C++" + + asmjit.includes() + + files { + path.join(asmjit.source, "src/**.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, asmjit) diff --git a/deps/premake/discord-rpc.lua b/deps/premake/discord-rpc.lua new file mode 100644 index 00000000..ef28bcb3 --- /dev/null +++ b/deps/premake/discord-rpc.lua @@ -0,0 +1,39 @@ +discordrpc = { + source = path.join(dependencies.basePath, "discord-rpc"), +} + +function discordrpc.import() + links { "discord-rpc" } + discordrpc.includes() +end + +function discordrpc.includes() + includedirs { + path.join(discordrpc.source, "include"), + } +end + +function discordrpc.project() + project "discord-rpc" + language "C++" + + discordrpc.includes() + rapidjson.import(); + + files { + path.join(discordrpc.source, "src/*.h"), + path.join(discordrpc.source, "src/*.cpp"), + } + + removefiles { + path.join(discordrpc.source, "src/dllmain.cpp"), + path.join(discordrpc.source, "src/*_linux.cpp"), + path.join(discordrpc.source, "src/*_unix.cpp"), + path.join(discordrpc.source, "src/*_osx.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, discordrpc) diff --git a/deps/premake/gsl.lua b/deps/premake/gsl.lua new file mode 100644 index 00000000..7a2daf64 --- /dev/null +++ b/deps/premake/gsl.lua @@ -0,0 +1,19 @@ +gsl = { + source = path.join(dependencies.basePath, "GSL"), +} + +function gsl.import() + gsl.includes() +end + +function gsl.includes() + includedirs { + path.join(gsl.source, "include") + } +end + +function gsl.project() + +end + +table.insert(dependencies, gsl) diff --git a/deps/premake/l_u_a.lua b/deps/premake/l_u_a.lua new file mode 100644 index 00000000..618f10c9 --- /dev/null +++ b/deps/premake/l_u_a.lua @@ -0,0 +1,37 @@ +-- Scripts or variables named lua fuck with premake ._. +l_u_a = { + source = path.join(dependencies.basePath, "lua"), +} + +function l_u_a.import() + links { "lua" } + l_u_a.includes() +end + +function l_u_a.includes() + includedirs { + l_u_a.source + } + +end + +function l_u_a.project() + project "lua" + language "C" + + l_u_a.includes() + + files { + path.join(l_u_a.source, "*.h"), + path.join(l_u_a.source, "*.c"), + } + + removefiles { + path.join(l_u_a.source, "onelua.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, l_u_a) diff --git a/deps/premake/libtomcrypt.lua b/deps/premake/libtomcrypt.lua new file mode 100644 index 00000000..6c6f28d1 --- /dev/null +++ b/deps/premake/libtomcrypt.lua @@ -0,0 +1,61 @@ +libtomcrypt = { + source = path.join(dependencies.basePath, "libtomcrypt"), +} + +function libtomcrypt.import() + links { + "libtomcrypt" + } + + libtomcrypt.includes() +end + +function libtomcrypt.includes() + includedirs { + path.join(libtomcrypt.source, "src/headers") + } + + defines { + "LTC_NO_FAST", + "LTC_NO_PROTOTYPES", + "LTC_NO_RSA_BLINDING", + } +end + +function libtomcrypt.project() + project "libtomcrypt" + language "C" + + libtomcrypt.includes() + libtommath.import() + + files { + path.join(libtomcrypt.source, "src/**.c"), + } + + removefiles { + path.join(libtomcrypt.source, "src/**/*tab.c"), + path.join(libtomcrypt.source, "src/encauth/ocb3/**.c"), + } + + defines { + "_CRT_SECURE_NO_WARNINGS", + "LTC_SOURCE", + "_LIB", + "USE_LTM" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtomcrypt) diff --git a/deps/premake/libtommath.lua b/deps/premake/libtommath.lua new file mode 100644 index 00000000..ab4cdde3 --- /dev/null +++ b/deps/premake/libtommath.lua @@ -0,0 +1,52 @@ +libtommath = { + source = path.join(dependencies.basePath, "libtommath"), +} + +function libtommath.import() + links { + "libtommath" + } + + libtommath.includes() +end + +function libtommath.includes() + includedirs { + libtommath.source + } + + defines { + "LTM_DESC", + "__STDC_IEC_559__", + "MP_NO_DEV_URANDOM", + } +end + +function libtommath.project() + project "libtommath" + language "C" + + libtommath.includes() + + files { + path.join(libtommath.source, "*.c"), + } + + defines { + "_LIB" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtommath) diff --git a/deps/premake/minhook.lua b/deps/premake/minhook.lua new file mode 100644 index 00000000..396d4d38 --- /dev/null +++ b/deps/premake/minhook.lua @@ -0,0 +1,31 @@ +minhook = { + source = path.join(dependencies.basePath, "minhook"), +} + +function minhook.import() + links { "minhook" } + minhook.includes() +end + +function minhook.includes() + includedirs { + path.join(minhook.source, "include") + } +end + +function minhook.project() + project "minhook" + language "C" + + minhook.includes() + + files { + path.join(minhook.source, "src/**.h"), + path.join(minhook.source, "src/**.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minhook) diff --git a/deps/premake/minizip.lua b/deps/premake/minizip.lua new file mode 100644 index 00000000..4a5754bc --- /dev/null +++ b/deps/premake/minizip.lua @@ -0,0 +1,43 @@ +minizip = { + source = path.join(dependencies.basePath, "zlib/contrib/minizip"), +} + +function minizip.import() + links { "minizip" } + zlib.import() + minizip.includes() +end + +function minizip.includes() + includedirs { + minizip.source + } + + zlib.includes() +end + +function minizip.project() + project "minizip" + language "C" + + minizip.includes() + + files { + path.join(minizip.source, "*.h"), + path.join(minizip.source, "*.c"), + } + + removefiles { + path.join(minizip.source, "miniunz.c"), + path.join(minizip.source, "minizip.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minizip) diff --git a/deps/premake/protobuf.lua b/deps/premake/protobuf.lua new file mode 100644 index 00000000..1c58972c --- /dev/null +++ b/deps/premake/protobuf.lua @@ -0,0 +1,60 @@ +protobuf = { + source = path.join(dependencies.basePath, "protobuf"), +} + +function protobuf.import() + links { + "protobuf" + } + + protobuf.includes() +end + +function protobuf.includes() + includedirs { + path.join(protobuf.source, "src"), + } +end + +function protobuf.project() + project "protobuf" + language "C++" + + protobuf.includes() + + files { + path.join(protobuf.source, "src/**.cc"), + "./src/**.proto", + } + + removefiles { + path.join(protobuf.source, "src/**/*test.cc"), + path.join(protobuf.source, "src/google/protobuf/*test*.cc"), + + path.join(protobuf.source, "src/google/protobuf/testing/**.cc"), + path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"), + + path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"), + path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"), + path.join(protobuf.source, "**/*_gcc.cc"), + } + + rules { + "ProtobufCompiler" + } + + defines { + "_SCL_SECURE_NO_WARNINGS", + "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", + "_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS", + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, protobuf) diff --git a/deps/premake/rapidjson.lua b/deps/premake/rapidjson.lua new file mode 100644 index 00000000..d1085120 --- /dev/null +++ b/deps/premake/rapidjson.lua @@ -0,0 +1,19 @@ +rapidjson = { + source = path.join(dependencies.basePath, "rapidjson"), +} + +function rapidjson.import() + rapidjson.includes() +end + +function rapidjson.includes() + includedirs { + path.join(rapidjson.source, "include"), + } +end + +function rapidjson.project() + +end + +table.insert(dependencies, rapidjson) diff --git a/deps/premake/sol2.lua b/deps/premake/sol2.lua new file mode 100644 index 00000000..253a25ee --- /dev/null +++ b/deps/premake/sol2.lua @@ -0,0 +1,20 @@ +sol2 = { + source = path.join(dependencies.basePath, "sol2"), +} + +function sol2.import() + sol2.includes() + l_u_a.import() +end + +function sol2.includes() + includedirs { + path.join(sol2.source, "include") + } +end + +function sol2.project() + +end + +table.insert(dependencies, sol2) diff --git a/deps/premake/stb.lua b/deps/premake/stb.lua new file mode 100644 index 00000000..6f20a983 --- /dev/null +++ b/deps/premake/stb.lua @@ -0,0 +1,19 @@ +stb = { + source = path.join(dependencies.basePath, "stb"), +} + +function stb.import() + stb.includes() +end + +function stb.includes() + includedirs { + stb.source + } +end + +function stb.project() + +end + +table.insert(dependencies, stb) diff --git a/deps/premake/udis86.lua b/deps/premake/udis86.lua new file mode 100644 index 00000000..896ec8b7 --- /dev/null +++ b/deps/premake/udis86.lua @@ -0,0 +1,37 @@ +udis86 = { + source = path.join(dependencies.basePath, "udis86"), +} + +function udis86.import() + links { + "udis86" + } + + udis86.includes() +end + +function udis86.includes() + includedirs { + udis86.source, + path.join(udis86.source, "libudis86"), + path.join(dependencies.basePath, "extra/udis86"), + path.join(dependencies.basePath, "extra/udis86/libudis86"), + } +end + +function udis86.project() + project "udis86" + language "C" + + udis86.includes() + + files { + path.join(udis86.source, "libudis86/*.c"), + path.join(dependencies.basePath, "extra/udis86/libudis86/*.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, udis86) diff --git a/deps/premake/wintoast.lua b/deps/premake/wintoast.lua new file mode 100644 index 00000000..c13ceadf --- /dev/null +++ b/deps/premake/wintoast.lua @@ -0,0 +1,32 @@ +wintoast = { + source = path.join(dependencies.basePath, "WinToast"), +} + +function wintoast.import() + links { "WinToast" } + wintoast.includes() +end + +function wintoast.includes() + includedirs { + path.join(wintoast.source, "src"), + } +end + +function wintoast.project() + project "WinToast" + language "C++" + + wintoast.includes() + rapidjson.import(); + + files { + path.join(wintoast.source, "src/*.h"), + path.join(wintoast.source, "src/*.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, wintoast) diff --git a/deps/premake/zlib.lua b/deps/premake/zlib.lua new file mode 100644 index 00000000..566a707b --- /dev/null +++ b/deps/premake/zlib.lua @@ -0,0 +1,39 @@ +zlib = { + source = path.join(dependencies.basePath, "zlib"), +} + +function zlib.import() + links { "zlib" } + zlib.includes() +end + +function zlib.includes() + includedirs { + zlib.source + } + + defines { + "ZLIB_CONST", + } +end + +function zlib.project() + project "zlib" + language "C" + + zlib.includes() + + files { + path.join(zlib.source, "*.h"), + path.join(zlib.source, "*.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, zlib) diff --git a/deps/protobuf b/deps/protobuf new file mode 160000 index 00000000..5500c72c --- /dev/null +++ b/deps/protobuf @@ -0,0 +1 @@ +Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b diff --git a/deps/rapidjson b/deps/rapidjson new file mode 160000 index 00000000..fd3dc29a --- /dev/null +++ b/deps/rapidjson @@ -0,0 +1 @@ +Subproject commit fd3dc29a5c2852df569e1ea81dbde2c412ac5051 diff --git a/deps/sol2 b/deps/sol2 new file mode 160000 index 00000000..50b62c93 --- /dev/null +++ b/deps/sol2 @@ -0,0 +1 @@ +Subproject commit 50b62c9346750b7c2c406c9e4c546f96b0bf021d diff --git a/deps/stb b/deps/stb new file mode 160000 index 00000000..af1a5bc3 --- /dev/null +++ b/deps/stb @@ -0,0 +1 @@ +Subproject commit af1a5bc352164740c1cc1354942b1c6b72eacb8a diff --git a/deps/udis86 b/deps/udis86 new file mode 160000 index 00000000..56ff6c87 --- /dev/null +++ b/deps/udis86 @@ -0,0 +1 @@ +Subproject commit 56ff6c87c11de0ffa725b14339004820556e343d diff --git a/deps/zlib b/deps/zlib new file mode 160000 index 00000000..2014a993 --- /dev/null +++ b/deps/zlib @@ -0,0 +1 @@ +Subproject commit 2014a993addbc8f1b9785d97f55fd189792c2f78 diff --git a/generate.bat b/generate.bat new file mode 100644 index 00000000..b9ffdf6f --- /dev/null +++ b/generate.bat @@ -0,0 +1,3 @@ +@echo off +git submodule update --init --recursive +tools\premake5 %* vs2019 \ No newline at end of file diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 00000000..b3f026af --- /dev/null +++ b/premake5.lua @@ -0,0 +1,365 @@ +gitVersioningCommand = "git describe --tags --dirty --always" +gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD" + +-- Quote the given string input as a C string +function cstrquote(value) + if value == nil then + return "\"\"" + end + result = value:gsub("\\", "\\\\") + result = result:gsub("\"", "\\\"") + result = result:gsub("\n", "\\n") + result = result:gsub("\t", "\\t") + result = result:gsub("\r", "\\r") + result = result:gsub("\a", "\\a") + result = result:gsub("\b", "\\b") + result = "\"" .. result .. "\"" + return result +end + +-- Converts tags in "vX.X.X" format and given revision number Y to an array of numbers {X,X,X,Y}. +-- In the case where the format does not work fall back to padding with zeroes and just ending with the revision number. +-- partscount can be either 3 or 4. +function vertonumarr(value, vernumber, partscount) + vernum = {} + for num in string.gmatch(value or "", "%d+") do + if #vernum < 3 then + table.insert(vernum, tonumber(num)) + end + end + while #vernum < 3 do + table.insert(vernum, 0) + end + if #vernum < partscount then + table.insert(vernum, tonumber(vernumber)) + end + return vernum +end + +dependencies = { + basePath = "./deps" +} + +function dependencies.load() + dir = path.join(dependencies.basePath, "premake/*.lua") + deps = os.matchfiles(dir) + + for i, dep in pairs(deps) do + dep = dep:gsub(".lua", "") + require(dep) + end +end + +function dependencies.imports() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.import() + end + end +end + +function dependencies.projects() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.project() + end + end +end + +newoption { + trigger = "copy-to", + description = "Optional, copy the EXE to a custom folder after build, define the path here if wanted.", + value = "PATH" +} + +newoption { + trigger = "dev-build", + description = "Enable development builds of the client." +} + +newaction { + trigger = "version", + description = "Returns the version string for the current commit of the source code.", + onWorkspace = function(wks) + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + local version = gitDescribeOutput + + proc = assert(io.popen(gitCurrentBranchCommand, "r")) + local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "") + local gitCurrentBranchSuccess = proc:close() + if gitCurrentBranchSuccess then + -- We got a branch name, check if it is a feature branch + if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then + version = version .. "-" .. gitCurrentBranchOutput + end + end + + print(version) + os.exit(0) + end +} + +newaction { + trigger = "generate-buildinfo", + description = "Sets up build information file like version.h.", + onWorkspace = function(wks) + -- get old version number from version.hpp if any + local oldVersion = "(none)" + local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") + if oldVersionHeader ~= nil then + local oldVersionHeaderContent = assert(oldVersionHeader:read('*l')) + while oldVersionHeaderContent do + m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$") + if m ~= nil then + oldVersion = m + end + + oldVersionHeaderContent = oldVersionHeader:read('*l') + end + end + + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- generate version.hpp with a revision number if not equal + gitDescribeOutputQuoted = cstrquote(gitDescribeOutput) + if oldVersion ~= gitDescribeOutputQuoted then + -- get current git hash and write to version.txt (used by the preliminary updater) + -- TODO - remove once proper updater and release versioning exists + local proc = assert(io.popen("git rev-parse HEAD", "r")) + local gitCommitHash = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- get whether this is a clean revision (no uncommitted changes) + proc = assert(io.popen("git status --porcelain", "r")) + local revDirty = (assert(proc:read('*a')) ~= "") + if revDirty then revDirty = 1 else revDirty = 0 end + proc:close() + + -- get current tag name + proc = assert(io.popen("git describe --tags --abbrev=0")) + local tagName = proc:read('*l') + + -- get current branch name + proc = assert(io.popen("git branch --show-current")) + local branchName = proc:read('*l') + + -- branch for ci + if branchName == nil or branchName == '' then + proc = assert(io.popen("git show -s --pretty=%d HEAD")) + local branchInfo = proc:read('*l') + m = string.match(branchInfo, ".+,.+, ([^)]+)") + if m ~= nil then + branchName = m + end + end + + if branchName == nil then + branchName = "develop" + end + + print("Detected branch: " .. branchName) + + -- get revision number via git + local proc = assert(io.popen("git rev-list --count HEAD", "r")) + local revNumber = assert(proc:read('*a')):gsub("%s+", "") + + print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted) + + -- write to version.txt for preliminary updater + -- NOTE - remove this once we have a proper updater and proper release versioning + local versionFile = assert(io.open(wks.location .. "/version.txt", "w")) + versionFile:write(gitCommitHash) + versionFile:close() + + -- write version header + local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") + versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") + versionHeader:write("#define GIT_HASH " .. cstrquote(gitCommitHash) .. "\n") + versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") + versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Version transformed for RC files\n") + versionHeader:write("#define VERSION_PRODUCT_RC " .. table.concat(vertonumarr(tagName, revNumber, 3), ",") .. "\n") + versionHeader:write("#define VERSION_PRODUCT " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 3), ".")) .. "\n") + versionHeader:write("#define VERSION_FILE_RC " .. table.concat(vertonumarr(tagName, revNumber, 4), ",") .. "\n") + versionHeader:write("#define VERSION_FILE " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 4), ".")) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Alias definitions\n") + versionHeader:write("#define VERSION GIT_DESCRIBE\n") + versionHeader:write("#define SHORTVERSION VERSION_PRODUCT\n") + versionHeader:close() + local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" *\n") + versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") + versionHeader:write(" *\n") + versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n") + versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#include \".\\version.h\"\n") + versionHeader:close() + end + end +} + +dependencies.load() + +workspace "h1-mod" +startproject "client" +location "./build" +objdir "%{wks.location}/obj" +targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}" + +configurations {"Debug", "Release"} + +architecture "x64" +platforms "x64" + +buildoptions "/std:c++latest" +systemversion "latest" +symbols "On" +staticruntime "On" +editandcontinue "Off" +warnings "Extra" +characterset "ASCII" + +if _OPTIONS["dev-build"] then + defines {"DEV_BUILD"} +end + +if os.getenv("CI") then + defines {"CI"} +end + +flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"} + + +configuration "windows" +defines {"_WINDOWS", "WIN32"} + +configuration "Release" +optimize "Size" +buildoptions {"/GL"} +linkoptions { "/IGNORE:4702", "/LTCG" } + +defines {"NDEBUG"} + +flags {"FatalCompileWarnings"} + +configuration "Debug" +optimize "Debug" + +defines {"DEBUG", "_DEBUG"} + +configuration {} + +project "common" +kind "StaticLib" +language "C++" + +files {"./src/common/**.hpp", "./src/common/**.cpp"} + +includedirs {"./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +dependencies.imports() + +project "runner" +kind "WindowedApp" +language "C++" + +files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"} + +includedirs {"./src/runner", "./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +links {"common"} + +dependencies.imports() + +project "client" +kind "ConsoleApp" +language "C++" + +targetname "h1-mod" + +pchheader "std_include.hpp" +pchsource "src/client/std_include.cpp" + +linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"} + +files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"} + +includedirs {"./src/client", "./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +dependson {"tlsdll", "runner"} + +links {"common"} + +prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"} + +if _OPTIONS["copy-to"] then + postbuildcommands {"copy /y \"$(TargetPath)\" \"" .. _OPTIONS["copy-to"] .. "\""} +end + +dependencies.imports() + +project "tlsdll" +kind "SharedLib" +language "C++" + +files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"} + +includedirs {"./src/tlsdll", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +project "runner" +kind "WindowedApp" +language "C++" + +files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"} + +includedirs {"./src/runner", "./src/common", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +links {"common"} + +dependencies.imports() + +group "Dependencies" +dependencies.projects() + +rule "ProtobufCompiler" +display "Protobuf compiler" +location "./build" +fileExtension ".proto" +buildmessage "Compiling %(Identity) with protoc..." +buildcommands {'@echo off', 'path "$(SolutionDir)\\..\\tools"', + 'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"', + 'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)'} +buildoutputs {'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc', '$(ProjectDir)\\src\\proto\\%(Filename).pb.h'} diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp new file mode 100644 index 00000000..e6d47209 --- /dev/null +++ b/src/client/component/auth.cpp @@ -0,0 +1,231 @@ +#include +#include "loader/component_loader.hpp" + +#include "auth.hpp" +#include "component/command.hpp" +#include "network.hpp" + +#include +#include +#include +#include +#include + +#include "game/game.hpp" +#include "steam/steam.hpp" + +namespace auth +{ + namespace + { + std::string get_hdd_serial() + { + DWORD serial{}; + if (!GetVolumeInformationA("C:\\", nullptr, 0, &serial, nullptr, nullptr, nullptr, 0)) + { + return {}; + } + + return utils::string::va("%08X", serial); + } + + std::string get_hw_profile_guid() + { + HW_PROFILE_INFO info; + if (!GetCurrentHwProfileA(&info)) + { + return {}; + } + + return std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) }; + } + + std::string get_protected_data() + { + std::string input = "X-Labs-S1x-Auth"; + + DATA_BLOB data_in{}, data_out{}; + data_in.pbData = reinterpret_cast(input.data()); + data_in.cbData = static_cast(input.size()); + if (CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE) + { + return {}; + } + + const auto size = std::min(data_out.cbData, 52ul); + std::string result{ reinterpret_cast(data_out.pbData), size }; + LocalFree(data_out.pbData); + + return result; + } + + std::string get_key_entropy() + { + std::string entropy{}; + entropy.append(utils::smbios::get_uuid()); + entropy.append(get_hw_profile_guid()); + entropy.append(get_protected_data()); + entropy.append(get_hdd_serial()); + + if (entropy.empty()) + { + entropy.resize(32); + utils::cryptography::random::get_data(entropy.data(), entropy.size()); + } + + return entropy; + } + + utils::cryptography::ecc::key& get_key() + { + static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy()); + return key; + } + + int send_connect_data_stub(game::netsrc_t sock, game::netadr_s* adr, const char* format, const int len) + { + std::string connect_string(format, len); + game::SV_Cmd_TokenizeString(connect_string.data()); + const auto _ = gsl::finally([]() + { + game::SV_Cmd_EndTokenizedString(); + }); + + const command::params_sv params; + if (params.size() < 3) + { + return false; + } + + const utils::info_string info_string{ std::string{params[2]} }; + const auto challenge = info_string.get("challenge"); + + connect_string.clear(); + connect_string.append(params[0]); + connect_string.append(" "); + connect_string.append(params[1]); + connect_string.append(" "); + connect_string.append("\"" + info_string.build() + "\""); + + proto::network::connect_info info; + info.set_publickey(get_key().get_public_key()); + info.set_signature(sign_message(get_key(), challenge)); + info.set_infostring(connect_string); + + network::send(*adr, "connect", info.SerializeAsString()); + return true; + } + + void direct_connect(game::netadr_s* from, game::msg_t* msg) + { + const auto offset = sizeof("connect") + 4; + + proto::network::connect_info info; + if (!info.ParseFromArray(msg->data + offset, msg->cursize - offset)) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + game::SV_Cmd_EndTokenizedString(); + game::SV_Cmd_TokenizeString(info.infostring().data()); + + const command::params_sv params; + if (params.size() < 3) + { + network::send(*from, "error", "Invalid connect string!", '\n'); + return; + } + + const utils::info_string info_string{ std::string{params[2]} }; + + const auto steam_id = info_string.get("xuid"); + const auto challenge = info_string.get("challenge"); + + if (steam_id.empty() || challenge.empty()) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + utils::cryptography::ecc::key key; + key.set(info.publickey()); + + const auto xuid = strtoull(steam_id.data(), nullptr, 16); + if (xuid != key.get_hash()) + { + //MessageBoxA(nullptr, steam_id.data(), std::to_string(key.get_hash()).data(), 0); + network::send(*from, "error", + utils::string::va("XUID doesn't match the certificate: %llX != %llX", xuid, key.get_hash()), '\n'); + return; + } + + if (!key.is_valid() || !verify_message(key, challenge, info.signature())) + { + network::send(*from, "error", "Challenge signature was invalid!", '\n'); + return; + } + + game::SV_DirectConnect(from); + } + + void* get_direct_connect_stub() + { + return utils::hook::assemble([](utils::hook::assembler& a) + { + a.lea(rcx, qword_ptr(rsp, 0x20)); + a.movaps(xmmword_ptr(rsp, 0x20), xmm0); + + a.pushad64(); + a.mov(rdx, rdi); + a.call_aligned(direct_connect); + a.popad64(); + + a.jmp(0x140488CE2); // H1MP64(1.4) + }); + } + } + + uint64_t get_guid() + { + if (game::environment::is_dedi()) + { + return 0x110000100000000 | (::utils::cryptography::random::get_integer() & ~0x80000000); + } + + return get_key().get_hash(); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Patch steam id bit check + if (game::environment::is_sp()) + { + utils::hook::jump(0x1404267F0, 0x140426846); // S1SP + utils::hook::jump(0x14042760F, 0x140427650); // S1SP + utils::hook::jump(0x140427AB4, 0x140427B02); // S1SP + } + else + { + utils::hook::jump(0x140571E07, 0x140571E5A); // H1MP64[1.4] + utils::hook::jump(0x14004B223, 0x14004B4F2); // H1MP64[1.4] + utils::hook::jump(0x14004B4AD, 0x140009B48); // H1MP64[1.4] + utils::hook::jump(0x140572F6F, 0x140572FB0); // H1MP64[1.4] + utils::hook::jump(0x140573470, 0x1405734B6); // H1MP64[1.4] + + utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1MP64[1.4] + utils::hook::call(0x140250ED2, send_connect_data_stub); // H1MP64[1.4] + } + + command::add("guid", []() + { + printf("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); + }); + } + }; +} + +REGISTER_COMPONENT(auth::component) diff --git a/src/client/component/auth.hpp b/src/client/component/auth.hpp new file mode 100644 index 00000000..2a6b92f2 --- /dev/null +++ b/src/client/component/auth.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace auth +{ + uint64_t get_guid(); +} \ No newline at end of file diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp new file mode 100644 index 00000000..060eaa91 --- /dev/null +++ b/src/client/component/branding.cpp @@ -0,0 +1,60 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include "scheduler.hpp" +#include "command.hpp" +#include "game/game.hpp" + +#include +#include + +namespace branding +{ + game::dvar_t* dvar_draw2d; + + class component final : public component_interface + { + public: + void post_unpack() override + { + //localized_strings::override("MENU_SP_CAMPAIGN", "COD DEVELOPER COMPANION"); + localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "H1-Mod: MULTIPLAYER\n"); + localized_strings::override("MENU_MULTIPLAYER_CAPS", "H1-Mod: MULTIPLAYER"); + localized_strings::override("PLATFORM_UI_HEADER_PLAY_MP_CAPS", "H1-ONLINE"); + + scheduler::loop([]() + { + if (!dvar_draw2d) + { + dvar_draw2d = game::Dvar_FindVar("cg_draw2d"); + } + + if (dvar_draw2d && !dvar_draw2d->current.enabled) + { + return; + } + + const auto x = 4; + const auto y = 4; + const auto scale = 1.0f; + float color[4] = { 1.0f, 0.5f, 0.0f, 1.0f }; + + const auto* text = "H1-Mod 1.4"; + + auto* font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20); + + if (!font) return; + + game::R_AddCmdDrawText(text, 0x7FFFFFFF, font, static_cast(x), + y + static_cast(font->pixelHeight) * scale, + scale, scale, 0.0f, color, 0); + + }, scheduler::pipeline::renderer); + } + }; +} + +REGISTER_COMPONENT(branding::component) + + +// fonts/default.otf, fonts/defaultBold.otf, fonts/fira_mono_regular.ttf, fonts/fira_mono_bold.ttf diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp new file mode 100644 index 00000000..5fe14c71 --- /dev/null +++ b/src/client/component/command.cpp @@ -0,0 +1,418 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "game_console.hpp" + + +#include +#include +#include +#include "utils/io.hpp" + +namespace command +{ + namespace + { + utils::hook::detour dvar_command_hook; + + std::unordered_map> handlers; + + std::unordered_map> handlers_sv; + + void main_handler() + { + params params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (handlers.find(command) != handlers.end()) + { + handlers[command](params); + } + } + + void client_command(const int client_num, void* a2) + { + params_sv params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (handlers_sv.find(command) != handlers_sv.end()) + { + handlers_sv[command](client_num, params); + } + + dvar_command_hook.invoke(client_num, a2); + } + + void enum_assets(const game::XAssetType type, const std::function& callback, const bool includeOverride) + { + game::DB_EnumXAssets_Internal(type, static_cast([](game::XAssetHeader header, void* data) + { + const auto& cb = *static_cast*>(data); + cb(header); + }), &callback, includeOverride); + } + + game::dvar_t* dvar_command_stub() + { + const params args; + + if (args.size() <= 0) + { + return 0; + } + + const auto dvar = game::Dvar_FindVar(args[0]); + + if (dvar) + { + if (args.size() == 1) + { + const auto current = game::Dvar_ValueToString(dvar, dvar->current, 0); + const auto reset = game::Dvar_ValueToString(dvar, dvar->reset, 0); + + game_console::print(game_console::con_type_info, "\"%s\" is: \"%s\" default: \"%s\" hash: %i", + args[0], current, reset, dvar->name); + + game_console::print(game_console::con_type_info, " %s\n", + dvars::dvar_get_domain(dvar->type, dvar->domain).data()); + } + //else + //{ + // char command[0x1000] = { 0 }; + // game::Dvar_GetCombinedString(command, 1); + // game::Dvar_SetCommand(dvar->name, command); + //} + + return dvar; + } + + return 0; + } + } + + params::params() + : nesting_(game::cmd_args->nesting) + { + } + + int params::size() const + { + return game::cmd_args->argc[this->nesting_]; + } + + const char* params::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::cmd_args->argv[this->nesting_][index]; + } + + std::string params::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + params_sv::params_sv() + : nesting_(game::sv_cmd_args->nesting) + { + } + + int params_sv::size() const + { + return game::sv_cmd_args->argc[this->nesting_]; + } + + const char* params_sv::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; + } + + std::string params_sv::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + void add_raw(const char* name, void (*callback)()) + { + game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate()); + } + + void add(const char* name, const std::function& callback) + { + const auto command = utils::string::to_lower(name); + + if (handlers.find(command) == handlers.end()) + add_raw(name, main_handler); + + handlers[command] = callback; + } + + void add(const char* name, const std::function& callback) + { + add(name, [callback](const params&) + { + callback(); + }); + } + + void add_sv(const char* name, std::function callback) + { + // doing this so the sv command would show up in the console + add_raw(name, nullptr); + + const auto command = utils::string::to_lower(name); + + if (handlers_sv.find(command) == handlers_sv.end()) + handlers_sv[command] = std::move(callback); + } + + void execute(std::string command, const bool sync) + { + command += "\n"; + + if (sync) + { + game::Cmd_ExecuteSingleCommand(0, 0, command.data()); + } + else + { + game::Cbuf_AddText(0, command.data()); + } + } + + void parse_command_line() + { + static auto parsed = false; + if (parsed) + { + return; + } + + static std::string comand_line_buffer = GetCommandLineA(); + auto* command_line = comand_line_buffer.data(); + + auto& com_num_console_lines = *reinterpret_cast(0x142623FB4); + auto* com_console_lines = reinterpret_cast(0x142623FC0); + + auto inq = false; + com_console_lines[0] = command_line; + com_num_console_lines = 0; + + while (*command_line) + { + if (*command_line == '"') + { + inq = !inq; + } + // look for a + separating character + // if commandLine came from a file, we might have real line seperators + if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r') + { + if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES + { + break; + } + com_console_lines[com_num_console_lines] = command_line + 1; + com_num_console_lines++; + *command_line = '\0'; + } + command_line++; + } + parsed = true; + } + + void parse_commandline_stub() + { + parse_command_line(); + reinterpret_cast(0x1400D8210)(); // mwr: test + } + + void read_startup_variable(const std::string& dvar) + { + // parse the commandline if it's not parsed + parse_command_line(); + + auto& com_num_console_lines = *reinterpret_cast(0x142623FB4); + auto* com_console_lines = reinterpret_cast(0x142623FC0); + + for (int i = 0; i < com_num_console_lines; i++) + { + game::Cmd_TokenizeString(com_console_lines[i]); + + // only +set dvar value + if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar) + { + game::Dvar_SetCommand(game::Cmd_Argv(1), game::Cmd_Argv(2)); + } + + game::Cmd_EndTokenizeString(); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + //utils::hook::jump(game::base_address + 0x000000, dvar_command_stub, true); // H1 + + static game::cmd_function_s cmd_test; + + game::Cmd_AddCommandInternal("quit", game::Com_Quit_f, &cmd_test); + /*game::Cmd_AddCommandInternal("connect", []() { + + }, game::cmd_function_s);*/ + //add_raw("quit", main_handler); + + //add("quit", game::Com_Quit_f); + + //add("startmap", [](const params& params) + //{ + // const auto map = params.get(1); + + // const auto exists = utils::hook::invoke(game::base_address + 0x412B50, map, 0); + + // if (!exists) + // { + // game_console::print(game_console::con_type_error, "map '%s' not found\n", map); + // return; + // } + + // // SV_SpawnServer + // utils::hook::invoke(game::base_address + 0x6B3AA0, map, 0, 0, 0, 0); + //}); + + /*add("say", [](const params& params) + { + chat::print(params.join(1)); + });*/ + + //add("listassetpool", [](const params& params) + //{ + // if (params.size() < 2) + // { + // game_console::print(game_console::con_type_info, "listassetpool : list all the assets in the specified pool\n"); + + // for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++) + // { + // game_console::print(game_console::con_type_info, "%d %s\n", i, game::g_assetNames[i]); + // } + // } + // else + // { + // const auto type = static_cast(atoi(params.get(1))); + + // if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT) + // { + // game_console::print(game_console::con_type_info, "Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1); + // return; + // } + + // game_console::print(game_console::con_type_info, "Listing assets in pool %s\n", game::g_assetNames[type]); + + // enum_assets(type, [type](const game::XAssetHeader header) + // { + // const auto asset = game::XAsset{type, header}; + // const auto* const asset_name = game::DB_GetXAssetName(&asset); + // //const auto entry = game::DB_FindXAssetEntry(type, asset_name); + // //TODO: display which zone the asset is from + // game_console::print(game_console::con_type_info, "%s\n", asset_name); + // }, true); + // } + //}); + + //add("commandDump", []() + //{ + // printf("======== Start command dump =========\n"); + + // game::cmd_function_s* cmd = (*game::cmd_functions); + + // while (cmd) + // { + // if (cmd->name) + // { + // game_console::print(game_console::con_type_info, "%s\n", cmd->name); + // } + + // cmd = cmd->next; + // } + + // printf("======== End command dump =========\n"); + //}); + + + /*add("god", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::mp::g_entities[0].flags ^= game::FL_GODMODE; + game::CG_GameMessage(0, utils::string::va("godmode %s", + game::g_entities[0].flags & game::FL_GODMODE + ? "^2on" + : "^1off")); + });*/ + + + + //add("notarget", []() + //{ + // if (!game::SV_Loaded()) + // { + // return; + // } + + // game::g_entities[0].flags ^= game::FL_NOTARGET; + // game::CG_GameMessage(0, utils::string::va("notarget %s", + // game::g_entities[0].flags & game::FL_NOTARGET + // ? "^2on" + // : "^1off")); + //}); + + //add("noclip", []() + //{ + // if (!game::SV_Loaded()) + // { + // return; + // } + + // game::g_entities[0].client->flags ^= 1; + // game::CG_GameMessage(0, utils::string::va("noclip %s", + // game::g_entities[0].client->flags & 1 + // ? "^2on" + // : "^1off")); + //}); + } + }; +} + +REGISTER_COMPONENT(command::component) diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp new file mode 100644 index 00000000..bd70d0c6 --- /dev/null +++ b/src/client/component/command.hpp @@ -0,0 +1,50 @@ +#pragma once + +namespace command +{ + class params + { + public: + params(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + class params_sv + { + public: + params_sv(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + void read_startup_variable(const std::string& dvar); + + void add_raw(const char* name, void (*callback)()); + void add(const char* name, const std::function& callback); + void add(const char* name, const std::function& callback); + + void add_sv(const char* name, std::function callback); + + void execute(std::string command, bool sync = false); +} \ No newline at end of file diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp new file mode 100644 index 00000000..48016a10 --- /dev/null +++ b/src/client/component/console.cpp @@ -0,0 +1,265 @@ +#include +#include "console.hpp" +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "command.hpp" + +#include +#include +#include +#include + +namespace game_console +{ + void print(int type, const std::string& data); +} + +namespace console +{ + namespace + { + using message_queue = std::queue; + utils::concurrency::container messages; + + void hide_console() + { + auto* const con_window = GetConsoleWindow(); + + DWORD process; + GetWindowThreadProcessId(con_window, &process); + + if (process == GetCurrentProcessId() || IsDebuggerPresent()) + { + ShowWindow(con_window, SW_HIDE); + } + } + + std::string format(va_list* ap, const char* message) + { + static thread_local char buffer[0x1000]; + + const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); + + if (count < 0) return {}; + return { buffer, static_cast(count) }; + } + + void dispatch_message(const int type, const std::string& message) + { + /*if (rcon::message_redirect(message)) + { + return; + }*/ + + } + + void append_text(const char* text) + { + dispatch_message(con_type_info, text); + } + } + + class component final : public component_interface + { + public: + component() + { + hide_console(); + + (void)_pipe(this->handles_, 1024, _O_TEXT); + (void)_dup2(this->handles_[1], 1); + (void)_dup2(this->handles_[1], 2); + + //setvbuf(stdout, nullptr, _IONBF, 0); + //setvbuf(stderr, nullptr, _IONBF, 0); + } + + void post_start() override + { + this->terminate_runner_ = false; + + this->console_runner_ = utils::thread::create_named_thread("Console IO", [this] + { + this->runner(); + }); + } + + void pre_destroy() override + { + this->terminate_runner_ = true; + + printf("\r\n"); + _flushall(); + + if (this->console_runner_.joinable()) + { + this->console_runner_.join(); + } + + if (this->console_thread_.joinable()) + { + this->console_thread_.join(); + } + + _close(this->handles_[0]); + _close(this->handles_[1]); + + messages.access([&](message_queue& msgs) + { + msgs = {}; + }); + } + + void post_unpack() override + { + // Redirect input (]command) + utils::hook::jump(SELECT_VALUE(0x000000000, 0x1405141E0), append_text); // H1MP1.4 + + this->initialize(); + } + + private: + volatile bool console_initialized_ = false; + volatile bool terminate_runner_ = false; + + std::thread console_runner_; + std::thread console_thread_; + + int handles_[2]{}; + + void initialize() + { + this->console_thread_ = utils::thread::create_named_thread("Console", [this]() + { + if (game::environment::is_dedi() || !utils::flags::has_flag("noconsole")) + { + game::Sys_ShowConsole(); + } + + if (!game::environment::is_dedi()) + { + // Hide that shit + ShowWindow(console::get_window(), SW_MINIMIZE); + } + + { + messages.access([&](message_queue&) + { + this->console_initialized_ = true; + }); + } + + MSG msg; + while (!this->terminate_runner_) + { + if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + command::execute("quit", false); + break; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + this->log_messages(); + std::this_thread::sleep_for(1ms); + } + } + }); + } + + + void log_messages() + { + /*while*/ + if (this->console_initialized_ && !messages.get_raw().empty()) + { + std::queue message_queue_copy; + + { + messages.access([&](message_queue& msgs) + { + message_queue_copy = std::move(msgs); + msgs = {}; + }); + } + + while (!message_queue_copy.empty()) + { + log_message(message_queue_copy.front()); + message_queue_copy.pop(); + } + } + + fflush(stdout); + fflush(stderr); + } + + static void log_message(const std::string& message) + { + OutputDebugStringA(message.data()); + game::Conbuf_AppendText(message.data()); //0x140513FF0 + FILE* pFile = fopen("debug.log", "a"); + fprintf(pFile, "%s\n", message.data()); + fclose(pFile); + + } + + void runner() + { + char buffer[1024]; + + while (!this->terminate_runner_ && this->handles_[0]) + { + const auto len = _read(this->handles_[0], buffer, sizeof(buffer)); + if (len > 0) + { + dispatch_message(con_type_info, std::string(buffer, len)); + } + else + { + std::this_thread::sleep_for(1ms); + } + } + + std::this_thread::yield(); + } + }; + + HWND get_window() + { + return *reinterpret_cast((SELECT_VALUE(0x000000000, 0x14DDFC2D0))); // H1MP1.4 + } + + void set_title(std::string title) + { + SetWindowText(get_window(), title.data()); + } + + void set_size(const int width, const int height) + { + RECT rect; + GetWindowRect(get_window(), &rect); + + SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); + + auto* const logo_window = *reinterpret_cast(SELECT_VALUE(0x000000000, 0x14DDFC2E0)); // H1MP64(1.4) + SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); + } + + void print(const int type, const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + const auto result = format(&ap, fmt); + va_end(ap); + + dispatch_message(type, result); + } +} + +REGISTER_COMPONENT(console::component) \ No newline at end of file diff --git a/src/client/component/console.hpp b/src/client/component/console.hpp new file mode 100644 index 00000000..302951a8 --- /dev/null +++ b/src/client/component/console.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace console +{ + HWND get_window(); + void set_title(std::string title); + void set_size(int width, int height); + + enum console_type + { + con_type_error = 1, + con_type_warning = 3, + con_type_info = 7 + }; + + void print(int type, const char* fmt, ...); + + template + void error(const char* fmt, Args&&... args) + { + print(con_type_error, fmt, std::forward(args)...); + } + + template + void warn(const char* fmt, Args&&... args) + { + print(con_type_warning, fmt, std::forward(args)...); + } + + template + void info(const char* fmt, Args&&... args) + { + print(con_type_info, fmt, std::forward(args)...); + } +} \ No newline at end of file diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp new file mode 100644 index 00000000..c2994fcb --- /dev/null +++ b/src/client/component/demonware.cpp @@ -0,0 +1,453 @@ +#include +#include "loader/component_loader.hpp" + +#include +#include + +#include "game/game.hpp" +#include "game/demonware/servers/lobby_server.hpp" +#include "game/demonware/servers/auth3_server.hpp" +#include "game/demonware/servers/stun_server.hpp" +#include "game/demonware/servers/umbrella_server.hpp" +#include "game/demonware/server_registry.hpp" +#include + +#define TCP_BLOCKING true +#define UDP_BLOCKING false + +namespace demonware +{ + namespace + { + volatile bool exit_server; + std::thread server_thread; + utils::concurrency::container> blocking_sockets; + utils::concurrency::container> socket_map; + server_registry tcp_servers; + server_registry udp_servers; + + tcp_server* find_server(const SOCKET socket) + { + return socket_map.access([&](const std::unordered_map& map) -> tcp_server* + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return nullptr; + } + + return entry->second; + }); + } + + bool socket_link(const SOCKET socket, const uint32_t address) + { + auto* server = tcp_servers.find(address); + if (!server) + { + return false; + } + + socket_map.access([&](std::unordered_map& map) + { + map[socket] = server; + }); + + return true; + } + + void socket_unlink(const SOCKET socket) + { + socket_map.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + bool is_socket_blocking(const SOCKET socket, const bool def) + { + return blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return def; + } + + return entry->second; + }); + } + + void remove_blocking_socket(const SOCKET socket) + { + blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + void add_blocking_socket(const SOCKET socket, const bool block) + { + blocking_sockets.access([&](std::unordered_map& map) + { + map[socket] = block; + }); + } + + void server_main() + { + exit_server = false; + + while (!exit_server) + { + tcp_servers.frame(); + udp_servers.frame(); + std::this_thread::sleep_for(50ms); + } + } + + namespace io + { + hostent* gethostbyname_stub(const char* name) + { +#ifdef DEBUG + printf("[ network ]: [gethostbyname]: \"%s\"\n", name); +#endif + + base_server* server = tcp_servers.find(name); + if (!server) + { + server = udp_servers.find(name); + } + + if (!server) + { +#pragma warning(push) +#pragma warning(disable: 4996) + return gethostbyname(name); +#pragma warning(pop) + } + + static thread_local in_addr address{}; + address.s_addr = server->get_address(); + + static thread_local in_addr* addr_list[2]{}; + addr_list[0] = &address; + addr_list[1] = nullptr; + + static thread_local hostent host{}; + host.h_name = const_cast(name); + host.h_aliases = nullptr; + host.h_addrtype = AF_INET; + host.h_length = sizeof(in_addr); + host.h_addr_list = reinterpret_cast(addr_list); + + return &host; + } + + int connect_stub(const SOCKET s, const struct sockaddr* addr, const int len) + { + if (len == sizeof(sockaddr_in)) + { + const auto* in_addr = reinterpret_cast(addr); + if (socket_link(s, in_addr->sin_addr.s_addr)) return 0; + } + + return connect(s, addr, len); + } + + int closesocket_stub(const SOCKET s) + { + remove_blocking_socket(s); + socket_unlink(s); + + return closesocket(s); + } + + int send_stub(const SOCKET s, const char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + server->handle_input(buf, len); + return len; + } + + return send(s, buf, len, flags); + } + + int recv_stub(const SOCKET s, char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + if (server->pending_data()) + { + return static_cast(server->handle_output(buf, len)); + } + else + { + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + } + + return recv(s, buf, len, flags); + } + + int sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to, + const int tolen) + { + const auto* in_addr = reinterpret_cast(to); + auto* server = udp_servers.find(in_addr->sin_addr.s_addr); + + if (server) + { + server->handle_input(buf, len, { s, to, tolen }); + return len; + } + + return sendto(s, buf, len, flags, to, tolen); + } + + int recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, struct sockaddr* from, + int* fromlen) + { + // Not supported yet + if (is_socket_blocking(s, UDP_BLOCKING)) + { + return recvfrom(s, buf, len, flags, from, fromlen); + } + + size_t result = 0; + udp_servers.for_each([&](udp_server& server) + { + if (server.pending_data(s)) + { + result = server.handle_output( + s, buf, static_cast(len), from, fromlen); + } + }); + + if (result) + { + return static_cast(result); + } + + return recvfrom(s, buf, len, flags, from, fromlen); + } + + int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + struct timeval* timeout) + { + if (exit_server) + { + return select(nfds, readfds, writefds, exceptfds, timeout); + } + + auto result = 0; + std::vector read_sockets; + std::vector write_sockets; + + socket_map.access([&](std::unordered_map& sockets) + { + for (auto& s : sockets) + { + if (readfds) + { + if (FD_ISSET(s.first, readfds)) + { + if (s.second->pending_data()) + { + read_sockets.push_back(s.first); + FD_CLR(s.first, readfds); + } + } + } + + if (writefds) + { + if (FD_ISSET(s.first, writefds)) + { + write_sockets.push_back(s.first); + FD_CLR(s.first, writefds); + } + } + + if (exceptfds) + { + if (FD_ISSET(s.first, exceptfds)) + { + FD_CLR(s.first, exceptfds); + } + } + } + }); + + if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0)) + { + timeout->tv_sec = 0; + timeout->tv_usec = 0; + } + + result = select(nfds, readfds, writefds, exceptfds, timeout); + if (result < 0) result = 0; + + for (const auto& socket : read_sockets) + { + if (readfds) + { + FD_SET(socket, readfds); + result++; + } + } + + for (const auto& socket : write_sockets) + { + if (writefds) + { + FD_SET(socket, writefds); + result++; + } + } + + return result; + } + + int ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp) + { + if (static_cast(cmd) == (FIONBIO)) + { + add_blocking_socket(s, *argp == 0); + } + + return ioctlsocket(s, cmd, argp); + } + + BOOL internet_get_connected_state_stub(LPDWORD, DWORD) + { + // Allow offline play + return TRUE; + } + } + + void bd_logger_stub(const char* const function, const char* const msg, ...) + { + game::dvar_t* enabled; + + enabled = dvars::register_bool("bd_logger_enabled", false, game::DVAR_FLAG_SAVED, true); + + + //game::Dvar_RegisterBool("bd_logger_enabled", false, game::DVAR_FLAG_SAVED, "bdLogger") + if (!enabled->current.enabled) + { + return; + } + + char buffer[2048]; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap); + printf("%s: %s\n", function, buffer); + + va_end(ap); + } + } + + class component final : public component_interface + { + public: + component() + { + udp_servers.create("phoenix.stun.us.demonware.net"); + udp_servers.create("phoenix.stun.eu.demonware.net"); + udp_servers.create("phoenix.stun.jp.demonware.net"); + udp_servers.create("phoenix.stun.au.demonware.net"); + + udp_servers.create("stun.us.demonware.net"); + udp_servers.create("stun.eu.demonware.net"); + udp_servers.create("stun.jp.demonware.net"); + udp_servers.create("stun.au.demonware.net"); + + tcp_servers.create("mwr-pc-steam-auth3.prod.demonware.net"); + tcp_servers.create("mwr-pc-steam-lobby.prod.demonware.net"); + tcp_servers.create("prod.umbrella.demonware.net"); + } + + void post_load() override + { + server_thread = utils::thread::create_named_thread("Demonware", server_main); + } + + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "WS2_32.dll") + { + if (function == "#3") return io::closesocket_stub; + if (function == "#4") return io::connect_stub; + if (function == "#10") return io::ioctlsocket_stub; + if (function == "#16") return io::recv_stub; + if (function == "#17") return io::recvfrom_stub; + if (function == "#18") return io::select_stub; + if (function == "#19") return io::send_stub; + if (function == "#20") return io::sendto_stub; + if (function == "#52") return io::gethostbyname_stub; + } + + if (function == "InternetGetConnectedState") + { + return io::internet_get_connected_state_stub; + } + + return nullptr; + } + + void post_unpack() override + { + utils::hook::jump(SELECT_VALUE(0, 0x1407400B0), bd_logger_stub); // H1MP64(1.4) + + //singleplayer not supported so far. + if (game::environment::is_sp()) + { + utils::hook::set(0x1405632E0, 0xC3); // bdAuthSteam + utils::hook::set(0x1402DF2C0, 0xC3); // dwNet + return; + } + + utils::hook::set(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.4) + utils::hook::set(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.4) + utils::hook::set(0x14095433C, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] + + //HTTPS -> HTTP + utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003852E] + utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003884F] + utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x140038A07] + + utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) + utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + } + + void pre_destroy() override + { + exit_server = true; + if (server_thread.joinable()) + { + server_thread.join(); + } + } + }; +} + +REGISTER_COMPONENT(demonware::component) \ No newline at end of file diff --git a/src/client/component/demonware.hpp b/src/client/component/demonware.hpp new file mode 100644 index 00000000..d26d1ccd --- /dev/null +++ b/src/client/component/demonware.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace demonware +{ + +} \ No newline at end of file diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp new file mode 100644 index 00000000..192870ad --- /dev/null +++ b/src/client/component/game_console.cpp @@ -0,0 +1,756 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "game_console.hpp" +#include "command.hpp" +#include "scheduler.hpp" + +#include +#include + +#define console_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 18) +#define material_white game::Material_RegisterHandle("white") + +namespace game_console +{ + namespace + { + struct console_globals + { + float x; + float y; + float left_x; + float font_height; + bool may_auto_complete; + char auto_complete_choice[64]; + int info_line_count; + }; + + struct ingame_console + { + char buffer[256]; + int cursor; + int font_height; + int visible_line_count; + int visible_pixel_width; + float screen_min[2]; //left & top + float screen_max[2]; //right & bottom + console_globals globals; + bool output_visible; + int display_line_offset; + int line_count; + std::deque output; + }; + + ingame_console con; + + std::int32_t history_index = -1; + std::deque history; + + std::string fixed_input; + std::vector matches; + + float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float color_title[4] = { 0.9f, 0.9f, 0.5f, 1.0f }; + + void clear() + { + strncpy_s(con.buffer, "", 256); + con.cursor = 0; + + fixed_input = ""; + matches.clear(); + } + + void print(const std::string& data) + { + if (con.visible_line_count > 0 && con.display_line_offset == (con.output.size() - con.visible_line_count)) + { + con.display_line_offset++; + } + + con.output.push_back(data); + + printf("%s\n", data.data()); + + if (con.output.size() > 1024) + { + con.output.pop_front(); + } + } + + void toggle_console() + { + clear(); + + con.output_visible = false; + *game::keyCatchers ^= 1; + } + + void toggle_console_output() + { + con.output_visible = con.output_visible == 0; + } + + void check_resize() + { + con.screen_min[0] = 6.0f; + con.screen_min[1] = 6.0f; + con.screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 6.0f; + con.screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1] - 6.0f; + + if (console_font) + { + con.font_height = console_font->pixelHeight; + con.visible_line_count = static_cast((con.screen_max[1] - con.screen_min[1] - (con.font_height * 2) + ) - + 24.0f) / con.font_height; + con.visible_pixel_width = static_cast(((con.screen_max[0] - con.screen_min[0]) - 10.0f) - 18.0f); + } + else + { + con.font_height = 0; + con.visible_line_count = 0; + con.visible_pixel_width = 0; + } + } + + void draw_box(const float x, const float y, const float w, const float h, float* color) + { + game::vec4_t dark_color; + + dark_color[0] = color[0] * 0.5f; + dark_color[1] = color[1] * 0.5f; + dark_color[2] = color[2] * 0.5f; + dark_color[3] = color[3]; + + game::R_AddCmdDrawStretchPic(x, y, w, h, 0.0f, 0.0f, 0.0f, 0.0f, color, material_white); + game::R_AddCmdDrawStretchPic(x, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic((x + w) - 2.0f, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + game::R_AddCmdDrawStretchPic(x, y, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic(x, (y + h) - 2.0f, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + } + + void draw_input_box(const int lines, float* color) + { + draw_box( + con.globals.x - 6.0f, + con.globals.y - 6.0f, + (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]), + (lines * con.globals.font_height) + 12.0f, + color); + } + + void draw_input_text_and_over(const char* str, float* color) + { + game::R_AddCmdDrawText(str, 0x7FFFFFFF, console_font, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, + 1.0f, 0.0f, color, 0); + con.globals.x = game::R_TextWidth(str, 0, console_font) + con.globals.x + 6.0f; + } + + void draw_hint_box(const int lines, float* color, [[maybe_unused]] float offset_x = 0.0f, + [[maybe_unused]] float offset_y = 0.0f) + { + const auto _h = lines * con.globals.font_height + 12.0f; + const auto _y = con.globals.y - 3.0f + con.globals.font_height + 12.0f; + const auto _w = (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]); + + draw_box(con.globals.x - 6.0f, _y, _w, _h, color); + } + + void draw_hint_text(const int line, const char* text, float* color, const float offset = 0.0f) + { + const auto _y = con.globals.font_height + con.globals.y + (con.globals.font_height * (line + 1)) + 15.0f; + + game::R_AddCmdDrawText(text, 0x7FFFFFFF, console_font, con.globals.x + offset, _y, 1.0f, 1.0f, 0.0f, color, 0); + } + + bool match_compare(const std::string& input, const std::string& text, const bool exact) + { + if (exact && text == input) return true; + if (!exact && text.find(input) != std::string::npos) return true; + return false; + } + + void find_matches(std::string input, std::vector& suggestions, const bool exact) + { + input = utils::string::to_lower(input); + + for (const auto& dvar : dvars::dvar_list) + { + auto name = utils::string::to_lower(dvar); + if (match_compare(input, name, exact)) + { + suggestions.push_back(dvar); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + + if (suggestions.size() == 0 && game::Dvar_FindVar(input.data())) + { + suggestions.push_back(input.data()); + } + + game::cmd_function_s* cmd = (*game::cmd_functions); + while (cmd) + { + if (cmd->name) + { + std::string name = utils::string::to_lower(cmd->name); + + if (match_compare(input, name, exact)) + { + suggestions.push_back(cmd->name); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + cmd = cmd->next; + } + } + + void draw_input() + { + con.globals.font_height = static_cast(console_font->pixelHeight); + con.globals.x = con.screen_min[0] + 6.0f; + con.globals.y = con.screen_min[1] + 6.0f; + con.globals.left_x = con.screen_min[0] + 6.0f; + + draw_input_box(1, dvars::con_inputBoxColor->current.vector); + draw_input_text_and_over("H1-Mod >", color_title); + + con.globals.left_x = con.globals.x; + con.globals.auto_complete_choice[0] = 0; + + + game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, 18, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, color_white, 0, + con.cursor, '|'); + + //game::R_AddCmdDrawText(con.buffer, 0x7FFF, console_font, con.globals.x, + // con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0); + + + // check if using a prefixed '/' or not + const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\') + ? std::string(con.buffer).substr(1) + : std::string(con.buffer); + + if (!input.length()) + { + return; + } + + if (input != fixed_input) + { + matches.clear(); + + if (input.find(" ") != std::string::npos) + { + find_matches(input.substr(0, input.find(" ")), matches, true); + } + else + { + find_matches(input, matches, false); + } + + fixed_input = input; + } + + con.globals.may_auto_complete = false; + if (matches.size() > 24) + { + draw_hint_box(1, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()), + dvars::con_inputDvarMatchColor->current.vector); + } + else if (matches.size() == 1) + { + auto* const dvar = game::Dvar_FindVar(matches[0].data()); + const auto line_count = dvar ? 2 : 1; + + draw_hint_box(line_count, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, matches[0].data(), dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + draw_hint_text(0, game::Dvar_ValueToString(dvar, dvar->current, 0), + dvars::con_inputDvarValueColor->current.vector, offset); + draw_hint_text(1, " default", dvars::con_inputDvarInactiveValueColor->current.vector); + draw_hint_text(1, game::Dvar_ValueToString(dvar, dvar->reset, 0), + dvars::con_inputDvarInactiveValueColor->current.vector, offset); + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64); + con.globals.may_auto_complete = true; + } + else if (matches.size() > 1) + { + draw_hint_box(static_cast(matches.size()), dvars::con_inputHintBoxColor->current.vector); + + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + for (size_t i = 0; i < matches.size(); i++) + { + auto* const dvar = game::Dvar_FindVar(matches[i].data()); + + draw_hint_text(static_cast(i), matches[i].data(), + dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + draw_hint_text(static_cast(i), game::Dvar_ValueToString(dvar, dvar->current, 0), + dvars::con_inputDvarValueColor->current.vector, offset); + } + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64); + con.globals.may_auto_complete = true; + } + } + + void draw_output_scrollbar(const float x, float y, const float width, const float height) + { + const auto _x = (x + width) - 10.0f; + draw_box(_x, y, 10.0f, height, dvars::con_outputBarColor->current.vector); + + auto _height = height; + if (con.output.size() > con.visible_line_count) + { + const auto percentage = static_cast(con.visible_line_count) / con.output.size(); + _height *= percentage; + + const auto remainingSpace = height - _height; + const auto percentageAbove = static_cast(con.display_line_offset) / (con.output.size() - con. + visible_line_count); + + y = y + (remainingSpace * percentageAbove); + } + + draw_box(_x, y, 10.0f, _height, dvars::con_outputSliderColor->current.vector); + } + + void draw_output_text(const float x, float y) + { + const auto offset = con.output.size() >= con.visible_line_count + ? 0.0f + : (con.font_height * (con.visible_line_count - con.output.size())); + + for (auto i = 0; i < con.visible_line_count; i++) + { + y = console_font->pixelHeight + y; + + const auto index = i + con.display_line_offset; + if (index >= con.output.size()) + { + break; + } + + game::R_AddCmdDrawText(con.output.at(index).data(), 0x7FFF, console_font, x, y + offset, 1.0f, 1.0f, + 0.0f, color_white, 0); + } + } + + void draw_output_window() + { + draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0], + (con.screen_max[1] - con.screen_min[1]) - 32.0f, dvars::con_outputWindowColor->current.vector); + + const auto x = con.screen_min[0] + 6.0f; + const auto y = (con.screen_min[1] + 32.0f) + 6.0f; + const auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f; + const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f; + + game::R_AddCmdDrawText("H1-Mod 1.4", 0x7FFFFFFF, console_font, x, + ((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_title, 0); + + draw_output_scrollbar(x, y, width, height); + draw_output_text(x, y); + } + + void draw_console() + { + check_resize(); + + if (*game::keyCatchers & 1) + { + if (!(*game::keyCatchers & 1)) + { + con.output_visible = false; + } + + if (con.output_visible) + { + draw_output_window(); + } + + draw_input(); + } + } + } + + void print(const int type, const char* fmt, ...) + { + char va_buffer[0x200] = { 0 }; + + va_list ap; + va_start(ap, fmt); + vsprintf_s(va_buffer, fmt, ap); + va_end(ap); + + const auto formatted = std::string(va_buffer); + const auto lines = utils::string::split(formatted, '\n'); + + for (auto& line : lines) + { + print(type == con_type_info ? line : "^"s.append(std::to_string(type)).append(line)); + } + } + + bool console_char_event(const int localClientNum, const int key) + { + if (key == '`' || key == '~' || key == '|' || key == '\\') + { + return false; + } + + if (key > 127) + { + return true; + } + + if (*game::keyCatchers & 1) + { + if (key == game::keyNum_t::K_TAB) // tab (auto complete) + { + if (con.globals.may_auto_complete) + { + const auto firstChar = con.buffer[0]; + + clear(); + + if (firstChar == '\\' || firstChar == '/') + { + con.buffer[0] = firstChar; + con.buffer[1] = '\0'; + } + + strncat_s(con.buffer, con.globals.auto_complete_choice, 64); + con.cursor = static_cast(std::string(con.buffer).length()); + + if (con.cursor != 254) + { + con.buffer[con.cursor++] = ' '; + con.buffer[con.cursor] = '\0'; + } + } + } + + if (key == 'v' - 'a' + 1) // paste + { + const auto clipboard = utils::string::get_clipboard_data(); + if (clipboard.empty()) + { + return false; + } + + for (auto i = 0; i < clipboard.length(); i++) + { + console_char_event(localClientNum, clipboard[i]); + } + + return false; + } + + if (key == 'c' - 'a' + 1) // clear + { + clear(); + con.line_count = 0; + con.output.clear(); + history_index = -1; + history.clear(); + + return false; + } + + if (key == 'h' - 'a' + 1) // backspace + { + if (con.cursor > 0) + { + memmove(con.buffer + con.cursor - 1, con.buffer + con.cursor, + strlen(con.buffer) + 1 - con.cursor); + con.cursor--; + } + + return false; + } + + if (key < 32) + { + return false; + } + + if (con.cursor == 256 - 1) + { + return false; + } + + memmove(con.buffer + con.cursor + 1, con.buffer + con.cursor, strlen(con.buffer) + 1 - con.cursor); + con.buffer[con.cursor] = static_cast(key); + con.cursor++; + + if (con.cursor == strlen(con.buffer) + 1) + { + con.buffer[con.cursor] = 0; + } + } + + return true; + } + + void execute(const char* cmd) + { + game::Cbuf_AddText(0, utils::string::va("%s \n", cmd)); + } + + bool console_key_event(const int localClientNum, const int key, const int down) + { + if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) + { + if (!down) + { + return false; + } + + if (game::playerKeys[localClientNum].keys[game::keyNum_t::K_SHIFT].down) + { + if (!(*game::keyCatchers & 1)) + toggle_console(); + + toggle_console_output(); + return false; + } + + toggle_console(); + + return false; + } + + if (*game::keyCatchers & 1) + { + if (down) + { + if (key == game::keyNum_t::K_UPARROW) + { + if (++history_index >= history.size()) + { + history_index = static_cast(history.size()) - 1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), 0x100); + con.cursor = static_cast(strlen(con.buffer)); + } + } + else if (key == game::keyNum_t::K_DOWNARROW) + { + if (--history_index < -1) + { + history_index = -1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), 0x100); + con.cursor = static_cast(strlen(con.buffer)); + } + } + + if (key == game::keyNum_t::K_RIGHTARROW) + { + if (con.cursor < strlen(con.buffer)) + { + con.cursor++; + } + + return false; + } + + if (key == game::keyNum_t::K_LEFTARROW) + { + if (con.cursor > 0) + { + con.cursor--; + } + + return false; + } + + //scroll through output + if (key == game::keyNum_t::K_MWHEELUP || key == game::keyNum_t::K_PGUP) + { + if (con.output.size() > con.visible_line_count && con.display_line_offset > 0) + { + con.display_line_offset--; + } + } + else if (key == game::keyNum_t::K_MWHEELDOWN || key == game::keyNum_t::K_PGDN) + { + if (con.output.size() > con.visible_line_count && con.display_line_offset < (con.output.size() - + con. + visible_line_count)) + { + con.display_line_offset++; + } + } + + if (key == game::keyNum_t::K_ENTER) + { + execute(fixed_input.data()); + + if (history_index != -1) + { + const auto itr = history.begin() + history_index; + + if (*itr == con.buffer) + { + history.erase(history.begin() + history_index); + } + } + + history.push_front(con.buffer); + + print(""s.append(con.buffer)); + + if (history.size() > 10) + { + history.erase(history.begin() + 10); + } + + history_index = -1; + + clear(); + } + } + } + + return true; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + scheduler::loop(draw_console, scheduler::pipeline::renderer); + + con.cursor = 0; + con.visible_line_count = 0; + con.output_visible = false; + con.display_line_offset = 0; + con.line_count = 0; + strncpy_s(con.buffer, "", 256); + + con.globals.x = 0.0f; + con.globals.y = 0.0f; + con.globals.left_x = 0.0f; + con.globals.font_height = 0.0f; + con.globals.may_auto_complete = false; + con.globals.info_line_count = 0; + strncpy_s(con.globals.auto_complete_choice, "", 64); + + // //add clear command + //command::add("clear", [&]() + //{ + //clear(); + //con.line_count = 0; + //con.output.clear(); + //history_index = -1; + //history.clear(); + //}); + + char a2[1] = {}; + + // add our dvars + dvars::con_inputBoxColor = dvars::register_vec4( + "con_inputBoxColor", + 0.2f, 0.2f, 0.2f, 0.9f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_inputHintBoxColor = dvars::register_vec4( + "con_inputHintBoxColor", + 0.3f, 0.3f, 0.3f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_outputBarColor = dvars::register_vec4( + "con_outputBarColor", + 0.5f, 0.5f, 0.5f, 0.6f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_outputSliderColor = dvars::register_vec4( + "con_outputSliderColor", + 0.9f, 0.9f, 0.5f, 1.00f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_outputWindowColor = dvars::register_vec4( + "con_outputWindowColor", + 0.25f, 0.25f, 0.25f, 0.85f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_inputDvarMatchColor = dvars::register_vec4( + "con_inputDvarMatchColor", + 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_inputDvarValueColor = dvars::register_vec4( + "con_inputDvarValueColor", + 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_inputDvarInactiveValueColor = dvars::register_vec4( + "con_inputDvarInactiveValueColor", + 0.8f, 0.8f, 0.8f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + + dvars::con_inputCmdMatchColor = dvars::register_vec4( + "con_inputCmdMatchColor", + 0.80f, 0.80f, 1.0f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED); + } + }; +} + +REGISTER_COMPONENT(game_console::component) \ No newline at end of file diff --git a/src/client/component/game_console.hpp b/src/client/component/game_console.hpp new file mode 100644 index 00000000..7c4fc21a --- /dev/null +++ b/src/client/component/game_console.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace game_console +{ + enum console_type + { + con_type_error = 1, + con_type_warning = 3, + con_type_info = 7 + }; + + void print(int type, const char* fmt, ...); + + bool console_char_event(int local_client_num, int key); + bool console_key_event(int local_client_num, int key, int down); + + void execute(const char* cmd); +} \ No newline at end of file diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp new file mode 100644 index 00000000..e53997bb --- /dev/null +++ b/src/client/component/game_module.cpp @@ -0,0 +1,118 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" + +#include + +namespace game_module +{ + namespace + { + utils::hook::detour handle_a_hook; + utils::hook::detour handle_w_hook; + utils::hook::detour handle_ex_a_hook; + utils::hook::detour handle_ex_w_hook; + utils::hook::detour file_name_a_hook; + utils::hook::detour file_name_w_hook; + + HMODULE __stdcall get_module_handle_a(const LPCSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_a_hook.invoke(module_name); + } + + HMODULE __stdcall get_module_handle_w(const LPWSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_w_hook.invoke(module_name); + } + + BOOL __stdcall get_module_handle_ex_a(const DWORD flags, const LPCSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_a_hook.invoke(flags, module_name, hmodule); + } + + BOOL __stdcall get_module_handle_ex_w(const DWORD flags, const LPCWSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_w_hook.invoke(flags, module_name, hmodule); + } + + DWORD __stdcall get_module_file_name_a(HMODULE hmodule, const LPSTR filename, const DWORD size) + { + if (!hmodule) + { + hmodule = get_game_module(); + } + + return file_name_a_hook.invoke(hmodule, filename, size); + } + + DWORD __stdcall get_module_file_name_w(HMODULE hmodule, const LPWSTR filename, const DWORD size) + { + if (!hmodule) + { + hmodule = get_game_module(); + } + + return file_name_w_hook.invoke(hmodule, filename, size); + } + + void hook_module_resolving() + { + handle_a_hook.create(&GetModuleHandleA, &get_module_handle_a); + handle_w_hook.create(&GetModuleHandleW, &get_module_handle_w); + handle_ex_w_hook.create(&GetModuleHandleExA, &get_module_handle_ex_a); + handle_ex_w_hook.create(&GetModuleHandleExW, &get_module_handle_ex_w); + file_name_a_hook.create(&GetModuleFileNameA, &get_module_file_name_a); + file_name_w_hook.create(&GetModuleFileNameW, &get_module_file_name_w); + } + } + + utils::nt::library get_game_module() + { + static utils::nt::library game{ HMODULE(0x140000000) }; + return game; + } + + utils::nt::library get_host_module() + { + static utils::nt::library host{}; + return host; + } + + class component final : public component_interface + { + public: + void post_start() override + { + get_host_module(); + } + + void post_load() override + { + hook_module_resolving(); + } + }; +} + +REGISTER_COMPONENT(game_module::component) \ No newline at end of file diff --git a/src/client/component/game_module.hpp b/src/client/component/game_module.hpp new file mode 100644 index 00000000..e2ca5f56 --- /dev/null +++ b/src/client/component/game_module.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace game_module +{ + utils::nt::library get_game_module(); + utils::nt::library get_host_module(); +} \ No newline at end of file diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp new file mode 100644 index 00000000..216b0ed6 --- /dev/null +++ b/src/client/component/input.cpp @@ -0,0 +1,54 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "game_console.hpp" + +#include + +namespace input +{ + namespace + { + utils::hook::detour cl_char_event_hook; + utils::hook::detour cl_key_event_hook; + + void cl_char_event_stub(const int local_client_num, const int key) + { + if (!game_console::console_char_event(local_client_num, key)) + { + return; + } + + cl_char_event_hook.invoke(local_client_num, key); + } + + void cl_key_event_stub(const int local_client_num, const int key, const int down) + { + if (!game_console::console_key_event(local_client_num, key, down)) + { + return; + } + + cl_key_event_hook.invoke(local_client_num, key, down); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + cl_char_event_hook.create(SELECT_VALUE(0x000000000, 0x14024E810), cl_char_event_stub); + cl_key_event_hook.create(SELECT_VALUE(0x000000000, 0x14024EA60), cl_key_event_stub); + } + }; +} + +REGISTER_COMPONENT(input::component) \ No newline at end of file diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp new file mode 100644 index 00000000..f3eb78dd --- /dev/null +++ b/src/client/component/localized_strings.cpp @@ -0,0 +1,58 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include +#include +#include "game/game.hpp" + +namespace localized_strings +{ + namespace + { + utils::hook::detour seh_string_ed_get_string_hook; + + std::unordered_map& get_localized_overrides() + { + static std::unordered_map overrides; + return overrides; + } + + std::mutex& get_synchronization_mutex() + { + static std::mutex mutex; + return mutex; + } + + const char* seh_string_ed_get_string(const char* reference) + { + std::lock_guard _(get_synchronization_mutex()); + + auto& overrides = get_localized_overrides(); + const auto entry = overrides.find(reference); + if (entry != overrides.end()) + { + return utils::string::va("%s", entry->second.data()); + } + + return seh_string_ed_get_string_hook.invoke(reference); + } + } + + void override(const std::string& key, const std::string& value) + { + std::lock_guard _(get_synchronization_mutex()); + get_localized_overrides()[key] = value; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Change some localized strings + seh_string_ed_get_string_hook.create(SELECT_VALUE(0x000000000, 0x1404BB2A0), &seh_string_ed_get_string); + } + }; +} + +REGISTER_COMPONENT(localized_strings::component) \ No newline at end of file diff --git a/src/client/component/localized_strings.hpp b/src/client/component/localized_strings.hpp new file mode 100644 index 00000000..01d15907 --- /dev/null +++ b/src/client/component/localized_strings.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace localized_strings +{ + void override(const std::string& key, const std::string& value); +} \ No newline at end of file diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp new file mode 100644 index 00000000..27346929 --- /dev/null +++ b/src/client/component/network.cpp @@ -0,0 +1,279 @@ +#include +#include "loader/component_loader.hpp" + +#include "command.hpp" +#include "network.hpp" +#include "game_console.hpp" +#include "../game/game.hpp" + +#include +#include +#include + +namespace network +{ + namespace + { + std::unordered_map& get_callbacks() + { + static std::unordered_map callbacks{}; + return callbacks; + } + + bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) + { + const auto cmd_string = utils::string::to_lower(command); + auto& callbacks = get_callbacks(); + const auto handler = callbacks.find(cmd_string); + if (handler == callbacks.end()) + { + return false; + } + + const auto offset = cmd_string.size() + 5; + const std::string_view data(message->data + offset, message->cursize - offset); + + handler->second(*address, data); + return true; + } + + void handle_command_stub(utils::hook::assembler& a) + { + const auto return_unhandled = a.newLabel(); + + a.pushad64(); + + a.mov(r8, rsi); // message + a.mov(rdx, rdi); // command + a.mov(rcx, r14); // netaddr + + a.call_aligned(handle_command); + + a.test(al, al); + a.jz(return_unhandled); + + // Command handled + a.popad64(); + a.mov(al, 1); + a.jmp(0x14020AA10); + + a.bind(return_unhandled); + a.popad64(); + a.jmp(0x14020A19A); + } + + int net_compare_base_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + if (a1->type == a2->type) + { + switch (a1->type) + { + case game::netadrtype_t::NA_BOT: + case game::netadrtype_t::NA_LOOPBACK: + return a1->port == a2->port; + + case game::netadrtype_t::NA_IP: + return !memcmp(a1->ip, a2->ip, 4); + case game::netadrtype_t::NA_BROADCAST: + return true; + default: + break; + } + } + + return false; + } + + int net_compare_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + return net_compare_base_address(a1, a2) && a1->port == a2->port; + } + + void reconnect_migratated_client(void*, game::netadr_s* from, const int, const int, const char*, + const char*, bool) + { + // This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid + // We don't want this to do anything. It decides to crash seemingly randomly + // Rather than try and let the player in, just tell them they are a duplicate player and reject connection + game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server."); + } + } + + void on(const std::string& command, const callback& callback) + { + get_callbacks()[utils::string::to_lower(command)] = callback; + } + + void dw_send_to_stub(const unsigned int size, const char* src, game::netadr_s* a3) + { + sockaddr s = {}; + game::NetadrToSockadr(a3, &s); //0x1404F62F0 + sendto(*game::query_socket, src, size - 2, 0, &s, 16); + } + + void send(const game::netadr_s& address, const std::string& command, const std::string& data, const char separator) + { + std::string packet = "\xFF\xFF\xFF\xFF"; + packet.append(command); + packet.push_back(separator); + packet.append(data); + + send_data(address, packet); + } + + + void send_data(const game::netadr_s& address, const std::string& data) + { + if (address.type == game::NA_LOOPBACK) + { + game::NET_SendLoopPacket(game::NS_CLIENT1, static_cast(data.size()), data.data(), &address); + } + else + { + game::Sys_SendPacket(static_cast(data.size()), data.data(), &address); + } + } + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b) + { + return net_compare_address(&a, &b); + } + + const char* net_adr_to_string(const game::netadr_s& a) + { + if (a.type == game::netadrtype_t::NA_LOOPBACK) + { + return "loopback"; + } + + if (a.type == game::netadrtype_t::NA_BOT) + { + return "bot"; + } + + if (a.type == game::netadrtype_t::NA_IP || a.type == game::netadrtype_t::NA_BROADCAST) + { + if (a.port) + { + return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port)); + } + + return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + } + + return "bad"; + } + + game::dvar_t* register_netport_stub(const char* dvarName, int value, int min, int max, unsigned int flags, + const char* description) + { + auto dvar = dvars::register_int("net_port", 27016, 0, 0xFFFFu, game::DVAR_FLAG_LATCHED, "Network port"); + + // read net_port from command line + command::read_startup_variable("net_port"); + + return dvar; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + { + if (game::environment::is_sp()) + { + return; + } + + // redirect dw_sendto to raw socket + //utils::hook::jump(0x1404D850A, reinterpret_cast(0x1404D849A)); + utils::hook::call(0x140513467, dw_send_to_stub); // H1MP64(1.4) + utils::hook::jump(game::Sys_SendPacket, dw_send_to_stub); + + // intercept command handling + utils::hook::jump(0x140252327, utils::hook::assemble(handle_command_stub), true); // H1MP64(1.4) + + // handle xuid without secure connection + utils::hook::nop(0x140486AAF, 6); // H1MP64(1.4) + + utils::hook::jump(0x140424F20, net_compare_address); // H1MP64(1.4) + utils::hook::jump(0x140424F70, net_compare_base_address); // H1MP64(1.4) + + // don't establish secure conenction + utils::hook::set(0x14027EA4D, 0xEB); // H1MP64(1.4) + utils::hook::set(0x14027EB1E, 0xEB); // H1MP64(1.4) + utils::hook::set(0x14027EF8D, 0xEB); // H1MP64(1.4) + utils::hook::set(0x14025081F, 0xEB); // H1MP64(1.4) + + // ignore unregistered connection + utils::hook::jump(0x140480F46, reinterpret_cast(0x140480EE5)); // H1MP64(1.4) + utils::hook::set(0x140480F3B, 0xEB); // H1MP64(1.4) + + // disable xuid verification + utils::hook::set(0x14005B62D, 0xEB); // H1MP64(1.4) + utils::hook::set(0x14005B649, 0xEB); // H1MP64(1.4) NOT_SURE SHOULD JZ BUT LEA + + // disable xuid verification + utils::hook::nop(0x14048382C, 2); // H1MP64(1.4) + utils::hook::set(0x140483889, 0xEB); // H1MP64(1.4) NOT_SURE + + // ignore configstring mismatch + utils::hook::set(0x1402591C9, 0xEB); // H1MP64(1.4) + + // ignore dw handle in SV_PacketEvent + utils::hook::set(0x1404898E2, 0xEB); // H1MP64(1.4) + utils::hook::call(0x1404898D6, &net_compare_address); // H1MP64(1.4) + + // ignore dw handle in SV_FindClientByAddress + utils::hook::set(0x140488EFD, 0xEB); // H1MP64(1.4) + utils::hook::call(0x140488EF1, &net_compare_address); // H1MP64(1.4) + + // ignore dw handle in SV_DirectConnect + utils::hook::set(0x140480C58, 0xEB); // H1MP64(1.4) + utils::hook::set(0x140480CF2, 0xEB); // H1MP64(1.4) NOT_SURE + utils::hook::call(0x140480C4B, &net_compare_address); // H1MP64(1.4) + utils::hook::call(0x140480E62, &net_compare_address); // H1MP64(1.4) + + // increase cl_maxpackets + //dvars::override::Dvar_RegisterInt("cl_maxpackets", 1000, 1, 1000, 0x1); + dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, 0x1, true); + + // ignore impure client + utils::hook::jump(0x140481B58, reinterpret_cast(0x140481BEE)); // H1MP64(1.4) + + // don't send checksum + utils::hook::set(0x140513433, 0); // H1MP64(1.4) mov: r8d, edi ; LEN + + // don't read checksum + utils::hook::jump(0x140513389, 0x14051339F); // H1MP64(1.4) + + // don't try to reconnect client + utils::hook::call(0x140480DFF, reconnect_migratated_client); // H1MP64(1.4) + utils::hook::nop(0x140480DDB, 4); // H1MP64(1.4) this crashes when reconnecting for some reason + + // allow server owner to modify net_port before the socket bind + utils::hook::call(0x140512BE5, register_netport_stub); // H1MP64(1.4) + utils::hook::call(0x140512D20, register_netport_stub); // H1MP64(1.4) + + // ignore built in "print" oob command and add in our own + utils::hook::set(0x14025280E, 0xEB); // H1MP64(1.4) + on("print", [](const game::netadr_s& addr, const std::string_view& data) + { + const std::string message{ data }; + + if (game::environment::is_dedi()) + { + printf("%s\n", message.data()); + } + else + { + game_console::print(game_console::con_type_info, "%s\n", message.data()); + } + }); + } + } + }; +} + +REGISTER_COMPONENT(network::component) \ No newline at end of file diff --git a/src/client/component/network.hpp b/src/client/component/network.hpp new file mode 100644 index 00000000..c8c9d7fc --- /dev/null +++ b/src/client/component/network.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "game/game.hpp" + +namespace network +{ + using callback = std::function; + + void on(const std::string& command, const callback& callback); + void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' '); + void send_data(const game::netadr_s& address, const std::string& data); + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b); + + const char* net_adr_to_string(const game::netadr_s& a); +} + +inline bool operator==(const game::netadr_s& a, const game::netadr_s& b) +{ + return network::are_addresses_equal(a, b); // +} + +inline bool operator!=(const game::netadr_s& a, const game::netadr_s& b) +{ + return !(a == b); // +} + +namespace std +{ + template <> + struct equal_to + { + using result_type = bool; + + bool operator()(const game::netadr_s& lhs, const game::netadr_s& rhs) const + { + return network::are_addresses_equal(lhs, rhs); + } + }; + + template <> + struct hash + { + size_t operator()(const game::netadr_s& x) const noexcept + { + return hash()(*reinterpret_cast(&x.ip[0])) ^ hash()(x.port); + } + }; +} diff --git a/src/client/component/redirect.cpp b/src/client/component/redirect.cpp new file mode 100644 index 00000000..0443df55 --- /dev/null +++ b/src/client/component/redirect.cpp @@ -0,0 +1,83 @@ +#include +#include "loader/component_loader.hpp" +#include +#include +#include "game_module.hpp" + +namespace redirect +{ + namespace + { + void launch_complementary_game(const bool singleplayer, const std::string& mode = "") + { + const auto self = game_module::get_host_module(); + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + auto* arguments = const_cast(utils::string::va("%s%s%s", self.get_path().data(), + (singleplayer ? " -singleplayer" : " -multiplayer"), + (mode.empty() ? "" : (" +"s + mode).data()))); + CreateProcessA(self.get_path().data(), arguments, nullptr, nullptr, false, NULL, nullptr, nullptr, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hThread); + } + + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hProcess); + } + } + + HINSTANCE shell_execute_a(const HWND hwnd, const LPCSTR operation, const LPCSTR file, const LPCSTR parameters, + const LPCSTR directory, const INT show_cmd) + { + if (utils::string::starts_with(file, "steam://run/393080/")) + { + launch_complementary_game(true); + return HINSTANCE(33); + } + else if (utils::string::starts_with(file, "steam://run/393100/")) + { + std::string mode(file); + mode.erase(0, 20); + if (!mode.empty()) + { + mode = utils::string::replace(mode, "%2b", ""); // '+' + mode = utils::string::replace(mode, "%2", " "); // ' ' + } + + launch_complementary_game(false, mode); + return HINSTANCE(33); + } + + return ShellExecuteA(hwnd, operation, file, parameters, directory, show_cmd); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "SHELL32.dll") + { + if (function == "ShellExecuteA") + { + return shell_execute_a; + } + } + + return nullptr; + } + }; +} + +REGISTER_COMPONENT(redirect::component) diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp new file mode 100644 index 00000000..3a3cf97f --- /dev/null +++ b/src/client/component/scheduler.cpp @@ -0,0 +1,170 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" +#include "game/game.hpp" + +#include +#include +#include + +namespace scheduler +{ + namespace + { + struct task + { + std::function handler{}; + std::chrono::milliseconds interval{}; + std::chrono::high_resolution_clock::time_point last_call{}; + }; + + using task_list = std::vector; + + class task_pipeline + { + public: + void add(task&& task) + { + new_callbacks_.access([&task](task_list& tasks) + { + tasks.emplace_back(std::move(task)); + }); + } + + void execute() + { + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + + for (auto i = tasks.begin(); i != tasks.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - i->last_call; + + if (diff < i->interval) + { + ++i; + continue; + } + + i->last_call = now; + + const auto res = i->handler(); + if (res == cond_end) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + private: + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + + void merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } + }; + + volatile bool kill = false; + std::thread thread; + task_pipeline pipelines[pipeline::count]; + utils::hook::detour r_end_frame_hook; + utils::hook::detour g_run_frame_hook; + utils::hook::detour main_frame_hook; + + void execute(const pipeline type) + { + assert(type >= 0 && type < pipeline::count); + pipelines[type].execute(); + } + + void r_end_frame_stub() + { + execute(pipeline::renderer); + r_end_frame_hook.invoke(); + } + + void server_frame_stub() + { + g_run_frame_hook.invoke(); + execute(pipeline::server); + } + + void main_frame_stub() + { + main_frame_hook.invoke(); + execute(pipeline::main); + } + } + + void schedule(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + assert(type >= 0 && type < pipeline::count); + + task task; + task.handler = callback; + task.interval = delay; + task.last_call = std::chrono::high_resolution_clock::now(); + + pipelines[type].add(std::move(task)); + } + + void loop(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_continue; + }, type, delay); + } + + void once(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_end; + }, type, delay); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + //thread = std::thread([]() + //{ + // while (!kill) + // { + // execute(pipeline::async); + // std::this_thread::sleep_for(10ms); + // } + //}); + + r_end_frame_hook.create(0x1405FE470, scheduler::r_end_frame_stub); // H1MP64[1.4] + g_run_frame_hook.create(0x1402772D0, scheduler::server_frame_stub); // H1MP64[1.4] + main_frame_hook.create(0x1401CE8D0, scheduler::main_frame_stub); // H1MP64[1.4] + } + }; +} + +REGISTER_COMPONENT(scheduler::component) diff --git a/src/client/component/scheduler.hpp b/src/client/component/scheduler.hpp new file mode 100644 index 00000000..f26c60ce --- /dev/null +++ b/src/client/component/scheduler.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace scheduler +{ + enum pipeline + { + // Asynchronuous pipeline, disconnected from the game + async = 0, + + // The game's rendering pipeline + renderer, + + // The game's server thread + server, + + // The game's main thread + main, + + count, + }; + + static const bool cond_continue = false; + static const bool cond_end = true; + + void schedule(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void loop(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void once(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void on_game_initialized(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); +} \ No newline at end of file diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp new file mode 100644 index 00000000..ff6c52a4 --- /dev/null +++ b/src/client/component/steam_proxy.cpp @@ -0,0 +1,188 @@ +#include +#include "loader/component_loader.hpp" +#include "steam_proxy.hpp" +#include "scheduler.hpp" + +#include +#include +#include +#include + +#include "game/game.hpp" + +#include "steam/interface.hpp" +#include "steam/steam.hpp" + +namespace steam_proxy +{ + namespace + { + utils::binary_resource runner_file(RUNNER, "runner.exe"); + + bool is_disabled() + { + static const auto disabled = utils::flags::has_flag("nosteam"); + return disabled; + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi() || is_disabled()) + { + return; + } + + this->load_client(); + this->clean_up_on_error(); + +#ifndef DEV_BUILD + try + { + this->start_mod("\xF0\x9F\x90\xA4" " H1-Mod: "s + (game::environment::is_sp() ? "Singleplayer" : "Multiplayer"), game::environment::is_sp() ? 393080 : 393100); + } + catch (std::exception& e) + { + printf("Steam: %s\n", e.what()); + } +#endif + } + + void pre_destroy() override + { + if (this->steam_client_module_) + { + if (this->steam_pipe_) + { + if (this->global_user_) + { + this->steam_client_module_.invoke("Steam_ReleaseUser", this->steam_pipe_, + this->global_user_); + } + + this->steam_client_module_.invoke("Steam_BReleaseSteamPipe", this->steam_pipe_); + } + } + } + + const utils::nt::library& get_overlay_module() const + { + return steam_overlay_module_; + } + + private: + utils::nt::library steam_client_module_{}; + utils::nt::library steam_overlay_module_{}; + + steam::interface client_engine_ {}; + steam::interface client_user_ {}; + steam::interface client_utils_ {}; + + void* steam_pipe_ = nullptr; + void* global_user_ = nullptr; + + void* load_client_engine() const + { + if (!this->steam_client_module_) return nullptr; + + for (auto i = 1; i > 0; ++i) + { + std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); + auto* const client_engine = this->steam_client_module_ + .invoke("CreateInterface", name.data(), nullptr); + if (client_engine) return client_engine; + } + + return nullptr; + } + + void load_client() + { + const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); + if (steam_path.empty()) return; + + utils::nt::library::load(steam_path / "tier0_s64.dll"); + utils::nt::library::load(steam_path / "vstdlib_s64.dll"); + this->steam_overlay_module_ = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); + this->steam_client_module_ = utils::nt::library::load(steam_path / "steamclient64.dll"); + if (!this->steam_client_module_) return; + + this->client_engine_ = load_client_engine(); + if (!this->client_engine_) return; + + this->steam_pipe_ = this->steam_client_module_.invoke("Steam_CreateSteamPipe"); + this->global_user_ = this->steam_client_module_.invoke( + "Steam_ConnectToGlobalUser", this->steam_pipe_); + this->client_user_ = this->client_engine_.invoke(8, this->steam_pipe_, this->global_user_); + // GetIClientUser + this->client_utils_ = this->client_engine_.invoke(14, this->steam_pipe_); // GetIClientUtils + } + + void start_mod(const std::string& title, size_t app_id) + { + if (!this->client_utils_ || !this->client_user_) return; + + if (!this->client_user_.invoke("BIsSubscribedApp", app_id)) + { + app_id = 480; // Spacewar + } + + this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); + + char our_directory[MAX_PATH] = { 0 }; + GetCurrentDirectoryA(sizeof(our_directory), our_directory); + + const auto path = runner_file.get_extracted_file(); + const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); + + steam::game_id game_id; + game_id.raw.type = 1; // k_EGameIDTypeGameMod + game_id.raw.app_id = app_id & 0xFFFFFF; + + const auto* mod_id = "H1-Mod"; + game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; + + this->client_user_.invoke("SpawnProcess", path.data(), cmdline.data(), our_directory, + &game_id.bits, title.data(), 0, 0, 0); + } + + void clean_up_on_error() + { + scheduler::schedule([this]() + { + if (this->steam_client_module_ + && this->steam_pipe_ + && this->global_user_ + && this->steam_client_module_.invoke("Steam_BConnected", this->global_user_, + this->steam_pipe_) + && this->steam_client_module_.invoke("Steam_BLoggedOn", this->global_user_, this->steam_pipe_) + ) + { + return scheduler::cond_continue; + } + + this->client_engine_ = nullptr; + this->client_user_ = nullptr; + this->client_utils_ = nullptr; + + this->steam_pipe_ = nullptr; + this->global_user_ = nullptr; + + this->steam_client_module_ = utils::nt::library{ nullptr }; + + return scheduler::cond_end; + }); + } + }; + + const utils::nt::library& get_overlay_module() + { + // TODO: Find a better way to do this + return component_loader::get()->get_overlay_module(); + } +} + +REGISTER_COMPONENT(steam_proxy::component) \ No newline at end of file diff --git a/src/client/component/steam_proxy.hpp b/src/client/component/steam_proxy.hpp new file mode 100644 index 00000000..8f7d0b8f --- /dev/null +++ b/src/client/component/steam_proxy.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace steam_proxy +{ + const utils::nt::library& get_overlay_module(); +} \ No newline at end of file diff --git a/src/client/game/demonware/bit_buffer.cpp b/src/client/game/demonware/bit_buffer.cpp new file mode 100644 index 00000000..2b65be2d --- /dev/null +++ b/src/client/game/demonware/bit_buffer.cpp @@ -0,0 +1,182 @@ +#include +#include "bit_buffer.hpp" + +namespace demonware +{ + bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output) + { + return this->read(bytes * 8, output); + } + + bool bit_buffer::read_bool(bool* output) + { + if (!this->read_data_type(1)) + { + return false; + } + + return this->read(1, output); + } + + bool bit_buffer::read_uint32(unsigned int* output) + { + if (!this->read_data_type(8)) + { + return false; + } + + return this->read(32, output); + } + + bool bit_buffer::read_data_type(const char expected) + { + char data_type = 0; + + if (!this->use_data_types_) return true; + if (this->read(5, &data_type)) + { + return (data_type == expected); + } + + return false; + } + + bool bit_buffer::write_bytes(const unsigned int bytes, const char* data) + { + return this->write_bytes(bytes, reinterpret_cast(data)); + } + + bool bit_buffer::write_bytes(const unsigned int bytes, const unsigned char* data) + { + return this->write(bytes * 8, data); + } + + bool bit_buffer::write_bool(bool data) + { + if (this->write_data_type(1)) + { + return this->write(1, &data); + } + + return false; + } + + bool bit_buffer::write_int32(int data) + { + if (this->write_data_type(7)) + { + return this->write(32, &data); + } + + return false; + } + + bool bit_buffer::write_uint32(unsigned int data) + { + if (this->write_data_type(8)) + { + return this->write(32, &data); + } + + return false; + } + + bool bit_buffer::write_data_type(char data) + { + if (!this->use_data_types_) + { + return true; + } + + return this->write(5, &data); + } + + bool bit_buffer::read(unsigned int bits, void* output) + { + if (bits == 0) return false; + if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false; + + int cur_byte = this->current_bit_ >> 3; + auto cur_out = 0; + + const char* bytes = this->buffer_.data(); + const auto output_bytes = static_cast(output); + + while (bits > 0) + { + const int min_bit = (bits < 8) ? bits : 8; + const auto this_byte = bytes[cur_byte++] & 0xFF; + const int remain = this->current_bit_ & 7; + + if ((min_bit + remain) <= 8) + { + output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain)); + } + else + { + output_bytes[cur_out] = BYTE( + (0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain)); + } + + cur_out++; + this->current_bit_ += min_bit; + bits -= min_bit; + } + + return true; + } + + bool bit_buffer::write(const unsigned int bits, const void* data) + { + if (bits == 0) return false; + this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1); + + int bit = bits; + const auto bytes = const_cast(this->buffer_.data()); + const auto* input_bytes = static_cast(data); + + while (bit > 0) + { + const int bit_pos = this->current_bit_ & 7; + auto rem_bit = 8 - bit_pos; + const auto this_write = (bit < rem_bit) ? bit : rem_bit; + + const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write))); + const int byte_pos = this->current_bit_ >> 3; + + const BYTE temp_byte = (mask & bytes[byte_pos]); + const BYTE this_bit = ((bits - bit) & 7); + const auto this_byte = (bits - bit) >> 3; + + auto this_data = input_bytes[this_byte]; + + const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0; + + this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit)); + + const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte); + bytes[byte_pos] = out_byte; + + this->current_bit_ += this_write; + bit -= this_write; + } + + return true; + } + + void bit_buffer::set_use_data_types(const bool use_data_types) + { + this->use_data_types_ = use_data_types; + } + + unsigned int bit_buffer::size() const + { + return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0); + } + + std::string& bit_buffer::get_buffer() + { + this->buffer_.resize(this->size()); + return this->buffer_; + } +} diff --git a/src/client/game/demonware/bit_buffer.hpp b/src/client/game/demonware/bit_buffer.hpp new file mode 100644 index 00000000..f2fd5c09 --- /dev/null +++ b/src/client/game/demonware/bit_buffer.hpp @@ -0,0 +1,40 @@ +#pragma once + +namespace demonware +{ + class bit_buffer final + { + public: + bit_buffer() = default; + + explicit bit_buffer(std::string buffer) : buffer_(std::move(buffer)) + { + } + + bool read_bytes(unsigned int bytes, unsigned char* output); + bool read_bool(bool* output); + bool read_uint32(unsigned int* output); + bool read_data_type(char expected); + + bool write_bytes(unsigned int bytes, const char* data); + bool write_bytes(unsigned int bytes, const unsigned char* data); + bool write_bool(bool data); + bool write_int32(int data); + bool write_uint32(unsigned int data); + bool write_data_type(char data); + + bool read(unsigned int bits, void* output); + bool write(unsigned int bits, const void* data); + + void set_use_data_types(bool use_data_types); + + unsigned int size() const; + + std::string& get_buffer(); + + private: + std::string buffer_{}; + unsigned int current_bit_ = 0; + bool use_data_types_ = true; + }; +} diff --git a/src/client/game/demonware/byte_buffer.cpp b/src/client/game/demonware/byte_buffer.cpp new file mode 100644 index 00000000..25673496 --- /dev/null +++ b/src/client/game/demonware/byte_buffer.cpp @@ -0,0 +1,308 @@ +#include +#include "byte_buffer.hpp" + +namespace demonware +{ + bool byte_buffer::read_byte(unsigned char* output) + { + if (!this->read_data_type(3)) return false; + return this->read(1, output); + } + + bool byte_buffer::read_bool(bool* output) + { + if (!this->read_data_type(1)) return false; + return this->read(1, output); + } + + bool byte_buffer::read_int16(short* output) + { + if (!this->read_data_type(5)) return false; + return this->read(2, output); + } + + bool byte_buffer::read_uint16(unsigned short* output) + { + if (!this->read_data_type(6)) return false; + return this->read(2, output); + } + + bool byte_buffer::read_int32(int* output) + { + if (!this->read_data_type(7)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_uint32(unsigned int* output) + { + if (!this->read_data_type(8)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_int64(__int64* output) + { + if (!this->read_data_type(9)) return false; + return this->read(8, output); + } + + bool byte_buffer::read_uint64(unsigned __int64* output) + { + if (!this->read_data_type(10)) return false; + return this->read(8, output); + } + + bool byte_buffer::read_float(float* output) + { + if (!this->read_data_type(13)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_string(std::string* output) + { + char* out_data; + if (this->read_string(&out_data)) + { + output->clear(); + output->append(out_data); + return true; + } + + return false; + } + + bool byte_buffer::read_string(char** output) + { + if (!this->read_data_type(16)) return false; + + *output = const_cast(this->buffer_.data()) + this->current_byte_; + this->current_byte_ += strlen(*output) + 1; + + return true; + } + + bool byte_buffer::read_string(char* output, const int length) + { + if (!this->read_data_type(16)) return false; + + strcpy_s(output, length, const_cast(this->buffer_.data()) + this->current_byte_); + this->current_byte_ += strlen(output) + 1; + + return true; + } + + bool byte_buffer::read_blob(std::string* output) + { + char* out_data; + int length; + if (this->read_blob(&out_data, &length)) + { + output->clear(); + output->append(out_data, length); + return true; + } + + return false; + } + + bool byte_buffer::read_blob(char** output, int* length) + { + if (!this->read_data_type(0x13)) + { + return false; + } + + unsigned int size; + this->read_uint32(&size); + + *output = const_cast(this->buffer_.data()) + this->current_byte_; + *length = static_cast(size); + + this->current_byte_ += size; + + return true; + } + + bool byte_buffer::read_data_type(const char expected) + { + if (!this->use_data_types_) return true; + + char type; + this->read(1, &type); + return type == expected; + } + + bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count, + unsigned int* element_size) + { + if (element_count) *element_count = 0; + if (element_size) *element_size = 0; + + if (!this->read_data_type(expected + 100)) return false; + + uint32_t array_size, el_count; + if (!this->read_uint32(&array_size)) return false; + + this->set_use_data_types(false); + this->read_uint32(&el_count); + this->set_use_data_types(true); + + if (element_count) *element_count = el_count; + if (element_size) *element_size = array_size / el_count; + + return true; + } + + bool byte_buffer::write_byte(char data) + { + this->write_data_type(3); + return this->write(1, &data); + } + + bool byte_buffer::write_bool(bool data) + { + this->write_data_type(1); + return this->write(1, &data); + } + + bool byte_buffer::write_int16(short data) + { + this->write_data_type(5); + return this->write(2, &data); + } + + bool byte_buffer::write_uint16(unsigned short data) + { + this->write_data_type(6); + return this->write(2, &data); + } + + bool byte_buffer::write_int32(int data) + { + this->write_data_type(7); + return this->write(4, &data); + } + + bool byte_buffer::write_uint32(unsigned int data) + { + this->write_data_type(8); + return this->write(4, &data); + } + + bool byte_buffer::write_int64(__int64 data) + { + this->write_data_type(9); + return this->write(8, &data); + } + + bool byte_buffer::write_uint64(unsigned __int64 data) + { + this->write_data_type(10); + return this->write(8, &data); + } + + bool byte_buffer::write_data_type(char data) + { + if (!this->use_data_types_) return true; + return this->write(1, &data); + } + + bool byte_buffer::write_float(float data) + { + this->write_data_type(13); + return this->write(4, &data); + } + + bool byte_buffer::write_string(const std::string& data) + { + return this->write_string(data.data()); + } + + bool byte_buffer::write_string(const char* data) + { + this->write_data_type(16); + return this->write(static_cast(strlen(data)) + 1, data); + } + + bool byte_buffer::write_blob(const std::string& data) + { + return this->write_blob(data.data(), INT(data.size())); + } + + bool byte_buffer::write_blob(const char* data, const int length) + { + this->write_data_type(0x13); + this->write_uint32(length); + + return this->write(length, data); + } + + bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count, + const unsigned int element_size) + { + const auto using_types = this->is_using_data_types(); + this->set_use_data_types(false); + + auto result = this->write_byte(type + 100); + + this->set_use_data_types(true); + result &= this->write_uint32(element_count * element_size); + this->set_use_data_types(false); + + result &= this->write_uint32(element_count); + + this->set_use_data_types(using_types); + return result; + } + + bool byte_buffer::read(const int bytes, void* output) + { + if (bytes + this->current_byte_ > this->buffer_.size()) return false; + + std::memmove(output, this->buffer_.data() + this->current_byte_, bytes); + this->current_byte_ += bytes; + + return true; + } + + bool byte_buffer::write(const int bytes, const void* data) + { + this->buffer_.append(static_cast(data), bytes); + this->current_byte_ += bytes; + return true; + } + + bool byte_buffer::write(const std::string& data) + { + return this->write(static_cast(data.size()), data.data()); + } + + void byte_buffer::set_use_data_types(const bool use_data_types) + { + this->use_data_types_ = use_data_types; + } + + size_t byte_buffer::size() const + { + return this->buffer_.size(); + } + + bool byte_buffer::is_using_data_types() const + { + return use_data_types_; + } + + std::string& byte_buffer::get_buffer() + { + return this->buffer_; + } + + std::string byte_buffer::get_remaining() + { + return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end()); + } + + bool byte_buffer::has_more_data() const + { + return this->buffer_.size() > this->current_byte_; + } +} diff --git a/src/client/game/demonware/byte_buffer.hpp b/src/client/game/demonware/byte_buffer.hpp new file mode 100644 index 00000000..43e462aa --- /dev/null +++ b/src/client/game/demonware/byte_buffer.hpp @@ -0,0 +1,69 @@ +#pragma once + +namespace demonware +{ + class byte_buffer final + { + public: + byte_buffer() = default; + + explicit byte_buffer(std::string buffer) : buffer_(std::move(buffer)) + { + } + + bool read_byte(unsigned char* output); + bool read_bool(bool* output); + bool read_int16(short* output); + bool read_uint16(unsigned short* output); + bool read_int32(int* output); + bool read_uint32(unsigned int* output); + bool read_int64(__int64* output); + bool read_uint64(unsigned __int64* output); + bool read_float(float* output); + bool read_string(char** output); + bool read_string(char* output, int length); + bool read_string(std::string* output); + bool read_blob(char** output, int* length); + bool read_blob(std::string* output); + bool read_data_type(char expected); + + bool read_array_header(unsigned char expected, unsigned int* element_count, + unsigned int* element_size = nullptr); + + bool write_byte(char data); + bool write_bool(bool data); + bool write_int16(short data); + bool write_uint16(unsigned short data); + bool write_int32(int data); + bool write_uint32(unsigned int data); + bool write_int64(__int64 data); + bool write_uint64(unsigned __int64 data); + bool write_data_type(char data); + bool write_float(float data); + bool write_string(const char* data); + bool write_string(const std::string& data); + bool write_blob(const char* data, int length); + bool write_blob(const std::string& data); + + bool write_array_header(unsigned char type, unsigned int element_count, unsigned int element_size); + + bool read(int bytes, void* output); + bool write(int bytes, const void* data); + bool write(const std::string& data); + + void set_use_data_types(bool use_data_types); + size_t size() const; + + bool is_using_data_types() const; + + std::string& get_buffer(); + std::string get_remaining(); + + bool has_more_data() const; + + private: + std::string buffer_; + size_t current_byte_ = 0; + bool use_data_types_ = true; + }; +} diff --git a/src/client/game/demonware/data_types.hpp b/src/client/game/demonware/data_types.hpp new file mode 100644 index 00000000..c7ba4929 --- /dev/null +++ b/src/client/game/demonware/data_types.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include "byte_buffer.hpp" + +namespace demonware +{ + class bdTaskResult + { + public: + virtual ~bdTaskResult() = default; + + virtual void serialize(byte_buffer*) + { + } + + virtual void deserialize(byte_buffer*) + { + } + }; + + class bdFileData final : public bdTaskResult + { + public: + std::string file_data; + + explicit bdFileData(std::string buffer) : file_data(std::move(buffer)) + { + } + + void serialize(byte_buffer* buffer) override + { + buffer->write_blob(this->file_data); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_blob(&this->file_data); + } + }; + + class bdFileInfo final : public bdTaskResult + { + public: + uint64_t file_id; + uint32_t create_time; + uint32_t modified_time; + bool priv; + uint64_t owner_id; + std::string filename; + uint32_t file_size; + + void serialize(byte_buffer* buffer) override + { + buffer->write_uint32(this->file_size); + buffer->write_uint64(this->file_id); + buffer->write_uint32(this->create_time); + buffer->write_uint32(this->modified_time); + buffer->write_bool(this->priv); + buffer->write_uint64(this->owner_id); + buffer->write_string(this->filename); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_uint32(&this->file_size); + buffer->read_uint64(&this->file_id); + buffer->read_uint32(&this->create_time); + buffer->read_uint32(&this->modified_time); + buffer->read_bool(&this->priv); + buffer->read_uint64(&this->owner_id); + buffer->read_string(&this->filename); + } + }; + + class bdTimeStamp final : public bdTaskResult + { + public: + uint32_t unix_time; + + void serialize(byte_buffer* buffer) override + { + buffer->write_uint32(this->unix_time); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_uint32(&this->unix_time); + } + }; + + class bdDMLInfo : public bdTaskResult + { + public: + std::string country_code; // Char [3] + std::string country; // Char [65] + std::string region; // Char [65] + std::string city; // Char [129] + float latitude; + float longitude; + + void serialize(byte_buffer* buffer) override + { + buffer->write_string(this->country_code); + buffer->write_string(this->country); + buffer->write_string(this->region); + buffer->write_string(this->city); + buffer->write_float(this->latitude); + buffer->write_float(this->longitude); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_string(&this->country_code); + buffer->read_string(&this->country); + buffer->read_string(&this->region); + buffer->read_string(&this->city); + buffer->read_float(&this->latitude); + buffer->read_float(&this->longitude); + } + }; + + class bdDMLRawData final : public bdDMLInfo + { + public: + uint32_t asn; // Autonomous System Number. + std::string timezone; + + void serialize(byte_buffer* buffer) override + { + bdDMLInfo::serialize(buffer); + + buffer->write_uint32(this->asn); + buffer->write_string(this->timezone); + } + + void deserialize(byte_buffer* buffer) override + { + bdDMLInfo::deserialize(buffer); + + buffer->read_uint32(&this->asn); + buffer->read_string(&this->timezone); + } + }; +} diff --git a/src/client/game/demonware/keys.cpp b/src/client/game/demonware/keys.cpp new file mode 100644 index 00000000..b5ad226a --- /dev/null +++ b/src/client/game/demonware/keys.cpp @@ -0,0 +1,130 @@ +#include +#include "keys.hpp" + +#include +#include + +namespace demonware +{ + struct data_t + { + char m_session_key[24]; + char m_response[8]; + char m_hmac_key[20]; + char m_enc_key[16]; + char m_dec_key[16]; + } data{}; + + std::string packet_buffer; + + void calculate_hmacs_s1(const char* data_, const unsigned int data_size, const char* key, + const unsigned int key_size, + char* dst, const unsigned int dst_size) + { + char buffer[64]; + unsigned int pos = 0; + unsigned int out_offset = 0; + char count = 1; + std::string result; + + // buffer add key + std::memcpy(&buffer[pos], key, key_size); + pos += key_size; + + // buffer add count + buffer[pos] = count; + pos++; + + // calculate hmac + result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size)); + + // save output + std::memcpy(dst, result.data(), std::min(20u, (dst_size - out_offset))); + out_offset = 20; + + // second loop + while (true) + { + // if we filled the output buffer, exit + if (out_offset >= dst_size) + break; + + // buffer add last result + pos = 0; + std::memcpy(&buffer[pos], result.data(), 20); + pos += 20; + + // buffer add key + std::memcpy(&buffer[pos], key, key_size); + pos += key_size; + + // buffer add count + count++; + buffer[pos] = count; + pos++; + + // calculate hmac + result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size)); + + // save output + std::memcpy(dst + out_offset, result.data(), std::min(20u, (dst_size - out_offset))); + out_offset += 20; + } + } + + void derive_keys_s1() + { + const auto out_1 = utils::cryptography::sha1::compute(packet_buffer); // out_1 size 20 + + auto data_3 = utils::cryptography::hmac_sha1::compute(data.m_session_key, out_1); + + char out_2[16]; + calculate_hmacs_s1(data_3.data(), 20, "CLIENTCHAL", 10, out_2, 16); + + char out_3[72]; + calculate_hmacs_s1(data_3.data(), 20, "BDDATA", 6, out_3, 72); + + std::memcpy(data.m_response, &out_2[8], 8); + std::memcpy(data.m_hmac_key, &out_3[20], 20); + std::memcpy(data.m_dec_key, &out_3[40], 16); + std::memcpy(data.m_enc_key, &out_3[56], 16); + +#ifdef DEBUG + printf("[DW] Response id: %s\n", utils::string::dump_hex(std::string(&out_2[8], 8)).data()); + printf("[DW] Hash verify: %s\n", utils::string::dump_hex(std::string(&out_3[20], 20)).data()); + printf("[DW] AES dec key: %s\n", utils::string::dump_hex(std::string(&out_3[40], 16)).data()); + printf("[DW] AES enc key: %s\n", utils::string::dump_hex(std::string(&out_3[56], 16)).data()); + printf("[DW] Bravo 6, going dark.\n"); +#endif + } + + void queue_packet_to_hash(const std::string& packet) + { + packet_buffer.append(packet); + } + + void set_session_key(const std::string& key) + { + std::memcpy(data.m_session_key, key.data(), 24); + } + + std::string get_decrypt_key() + { + return std::string(data.m_dec_key, 16); + } + + std::string get_encrypt_key() + { + return std::string(data.m_enc_key, 16); + } + + std::string get_hmac_key() + { + return std::string(data.m_hmac_key, 20); + } + + std::string get_response_id() + { + return std::string(data.m_response, 8); + } +} diff --git a/src/client/game/demonware/keys.hpp b/src/client/game/demonware/keys.hpp new file mode 100644 index 00000000..e2d29c69 --- /dev/null +++ b/src/client/game/demonware/keys.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace demonware +{ + void derive_keys_s1(); + void queue_packet_to_hash(const std::string& packet); + void set_session_key(const std::string& key); + std::string get_decrypt_key(); + std::string get_encrypt_key(); + std::string get_hmac_key(); + std::string get_response_id(); +} diff --git a/src/client/game/demonware/reply.cpp b/src/client/game/demonware/reply.cpp new file mode 100644 index 00000000..09c5cc74 --- /dev/null +++ b/src/client/game/demonware/reply.cpp @@ -0,0 +1,87 @@ +#include +#include "keys.hpp" +#include "reply.hpp" +#include "servers/service_server.hpp" + +#include + +namespace demonware +{ + std::string unencrypted_reply::data() + { + byte_buffer result; + result.set_use_data_types(false); + + result.write_int32(static_cast(this->buffer_.size()) + 2); + result.write_bool(false); + result.write_byte(this->type()); + result.write(this->buffer_); + + return result.get_buffer(); + } + + std::string encrypted_reply::data() + { + byte_buffer result; + result.set_use_data_types(false); + + byte_buffer enc_buffer; + enc_buffer.set_use_data_types(false); + + enc_buffer.write_uint32(static_cast(this->buffer_.size())); // service data size CHECKTHIS!! + enc_buffer.write_byte(this->type()); // TASK_REPLY type + enc_buffer.write(this->buffer_); // service data + + auto aligned_data = enc_buffer.get_buffer(); + auto size = aligned_data.size(); + size = ~15 & (size + 15); // 16 byte align + aligned_data.resize(size); + + // seed + std::string seed("\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED", 16); + + // encrypt + const auto enc_data = utils::cryptography::aes::encrypt(aligned_data, seed, demonware::get_encrypt_key()); + + // header : encrypted service data : hash + static auto msg_count = 0; + msg_count++; + + byte_buffer response; + response.set_use_data_types(false); + + response.write_int32(30 + static_cast(enc_data.size())); + response.write_byte(static_cast(0xAB)); + response.write_byte(static_cast(0x85)); + response.write_int32(msg_count); + response.write(16, seed.data()); + response.write(enc_data); + + // hash entire packet and append end + auto hash_data = utils::cryptography::hmac_sha1::compute(response.get_buffer(), demonware::get_hmac_key()); + hash_data.resize(8); + response.write(8, hash_data.data()); + + return response.get_buffer(); + } + + void remote_reply::send(bit_buffer* buffer, const bool encrypted) + { + std::unique_ptr reply; + + if (encrypted) reply = std::make_unique(this->type_, buffer); + else reply = std::make_unique(this->type_, buffer); + + this->server_->send_reply(reply.get()); + } + + void remote_reply::send(byte_buffer* buffer, const bool encrypted) + { + std::unique_ptr reply; + + if (encrypted) reply = std::make_unique(this->type_, buffer); + else reply = std::make_unique(this->type_, buffer); + + this->server_->send_reply(reply.get()); + } +} diff --git a/src/client/game/demonware/reply.hpp b/src/client/game/demonware/reply.hpp new file mode 100644 index 00000000..b7724dfd --- /dev/null +++ b/src/client/game/demonware/reply.hpp @@ -0,0 +1,164 @@ +#pragma once + +#include "bit_buffer.hpp" +#include "byte_buffer.hpp" +#include "data_types.hpp" + +namespace demonware +{ + class reply + { + public: + reply() = default; + + reply(reply&&) = delete; + reply(const reply&) = delete; + reply& operator=(reply&&) = delete; + reply& operator=(const reply&) = delete; + + virtual ~reply() = default; + virtual std::string data() = 0; + }; + + class raw_reply : public reply + { + protected: + std::string buffer_; + + public: + raw_reply() = default; + + explicit raw_reply(std::string data) : buffer_(std::move(data)) + { + } + + std::string data() override + { + return this->buffer_; + } + }; + + class typed_reply : public raw_reply + { + public: + typed_reply(const uint8_t _type) : type_(_type) + { + } + + protected: + uint8_t type() const { return this->type_; } + + private: + uint8_t type_; + }; + + class encrypted_reply final : public typed_reply + { + public: + encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + std::string data() override; + }; + + class unencrypted_reply final : public typed_reply + { + public: + unencrypted_reply(const uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + unencrypted_reply(const uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + std::string data() override; + }; + + class service_server; + + class remote_reply final + { + public: + remote_reply(service_server* server, uint8_t _type) : type_(_type), server_(server) + { + } + + void send(bit_buffer* buffer, bool encrypted); + void send(byte_buffer* buffer, bool encrypted); + + uint8_t type() const { return this->type_; } + + private: + uint8_t type_; + service_server* server_; + }; + + class service_reply final + { + public: + service_reply(service_server* _server, const uint8_t _type, const uint32_t _error) + : type_(_type), error_(_error), reply_(_server, 1) + { + } + + uint64_t send() + { + static uint64_t id = 0x0000000000000000; + const auto transaction_id = ++id; + + byte_buffer buffer; + buffer.write_uint64(transaction_id); + buffer.write_uint32(this->error_); + buffer.write_byte(this->type_); + + if (!this->error_) + { + buffer.write_uint32(uint32_t(this->objects_.size())); + if (!this->objects_.empty()) + { + buffer.write_uint32(uint32_t(this->objects_.size())); + + for (auto& object : this->objects_) + { + object->serialize(&buffer); + } + + this->objects_.clear(); + } + } + else + { + buffer.write_uint64(transaction_id); + } + + this->reply_.send(&buffer, true); + return transaction_id; + } + + void add(const std::shared_ptr& object) + { + this->objects_.push_back(object); + } + + void add(bdTaskResult* object) + { + this->add(std::shared_ptr(object)); + } + + private: + uint8_t type_; + uint32_t error_; + remote_reply reply_; + std::vector> objects_; + }; +} diff --git a/src/client/game/demonware/server_registry.hpp b/src/client/game/demonware/server_registry.hpp new file mode 100644 index 00000000..725e24c6 --- /dev/null +++ b/src/client/game/demonware/server_registry.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "servers/base_server.hpp" +#include + +namespace demonware +{ + template + class server_registry + { + static_assert(std::is_base_of::value, "Invalid server registry type"); + + public: + template + void create(Args&&... args) + { + static_assert(std::is_base_of::value, "Invalid server type"); + + auto server = std::make_unique(std::forward(args)...); + const auto address = server->get_address(); + servers_[address] = std::move(server); + } + + void for_each(const std::function& callback) const + { + for (auto& server : servers_) + { + callback(*server.second); + } + } + + T* find(const std::string& name) + { + const auto address = utils::cryptography::jenkins_one_at_a_time::compute(name); + return find(address); + } + + T* find(const uint32_t address) + { + const auto it = servers_.find(address); + if (it == servers_.end()) + { + return nullptr; + } + + return it->second.get(); + } + + void frame() + { + for (auto& server : servers_) + { + server.second->frame(); + } + } + + private: + std::unordered_map> servers_; + }; +} diff --git a/src/client/game/demonware/servers/auth3_server.cpp b/src/client/game/demonware/servers/auth3_server.cpp new file mode 100644 index 00000000..4f35d427 --- /dev/null +++ b/src/client/game/demonware/servers/auth3_server.cpp @@ -0,0 +1,162 @@ +#include + +#include "auth3_server.hpp" +#include "../keys.hpp" + +#include +#include + +namespace demonware +{ + namespace + { +#pragma pack(push, 1) + struct auth_ticket + { + unsigned int m_magicNumber; + char m_type; + unsigned int m_titleID; + unsigned int m_timeIssued; + unsigned int m_timeExpires; + unsigned __int64 m_licenseID; + unsigned __int64 m_userID; + char m_username[64]; + char m_sessionKey[24]; + char m_usingHashMagicNumber[3]; + char m_hash[4]; + }; +#pragma pack(pop) + } + + void auth3_server::send_reply(reply* data) + { + if (!data) return; + this->send(data->data()); + } + + void auth3_server::handle(const std::string& packet) + { + if (packet.starts_with("POST /auth/")) + { +#ifdef DEBUG + printf("[DW]: [auth]: user requested authentication.\n"); +#endif + return; + } + + unsigned int title_id = 0; + unsigned int iv_seed = 0; + std::string identity{}; + std::string token{}; + + rapidjson::Document j; + j.Parse(packet.data(), packet.size()); + + if (j.HasMember("title_id") && j["title_id"].IsString()) + { + title_id = std::stoul(j["title_id"].GetString()); + } + + if (j.HasMember("iv_seed") && j["iv_seed"].IsString()) + { + iv_seed = std::stoul(j["iv_seed"].GetString()); + } + + if (j.HasMember("extra_data") && j["extra_data"].IsString()) + { + rapidjson::Document extra_data; + auto& ed = j["extra_data"]; + extra_data.Parse(ed.GetString(), ed.GetStringLength()); + + if (extra_data.HasMember("token") && extra_data["token"].IsString()) + { + auto& token_field = extra_data["token"]; + std::string token_b64(token_field.GetString(), token_field.GetStringLength()); + token = utils::cryptography::base64::decode(token_b64); + } + } + +#ifdef DEBUG + printf("[DW]: [auth]: authenticating user %s\n", token.data() + 64); +#endif + + std::string auth_key(reinterpret_cast(token.data() + 32), 24); + std::string session_key( + "\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24); + + // client_ticket + auth_ticket ticket{}; + std::memset(&ticket, 0x0, sizeof ticket); + ticket.m_magicNumber = 0x0EFBDADDE; + ticket.m_type = 0; + ticket.m_titleID = title_id; + ticket.m_timeIssued = static_cast(time(nullptr)); + ticket.m_timeExpires = ticket.m_timeIssued + 30000; + ticket.m_licenseID = 0; + ticket.m_userID = reinterpret_cast(token.data() + 56); + strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast(token.data() + 64), 64); + std::memcpy(ticket.m_sessionKey, session_key.data(), 24); + + const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast(&iv_seed), 4)); + const auto ticket_enc = utils::cryptography::des3::encrypt( + std::string(reinterpret_cast(&ticket), sizeof(ticket)), iv, auth_key); + const auto ticket_b64 = utils::cryptography::base64::encode( + reinterpret_cast(ticket_enc.data()), 128); + + // server_ticket + uint8_t auth_data[128]; + std::memset(&auth_data, 0, sizeof auth_data); + std::memcpy(auth_data, session_key.data(), 24); + const auto auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128); + + demonware::set_session_key(session_key); + + // header time + char date[64]; + const auto now = time(nullptr); + tm gmtm{}; + gmtime_s(&gmtm, &now); + strftime(date, 64, "%a, %d %b %G %T", &gmtm); + + // json content + rapidjson::Document doc; + doc.SetObject(); + + doc.AddMember("auth_task", "29", doc.GetAllocator()); + doc.AddMember("code", "700", doc.GetAllocator()); + + auto seed = std::to_string(iv_seed); + doc.AddMember("iv_seed", rapidjson::StringRef(seed.data(), seed.size()), doc.GetAllocator()); + doc.AddMember("client_ticket", rapidjson::StringRef(ticket_b64.data(), ticket_b64.size()), doc.GetAllocator()); + doc.AddMember("server_ticket", rapidjson::StringRef(auth_data_b64.data(), auth_data_b64.size()), + doc.GetAllocator()); + doc.AddMember("client_id", "", doc.GetAllocator()); + doc.AddMember("account_type", "steam", doc.GetAllocator()); + doc.AddMember("crossplay_enabled", false, doc.GetAllocator()); + doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator()); + + rapidjson::Value value{}; + doc.AddMember("lsg_endpoint", value, doc.GetAllocator()); + + rapidjson::StringBuffer buffer{}; + rapidjson::Writer> + writer(buffer); + doc.Accept(writer); + + // http stuff + std::string result; + result.append("HTTP/1.1 200 OK\r\n"); + result.append("Server: TornadoServer/4.5.3\r\n"); + result.append("Content-Type: application/json\r\n"); + result.append(utils::string::va("Date: %s GMT\r\n", date)); + result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength())); + result.append(buffer.GetString(), buffer.GetLength()); + + raw_reply reply(result); + this->send_reply(&reply); + +#ifdef DEBUG + printf("[DW]: [auth]: user successfully authenticated.\n"); +#endif + } +} diff --git a/src/client/game/demonware/servers/auth3_server.hpp b/src/client/game/demonware/servers/auth3_server.hpp new file mode 100644 index 00000000..e58e73e7 --- /dev/null +++ b/src/client/game/demonware/servers/auth3_server.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "tcp_server.hpp" +#include "../reply.hpp" + +namespace demonware +{ + class auth3_server : public tcp_server + { + public: + using tcp_server::tcp_server; + + private: + void send_reply(reply* data); + void handle(const std::string& packet) override; + }; +} diff --git a/src/client/game/demonware/servers/base_server.cpp b/src/client/game/demonware/servers/base_server.cpp new file mode 100644 index 00000000..727a36a6 --- /dev/null +++ b/src/client/game/demonware/servers/base_server.cpp @@ -0,0 +1,22 @@ +#include +#include "base_server.hpp" + +#include + +namespace demonware +{ + base_server::base_server(std::string name): name_(std::move(name)) + { + this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_); + } + + const std::string& base_server::get_name() const + { + return this->name_; + } + + uint32_t base_server::get_address() const + { + return this->address_; + } +} diff --git a/src/client/game/demonware/servers/base_server.hpp b/src/client/game/demonware/servers/base_server.hpp new file mode 100644 index 00000000..1c3e5aa0 --- /dev/null +++ b/src/client/game/demonware/servers/base_server.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace demonware +{ + class base_server + { + public: + using stream_queue = std::queue; + using data_queue = std::queue; + + base_server(std::string name); + + base_server(base_server&&) = delete; + base_server(const base_server&) = delete; + base_server& operator=(base_server&&) = delete; + base_server& operator=(const base_server&) = delete; + + virtual ~base_server() = default; + + const std::string& get_name() const; + + uint32_t get_address() const; + + virtual void frame() = 0; + + private: + std::string name_; + std::uint32_t address_ = 0; + }; +} diff --git a/src/client/game/demonware/servers/lobby_server.cpp b/src/client/game/demonware/servers/lobby_server.cpp new file mode 100644 index 00000000..822b7912 --- /dev/null +++ b/src/client/game/demonware/servers/lobby_server.cpp @@ -0,0 +1,177 @@ +#include +#include "lobby_server.hpp" + +#include "../services.hpp" +#include "../keys.hpp" + +#include + +namespace demonware +{ + lobby_server::lobby_server(std::string name) : tcp_server(std::move(name)) + { + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + this->register_service(); + }; + + void lobby_server::send_reply(reply* data) + { + if (!data) return; + this->send(data->data()); + } + + void lobby_server::handle(const std::string& packet) + { + byte_buffer buffer(packet); + buffer.set_use_data_types(false); + + try + { + while (buffer.has_more_data()) + { + int size; + buffer.read_int32(&size); + + if (size <= 0) + { + const std::string zero("\x00\x00\x00\x00", 4); + raw_reply reply(zero); + this->send_reply(&reply); + return; + } + else if (size == 0xC8) + { +#ifdef DEBUG + printf("[DW]: [lobby]: received client_header_ack.\n"); +#endif + + int c8; + buffer.read_int32(&c8); + std::string packet_1 = buffer.get_remaining(); + demonware::queue_packet_to_hash(packet_1); + + const std::string packet_2( + "\x16\x00\x00\x00\xab\x81\xd2\x00\x00\x00\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", + 26); + demonware::queue_packet_to_hash(packet_2); + + raw_reply reply(packet_2); + this->send_reply(&reply); +#ifdef DEBUG + printf("[DW]: [lobby]: sending server_header_ack.\n"); +#endif + return; + } + + if (buffer.size() < size_t(size)) return; + + uint8_t check_ab; + buffer.read_byte(&check_ab); + if (check_ab == 0xAB) + { + uint8_t type; + buffer.read_byte(&type); + + if (type == 0x82) + { +#ifdef DEBUG + printf("[DW]: [lobby]: received client_auth.\n"); +#endif + std::string packet_3(packet.data(), packet.size() - 8); // this 8 are client hash check? + + demonware::queue_packet_to_hash(packet_3); + demonware::derive_keys_s1(); + + char buff[14] = "\x0A\x00\x00\x00\xAB\x83"; + std::memcpy(&buff[6], demonware::get_response_id().data(), 8); + std::string response(buff, 14); + + raw_reply reply(response); + this->send_reply(&reply); + +#ifdef DEBUG + printf("[DW]: [lobby]: sending server_auth_done.\n"); +#endif + return; + } + else if (type == 0x85) + { + uint32_t msg_count; + buffer.read_uint32(&msg_count); + + char seed[16]; + buffer.read(16, &seed); + + std::string enc = buffer.get_remaining(); + + char hash[8]; + std::memcpy(hash, &(enc.data()[enc.size() - 8]), 8); + + std::string dec = utils::cryptography::aes::decrypt( + std::string(enc.data(), enc.size() - 8), std::string(seed, 16), + demonware::get_decrypt_key()); + + byte_buffer serv(dec); + serv.set_use_data_types(false); + + uint32_t serv_size; + serv.read_uint32(&serv_size); + + uint8_t magic; // 0x86 + serv.read_byte(&magic); + + uint8_t service_id; + serv.read_byte(&service_id); + + this->call_service(service_id, serv.get_remaining()); + + return; + } + } + + printf("[DW]: [lobby]: ERROR! received unk message.\n"); + return; + } + } + catch (...) + { + } + } + + void lobby_server::call_service(const uint8_t id, const std::string& data) + { + const auto& it = this->services_.find(id); + + if (it != this->services_.end()) + { + it->second->exec_task(this, data); + } + else + { + printf("[DW]: [lobby]: missing service '%s'\n", utils::string::va("%d", id)); + + // return no error + byte_buffer buffer(data); + uint8_t task_id; + buffer.read_byte(&task_id); + + this->create_reply(task_id)->send(); + } + } +} diff --git a/src/client/game/demonware/servers/lobby_server.hpp b/src/client/game/demonware/servers/lobby_server.hpp new file mode 100644 index 00000000..8f1bda94 --- /dev/null +++ b/src/client/game/demonware/servers/lobby_server.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "tcp_server.hpp" +#include "service_server.hpp" +#include "../service.hpp" + +namespace demonware +{ + class lobby_server : public tcp_server, service_server + { + public: + lobby_server(std::string name); + + template + void register_service() + { + static_assert(std::is_base_of::value, "service must inherit from service"); + + auto service = std::make_unique(); + const uint8_t id = service->id(); + + this->services_[id] = std::move(service); + } + + void send_reply(reply* data) override; + + private: + std::unordered_map> services_; + + void handle(const std::string& packet) override; + void call_service(uint8_t id, const std::string& data); + }; +} diff --git a/src/client/game/demonware/servers/service_server.hpp b/src/client/game/demonware/servers/service_server.hpp new file mode 100644 index 00000000..dcf40fe7 --- /dev/null +++ b/src/client/game/demonware/servers/service_server.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "../reply.hpp" + +namespace demonware +{ + class service_server + { + public: + virtual ~service_server() = default; + + virtual std::shared_ptr create_message(uint8_t type) + { + auto reply = std::make_shared(this, type); + return reply; + } + + + virtual std::shared_ptr create_reply(uint8_t type, uint32_t error = 0) + { + auto reply = std::make_shared(this, type, error); + return reply; + } + + virtual void send_reply(reply* data) = 0; + }; +} diff --git a/src/client/game/demonware/servers/stun_server.cpp b/src/client/game/demonware/servers/stun_server.cpp new file mode 100644 index 00000000..0814d5ff --- /dev/null +++ b/src/client/game/demonware/servers/stun_server.cpp @@ -0,0 +1,62 @@ +#include +#include "stun_server.hpp" + +#include "../byte_buffer.hpp" + +namespace demonware +{ + void stun_server::handle(const endpoint_data& endpoint, const std::string& packet) + { + uint8_t type, version, padding; + + byte_buffer buffer(packet); + buffer.set_use_data_types(false); + buffer.read_byte(&type); + buffer.read_byte(&version); + buffer.read_byte(&padding); + + switch (type) + { + case 30: + this->ip_discovery(endpoint); + break; + case 20: + this->nat_discovery(endpoint); + break; + default: + break; + } + } + + void stun_server::ip_discovery(const endpoint_data& endpoint) + { + const uint32_t ip = 0x0100007f; + + byte_buffer buffer; + buffer.set_use_data_types(false); + buffer.write_byte(31); // type + buffer.write_byte(2); // version + buffer.write_byte(0); // version + buffer.write_uint32(ip); // external ip + buffer.write_uint16(3074); // port + + this->send(endpoint, buffer.get_buffer()); + } + + void stun_server::nat_discovery(const endpoint_data& endpoint) + { + const uint32_t ip = 0x0100007f; + + byte_buffer buffer; + buffer.set_use_data_types(false); + buffer.write_byte(21); // type + buffer.write_byte(2); // version + buffer.write_byte(0); // version + buffer.write_uint32(ip); // external ip + buffer.write_uint16(3074); // port + buffer.write_uint32(this->get_address()); // server ip + buffer.write_uint16(3074); // server port + + this->send(endpoint, buffer.get_buffer()); + } +} diff --git a/src/client/game/demonware/servers/stun_server.hpp b/src/client/game/demonware/servers/stun_server.hpp new file mode 100644 index 00000000..cb4192e1 --- /dev/null +++ b/src/client/game/demonware/servers/stun_server.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "udp_server.hpp" + +namespace demonware +{ + class stun_server : public udp_server + { + public: + using udp_server::udp_server; + + private: + void handle(const endpoint_data& endpoint, const std::string& packet) override; + + void ip_discovery(const endpoint_data& endpoint); + void nat_discovery(const endpoint_data& endpoint); + }; +} diff --git a/src/client/game/demonware/servers/tcp_server.cpp b/src/client/game/demonware/servers/tcp_server.cpp new file mode 100644 index 00000000..8e60d20a --- /dev/null +++ b/src/client/game/demonware/servers/tcp_server.cpp @@ -0,0 +1,84 @@ +#include +#include "tcp_server.hpp" + +namespace demonware +{ + void tcp_server::handle_input(const char* buf, size_t size) + { + in_queue_.access([&](data_queue& queue) + { + queue.emplace(buf, size); + }); + } + + size_t tcp_server::handle_output(char* buf, size_t size) + { + if (out_queue_.get_raw().empty()) + { + return 0; + } + + return out_queue_.access([&](stream_queue& queue) + { + for (size_t i = 0; i < size; ++i) + { + if (queue.empty()) + { + return i; + } + + buf[i] = queue.front(); + queue.pop(); + } + + return size; + }); + } + + bool tcp_server::pending_data() + { + return !this->out_queue_.get_raw().empty(); + } + + void tcp_server::frame() + { + if (this->in_queue_.get_raw().empty()) + { + return; + } + + while (true) + { + std::string packet{}; + const auto result = this->in_queue_.access([&](data_queue& queue) + { + if (queue.empty()) + { + return false; + } + + packet = std::move(queue.front()); + queue.pop(); + return true; + }); + + if (!result) + { + break; + } + + this->handle(packet); + } + } + + void tcp_server::send(const std::string& data) + { + out_queue_.access([&](stream_queue& queue) + { + for (const auto& val : data) + { + queue.push(val); + } + }); + } +} diff --git a/src/client/game/demonware/servers/tcp_server.hpp b/src/client/game/demonware/servers/tcp_server.hpp new file mode 100644 index 00000000..3f6967ee --- /dev/null +++ b/src/client/game/demonware/servers/tcp_server.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "base_server.hpp" +#include + +namespace demonware +{ + class tcp_server : public base_server + { + public: + using base_server::base_server; + + void handle_input(const char* buf, size_t size); + size_t handle_output(char* buf, size_t size); + bool pending_data(); + void frame() override; + + protected: + virtual void handle(const std::string& data) = 0; + + void send(const std::string& data); + + private: + utils::concurrency::container in_queue_; + utils::concurrency::container out_queue_; + }; +} diff --git a/src/client/game/demonware/servers/udp_server.cpp b/src/client/game/demonware/servers/udp_server.cpp new file mode 100644 index 00000000..019c3f84 --- /dev/null +++ b/src/client/game/demonware/servers/udp_server.cpp @@ -0,0 +1,103 @@ +#include +#include "udp_server.hpp" + +namespace demonware +{ + void udp_server::handle_input(const char* buf, size_t size, endpoint_data endpoint) + { + in_queue_.access([&](in_queue& queue) + { + in_packet p; + p.data = std::string{buf, size}; + p.endpoint = std::move(endpoint); + + queue.emplace(std::move(p)); + }); + } + + size_t udp_server::handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen) + { + return out_queue_.access([&](socket_queue_map& map) -> size_t + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return 0; + } + + auto& queue = entry->second; + + if (queue.empty()) + { + return 0; + } + + auto data = std::move(queue.front()); + queue.pop(); + + const auto copy_size = std::min(size, data.data.size()); + std::memcpy(buf, data.data.data(), copy_size); + std::memcpy(address, &data.address, sizeof(data.address)); + *addrlen = sizeof(data.address); + + return copy_size; + }); + } + + bool udp_server::pending_data(SOCKET socket) + { + return this->out_queue_.access([&](const socket_queue_map& map) + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return false; + } + + return !entry->second.empty(); + }); + } + + void udp_server::send(const endpoint_data& endpoint, std::string data) + { + out_queue_.access([&](socket_queue_map& map) + { + out_packet p; + p.data = std::move(data); + p.address = endpoint.address; + + map[endpoint.socket].emplace(std::move(p)); + }); + } + + void udp_server::frame() + { + if (this->in_queue_.get_raw().empty()) + { + return; + } + + while (true) + { + in_packet packet{}; + const auto result = this->in_queue_.access([&](in_queue& queue) + { + if (queue.empty()) + { + return false; + } + + packet = std::move(queue.front()); + queue.pop(); + return true; + }); + + if (!result) + { + break; + } + + this->handle(packet.endpoint, std::move(packet.data)); + } + } +} diff --git a/src/client/game/demonware/servers/udp_server.hpp b/src/client/game/demonware/servers/udp_server.hpp new file mode 100644 index 00000000..340c5980 --- /dev/null +++ b/src/client/game/demonware/servers/udp_server.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "base_server.hpp" +#include + +namespace demonware +{ + class udp_server : public base_server + { + public: + struct endpoint_data + { + SOCKET socket{}; + sockaddr_in address{}; + + endpoint_data() = default; + + endpoint_data(const SOCKET sock, const sockaddr* addr, const int size) + { + if (size != sizeof(this->address)) + { + throw std::runtime_error("Invalid size"); + } + + this->socket = sock; + std::memcpy(&this->address, addr, sizeof(this->address)); + } + }; + + using base_server::base_server; + + void handle_input(const char* buf, size_t size, endpoint_data endpoint); + size_t handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen); + bool pending_data(SOCKET socket); + + void frame() override; + + protected: + virtual void handle(const endpoint_data& endpoint, const std::string& data) = 0; + void send(const endpoint_data& endpoint, std::string data); + + private: + struct in_packet + { + std::string data; + endpoint_data endpoint; + }; + + struct out_packet + { + std::string data; + sockaddr_in address; + }; + + using in_queue = std::queue; + using out_queue = std::queue; + using socket_queue_map = std::unordered_map; + + utils::concurrency::container in_queue_; + utils::concurrency::container out_queue_; + }; +} diff --git a/src/client/game/demonware/servers/umbrella_server.cpp b/src/client/game/demonware/servers/umbrella_server.cpp new file mode 100644 index 00000000..cadce9dd --- /dev/null +++ b/src/client/game/demonware/servers/umbrella_server.cpp @@ -0,0 +1,11 @@ +#include + +#include "umbrella_server.hpp" + +namespace demonware +{ + void umbrella_server::handle(const std::string& packet) + { + // TODO: + } +} diff --git a/src/client/game/demonware/servers/umbrella_server.hpp b/src/client/game/demonware/servers/umbrella_server.hpp new file mode 100644 index 00000000..6507270c --- /dev/null +++ b/src/client/game/demonware/servers/umbrella_server.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "tcp_server.hpp" + +namespace demonware +{ + class umbrella_server : public tcp_server + { + public: + using tcp_server::tcp_server; + + private: + void handle(const std::string& packet) override; + }; +} diff --git a/src/client/game/demonware/service.hpp b/src/client/game/demonware/service.hpp new file mode 100644 index 00000000..ada7e845 --- /dev/null +++ b/src/client/game/demonware/service.hpp @@ -0,0 +1,89 @@ +#pragma once +#include +#include "servers/service_server.hpp" + +namespace demonware +{ + class service + { + using callback_t = std::function; + + uint8_t id_; + std::string name_; + std::mutex mutex_; + uint8_t task_id_; + std::map tasks_; + + public: + virtual ~service() = default; + service(service&&) = delete; + service(const service&) = delete; + service& operator=(const service&) = delete; + + service(const uint8_t id, std::string name) : id_(id), name_(std::move(name)), task_id_(0) + { + } + + uint8_t id() const + { + return this->id_; + } + + const std::string& name() const + { + return this->name_; + } + + uint8_t task_id() const + { + return this->task_id_; + } + + virtual void exec_task(service_server* server, const std::string& data) + { + std::lock_guard _(this->mutex_); + + byte_buffer buffer(data); + + buffer.read_byte(&this->task_id_); + + const auto& it = this->tasks_.find(this->task_id_); + + if (it != this->tasks_.end()) + { +#ifdef DEBUG + printf("[DW] %s: executing task '%d'\n", name_.data(), this->task_id_); +#endif + + it->second(server, &buffer); + } + else + { + printf("[DW] %s: missing task '%d'\n", name_.data(), this->task_id_); + + // return no error + server->create_reply(this->task_id_)->send(); + } + } + + protected: + + template + void register_task(const uint8_t id, T (Class::* callback)(Args ...) const) + { + this->tasks_[id] = [this, callback](Args ... args) -> T + { + return (reinterpret_cast(this)->*callback)(args...); + }; + } + + template + void register_task(const uint8_t id, T (Class::* callback)(Args ...)) + { + this->tasks_[id] = [this, callback](Args ... args) -> T + { + return (reinterpret_cast(this)->*callback)(args...); + }; + } + }; +} diff --git a/src/client/game/demonware/services.hpp b/src/client/game/demonware/services.hpp new file mode 100644 index 00000000..c4d2d97a --- /dev/null +++ b/src/client/game/demonware/services.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "bit_buffer.hpp" +#include "byte_buffer.hpp" +#include "data_types.hpp" +#include "reply.hpp" +#include "service.hpp" +#include "servers/service_server.hpp" + +//#include "services/bdTeams.hpp" // 3 +#include "services/bdStats.hpp" // 4 +//#include "services/bdMessaging.hpp" // 6 +#include "services/bdProfiles.hpp" // 8 +#include "services/bdStorage.hpp" // 10 +#include "services/bdTitleUtilities.hpp" // 12 +#include "services/bdBandwidthTest.hpp" // 18 +//#include "services/bdMatchMaking.hpp" // 21 +#include "services/bdCounters.hpp" // 23 +#include "services/bdDML.hpp" // 27 +#include "services/bdGroups.hpp" // 28 +//#include "services/bdCMail.hpp" // 29 +#include "services/bdFacebook.hpp" // 36 +#include "services/bdAnticheat.hpp" // 38 +#include "services/bdContentStreaming.hpp" // 50 +//#include "services/bdTags.hpp" // 52 +#include "services/bdUNK63.hpp" // 63 +#include "services/bdEventLog.hpp" // 67 +#include "services/bdRichPresence.hpp" // 68 +//#include "services/bdTitleUtilities2.hpp" // 72 +#include "services/bdUNK80.hpp" +// AccountLinking // 86 +#include "services/bdPresence.hpp" //103 +#include "services/bdMarketingComms.hpp" //104 +#include "services/bdMatchMaking2.hpp" //138 +#include "services/bdMarketing.hpp" //139 diff --git a/src/client/game/demonware/services/bdAnticheat.cpp b/src/client/game/demonware/services/bdAnticheat.cpp new file mode 100644 index 00000000..9d69e186 --- /dev/null +++ b/src/client/game/demonware/services/bdAnticheat.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdAnticheat::bdAnticheat() : service(38, "bdAnticheat") + { + this->register_task(2, &bdAnticheat::unk2); + this->register_task(4, &bdAnticheat::report_console_details); + } + + void bdAnticheat::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: Read data as soon as needed + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdAnticheat::report_console_details(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: Read data as soon as needed + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdAnticheat.hpp b/src/client/game/demonware/services/bdAnticheat.hpp new file mode 100644 index 00000000..0e65bc2d --- /dev/null +++ b/src/client/game/demonware/services/bdAnticheat.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdAnticheat final : public service + { + public: + bdAnticheat(); + + private: + void unk2(service_server* server, byte_buffer* buffer) const; + void report_console_details(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdBandwidthTest.cpp b/src/client/game/demonware/services/bdBandwidthTest.cpp new file mode 100644 index 00000000..2c41e4d2 --- /dev/null +++ b/src/client/game/demonware/services/bdBandwidthTest.cpp @@ -0,0 +1,27 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + static uint8_t bandwidth_iw6[51] = + { + 0x0F, 0xC1, 0x1C, 0x37, 0xB8, 0xEF, 0x7C, 0xD6, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0xD0, 0x07, + 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x88, 0x13, 0x00, 0x00, 0xF4, 0x01, + 0x00, 0x00, 0x02, 0x0C, 0x88, 0xB3, 0x04, 0x65, 0x89, 0xBF, 0xC3, 0x6A, + 0x27, 0x94, 0xD4, 0x8F + }; + + bdBandwidthTest::bdBandwidthTest() : service(18, "bdBandwidthTest") + { + } + + void bdBandwidthTest::exec_task(service_server* server, const std::string& data) + { + byte_buffer buffer; + buffer.write(sizeof bandwidth_iw6, bandwidth_iw6); + + auto reply = server->create_message(5); + reply->send(&buffer, true); + } +} diff --git a/src/client/game/demonware/services/bdBandwidthTest.hpp b/src/client/game/demonware/services/bdBandwidthTest.hpp new file mode 100644 index 00000000..c4feb8e9 --- /dev/null +++ b/src/client/game/demonware/services/bdBandwidthTest.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdBandwidthTest final : public service + { + public: + bdBandwidthTest(); + + private: + void exec_task(service_server* server, const std::string& data) override; + }; +} diff --git a/src/client/game/demonware/services/bdContentStreaming.cpp b/src/client/game/demonware/services/bdContentStreaming.cpp new file mode 100644 index 00000000..efd4db18 --- /dev/null +++ b/src/client/game/demonware/services/bdContentStreaming.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdContentStreaming::bdContentStreaming() : service(50, "bdContentStreaming") + { + this->register_task(2, &bdContentStreaming::unk2); + this->register_task(3, &bdContentStreaming::unk3); + } + + void bdContentStreaming::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdContentStreaming::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdContentStreaming.hpp b/src/client/game/demonware/services/bdContentStreaming.hpp new file mode 100644 index 00000000..68319662 --- /dev/null +++ b/src/client/game/demonware/services/bdContentStreaming.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdContentStreaming final : public service + { + public: + bdContentStreaming(); + + private: + void unk2(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdCounters.cpp b/src/client/game/demonware/services/bdCounters.cpp new file mode 100644 index 00000000..70aa8736 --- /dev/null +++ b/src/client/game/demonware/services/bdCounters.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdCounters::bdCounters() : service(23, "bdCounters") + { + this->register_task(1, &bdCounters::unk1); + this->register_task(2, &bdCounters::unk2); + } + + void bdCounters::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdCounters::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdCounters.hpp b/src/client/game/demonware/services/bdCounters.hpp new file mode 100644 index 00000000..cc6a6932 --- /dev/null +++ b/src/client/game/demonware/services/bdCounters.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdCounters final : public service + { + public: + bdCounters(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk2(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdDML.cpp b/src/client/game/demonware/services/bdDML.cpp new file mode 100644 index 00000000..75e18ca4 --- /dev/null +++ b/src/client/game/demonware/services/bdDML.cpp @@ -0,0 +1,28 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdDML::bdDML() : service(27, "bdDML") + { + this->register_task(2, &bdDML::get_user_raw_data); + } + + void bdDML::get_user_raw_data(service_server* server, byte_buffer* /*buffer*/) const + { + auto result = new bdDMLRawData; + result->country_code = "US"; + result->country_code = "'Murica"; + result->region = "New York"; + result->city = "New York"; + result->latitude = 0; + result->longitude = 0; + + result->asn = 0x2119; + result->timezone = "+01:00"; + + auto reply = server->create_reply(this->task_id()); + reply->add(result); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdDML.hpp b/src/client/game/demonware/services/bdDML.hpp new file mode 100644 index 00000000..08faa594 --- /dev/null +++ b/src/client/game/demonware/services/bdDML.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdDML final : public service + { + public: + bdDML(); + + private: + void get_user_raw_data(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdEventLog.cpp b/src/client/game/demonware/services/bdEventLog.cpp new file mode 100644 index 00000000..c6eaa2b7 --- /dev/null +++ b/src/client/game/demonware/services/bdEventLog.cpp @@ -0,0 +1,17 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdEventLog::bdEventLog() : service(67, "bdEventLog") + { + this->register_task(6, &bdEventLog::unk6); + } + + void bdEventLog::unk6(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdEventLog.hpp b/src/client/game/demonware/services/bdEventLog.hpp new file mode 100644 index 00000000..ade4912d --- /dev/null +++ b/src/client/game/demonware/services/bdEventLog.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdEventLog final : public service + { + public: + bdEventLog(); + + private: + void unk6(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdFacebook.cpp b/src/client/game/demonware/services/bdFacebook.cpp new file mode 100644 index 00000000..ffa1c5b9 --- /dev/null +++ b/src/client/game/demonware/services/bdFacebook.cpp @@ -0,0 +1,41 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdFacebook::bdFacebook() : service(36, "bdFacebook") + { + this->register_task(1, &bdFacebook::unk1); + this->register_task(3, &bdFacebook::unk3); + this->register_task(7, &bdFacebook::unk7); + this->register_task(8, &bdFacebook::unk8); + } + + void bdFacebook::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdFacebook::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdFacebook::unk7(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdFacebook::unk8(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdFacebook.hpp b/src/client/game/demonware/services/bdFacebook.hpp new file mode 100644 index 00000000..dc12339a --- /dev/null +++ b/src/client/game/demonware/services/bdFacebook.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace demonware +{ + class bdFacebook final : public service + { + public: + bdFacebook(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + void unk7(service_server* server, byte_buffer* buffer) const; + void unk8(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdGroups.cpp b/src/client/game/demonware/services/bdGroups.cpp new file mode 100644 index 00000000..116d5e7e --- /dev/null +++ b/src/client/game/demonware/services/bdGroups.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdGroups::bdGroups() : service(28, "bdGroup") + { + this->register_task(1, &bdGroups::set_groups); + this->register_task(4, &bdGroups::unk4); + } + + void bdGroups::set_groups(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdGroups::unk4(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdGroups.hpp b/src/client/game/demonware/services/bdGroups.hpp new file mode 100644 index 00000000..ff42f1cf --- /dev/null +++ b/src/client/game/demonware/services/bdGroups.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdGroups final : public service + { + public: + bdGroups(); + + private: + void set_groups(service_server* server, byte_buffer* buffer) const; + void unk4(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdMarketing.cpp b/src/client/game/demonware/services/bdMarketing.cpp new file mode 100644 index 00000000..1009cc30 --- /dev/null +++ b/src/client/game/demonware/services/bdMarketing.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdMarketing::bdMarketing() : service(139, "bdMarketing") + { + this->register_task(2, &bdMarketing::unk2); + this->register_task(3, &bdMarketing::unk3); + } + + void bdMarketing::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdMarketing::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdMarketing.hpp b/src/client/game/demonware/services/bdMarketing.hpp new file mode 100644 index 00000000..455e1523 --- /dev/null +++ b/src/client/game/demonware/services/bdMarketing.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdMarketing final : public service + { + public: + bdMarketing(); + + private: + void unk2(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdMarketingComms.cpp b/src/client/game/demonware/services/bdMarketingComms.cpp new file mode 100644 index 00000000..5cbbe7bb --- /dev/null +++ b/src/client/game/demonware/services/bdMarketingComms.cpp @@ -0,0 +1,17 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdMarketingComms::bdMarketingComms() : service(104, "bdMarketingComms") + { + this->register_task(1, &bdMarketingComms::get_messages); + } + + void bdMarketingComms::get_messages(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdMarketingComms.hpp b/src/client/game/demonware/services/bdMarketingComms.hpp new file mode 100644 index 00000000..76179493 --- /dev/null +++ b/src/client/game/demonware/services/bdMarketingComms.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdMarketingComms final : public service + { + public: + bdMarketingComms(); + + private: + void get_messages(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdMatchMaking2.cpp b/src/client/game/demonware/services/bdMatchMaking2.cpp new file mode 100644 index 00000000..7ac7b7a2 --- /dev/null +++ b/src/client/game/demonware/services/bdMatchMaking2.cpp @@ -0,0 +1,49 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdMatchMaking2::bdMatchMaking2() : service(138, "bdMatchMaking2") + { + this->register_task(1, &bdMatchMaking2::unk1); + this->register_task(2, &bdMatchMaking2::unk2); + this->register_task(3, &bdMatchMaking2::unk3); + this->register_task(5, &bdMatchMaking2::unk5); + this->register_task(16, &bdMatchMaking2::unk16); + } + + void bdMatchMaking2::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdMatchMaking2::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdMatchMaking2::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdMatchMaking2::unk5(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdMatchMaking2::unk16(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdMatchMaking2.hpp b/src/client/game/demonware/services/bdMatchMaking2.hpp new file mode 100644 index 00000000..faea8e90 --- /dev/null +++ b/src/client/game/demonware/services/bdMatchMaking2.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace demonware +{ + class bdMatchMaking2 final : public service + { + public: + bdMatchMaking2(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk2(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + void unk5(service_server* server, byte_buffer* buffer) const; + void unk16(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdPresence.cpp b/src/client/game/demonware/services/bdPresence.cpp new file mode 100644 index 00000000..a043a169 --- /dev/null +++ b/src/client/game/demonware/services/bdPresence.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdPresence::bdPresence() : service(103, "bdPresence") + { + this->register_task(1, &bdPresence::unk1); + this->register_task(3, &bdPresence::unk3); + } + + void bdPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdPresence::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdPresence.hpp b/src/client/game/demonware/services/bdPresence.hpp new file mode 100644 index 00000000..df76cae2 --- /dev/null +++ b/src/client/game/demonware/services/bdPresence.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdPresence final : public service + { + public: + bdPresence(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdProfiles.cpp b/src/client/game/demonware/services/bdProfiles.cpp new file mode 100644 index 00000000..ded5fac4 --- /dev/null +++ b/src/client/game/demonware/services/bdProfiles.cpp @@ -0,0 +1,17 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdProfiles::bdProfiles() : service(8, "bdProfiles") + { + this->register_task(3, &bdProfiles::unk3); + } + + void bdProfiles::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdProfiles.hpp b/src/client/game/demonware/services/bdProfiles.hpp new file mode 100644 index 00000000..3c090e86 --- /dev/null +++ b/src/client/game/demonware/services/bdProfiles.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdProfiles final : public service + { + public: + bdProfiles(); + + private: + void unk3(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdRichPresence.cpp b/src/client/game/demonware/services/bdRichPresence.cpp new file mode 100644 index 00000000..917ebbad --- /dev/null +++ b/src/client/game/demonware/services/bdRichPresence.cpp @@ -0,0 +1,25 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdRichPresence::bdRichPresence() : service(68, "bdRichPresence") + { + this->register_task(1, &bdRichPresence::unk1); + this->register_task(2, &bdRichPresence::unk2); + } + + void bdRichPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdRichPresence::unk2(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdRichPresence.hpp b/src/client/game/demonware/services/bdRichPresence.hpp new file mode 100644 index 00000000..c04d91a5 --- /dev/null +++ b/src/client/game/demonware/services/bdRichPresence.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace demonware +{ + class bdRichPresence final : public service + { + public: + bdRichPresence(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk2(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdStats.cpp b/src/client/game/demonware/services/bdStats.cpp new file mode 100644 index 00000000..d01b5709 --- /dev/null +++ b/src/client/game/demonware/services/bdStats.cpp @@ -0,0 +1,49 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdStats::bdStats() : service(4, "bdStats") + { + this->register_task(1, &bdStats::unk1); + this->register_task(3, &bdStats::unk3); // leaderboards + this->register_task(4, &bdStats::unk4); + this->register_task(8, &bdStats::unk8); + this->register_task(11, &bdStats::unk11); + } + + void bdStats::unk1(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdStats::unk3(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdStats::unk4(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdStats::unk8(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdStats::unk11(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdStats.hpp b/src/client/game/demonware/services/bdStats.hpp new file mode 100644 index 00000000..e84a6436 --- /dev/null +++ b/src/client/game/demonware/services/bdStats.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace demonware +{ + class bdStats final : public service + { + public: + bdStats(); + + private: + void unk1(service_server* server, byte_buffer* buffer) const; + void unk3(service_server* server, byte_buffer* buffer) const; + void unk4(service_server* server, byte_buffer* buffer) const; + void unk8(service_server* server, byte_buffer* buffer) const; + void unk11(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdStorage.cpp b/src/client/game/demonware/services/bdStorage.cpp new file mode 100644 index 00000000..1534bffd --- /dev/null +++ b/src/client/game/demonware/services/bdStorage.cpp @@ -0,0 +1,194 @@ +#include +#include "../services.hpp" + +#include +#include +#include + +#include "game/game.hpp" + +namespace demonware +{ + bdStorage::bdStorage() : service(10, "bdStorage") + { + this->register_task(6, &bdStorage::list_publisher_files); + this->register_task(7, &bdStorage::get_publisher_file); + this->register_task(10, &bdStorage::set_user_file); + this->register_task(12, &bdStorage::get_user_file); + this->register_task(13, &bdStorage::unk13); + + this->map_publisher_resource("motd-.*\\.txt", DW_MOTD); + this->map_publisher_resource("ffotd-.*\\.ff", DW_FASTFILE); + this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLISTS); + this->map_publisher_resource("winStoreConfig_[Tt][Uu][0-9]+\\.csv", DW_STORE_CONFIG); + } + + void bdStorage::map_publisher_resource(const std::string& expression, const INT id) + { + auto data = utils::nt::load_resource(id); + this->map_publisher_resource_variant(expression, std::move(data)); + } + + void bdStorage::map_publisher_resource_variant(const std::string& expression, resource_variant resource) + { + if (resource.valueless_by_exception()) + { + throw std::runtime_error("Publisher resource variant is empty!"); + } + + this->publisher_resources_.emplace_back(std::regex{expression}, std::move(resource)); + } + + bool bdStorage::load_publisher_resource(const std::string& name, std::string& buffer) + { + for (const auto& resource : this->publisher_resources_) + { + if (std::regex_match(name, resource.first)) + { + if (std::holds_alternative(resource.second)) + { + buffer = std::get(resource.second); + } + else + { + buffer = std::get(resource.second)(); + } + + return true; + } + } + +#ifdef DEBUG + printf("[DW]: [bdStorage]: missing publisher file: %s\n", name.data()); +#endif + + return false; + } + + void bdStorage::list_publisher_files(service_server* server, byte_buffer* buffer) + { + uint32_t date; + uint16_t num_results, offset; + std::string filename, data; + + buffer->read_uint32(&date); + buffer->read_uint16(&num_results); + buffer->read_uint16(&offset); + buffer->read_string(&filename); + + auto reply = server->create_reply(this->task_id()); + + if (this->load_publisher_resource(filename, data)) + { + auto* info = new bdFileInfo; + + info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); + info->filename = filename; + info->create_time = 0; + info->modified_time = info->create_time; + info->file_size = uint32_t(data.size()); + info->owner_id = 0; + info->priv = false; + + reply->add(info); + } + + reply->send(); + } + + void bdStorage::get_publisher_file(service_server* server, byte_buffer* buffer) + { + std::string filename; + buffer->read_string(&filename); + +#ifdef DEBUG + printf("[DW]: [bdStorage]: loading publisher file: %s\n", filename.data()); +#endif + + std::string data; + + if (this->load_publisher_resource(filename, data)) + { +#ifdef DEBUG + printf("[DW]: [bdStorage]: sending publisher file: %s, size: %lld\n", filename.data(), data.size()); +#endif + + auto reply = server->create_reply(this->task_id()); + reply->add(new bdFileData(data)); + reply->send(); + } + else + { + server->create_reply(this->task_id(), game::BD_NO_FILE)->send(); + } + } + + std::string bdStorage::get_user_file_path(const std::string& name) + { + return "players2/user/" + name; + } + + void bdStorage::set_user_file(service_server* server, byte_buffer* buffer) const + { + bool priv; + uint64_t owner; + std::string game, filename, data; + + buffer->read_string(&game); + buffer->read_string(&filename); + buffer->read_bool(&priv); + buffer->read_blob(&data); + buffer->read_uint64(&owner); + + const auto path = get_user_file_path(filename); + utils::io::write_file(path, data); + + auto* info = new bdFileInfo; + + info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); + info->filename = filename; + info->create_time = uint32_t(time(nullptr)); + info->modified_time = info->create_time; + info->file_size = uint32_t(data.size()); + info->owner_id = owner; + info->priv = priv; + + auto reply = server->create_reply(this->task_id()); + reply->add(info); + reply->send(); + } + + void bdStorage::get_user_file(service_server* server, byte_buffer* buffer) const + { + uint64_t owner{}; + std::string game, filename, platform, data; + + buffer->read_string(&game); + buffer->read_string(&filename); + buffer->read_uint64(&owner); + buffer->read_string(&platform); + +#ifdef DEBUG + printf("[DW]: [bdStorage]: user file: %s, %s, %s\n", game.data(), filename.data(), platform.data()); +#endif + + const auto path = get_user_file_path(filename); + if (utils::io::read_file(path, &data)) + { + auto reply = server->create_reply(this->task_id()); + reply->add(new bdFileData(data)); + reply->send(); + } + else + { + server->create_reply(this->task_id(), game::BD_NO_FILE)->send(); + } + } + + void bdStorage::unk13(service_server* server, byte_buffer* buffer) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdStorage.hpp b/src/client/game/demonware/services/bdStorage.hpp new file mode 100644 index 00000000..05beff67 --- /dev/null +++ b/src/client/game/demonware/services/bdStorage.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace demonware +{ + class bdStorage final : public service + { + public: + bdStorage(); + + private: + using callback = std::function; + using resource_variant = std::variant; + std::vector> publisher_resources_; + + void map_publisher_resource(const std::string& expression, INT id); + void map_publisher_resource_variant(const std::string& expression, resource_variant resource); + bool load_publisher_resource(const std::string& name, std::string& buffer); + + void list_publisher_files(service_server* server, byte_buffer* buffer); + void get_publisher_file(service_server* server, byte_buffer* buffer); + void set_user_file(service_server* server, byte_buffer* buffer) const; + void get_user_file(service_server* server, byte_buffer* buffer) const; + void unk13(service_server* server, byte_buffer* buffer) const; + + static std::string get_user_file_path(const std::string& name); + }; +} diff --git a/src/client/game/demonware/services/bdTitleUtilities.cpp b/src/client/game/demonware/services/bdTitleUtilities.cpp new file mode 100644 index 00000000..8b1f90e9 --- /dev/null +++ b/src/client/game/demonware/services/bdTitleUtilities.cpp @@ -0,0 +1,20 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdTitleUtilities::bdTitleUtilities() : service(12, "bdTitleUtilities") + { + this->register_task(6, &bdTitleUtilities::get_server_time); + } + + void bdTitleUtilities::get_server_time(service_server* server, byte_buffer* /*buffer*/) const + { + auto* const time_result = new bdTimeStamp; + time_result->unix_time = uint32_t(time(nullptr)); + + auto reply = server->create_reply(this->task_id()); + reply->add(time_result); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdTitleUtilities.hpp b/src/client/game/demonware/services/bdTitleUtilities.hpp new file mode 100644 index 00000000..3f57105d --- /dev/null +++ b/src/client/game/demonware/services/bdTitleUtilities.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdTitleUtilities final : public service + { + public: + bdTitleUtilities(); + + private: + void get_server_time(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdUNK63.cpp b/src/client/game/demonware/services/bdUNK63.cpp new file mode 100644 index 00000000..e6f4945a --- /dev/null +++ b/src/client/game/demonware/services/bdUNK63.cpp @@ -0,0 +1,17 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdUNK63::bdUNK63() : service(63, "bdUNK63") + { + //this->register_task(6, "unk6", &bdUNK63::unk6); + } + + void bdUNK63::unk(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdUNK63.hpp b/src/client/game/demonware/services/bdUNK63.hpp new file mode 100644 index 00000000..85ed78bf --- /dev/null +++ b/src/client/game/demonware/services/bdUNK63.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace demonware +{ + class bdUNK63 final : public service + { + public: + bdUNK63(); + + private: + void unk(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/demonware/services/bdUNK80.cpp b/src/client/game/demonware/services/bdUNK80.cpp new file mode 100644 index 00000000..15281dc6 --- /dev/null +++ b/src/client/game/demonware/services/bdUNK80.cpp @@ -0,0 +1,57 @@ +#include +#include "../services.hpp" + +namespace demonware +{ + bdUNK80::bdUNK80() : service(80, "bdUNK80") + { + this->register_task(42, &bdUNK80::unk42); + this->register_task(49, &bdUNK80::unk49); + this->register_task(60, &bdUNK80::unk60); + this->register_task(130, &bdUNK80::unk130); + this->register_task(165, &bdUNK80::unk165); + this->register_task(193, &bdUNK80::unk193); + } + + void bdUNK80::unk42(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdUNK80::unk49(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdUNK80::unk60(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdUNK80::unk130(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdUNK80::unk165(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } + + void bdUNK80::unk193(service_server* server, byte_buffer* /*buffer*/) const + { + // TODO: + auto reply = server->create_reply(this->task_id()); + reply->send(); + } +} diff --git a/src/client/game/demonware/services/bdUNK80.hpp b/src/client/game/demonware/services/bdUNK80.hpp new file mode 100644 index 00000000..3d4026e2 --- /dev/null +++ b/src/client/game/demonware/services/bdUNK80.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace demonware +{ + class bdUNK80 final : public service + { + public: + bdUNK80(); + + private: + void unk42(service_server* server, byte_buffer* buffer) const; + void unk49(service_server* server, byte_buffer* buffer) const; + void unk60(service_server* server, byte_buffer* buffer) const; + void unk130(service_server* server, byte_buffer* buffer) const; + void unk165(service_server* server, byte_buffer* buffer) const; + void unk193(service_server* server, byte_buffer* buffer) const; + }; +} diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp new file mode 100644 index 00000000..5a185e99 --- /dev/null +++ b/src/client/game/dvars.cpp @@ -0,0 +1,547 @@ +#include +#include + +#include "game.hpp" + +namespace dvars +{ + game::dvar_t* con_inputBoxColor = nullptr; + game::dvar_t* con_inputHintBoxColor = nullptr; + game::dvar_t* con_outputBarColor = nullptr; + game::dvar_t* con_outputSliderColor = nullptr; + game::dvar_t* con_outputWindowColor = nullptr; + game::dvar_t* con_inputDvarMatchColor = nullptr; + game::dvar_t* con_inputDvarValueColor = nullptr; + game::dvar_t* con_inputDvarInactiveValueColor = nullptr; + game::dvar_t* con_inputCmdMatchColor = nullptr; + + game::dvar_t* jump_enableFallDamage; + + game::dvar_t* r_fullbright; + game::dvar_t* r_chams; + + std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain) + { + if (domain.vector.min == -FLT_MAX) + { + if (domain.vector.max == FLT_MAX) + { + return utils::string::va("Domain is any %iD vector", components); + } + else + { + return utils::string::va("Domain is any %iD vector with components %g or smaller", components, + domain.vector.max); + } + } + else if (domain.vector.max == FLT_MAX) + { + return utils::string::va("Domain is any %iD vector with components %g or bigger", components, + domain.vector.min); + } + else + { + return utils::string::va("Domain is any %iD vector with components from %g to %g", components, + domain.vector.min, domain.vector.max); + } + } + + std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain) + { + std::string str; + + switch (type) + { + case game::dvar_type::boolean: + return "Domain is 0 or 1"s; + + case game::dvar_type::value: + if (domain.value.min == -FLT_MAX) + { + if (domain.value.max == FLT_MAX) + { + return "Domain is any number"s; + } + + return utils::string::va("Domain is any number %g or smaller", domain.value.max); + } + + if (domain.value.max == FLT_MAX) + { + return utils::string::va("Domain is any number %g or bigger", domain.value.min); + } + + return utils::string::va("Domain is any number from %g to %g", domain.value.min, domain.value.max); + + case game::dvar_type::vec2: + return dvar_get_vector_domain(2, domain); + + case game::dvar_type::rgb: + case game::dvar_type::vec3: + return dvar_get_vector_domain(3, domain); + + case game::dvar_type::vec4: + return dvar_get_vector_domain(4, domain); + + case game::dvar_type::integer: + if (domain.enumeration.stringCount == INT_MIN) + { + if (domain.integer.max == INT_MAX) + { + return "Domain is any integer"s; + } + + return utils::string::va("Domain is any integer %i or smaller", domain.integer.max); + } + + if (domain.integer.max == INT_MAX) + { + return utils::string::va("Domain is any integer %i or bigger", domain.integer.min); + } + + return utils::string::va("Domain is any integer from %i to %i", domain.integer.min, domain.integer.max); + + case game::dvar_type::color: + return "Domain is any 4-component color, in RGBA format"s; + + case game::dvar_type::enumeration: + str = "Domain is one of the following:"s; + + for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index) + { + str += utils::string::va("\n %2i: %s", string_index, domain.enumeration.strings[string_index]); + } + + return str; + + case game::dvar_type::string: + return "Domain is any text"s; + + default: + return utils::string::va("unhandled dvar type '%i'", type); + } + } + + std::vector dvar_list = + { + "accessToSubscriberContent", + "acousticSpikeMaxRange", + "acousticSpikeMinRadius", + "acousticSpikeMinRange", + "acousticSpikeRingSize", + "acousticSpikeSize", + "actionSlotsHide", + "activeAction", + "activeFriendsMaxBackoffLevel", + "activeFriendsNumDayBuckets", + "activeFriendsNumPlayBuckets", + "activeFriendsRefreshDelay", + "activeFriendsSecondsPerBucket", + "aim_accel_turnrate_lerp", + "aim_aimAssistRangeScale", + "aim_alternate_lockon_deflection", + "aim_alternate_lockon_pitch_strength", + "aim_alternate_lockon_region_height", + "aim_alternate_lockon_region_width", + "aim_alternate_lockon_strength", + "aim_assist_min_target_distance", + "aim_assist_script_disable", + "cg_draw2D", + "cg_drawBigFPS", + "cg_drawBreathHint", + "cg_drawBuildName", + "cg_drawFPS", + "cg_drawFPSLabels", + "cg_drawFPSOnly", + "cg_drawFPSScale", + "cg_drawVersion", + "cg_drawVersionX", + "cg_drawVersionY", + "cg_drawViewpos", + "cg_drawgun", + "cg_fov", + "cg_fov_default", + "cg_fov_default_thirdperson", + "cg_fovCompMax", + "cg_fovExtraCam", + "cg_fovMin", + "cg_fovScale", + "cl_maxpackets", + "cl_maxPing", + "com_introPlayed", + "com_isNotice", + "com_maxclients", + "com_maxfps", + "com_maxFrameTime", + "fs_basegame", + "fs_basepath", + "fs_basepath_output", + "fs_cdpath", + "fs_copyfiles", + "fs_debug", + "fs_game", + "fs_homepath", + "fs_ignoreLocalized", + "fs_restrict", + "fs_savepath", + "fs_usedevdir", + "fs_userDocuments", + "fs_usermapdir", + "g_gametype", + "g_hardcore", + "g_listEntity", + "g_loadScripts", + "g_log", + "g_logSync", + "g_logTimeStampInSeconds", + "timescale", // Scale time of each frame ---> "5401" + "g_motd", + "g_scriptMainMenu", + "g_smoothClients", + "g_spawnai", + "g_speed", + "gamedate", + "gamedvr_active", + "gameMode", + "gamename", + "log_party_state", + "logfile", + "m_filter", + "m_forward", + "m_pitch", + "m_side", + "m_yaw", + "r_drawLightmapDrawlists", + "r_drawLitDrawlists", + "r_drawSun", + "r_drawWater", + "r_fog", + "r_fog_depthhack_scale", + "r_fog_disable", + "r_fog_ev_adjust", + "r_fogBaseDist", + "r_fogBaseHeight", + "r_fogColor", + "r_fogHalfDist", + "r_fogHalfHeight", + "r_fogOpacity", + "r_fogSunColor", + "r_fogSunInner", + "r_fogSunOpacity", + "r_fogSunOuter", + "r_fogSunPitch", + "r_fogSunYaw", + "r_fogTweak", + "r_forceLod", + "r_fullbright", + "r_fullPrepass", + "r_fullscreen", + "r_fullscreenWindow", + "r_fxaa", + "r_fxaaSubpixel", + "r_FXAverageColorFunc", + "r_gamma", + "r_glossMap", + "r_glow", + "r_glow_allowed", + "stat_version", + "stats_version_check", + "statsLocationFatal", + "stopspeed", + "storeMapPackMaskToStats", + "stringtable_debug", + "sv_allowAnonymous", + "sv_allowClientConsole", + "sv_allowDownload", + "sv_allowedClan1", + "sv_allowedClan2", + "sv_archiveClientsPositions", + "sv_assistWorkers", + "sv_authenticating", + "sv_bitfieldTracking", + "sv_botsPressAttackBtn", + "sv_cheats", + "sv_checkMinPlayers", + "sv_clientArchive", + "sv_clientFpsLimit", + "sv_clientside", + "sv_clientSideBullets", + "sv_clientSideVehicles", + "sv_connectTimeout", + "sv_cumulThinkTime", + "sv_debugRate", + "sv_debugReliableCmds", + "sv_disableClientConsole", + "sv_dwlsgerror", + "sv_endGameIfISuck", + "sv_error_on_baseline_failure", + "sv_expensive_bullet_time", + "sv_exponentialBackoffAfterNonAckedMsgs", + "sv_externalEventLoop", + "sv_FakeRemoteClient", + "sv_fakeServerLoad", + "sv_fakeServerLoadRand", + "sv_FFCheckSums", + "sv_FFNames", + "sv_floodprotect", + "sv_forceunranked", + "sv_fps", + "sv_hostname", + "sv_hugeSnapshotDelay", + "sv_hugeSnapshotSize", + "sv_iwdNames", + "sv_iwds", + "sv_keywords", + "sv_kickBanTime", + "sv_lastSaveCommitedToDevice", + "sv_local_client_snapshot_msec", + "sv_mapname", + "mapname", + "sv_mapRotation", + "sv_mapRotationCurrent", + "cl_maxpackets", + "sv_maxclients", + "sv_maxPhysExplosionSpheres", + "sv_maxPing", + "sv_maxRate", + "sv_minPing", + "sv_minPingClamp", + "sv_network_fps", + "sv_networkRateSolution", + "sv_noname", + "sv_NoShapshotWarnings", + "sv_numExpBackoffBeforeReleasingCachedSnapshots", + "sv_packet_info", + "sv_padPackets", + "sv_paused", + "sv_playlistFetchInterval", + "sv_privateClients", + "sv_privateClientsForClients", + "sv_privatePassword", + "sv_punkbuster", + "sv_pure", + "sv_reconnectlimit", + "sv_referencedFFCheckSums", + "sv_referencedFFNames", + "sv_referencedIwdNames", + "sv_referencedIwds", + "sv_rejoinTimeout", + "sv_remote_client_snapshot_joiningstate_msec", + "sv_remote_client_snapshot_msec", + "sv_resetOnSpawn", + "sv_restrictedTempEnts", + "sv_rewindPoseArchive", + "sv_running", + "sv_saveDeviceAvailable", + "sv_saveGameAvailable", + "sv_saveGameNotReadable", + "sv_saveOnStartMap", + "sv_serverid", + "sv_showAverageBPS", + "sv_showCommands", + "sv_smp", + "sv_SnapshotManLaw", + "sv_testValue", + "sv_timeout", + "sv_trackFrameMsecThreshold", + "sv_useExtraCompress", + "sv_voice", + "sv_voiceQuality", + "sv_writeConfigStrings", + "sv_wwwBaseURL", + "sv_wwwDlDisconnected", + "sv_wwwDownload", + "sv_zlib_threshold", + "sv_zombietime", + "svwp", + "syncTimeTimeout", + "sys_configSum", + "sys_configureGHz", + "sys_cpuGHz", + "sys_cpuName", + "sys_gpu", + "sys_lockThreads", + "sys_quitMigrateTime", + "sys_smp_allowed", + "sys_SSE", + "sys_sysMB", + "systemlink", + "systemlink_host", + "bot_AllowGrenades", + "bot_autoconnectdefault", + "bot_CloseDistance", + "bot_CrouchDistance", + "bot_difficulty", + "bot_difficultydefault", + "bot_enemies", + "bot_Fov", + "bot_friends", + "bot_GoalRadius", + "bot_MaxAdsTime", + "bot_MaxCrouchTime", + "bot_MaxDeathTime", + "bot_MaxFireTime", + "bot_MaxGrenadeTime", + "bot_MaxPitchTime", + "bot_MaxReactionTime", + "bot_MaxStrafeTime", + "bot_MeleeDist", + "bot_MinAdsTime", + "bot_MinCrouchTime", + "bot_MinDeathTime", + "bot_MinFireTime", + "bot_MinGrenadeTime", + "bot_MinPitchTime", + "bot_MinReactionTime", + "bot_MinStrafeTime", + "bot_PitchDown", + "bot_PitchSpeed", + "bot_PitchSpeedAds", + "bot_PitchUp", + "bot_SprintDistance", + "bot_StrafeChance", + "bot_TargetLeadBias", + "bot_tips", + "bot_UseFriendNames", + "bot_YawSpeed", + "bot_YawSpeedAds", + "custom_roundlimit", + "custom_scorelimit", + "custom_scr_allowannouncer", + "custom_scr_allowbattlechatter", + "custom_scr_bot_difficulty", + "custom_scr_ctf_enemycarriervisible", + "custom_scr_ctf_idleflagreturntime", + "custom_scr_ctf_roundswitch", + "custom_scr_ctf_touchreturn", + "custom_scr_custom_score_assist", + "custom_scr_dem_bombtimer", + "custom_scr_dem_defusetime", + "custom_scr_dem_extratime", + "custom_scr_dem_planttime", + "custom_scr_dem_roundswitch", + "custom_scr_dm_bonus_leader", + "custom_scr_dm_score_assist", + "custom_scr_dm_score_death", + "custom_scr_dm_score_headshot", + "custom_scr_dm_score_kill", + "custom_scr_dm_score_suicide", + "custom_scr_dom_flagcapturetime", + "custom_scr_game_allowkillcam", + "custom_scr_game_forceradar", + "custom_scr_game_hardpoints", + "custom_scr_game_onlyheadshots", + "custom_scr_game_perks", + "custom_scr_game_spectatetype", + "custom_scr_hardcore", + "custom_scr_num_bots", + "custom_scr_num_bots_enemy", + "custom_scr_num_bots_friendly", + "custom_scr_player_forcerespawn", + "custom_scr_player_healthregentime", + "custom_scr_player_maxhealth", + "custom_scr_player_sprintTime", + "custom_scr_rcbomb_notimeout", + "custom_scr_sab_bombtimer", + "custom_scr_sab_defusetime", + "custom_scr_sab_hotpotato", + "custom_scr_sab_planttime", + "custom_scr_sab_roundswitch", + "custom_scr_sd_bombtimer", + "custom_scr_sd_defusetime", + "custom_scr_sd_multibomb", + "custom_scr_sd_planttime", + "custom_scr_sd_roundswitch", + "custom_scr_tdm_bonus_leader", + "custom_scr_tdm_score_death", + "custom_scr_tdm_score_headshot", + "custom_scr_tdm_score_kill", + "custom_scr_tdm_score_suicide", + "custom_scr_team_fftype", + "custom_scr_team_teamkillspawndelay", + "custom_scr_vehicles_enabled", + "name", + "custom_timelimit" + }; + + game::dvar_t* register_int(const std::string& name, int value, int min, int max, + game::DvarFlags flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterInt(hash, "", value, min, max, flags); + } + + game::dvar_t* register_bool(const std::string& name, bool value, + game::DvarFlags flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterBool(hash, "", value, flags); + } + + game::dvar_t* register_string(const std::string& name, const char* value, + game::DvarFlags flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterString(hash, "", value, flags); + } + + + game::dvar_t* register_float(const std::string& name, float value, float min, + float max, game::DvarFlags flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterFloat(hash, "", value, min, max, flags); + } + + game::dvar_t* register_vec4(const std::string& name, float x, float y, float z, + float w, float min, float max, game::DvarFlags flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterVec4(hash, "", x, y, z, w, min, max, flags); + } + + namespace override { + game::dvar_t* register_int(const std::string& name, int value, int min, int max, + const unsigned int flags, bool add_to_list) + { + const auto hash = game::generateHashValue(name.data()); + + if (add_to_list) + { + dvar_list.push_back(name); + } + + return game::Dvar_RegisterInt(hash, "", value, min, max, flags); + } + } +} diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp new file mode 100644 index 00000000..2f68ccff --- /dev/null +++ b/src/client/game/dvars.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "game.hpp" +#include "structs.hpp" +#include + +namespace dvars +{ + extern game::dvar_t* con_inputBoxColor; + extern game::dvar_t* con_inputHintBoxColor; + extern game::dvar_t* con_outputBarColor; + extern game::dvar_t* con_outputSliderColor; + extern game::dvar_t* con_outputWindowColor; + extern game::dvar_t* con_inputDvarMatchColor; + extern game::dvar_t* con_inputDvarValueColor; + extern game::dvar_t* con_inputDvarInactiveValueColor; + extern game::dvar_t* con_inputCmdMatchColor; + + extern game::dvar_t* jump_enableFallDamage; + + extern game::dvar_t* r_fullbright; + extern game::dvar_t* r_chams; + + extern std::vector dvar_list; + + std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain); + std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain); + + game::dvar_t* register_int(const std::string& name, int value, int min, int max, game::DvarFlags flags, bool add_to_list = true); + game::dvar_t* register_bool(const std::string& name, bool value, game::DvarFlags flags, bool add_to_list = true); + game::dvar_t* register_string(const std::string& name, const char* value, game::DvarFlags flags, bool add_to_list = true); + game::dvar_t* register_float(const std::string& name, float value, float min, float max, game::DvarFlags flags, bool add_to_list = true); + game::dvar_t* register_vec4(const std::string& name, float x, float y, float z, float w, float min, float max, game::DvarFlags flags, bool add_to_list = true); + + namespace override { + game::dvar_t* register_int(const std::string& name, int value, int min, int max, const unsigned int flags, bool add_to_list = true); + } +} diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp new file mode 100644 index 00000000..dfb601c9 --- /dev/null +++ b/src/client/game/game.cpp @@ -0,0 +1,100 @@ +#include +#include "game.hpp" + +namespace game +{ + int Cmd_Argc() + { + return cmd_args->argc[cmd_args->nesting]; + } + + const char* Cmd_Argv(const int index) + { + return cmd_args->argv[cmd_args->nesting][index]; + } + + int SV_Cmd_Argc() + { + return sv_cmd_args->argc[sv_cmd_args->nesting]; + } + + const char* SV_Cmd_Argv(const int index) + { + return sv_cmd_args->argv[sv_cmd_args->nesting][index]; + } + + + namespace environment + { + launcher::mode mode = launcher::mode::none; + + launcher::mode translate_surrogate(const launcher::mode _mode) + { + switch (_mode) + { + case launcher::mode::survival: + case launcher::mode::zombies: + return launcher::mode::multiplayer; + default: + return _mode; + } + } + + launcher::mode get_real_mode() + { + if (mode == launcher::mode::none) + { + throw std::runtime_error("Launcher mode not valid. Something must be wrong."); + } + + return mode; + } + + launcher::mode get_mode() + { + return translate_surrogate(get_real_mode()); + } + + bool is_sp() + { + return get_mode() == launcher::mode::singleplayer; + } + + bool is_mp() + { + return get_mode() == launcher::mode::multiplayer; + } + + bool is_dedi() + { + return get_mode() == launcher::mode::server; + } + + void set_mode(const launcher::mode _mode) + { + mode = _mode; + } + + std::string get_string() + { + const auto current_mode = get_real_mode(); + switch (current_mode) + { + case launcher::mode::server: + return "Dedicated Server"; + + case launcher::mode::multiplayer: + return "Multiplayer"; + + case launcher::mode::singleplayer: + return "Singleplayer"; + + case launcher::mode::none: + return "None"; + + default: + return "Unknown (" + std::to_string(static_cast(mode)) + ")"; + } + } + } +} diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp new file mode 100644 index 00000000..47041ca9 --- /dev/null +++ b/src/client/game/game.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "structs.hpp" +#include "launcher/launcher.hpp" + +#define SELECT_VALUE(sp, mp) (game::environment::is_sp() ? (sp) : (mp)) + +#define SERVER_CD_KEY "S1X-CD-Key" + +namespace game +{ + namespace environment + { + launcher::mode get_mode(); + launcher::mode get_real_mode(); + + bool is_sp(); + bool is_mp(); + bool is_dedi(); + + void set_mode(launcher::mode mode); + + std::string get_string(); + } + + template + class symbol + { + public: + symbol(const size_t sp_address, const size_t mp_address) + : sp_object_(reinterpret_cast(sp_address)) + , mp_object_(reinterpret_cast(mp_address)) + { + } + + T* get() const + { + if (environment::is_sp()) + { + return sp_object_; + } + + return mp_object_; + } + + operator T* () const + { + return this->get(); + } + + T* operator->() const + { + return this->get(); + } + + private: + T* sp_object_; + T* mp_object_; + }; + + int Cmd_Argc(); + const char* Cmd_Argv(int index); + + int SV_Cmd_Argc(); + const char* SV_Cmd_Argv(int index); + + bool VirtualLobby_Loaded(); +} + +#include "symbols.hpp" diff --git a/src/client/game/scripting/entity.cpp b/src/client/game/scripting/entity.cpp new file mode 100644 index 00000000..b81dea1b --- /dev/null +++ b/src/client/game/scripting/entity.cpp @@ -0,0 +1,120 @@ +#include +#include "entity.hpp" +#include "script_value.hpp" +#include "execution.hpp" + +namespace scripting +{ + entity::entity() + : entity(0) + { + } + + entity::entity(const entity& other) : entity(other.entity_id_) + { + } + + entity::entity(entity&& other) noexcept + { + this->entity_id_ = other.entity_id_; + other.entity_id_ = 0; + } + + entity::entity(const unsigned int entity_id) + : entity_id_(entity_id) + { + this->add(); + } + + entity::entity(game::scr_entref_t entref) + : entity(game::FindEntityId(entref.entnum, entref.classnum)) + { + } + + entity::~entity() + { + this->release(); + } + + entity& entity::operator=(const entity& other) + { + if (&other != this) + { + this->release(); + this->entity_id_ = other.entity_id_; + this->add(); + } + + return *this; + } + + entity& entity::operator=(entity&& other) noexcept + { + if (&other != this) + { + this->release(); + this->entity_id_ = other.entity_id_; + other.entity_id_ = 0; + } + + return *this; + } + + unsigned int entity::get_entity_id() const + { + return this->entity_id_; + } + + game::scr_entref_t entity::get_entity_reference() const + { + if (!this->entity_id_) + { + const auto not_null = static_cast(~0ui16); + return game::scr_entref_t{not_null, not_null}; + } + + return game::Scr_GetEntityIdRef(this->get_entity_id()); + } + + bool entity::operator==(const entity& other) const noexcept + { + return this->get_entity_id() == other.get_entity_id(); + } + + bool entity::operator!=(const entity& other) const noexcept + { + return !this->operator==(other); + } + + void entity::add() const + { + if (this->entity_id_) + { + game::AddRefToValue(game::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); + } + } + + void entity::release() const + { + if (this->entity_id_) + { + game::RemoveRefToValue(game::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); + } + } + + void entity::set(const std::string& field, const script_value& value) const + { + set_entity_field(*this, field, value); + } + + template <> + script_value entity::get(const std::string& field) const + { + return get_entity_field(*this, field); + } + + script_value entity::call(const std::string& name, const std::vector& arguments) const + { + return call_function(name, *this, arguments); + } +} diff --git a/src/client/game/scripting/entity.hpp b/src/client/game/scripting/entity.hpp new file mode 100644 index 00000000..b1702379 --- /dev/null +++ b/src/client/game/scripting/entity.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "game/game.hpp" +#include "script_value.hpp" + +namespace scripting +{ + class entity final + { + public: + entity(); + entity(unsigned int entity_id); + entity(game::scr_entref_t entref); + + entity(const entity& other); + entity(entity&& other) noexcept; + + ~entity(); + + entity& operator=(const entity& other); + entity& operator=(entity&& other) noexcept; + + void set(const std::string& field, const script_value& value) const; + + template + T get(const std::string& field) const; + + script_value call(const std::string& name, const std::vector& arguments = {}) const; + + unsigned int get_entity_id() const; + game::scr_entref_t get_entity_reference() const; + + bool operator ==(const entity& other) const noexcept; + bool operator !=(const entity& other) const noexcept; + + private: + unsigned int entity_id_; + + void add() const; + void release() const; + }; + + template <> + script_value entity::get(const std::string& field) const; + + template + T entity::get(const std::string& field) const + { + return this->get(field).as(); + } +} diff --git a/src/client/game/scripting/event.hpp b/src/client/game/scripting/event.hpp new file mode 100644 index 00000000..bc1d53e0 --- /dev/null +++ b/src/client/game/scripting/event.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "script_value.hpp" +#include "entity.hpp" + +namespace scripting +{ + struct event + { + std::string name; + entity entity{}; + std::vector arguments; + }; +} diff --git a/src/client/game/scripting/execution.cpp b/src/client/game/scripting/execution.cpp new file mode 100644 index 00000000..ba4e4abd --- /dev/null +++ b/src/client/game/scripting/execution.cpp @@ -0,0 +1,250 @@ +#include +#include "execution.hpp" +#include "safe_execution.hpp" +#include "stack_isolation.hpp" + +#include "component/scripting.hpp" + +namespace scripting +{ + namespace + { + game::VariableValue* allocate_argument() + { + game::VariableValue* value_ptr = ++game::scr_VmPub->top; + ++game::scr_VmPub->inparamcount; + return value_ptr; + } + + void push_value(const script_value& value) + { + auto* value_ptr = allocate_argument(); + *value_ptr = value.get_raw(); + + game::AddRefToValue(value_ptr->type, value_ptr->u); + } + + int get_field_id(const int classnum, const std::string& field) + { + const auto class_id = game::g_classMap[classnum].id; + const auto field_str = game::SL_GetString(field.data(), 0); + const auto _ = gsl::finally([field_str]() + { + game::RemoveRefToValue(game::SCRIPT_STRING, {static_cast(field_str)}); + }); + + const auto offset = game::FindVariable(class_id, field_str); + if (offset) + { + const auto index = 3 * (offset + 0xFA00 * (class_id & 3)); + const auto id = reinterpret_cast(SELECT_VALUE(0x149BB5680, 0x14821DF80))[index]; + return static_cast(id); + } + + return -1; + } + + script_value get_return_value() + { + if (game::scr_VmPub->inparamcount == 0) + { + return {}; + } + + game::Scr_ClearOutParams(); + game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; + game::scr_VmPub->inparamcount = 0; + + return script_value(game::scr_VmPub->top[1 - game::scr_VmPub->outparamcount]); + } + } + + void notify(const entity& entity, const std::string& event, const std::vector& arguments) + { + stack_isolation _; + for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) + { + push_value(*i); + } + + const auto event_id = game::SL_GetString(event.data(), 0); + game::Scr_NotifyId(entity.get_entity_id(), event_id, game::scr_VmPub->inparamcount); + } + + script_value call_function(const std::string& name, const entity& entity, + const std::vector& arguments) + { + const auto entref = entity.get_entity_reference(); + + const auto is_method_call = *reinterpret_cast(&entref) != -1; + const auto function = find_function(name, !is_method_call); + if (function == nullptr) + { + throw std::runtime_error("Unknown "s + (is_method_call ? "method" : "function") + " '" + name + "'"); + } + + stack_isolation _; + + for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) + { + push_value(*i); + } + + game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; + game::scr_VmPub->inparamcount = 0; + + if (!safe_execution::call(function, entref)) + { + throw std::runtime_error( + "Error executing "s + (is_method_call ? "method" : "function") + " '" + name + "'"); + } + + return get_return_value(); + } + + script_value call_function(const std::string& name, const std::vector& arguments) + { + return call_function(name, entity(), arguments); + } + + template <> + script_value call(const std::string& name, const std::vector& arguments) + { + return call_function(name, arguments); + } + + script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments) + { + const auto id = entity.get_entity_id(); + + stack_isolation _; + for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) + { + scripting::push_value(*i); + } + + game::AddRefToObject(id); + + const auto local_id = game::AllocThread(id); + const auto result = game::VM_Execute(local_id, pos, (unsigned int)arguments.size()); + game::RemoveRefToObject(result); + + return get_return_value(); + } + + const char* get_function_pos(const std::string& filename, const std::string& function) + { + if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) + { + throw std::runtime_error("File '" + filename + "' not found"); + }; + + const auto functions = scripting::script_function_table[filename]; + if (functions.find(function) == functions.end()) + { + throw std::runtime_error("Function '" + function + "' in file '" + filename + "' not found"); + } + + return functions.at(function); + } + + script_value call_script_function(const entity& entity, const std::string& filename, + const std::string& function, const std::vector& arguments) + { + const auto pos = get_function_pos(filename, function); + return exec_ent_thread(entity, pos, arguments); + } + + static std::unordered_map> custom_fields; + + script_value get_custom_field(const entity& entity, const std::string& field) + { + auto& fields = custom_fields[entity.get_entity_id()]; + const auto _field = fields.find(field); + if (_field != fields.end()) + { + return _field->second; + } + return {}; + } + + void set_custom_field(const entity& entity, const std::string& field, const script_value& value) + { + const auto id = entity.get_entity_id(); + + if (custom_fields[id].find(field) != custom_fields[id].end()) + { + custom_fields[id][field] = value; + return; + } + + custom_fields[id].insert(std::make_pair(field, value)); + } + + void clear_entity_fields(const entity& entity) + { + const auto id = entity.get_entity_id(); + + if (custom_fields.find(id) != custom_fields.end()) + { + custom_fields[id].clear(); + } + } + + void clear_custom_fields() + { + custom_fields.clear(); + } + + void set_entity_field(const entity& entity, const std::string& field, const script_value& value) + { + const auto entref = entity.get_entity_reference(); + const int id = get_field_id(entref.classnum, field); + + if (id != -1) + { + stack_isolation _; + push_value(value); + + game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; + game::scr_VmPub->inparamcount = 0; + + if (!safe_execution::set_entity_field(entref, id)) + { + throw std::runtime_error("Failed to set value for field '" + field + "'"); + } + } + else + { + // Read custom fields + set_custom_field(entity, field, value); + } + } + + script_value get_entity_field(const entity& entity, const std::string& field) + { + const auto entref = entity.get_entity_reference(); + const auto id = get_field_id(entref.classnum, field); + + if (id != -1) + { + stack_isolation _; + + game::VariableValue value{}; + if (!safe_execution::get_entity_field(entref, id, &value)) + { + throw std::runtime_error("Failed to get value for field '" + field + "'"); + } + + const auto __ = gsl::finally([value]() + { + game::RemoveRefToValue(value.type, value.u); + }); + + return value; + } + + // Add custom fields + return get_custom_field(entity, field); + } +} diff --git a/src/client/game/scripting/execution.hpp b/src/client/game/scripting/execution.hpp new file mode 100644 index 00000000..7fff1840 --- /dev/null +++ b/src/client/game/scripting/execution.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "game/game.hpp" +#include "entity.hpp" +#include "script_value.hpp" + +namespace scripting +{ + script_value call_function(const std::string& name, const std::vector& arguments); + script_value call_function(const std::string& name, const entity& entity, + const std::vector& arguments); + + template + T call(const std::string& name, const std::vector& arguments = {}); + + template <> + script_value call(const std::string& name, const std::vector& arguments); + + template + T call(const std::string& name, const std::vector& arguments) + { + return call(name, arguments).as(); + } + + script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments); + const char* get_function_pos(const std::string& filename, const std::string& function); + script_value call_script_function(const entity& entity, const std::string& filename, + const std::string& function, const std::vector& arguments); + + void clear_entity_fields(const entity& entity); + void clear_custom_fields(); + + void set_entity_field(const entity& entity, const std::string& field, const script_value& value); + script_value get_entity_field(const entity& entity, const std::string& field); + + void notify(const entity& entity, const std::string& event, const std::vector& arguments); +} diff --git a/src/client/game/scripting/function_tables.cpp b/src/client/game/scripting/function_tables.cpp new file mode 100644 index 00000000..6eac3d97 --- /dev/null +++ b/src/client/game/scripting/function_tables.cpp @@ -0,0 +1,1535 @@ +#include + +// This file has been generated. +// Do not touch! + +namespace scripting +{ + std::unordered_map function_map = + { + {"precacheturret", 0}, + {"getweaponarray", 1}, + {"getnumparam", 15}, + {"getnumparam", 16}, + {"spawnturret", 23}, + {"canspawnturret", 24}, + {"assertexcmd", 25}, + {"badplace_delete", 30}, + {"badplace_cylinder", 31}, + {"badplace_arc", 32}, + {"badplace_brush", 33}, + {"assertexcmd0", 44}, + {"isdefined", 46}, + {"isvalidmissile", 47}, + {"isstring", 48}, + {"setomnvar", 49}, + {"getomnvar", 50}, + {"setdvar", 51}, + {"setdynamicdvar", 52}, + {"setdvarifuninitialized", 53}, + {"setdevdvar", 54}, + {"setdevdvarifuninitialized", 55}, + {"getdvar", 56}, + {"getdvarint", 57}, + {"getdvarfloat", 58}, + {"getdvarvector", 59}, + {"gettime", 60}, + {"getutc", 61}, + {"getradiometricunit", 62}, + {"getentbynum", 63}, + {"getweaponmodel", 64}, + {"setsunlight", 68}, + {"resetsunlight", 69}, + {"getweapondisplayname", 92}, + {"getweaponbasename", 93}, + {"getweaponattachments", 94}, + {"getweaponattachmentdisplaynames", 95}, + {"getweaponcamoname", 96}, + {"getweaponreticlename", 97}, + {"getanimlength", 98}, + {"animhasnotetrack", 99}, + {"getnotetracktimes", 100}, + {"spawn", 101}, + {"spawnloopingsound", 103}, + {"bullettrace", 104}, + {"getstartorigin", 108}, + {"getstartangles", 109}, + {"magicgrenademanual", 112}, + {"sub_140311ad0", 117}, + {"sub_140311d80", 118}, + {"sub_140311d90", 119}, + {"sub_140311df0", 120}, + {"sub_140311ef0", 121}, + {"sub_140311f50", 122}, + {"sub_14031fb60", 127}, + {"bullettracepassed", 138}, + {"sighttracepassed", 139}, + {"physicstrace", 140}, + {"playerphysicstrace", 141}, + {"getgroundposition", 142}, + {"getmovedelta", 143}, + {"getangledelta", 144}, + {"getnorthyaw", 145}, + {"setnorthyaw", 172}, + {"setslowmotion", 173}, + {"randomint", 174}, + {"randomfloat", 175}, + {"randomintrange", 176}, + {"randomfloatrange", 177}, + {"sin", 178}, + {"cos", 179}, + {"tan", 180}, + {"asin", 181}, + {"acos", 182}, + {"atan", 183}, + {"castint", 184}, + {"castfloat", 185}, + {"abs", 186}, + {"min", 187}, + {"getnode", 191}, + {"getnodearray", 192}, + {"getallnodes", 193}, + {"getnodesinradius", 194}, + {"getnodesinradiussorted", 195}, + {"getclosestnodeinsight", 196}, + {"isarray", 202}, + {"isai", 203}, + {"getindexforluincstring", 204}, + {"issentient", 205}, + {"max", 221}, + {"floor", 222}, + {"ceil", 223}, + {"exp", 224}, + {"log", 225}, + {"sqrt", 226}, + {"squared", 227}, + {"clamp", 228}, + {"angleclamp360", 229}, + {"angleclamp180", 230}, + {"vectorfromlinetopoint", 231}, + {"pointonsegmentnearesttopoint", 232}, + {"distance", 233}, + {"distance2d", 234}, + {"distancesquared", 235}, + {"length", 236}, + {"length2d", 237}, + {"lengthsquared", 238}, + {"length2dsquared", 239}, + {"closer", 240}, + {"vectordot", 241}, + {"vectorcross", 242}, + {"axistoangles", 243}, + {"visionsetthermal", 244}, + {"visionsetpain", 245}, + {"startservermigration", 246}, + {"setac130ambience", 247}, + {"getmapcustomfield", 248}, + {"spawnsighttrace", 249}, + {"incrementcounter", 250}, + {"getcountertotal", 251}, + {"createthreatbiasgroup", 258}, + {"threatbiasgroupexists", 259}, + {"getthreatbias", 260}, + {"setthreatbias", 261}, + {"setthreatbiasagainstall", 262}, + {"setignoremegroup", 263}, + {"isenemyteam", 264}, + {"vectornormalize", 271}, + {"vectortoangles", 272}, + {"vectortoyaw", 273}, + {"vectorlerp", 274}, + {"anglestoup", 275}, + {"anglestoright", 276}, + {"anglestoforward", 277}, + {"anglesdelta", 278}, + {"combineangles", 279}, + {"transformmove", 280}, + {"rotatevector", 281}, + {"rotatepointaroundvector", 282}, + {"issubstr", 283}, + {"isendstr", 284}, + {"getsubstr", 285}, + {"tolower", 286}, + {"strtok", 287}, + {"stricmp", 288}, + {"ambientplay", 289}, + {"getuavstrengthmax", 290}, + {"getuavstrengthlevelneutral", 291}, + {"getuavstrengthlevelshowenemyfastsweep", 292}, + {"getuavstrengthlevelshowenemydirectional", 293}, + {"blockteamradar", 294}, + {"unblockteamradar", 295}, + {"isteamradarblocked", 296}, + {"sub_140328710", 297}, + {"setmatchdata", 298}, + {"getmatchdata", 299}, + {"sendmatchdata", 300}, + {"clearmatchdata", 301}, + {"setmatchdatadef", 302}, + {"setmatchclientip", 303}, + {"setmatchdataid", 304}, + {"setclientmatchdata", 305}, + {"getclientmatchdata", 306}, + {"setclientmatchdatadef", 307}, + {"sendclientmatchdata", 308}, + {"getbuildversion", 309}, + {"getbuildnumber", 310}, + {"getsystemtime", 311}, + {"getmatchrulesdata", 312}, + {"isusingmatchrulesdata", 313}, + {"kickplayer", 314}, + {"issplitscreen", 315}, + {"setmapcenter", 316}, + {"setgameendtime", 317}, + {"visionsetnaked", 318}, + {"visionsetnight", 319}, + {"visionsetmissilecam", 320}, + {"ambientstop", 321}, + {"precachemodel", 322}, + {"precacheshellshock", 323}, + {"precacheitem", 324}, + {"precachematerial", 325}, + {"precachestring", 326}, + {"precachemenu", 327}, + {"precacherumble", 328}, + {"precachelocationselector", 329}, + {"precacheleaderboards", 330}, + {"loadfx", 331}, + {"playfx", 332}, + {"playfxontag", 333}, + {"stopfxontag", 334}, + {"killfxontag", 335}, + {"playloopedfx", 336}, + {"spawnfx", 337}, + {"triggerfx", 338}, + {"playfxontagforclients", 339}, + {"sub_1403326a0", 340}, + {"sub_14031be80", 341}, + {"setwinningteam", 342}, + {"announcement", 343}, + {"clientannouncement", 344}, + {"setteammode", 345}, + {"getteamscore", 346}, + {"setteamscore", 347}, + {"setclientnamemode", 348}, + {"updateclientnames", 349}, + {"getteamplayersalive", 350}, + {"worldentnumber", 352}, + {"obituary", 353}, + {"positionwouldtelefrag", 354}, + {"canspawn", 355}, + {"getstarttime", 356}, + {"precacheheadicon", 357}, + {"precacheminimapicon", 358}, + {"precachempanim", 359}, + {"maprestart", 360}, + {"exitlevel", 361}, + {"addtestclient", 362}, + {"addagent", 363}, + {"allclientsprint", 365}, + {"clientprint", 366}, + {"mapexists", 367}, + {"isvalidgametype", 368}, + {"setplayerteamrank", 370}, + {"setteamradar", 372}, + {"getteamradar", 373}, + {"setteamradarstrength", 374}, + {"getteamradarstrength", 375}, + {"getuavstrengthmin", 376}, + {"physicsexplosionsphere", 377}, + {"physicsexplosioncylinder", 378}, + {"physicsradiusjolt", 379}, + {"physicsradiusjitter", 380}, + {"setexpfog", 381}, + {"setexpfogext", 382}, + {"setexpfogdvarsonly", 383}, + {"setexpfogextdvarsonly", 384}, + {"setatmosfog", 385}, + {"setatmosfogdvarsonly", 386}, + {"isexplosivedamagemod", 387}, + {"radiusdamage", 388}, + {"setplayerignoreradiusdamage", 389}, + {"glassradiusdamage", 390}, + {"earthquake", 391}, + {"getnumparts", 392}, + {"objective_onentity", 393}, + {"objective_onentitywithrotation", 394}, + {"objective_team", 395}, + {"objective_player", 396}, + {"objective_playerteam", 397}, + {"objective_playerenemyteam", 398}, + {"objective_playermask_hidefromall", 399}, + {"objective_playermask_hidefrom", 400}, + {"objective_playermask_showtoall", 401}, + {"objective_playermask_showto", 402}, + {"iprintln", 403}, + {"iprintlnbold", 404}, + {"getent", 406}, + {"getentarray", 407}, + {"getspawnarray", 408}, + {"spawnplane", 409}, + {"addstruct", 410}, + {"spawnhelicopter", 411}, + {"isalive", 412}, + {"isspawner", 413}, + {"missilecreateattractorent", 414}, + {"missilecreateattractororigin", 415}, + {"missilecreaterepulsorent", 416}, + {"missilecreaterepulsororigin", 417}, + {"missiledeleteattractor", 418}, + {"playsoundatpos", 419}, + {"newhudelem", 420}, + {"newclienthudelem", 421}, + {"newteamhudelem", 422}, + {"resettimeout", 423}, + {"isplayer", 424}, + {"isplayernumber", 425}, + {"getpartname", 426}, + {"weaponfiretime", 427}, + {"weaponclipsize", 428}, + {"weaponisauto", 429}, + {"weaponissemiauto", 430}, + {"weaponisboltaction", 431}, + {"weaponinheritsperks", 432}, + {"weaponburstcount", 433}, + {"weapontype", 434}, + {"weaponclass", 435}, + {"getnextarraykey", 436}, + {"sortbydistance", 437}, + {"tablelookup", 438}, + {"tablelookupbyrow", 439}, + {"tablelookupistring", 440}, + {"tablelookupistringbyrow", 441}, + {"tablelookuprownum", 442}, + {"tableexists", 443}, + {"getmissileowner", 444}, + {"magicbullet", 445}, + {"getweaponflashtagname", 446}, + {"averagepoint", 447}, + {"averagenormal", 448}, + {"getspawnerarray", 449}, + {"playrumbleonposition", 450}, + {"playrumblelooponposition", 451}, + {"stopallrumbles", 452}, + {"soundexists", 453}, + {"setminimap", 460}, + {"setthermalbodymaterial", 461}, + {"getarraykeys", 462}, + {"getfirstarraykey", 463}, + {"getglass", 464}, + {"getglassarray", 465}, + {"getglassorigin", 466}, + {"isglassdestroyed", 467}, + {"destroyglass", 468}, + {"deleteglass", 469}, + {"getentchannelscount", 470}, + {"getentchannelname", 471}, + {"objective_add", 472}, + {"objective_delete", 473}, + {"objective_state", 474}, + {"objective_icon", 475}, + {"objective_position", 476}, + {"objective_current", 477}, + {"weaponinventorytype", 478}, + {"weaponstartammo", 479}, + {"weaponmaxammo", 480}, + {"weaponaltweaponname", 481}, + {"isweaponcliponly", 482}, + {"sub_14030dfc0", 483}, + {"sub_14030e400", 484}, + {"weaponhasthermalscope", 485}, + {"getvehiclenode", 486}, + {"getvehiclenodearray", 487}, + {"getallvehiclenodes", 488}, + {"getactivecount", 489}, + {"precache", 490}, + {"spawnvehicle", 491}, + {"getarray", 492}, + {"pow", 493}, + {"atan2", 494}, + {"botgetmemoryevents", 495}, + {"botautoconnectenabled", 496}, + {"botzonegetcount", 497}, + {"botzonesetteam", 498}, + {"botzonenearestcount", 499}, + {"botmemoryflags", 500}, + {"botflagmemoryevents", 501}, + {"botzonegetindoorpercent", 502}, + {"botsentientswap", 503}, + {"isbot", 504}, + {"isagent", 505}, + {"getmaxagents", 506}, + {"botgetclosestnavigablepoint", 508}, + {"getnodesintrigger", 509}, + {"nodesvisible", 510}, + {"getnodesonpath", 511}, + {"getzonecount", 512}, + {"getzonenearest", 513}, + {"getzonenodes", 514}, + {"getzonepath", 515}, + {"getzoneorigin", 516}, + {"getnodezone", 517}, + {"getzonenodesbydist", 518}, + {"getzonenodeforindex", 519}, + {"getweaponexplosionradius", 520}, + {"nodeexposedtosky", 523}, + {"findentrances", 524}, + {"badplace_global", 525}, + {"getpathdist", 526}, + {"getlinkednodes", 527}, + {"disconnectnodepair", 528}, + {"connectnodepair", 529}, + {"precachesound", 533}, + {"distance2dsquared", 543}, + {"getangledelta3d", 544}, + {"activateclientexploder", 545}, + {"trajectorycalculateinitialvelocity", 546}, + {"trajectorycalculateminimumvelocity", 547}, + {"trajectorycalculateexitangle", 548}, + {"trajectoryestimatedesiredinairtime", 549}, + {"trajectorycomputedeltaheightattime", 550}, + {"trajectorycanattemptaccuratejump", 551}, + {"ispointinvolume", 553}, + {"getscriptablearray", 560}, + {"clearfog", 561}, + {"setleveldopplerpreset", 562}, + {"isusinghdr", 564}, + {"sub_140321c40", 565}, + {"sub_140311a40", 567}, + {"sub_14030ec50", 568}, + {"sub_14030f050", 569}, + {"sub_14030f340", 570}, + {"sub_14030f550", 571}, + {"sub_14030f710", 572}, + {"sub_1403295e0", 573}, + {"sub_140322690", 574}, + {"sub_140329600", 575}, + {"sub_14031a690", 580}, + {"sub_1403163c0", 581}, + {"anglestoaxis", 582}, + {"invertangles", 587}, + {"rotatevectorinverted", 588}, + {"calculatestartorientation", 589}, + {"droptoground", 590}, + {"precachelaser", 592}, + {"getcsplinecount", 593}, + {"getcsplinepointcount", 594}, + {"getcsplinelength", 595}, + {"getcsplinepointid", 596}, + {"getcsplinepointlabel", 597}, + {"getcsplinepointtension", 598}, + {"getcsplinepointposition", 599}, + {"getcsplinepointcorridordims", 600}, + {"getcsplinepointtangent", 601}, + {"getcsplinepointdisttonextpoint", 602}, + {"calccsplineposition", 603}, + {"calccsplinetangent", 604}, + {"calccsplinecorridor", 605}, + {"setnojipscore", 606}, + {"setnojiptime", 607}, + {"getpredictedentityposition", 608}, + {"queuedialog", 615}, + {"triggerportableradarping", 622}, + {"botgetteamlimit", 624}, + {"spawnfxforclient", 625}, + {"botgetteamdifficulty", 626}, + {"loadluifile", 632}, + {"isdedicatedserver", 633}, + {"getplaylistversion", 634}, + {"getplaylistid", 635}, + {"getactiveclientcount", 636}, + {"issquadsmode", 637}, + {"visionsetpostapply", 639}, + {"addbot", 640}, + {"sub_140310ec0", 641}, + {"sub_14031bae0", 642}, + {"sub_14031c2b0", 643}, + {"isalliedsentient", 644}, + {"istestclient", 645}, + {"sub_1402d2850", 646}, + {"sub_140311ff0", 648}, + {"sub_140312040", 649}, + {"sub_140311100", 651}, + {"sub_140314c70", 652}, + {"sub_14030d340", 653}, + {"sub_14030da60", 654}, + {"sub_14030e5c0", 655}, + {"sub_14031fda0", 657}, + {"sub_140317140", 658}, + {"isremovedentity", 659}, + {"tablegetrowcount", 660}, + {"tablegetcolumncount", 661}, + {"batteryusepershot", 662}, + {"batteryreqtouse", 663}, + {"sub_14030e700", 664}, + {"getentityweaponname", 666}, + {"sub_14031fc20", 667}, + {"deployriotshield", 668}, + {"validatecostume", 669}, + {"randomcostume", 670}, + {"shootblank", 671}, + {"debugstringtostring", 673}, + {"sub_140319680", 675}, + {"playcinematicforall", 679}, + {"preloadcinematicforall", 680}, + {"stopcinematicforall", 681}, + {"capsuletracepassed", 682}, + {"sub_14031ca40", 683}, + {"sub_14031e1f0", 684}, + {"sub_140321880", 685}, + {"lootservicestarttrackingplaytime", 687}, + {"sub_1403297b0", 688}, + {"lootservicevalidateplaytime", 689}, + {"recordbreadcrumbdataforplayer", 690}, + {"sub_140317df0", 691}, + {"sysprint", 693}, + {"sub_140337920", 694}, + {"sub_140321ae0", 697}, + {"isonlinegame", 698}, + {"issystemlink", 699}, + {"getstanceandmotionstateforplayer", 701}, + {"sub_1402d3540", 702}, + {"sub_1402d35b0", 703}, + {"sub_140332a70", 704}, + {"sub_140332ae0", 705}, + {"getplaylistname", 706}, + {"getlocaltime", 707}, + {"sub_14032c820", 708}, + {"getchallengeid", 710}, + {"nodegetremotemissilename", 711}, + {"nodehasremotemissileset", 712}, + {"remotemissileenttracetooriginpassed", 713}, + {"bombingruntracepassed", 714}, + {"handlepickupdeployedriotshield", 716}, + {"sub_14032c6b0", 717}, + {"getcostumefromtable", 718}, + {"sub_1402d3460", 720}, + {"getchallenerewarditem", 722}, + {"setentplayerxuidforemblem", 723}, + {"resetentplayerxuidforemblems", 724}, + {"nodesetremotemissilename", 725}, + {"sub_14031aa80", 726}, + {"sub_14031ead0", 727}, + {"iszombie", 728}, + {"sub_14031b670", 729}, + {"sub_14031d3f0", 730}, + {"sub_14031e670", 731}, + {"getactiveplayerlist", 732}, + {"sub_140319200", 733}, + {"sub_140331e00", 734}, + }; + + std::unordered_map method_map = + { + {"thermaldrawdisable", 32768}, + {"heli_setdamagestage", 32770}, + {"playsoundtoteam", 32771}, + {"playsoundtoplayer", 32772}, + {"playerhide", 32773}, + {"playershow", 32774}, + {"showtoplayer", 32775}, + {"threatdetectedtoplayer", 32776}, + {"clearthreatdetected", 32777}, + {"enableplayeruse", 32778}, + {"disableplayeruse", 32779}, + {"enableammogeneration", 32780}, + {"disableammogeneration", 32781}, + {"makescrambler", 32782}, + {"makeportableradar", 32783}, + {"clearscrambler", 32784}, + {"clearportableradar", 32785}, + {"placespawnpoint", 32786}, + {"setteamfortrigger", 32787}, + {"clientclaimtrigger", 32788}, + {"clientreleasetrigger", 32789}, + {"releaseclaimedtrigger", 32790}, + {"isusingonlinedataoffline", 32791}, + {"getrestedtime", 32792}, + {"sendleaderboards", 32793}, + {"isonladder", 32794}, + {"getcorpseanim", 32795}, + {"playerforcedeathanim", 32796}, + {"attach", 32797}, + {"startragdoll", 32803}, + {"thermaldrawenable", 32809}, + {"detach", 32810}, + {"detachall", 32811}, + {"getattachsize", 32812}, + {"getattachmodelname", 32813}, + {"getattachtagname", 32814}, + {"gethighestnodestance", 32820}, + {"doesnodeallowstance", 32821}, + {"getlightcolor", 32835}, + {"setlightcolor", 32836}, + {"getattachignorecollision", 32839}, + {"hidepart", 32840}, + {"hidepartallinstances", 32841}, + {"hideallparts", 32842}, + {"showpart", 32843}, + {"showallparts", 32844}, + {"linkto", 32845}, + {"linktoblendtotag", 32846}, + {"unlink", 32847}, + {"setnormalhealth", 32848}, + {"dodamage", 32849}, + {"show", 32851}, + {"hide", 32852}, + {"disconnectpaths", 32855}, + {"connectpaths", 32856}, + {"disconnectnode", 32857}, + {"connectnode", 32858}, + {"digitaldistortsetparams", 32868}, + {"setmode", 32869}, + {"getmode", 32870}, + {"islinked", 32872}, + {"enablelinkto", 32873}, + {"setpitch", 32876}, + {"scalepitch", 32877}, + {"setvolume", 32878}, + {"scalevolume", 32879}, + {"playsound", 32884}, + {"playloopsound", 32885}, + {"getnormalhealth", 32891}, + {"playerlinkto", 32892}, + {"playerlinktodelta", 32893}, + {"playerlinkweaponviewtodelta", 32894}, + {"playerlinktoabsolute", 32895}, + {"playerlinktoblend", 32896}, + {"playerlinkedoffsetenable", 32897}, + {"setwaypointedgestyle_secondaryarrow", 32898}, + {"setwaypointiconoffscreenonly", 32899}, + {"fadeovertime", 32900}, + {"scaleovertime", 32901}, + {"moveovertime", 32902}, + {"reset", 32903}, + {"destroy", 32904}, + {"setpulsefx", 32905}, + {"setplayernamestring", 32906}, + {"changefontscaleovertime", 32907}, + {"playersetgroundreferenceent", 32913}, + {"dontinterpolate", 32914}, + {"getorigin", 32917}, + {"useby", 32921}, + {"playsoundasmaster", 32922}, + {"playerlinkedoffsetdisable", 32927}, + {"playerlinkedsetviewznear", 32928}, + {"playerlinkedsetusebaseangleforviewclamp", 32929}, + {"lerpviewangleclamp", 32930}, + {"geteye", 32936}, + {"istouching", 32937}, + {"getistouchingentities", 32938}, + {"stoploopsound", 32939}, + {"stopsounds", 32940}, + {"playrumbleonentity", 32941}, + {"playrumblelooponentity", 32942}, + {"stoprumble", 32943}, + {"delete", 32944}, + {"setmodel", 32945}, + {"laseron", 32946}, + {"laseroff", 32947}, + {"thermalvisionon", 32950}, + {"thermalvisionoff", 32951}, + {"thermalvisionfofoverlayon", 32952}, + {"thermalvisionfofoverlayoff", 32953}, + {"autospotoverlayon", 32954}, + {"autospotoverlayoff", 32955}, + {"seteyesonuplinkenabled", 32956}, + {"setcontents", 32958}, + {"makeusable", 32959}, + {"makeunusable", 32960}, + {"makeglobalusable", 32961}, + {"makeglobalunusable", 32962}, + {"settext", 32970}, + {"setmaterial", 32972}, + {"settargetent", 32973}, + {"cleartargetent", 32974}, + {"settimer", 32975}, + {"settimerup", 32976}, + {"settimerstatic", 32977}, + {"settenthstimer", 32978}, + {"settenthstimerup", 32979}, + {"settenthstimerstatic", 32980}, + {"setclock", 32981}, + {"setclockup", 32982}, + {"setvalue", 32983}, + {"setwaypoint", 32984}, + {"setwaypointedgestyle_rotatingicon", 32985}, + {"setcursorhint", 32986}, + {"sethintstring", 32987}, + {"setsecondaryhintstring", 32988}, + {"forceusehinton", 32989}, + {"forceusehintoff", 32990}, + {"makesoft", 32991}, + {"makehard", 32992}, + {"entitywillneverchange", 32993}, + {"startfiring", 32994}, + {"stopfiring", 32995}, + {"isfiringturret", 32996}, + {"startbarrelspin", 32997}, + {"stopbarrelspin", 32998}, + {"getbarrelspinrate", 32999}, + {"remotecontrolturret", 33000}, + {"remotecontrolturretoff", 33001}, + {"shootturret", 33002}, + {"getturretowner", 33003}, + {"giveachievement", 33017}, + {"sub_1402ddb00", 33022}, + {"sub_1402ddcc0", 33023}, + {"setsentryowner", 33027}, + {"setsentrycarrier", 33028}, + {"setturretminimapvisible", 33029}, + {"settargetentity", 33030}, + {"snaptotargetentity", 33031}, + {"cleartargetentity", 33032}, + {"getturrettarget", 33033}, + {"setplayerspread", 33034}, + {"setaispread", 33035}, + {"setsuppressiontime", 33036}, + {"allowstand", 33048}, + {"allowcrouch", 33049}, + {"allowprone", 33050}, + {"sub_1402dd9e0", 33051}, + {"isthrowinggrenade", 33068}, + {"isfiring", 33069}, + {"ismeleeing", 33070}, + {"allowmelee", 33072}, + {"allowfire", 33073}, + {"setconvergencetime", 33075}, + {"setconvergenceheightpercent", 33076}, + {"setturretteam", 33077}, + {"maketurretsolid", 33078}, + {"maketurretoperable", 33079}, + {"maketurretinoperable", 33080}, + {"makeentitysentient", 33081}, + {"freeentitysentient", 33082}, + {"setrightarc", 33109}, + {"setleftarc", 33110}, + {"settoparc", 33111}, + {"setbottomarc", 33112}, + {"setautorotationdelay", 33113}, + {"setdefaultdroppitch", 33114}, + {"restoredefaultdroppitch", 33115}, + {"turretfiredisable", 33116}, + {"getenemyinfo", 33125}, + {"getenemysqdist", 33141}, + {"getclosestenemysqdist", 33142}, + {"setthreatbiasgroup", 33143}, + {"getthreatbiasgroup", 33144}, + {"turretfireenable", 33145}, + {"setturretmodechangewait", 33146}, + {"usetriggerrequirelookat", 33147}, + {"getstance", 33148}, + {"setstance", 33149}, + {"itemweaponsetammo", 33150}, + {"getammocount", 33151}, + {"gettagorigin", 33152}, + {"gettagangles", 33153}, + {"shellshock", 33154}, + {"stunplayer", 33155}, + {"stopshellshock", 33156}, + {"fadeoutshellshock", 33157}, + {"setdepthoffield", 33158}, + {"setviewmodeldepthoffield", 33159}, + {"setmotionblurmovescale", 33160}, + {"getnegotiationstartnode", 33181}, + {"getnegotiationendnode", 33182}, + {"getnegotiationnextnode", 33183}, + {"setmotionblurturnscale", 33197}, + {"setmotionblurzoomscale", 33198}, + {"viewkick", 33199}, + {"localtoworldcoords", 33200}, + {"getentitynumber", 33201}, + {"getentityvelocity", 33202}, + {"enablegrenadetouchdamage", 33203}, + {"disablegrenadetouchdamage", 33204}, + {"enableaimassist", 33205}, + {"lastknowntime", 33216}, + {"lastknownpos", 33217}, + {"disableaimassist", 33236}, + {"entityradiusdamage", 33237}, + {"detonate", 33238}, + {"damageconetrace", 33239}, + {"sightconetrace", 33240}, + {"missilesettargetent", 33241}, + {"missilesettargetpos", 33242}, + {"missilecleartarget", 33243}, + {"missilesetflightmodedirect", 33244}, + {"missilesetflightmodetop", 33245}, + {"getlightintensity", 33246}, + {"setlightintensity", 33247}, + {"isragdoll", 33248}, + {"setmovespeedscale", 33249}, + {"cameralinkto", 33250}, + {"cameraunlink", 33251}, + {"controlslinkto", 33280}, + {"controlsunlink", 33281}, + {"makevehiclesolidcapsule", 33282}, + {"makevehiclesolidsphere", 33284}, + {"remotecontrolvehicle", 33286}, + {"remotecontrolvehicleoff", 33287}, + {"isfiringvehicleturret", 33288}, + {"remotecontrolvehicletarget", 33289}, + {"remotecontrolvehicletargetoff", 33290}, + {"drivevehicleandcontrolturret", 33291}, + {"drivevehicleandcontrolturretoff", 33292}, + {"getplayersetting", 33293}, + {"getlocalplayerprofiledata", 33294}, + {"setlocalplayerprofiledata", 33295}, + {"remotecamerasoundscapeon", 33296}, + {"remotecamerasoundscapeoff", 33297}, + {"setmotiontrackervisible", 33298}, + {"getmotiontrackervisible", 33299}, + {"worldpointinreticle_circle", 33300}, + {"worldpointinreticle_rect", 33301}, + {"getpointinbounds", 33302}, + {"transfermarkstonewscriptmodel", 33303}, + {"setwatersheeting", 33304}, + {"setweaponhudiconoverride", 33307}, + {"getweaponhudiconoverride", 33308}, + {"setempjammed", 33309}, + {"playersetexpfogext", 33310}, + {"playersetexpfog", 33311}, + {"playersetatmosfog", 33312}, + {"isitemunlocked", 33313}, + {"getplayerdata", 33314}, + {"getrankedplayerdata", 33315}, + {"getprivateplayerdata", 33316}, + {"getcoopplayerdata", 33317}, + {"getcommonplayerdata", 33318}, + {"vehicleturretcontroloff", 33319}, + {"isturretready", 33320}, + {"vehicledriveto", 33321}, + {"dospawn", 33322}, + {"isphysveh", 33323}, + {"crash", 33324}, + {"launch", 33325}, + {"disablecrashing", 33326}, + {"enablecrashing", 33327}, + {"setphysvehspeed", 33328}, + {"setconveyorbelt", 33329}, + {"freevehicle", 33330}, + {"setplayerdata", 33347}, + {"setrankedplayerdata", 33348}, + {"setprivateplayerdata", 33349}, + {"setcoopplayerdata", 33350}, + {"setcommonplayerdata", 33351}, + {"getcacplayerdata", 33352}, + {"setcacplayerdata", 33353}, + {"trackerupdate", 33354}, + {"pingplayer", 33355}, + {"buttonpressed", 33356}, + {"sayall", 33357}, + {"sayteam", 33358}, + {"setspawnweapon", 33359}, + {"dropitem", 33360}, + {"dropscavengerbag", 33361}, + {"setjitterparams", 33362}, + {"sethoverparams", 33363}, + {"joltbody", 33364}, + {"getwheelsurface", 33366}, + {"getvehicleowner", 33367}, + {"setvehiclelookattext", 33368}, + {"setvehicleteam", 33369}, + {"neargoalnotifydist", 33370}, + {"setvehgoalpos", 33371}, + {"setgoalyaw", 33372}, + {"cleargoalyaw", 33373}, + {"settargetyaw", 33374}, + {"cleartargetyaw", 33375}, + {"helisetgoal", 33376}, + {"setturrettargetvec", 33377}, + {"setturrettargetent", 33378}, + {"clearturrettargetent", 33379}, + {"canturrettargetpoint", 33380}, + {"setlookatent", 33381}, + {"clearlookatent", 33382}, + {"setweapon", 33383}, + {"fireweapon", 33384}, + {"vehicleturretcontrolon", 33385}, + {"finishplayerdamage", 33386}, + {"suicide", 33387}, + {"closeingamemenu", 33388}, + {"iclientprintln", 33389}, + {"iclientprintlnbold", 33390}, + {"spawn", 33391}, + {"setentertime", 33392}, + {"cloneplayer", 33393}, + {"istalking", 33394}, + {"allowspectateteam", 33395}, + {"forcespectatepov", 33396}, + {"getguid", 33397}, + {"physicslaunchserver", 33398}, + {"physicslaunchserveritem", 33399}, + {"clonebrushmodeltoscriptmodel", 33400}, + {"scriptmodelplayanim", 33401}, + {"scriptmodelclearanim", 33402}, + {"scriptmodelplayanimdeltamotion", 33403}, + {"teleport", 33404}, + {"attachpath", 33405}, + {"getattachpos", 33406}, + {"startpath", 33407}, + {"setswitchnode", 33408}, + {"setwaitspeed", 33409}, + {"finishdamage", 33410}, + {"setspeed", 33411}, + {"setspeedimmediate", 33412}, + {"rotatevehyaw", 33413}, + {"getspeed", 33414}, + {"getvehvelocity", 33415}, + {"getbodyvelocity", 33416}, + {"getsteering", 33417}, + {"getthrottle", 33418}, + {"turnengineoff", 33419}, + {"turnengineon", 33420}, + {"getgoalspeedmph", 33422}, + {"setacceleration", 33423}, + {"setdeceleration", 33424}, + {"resumespeed", 33425}, + {"setyawspeed", 33426}, + {"setyawspeedbyname", 33427}, + {"setmaxpitchroll", 33428}, + {"setairresitance", 33429}, + {"setturningability", 33430}, + {"getxuid", 33431}, + {"getucdidhigh", 33432}, + {"getucdidlow", 33433}, + {"getclanidhigh", 33434}, + {"getclanidlow", 33435}, + {"ishost", 33436}, + {"getspectatingplayer", 33437}, + {"predictstreampos", 33438}, + {"setrank", 33441}, + {"weaponlocknoclearance", 33443}, + {"visionsyncwithplayer", 33444}, + {"showhudsplash", 33445}, + {"setperk", 33446}, + {"hasperk", 33447}, + {"clearperks", 33448}, + {"unsetperk", 33449}, + {"registerparty", 33450}, + {"getfireteammembers", 33451}, + {"moveto", 33454}, + {"movex", 33455}, + {"movey", 33456}, + {"movez", 33457}, + {"gravitymove", 33458}, + {"moveslide", 33459}, + {"stopmoveslide", 33460}, + {"rotateto", 33461}, + {"rotatepitch", 33462}, + {"rotateyaw", 33463}, + {"rotateroll", 33464}, + {"addpitch", 33465}, + {"addyaw", 33466}, + {"addroll", 33467}, + {"vibrate", 33468}, + {"rotatevelocity", 33469}, + {"solid", 33470}, + {"notsolid", 33471}, + {"setcandamage", 33472}, + {"setcanradiusdamage", 33473}, + {"physicslaunchclient", 33474}, + {"setcarddisplayslot", 33477}, + {"kc_regweaponforfxremoval", 33478}, + {"laststandrevive", 33479}, + {"laststand", 33480}, + {"setspectatedefaults", 33481}, + {"getthirdpersoncrosshairoffset", 33482}, + {"disableweaponpickup", 33483}, + {"enableweaponpickup", 33484}, + {"issplitscreenplayer", 33485}, + {"getweaponslistoffhands", 33486}, + {"getweaponslistitems", 33487}, + {"getweaponslistexclusives", 33488}, + {"getweaponslist", 33489}, + {"canplayerplacesentry", 33490}, + {"canplayerplacetank", 33491}, + {"visionsetnakedforplayer", 33492}, + {"visionsetnightforplayer", 33493}, + {"visionsetmissilecamforplayer", 33494}, + {"visionsetthermalforplayer", 33495}, + {"visionsetpainforplayer", 33496}, + {"setblurforplayer", 33497}, + {"getplayerweaponmodel", 33498}, + {"getplayerknifemodel", 33499}, + {"notifyonplayercommand", 33501}, + {"canmantle", 33502}, + {"forcemantle", 33503}, + {"ismantling", 33504}, + {"playfx", 33505}, + {"playerrecoilscaleon", 33506}, + {"playerrecoilscaleoff", 33507}, + {"weaponlockstart", 33508}, + {"weaponlockfinalize", 33509}, + {"weaponlockfree", 33510}, + {"weaponlocktargettooclose", 33511}, + {"issplitscreenplayerprimary", 33512}, + {"markforeyeson", 33513}, + {"issighted", 33514}, + {"getsightedplayers", 33515}, + {"getplayerssightingme", 33516}, + {"getviewmodel", 33517}, + {"fragbuttonpressed", 33518}, + {"secondaryoffhandbuttonpressed", 33519}, + {"getcurrentweaponclipammo", 33520}, + {"setvelocity", 33521}, + {"getviewheight", 33522}, + {"getnormalizedmovement", 33523}, + {"playlocalsound", 33524}, + {"stoplocalsound", 33525}, + {"setweaponammoclip", 33526}, + {"setweaponammostock", 33527}, + {"getweaponammoclip", 33528}, + {"getweaponammostock", 33529}, + {"anyammoforweaponmodes", 33530}, + {"setclientomnvar", 33531}, + {"setclientdvar", 33532}, + {"setclientdvars", 33533}, + {"setclientspawnsighttraces", 33534}, + {"clientspawnsighttracepassed", 33535}, + {"allowads", 33536}, + {"allowjump", 33537}, + {"allowladder", 33538}, + {"allowmantle", 33539}, + {"allowsprint", 33540}, + {"setspreadoverride", 33541}, + {"resetspreadoverride", 33542}, + {"setaimspreadmovementscale", 33543}, + {"setactionslot", 33544}, + {"setviewkickscale", 33545}, + {"getviewkickscale", 33546}, + {"getweaponslistall", 33547}, + {"getweaponslistprimaries", 33548}, + {"getnormalizedcameramovement", 33549}, + {"giveweapon", 33550}, + {"takeweapon", 33551}, + {"takeallweapons", 33552}, + {"getcurrentweapon", 33553}, + {"getcurrentprimaryweapon", 33554}, + {"getcurrentoffhand", 33555}, + {"hasweapon", 33556}, + {"switchtoweapon", 33557}, + {"switchtoweaponimmediate", 33558}, + {"sub_1402e1d60", 33559}, + {"switchtooffhand", 33560}, + {"setoffhandsecondaryclass", 33561}, + {"getoffhandsecondaryclass", 33562}, + {"beginlocationselection", 33563}, + {"endlocationselection", 33564}, + {"disableweapons", 33565}, + {"enableweapons", 33566}, + {"disableoffhandweapons", 33567}, + {"enableoffhandweapons", 33568}, + {"disableweaponswitch", 33569}, + {"enableweaponswitch", 33570}, + {"openpopupmenu", 33571}, + {"openpopupmenunomouse", 33572}, + {"closepopupmenu", 33573}, + {"openmenu", 33574}, + {"closemenu", 33575}, + {"freezecontrols", 33577}, + {"disableusability", 33578}, + {"enableusability", 33579}, + {"setwhizbyspreads", 33580}, + {"setwhizbyradii", 33581}, + {"setchannelvolume", 33584}, + {"givestartammo", 33585}, + {"givemaxammo", 33586}, + {"getfractionstartammo", 33587}, + {"getfractionmaxammo", 33588}, + {"isdualwielding", 33589}, + {"isreloading", 33590}, + {"isswitchingweapon", 33591}, + {"setorigin", 33592}, + {"getvelocity", 33593}, + {"setangles", 33594}, + {"getangles", 33595}, + {"usebuttonpressed", 33596}, + {"attackbuttonpressed", 33597}, + {"adsbuttonpressed", 33598}, + {"meleebuttonpressed", 33599}, + {"playerads", 33600}, + {"isonground", 33601}, + {"isusingturret", 33602}, + {"setviewmodel", 33603}, + {"setoffhandprimaryclass", 33604}, + {"getoffhandprimaryclass", 33605}, + {"sub_14032dff0", 33610}, + {"sub_14032e040", 33611}, + {"enablemousesteer", 33612}, + {"setscriptmoverkillcam", 33613}, + {"usinggamepad", 33614}, + {"forcethirdpersonwhenfollowing", 33615}, + {"disableforcethirdpersonwhenfollowing", 33616}, + {"botsetflag", 33617}, + {"botsetstance", 33618}, + {"botsetscriptmove", 33619}, + {"botsetscriptgoal", 33620}, + {"botsetscriptgoalnode", 33621}, + {"botclearscriptgoal", 33622}, + {"botsetscriptenemy", 33623}, + {"botclearscriptenemy", 33624}, + {"botsetattacker", 33625}, + {"botgetscriptgoal", 33626}, + {"botgetscriptgoalradius", 33627}, + {"botgetscriptgoalyaw", 33628}, + {"botgetscriptgoaltype", 33629}, + {"botgetworldsize", 33631}, + {"botnodeavailable", 33632}, + {"botfindnoderandom", 33633}, + {"botmemoryevent", 33634}, + {"botnodepick", 33636}, + {"bothasscriptgoal", 33637}, + {"botgetpersonality", 33638}, + {"botthrowgrenade", 33639}, + {"botsetpersonality", 33641}, + {"botsetdifficulty", 33642}, + {"botgetdifficulty", 33643}, + {"botgetworldclosestedge", 33644}, + {"botlookatpoint", 33645}, + {"botpredictseepoint", 33646}, + {"botcanseeentity", 33647}, + {"botgetnodesonpath", 33648}, + {"botnodepickmultiple", 33649}, + {"botgetfovdot", 33651}, + {"botsetawareness", 33652}, + {"botpursuingscriptgoal", 33653}, + {"botgetscriptgoalnode", 33654}, + {"botgetimperfectenemyinfo", 33655}, + {"botsetpathingstyle", 33657}, + {"botsetdifficultysetting", 33658}, + {"botgetdifficultysetting", 33659}, + {"botgetpathdist", 33660}, + {"botisrandomized", 33661}, + {"botpressbutton", 33662}, + {"botclearbutton", 33663}, + {"botnodescoremultiple", 33664}, + {"getnodenumber", 33665}, + {"setclientowner", 33666}, + {"setotherent", 33667}, + {"setaisightlinevisible", 33668}, + {"setentityowner", 33669}, + {"nodeisdisconnected", 33670}, + {"getnearestnode", 33671}, + {"makeentitynomeleetarget", 33672}, + {"spawnagent", 33674}, + {"finishagentdamage", 33675}, + {"setagentattacker", 33676}, + {"cloneagent", 33677}, + {"agentcanseesentient", 33678}, + {"setagentwaypoint", 33679}, + {"setgoalpos", 33680}, + {"getgoalpos", 33681}, + {"setgoalnode", 33682}, + {"setgoalentity", 33683}, + {"setgoalradius", 33684}, + {"setanimscale", 33685}, + {"setorientmode", 33686}, + {"setanimmode", 33687}, + {"setphysicsmode", 33688}, + {"setclipmode", 33689}, + {"setmaxturnspeed", 33690}, + {"getmaxturnspeed", 33691}, + {"beginmelee", 33692}, + {"setscripted", 33693}, + {"dotrajectory", 33694}, + {"doanimlerp", 33695}, + {"setviewheight", 33696}, + {"claimnode", 33697}, + {"relinquishclaimednode", 33698}, + {"setradarping", 33699}, + {"visitfxent", 33700}, + {"sub_1402ef480", 33701}, + {"sub_1402ef4e0", 33702}, + {"sub_1402dd560", 33704}, + {"sub_1402dd590", 33705}, + {"allowhighjump", 33714}, + {"isjumping", 33715}, + {"ishighjumping", 33716}, + {"sub_140529a10", 33717}, + {"sub_140529a20", 33718}, + {"getbraggingright", 33719}, + {"getmodelfromentity", 33720}, + {"getweaponheatlevel", 33721}, + {"isweaponoverheated", 33722}, + {"isshiftbuttonpresseddown", 33723}, + {"sub_14052be00", 33724}, + {"sub_14052beb0", 33725}, + {"sub_14052bf30", 33726}, + {"lightsetforplayer", 33728}, + {"lightsetoverrideenableforplayer", 33729}, + {"lightsetoverridedisableforplayer", 33730}, + {"sub_140333c10", 33731}, + {"sub_140043710", 33732}, + {"sub_14052b420", 33733}, + {"sub_1402ddd70", 33734}, + {"setanimclass", 33744}, + {"enableanimstate", 33745}, + {"setanimstate", 33746}, + {"getanimentry", 33747}, + {"getanimentryname", 33748}, + {"getanimentryalias", 33749}, + {"getanimentrycount", 33750}, + {"issprinting", 33752}, + {"jumpbuttonpressed", 33758}, + {"rotateby", 33759}, + {"getlookaheaddir", 33760}, + {"getpathgoalpos", 33761}, + {"sub_140316940", 33762}, + {"setcorpsefalling", 33763}, + {"setsurfacetype", 33764}, + {"aiphysicstrace", 33765}, + {"aiphysicstracepassed", 33766}, + {"visionsetstage", 33770}, + {"linkwaypointtotargetwithoffset", 33771}, + {"getlinkedparent", 33772}, + {"getmovingplatformparent", 33773}, + {"setnameplatematerial", 33774}, + {"sub_140313d20", 33777}, + {"sub_1403131d0", 33778}, + {"makevehiclenotcollidewithplayers", 33779}, + {"setscriptablepartstate", 33782}, + {"stopsliding", 33783}, + {"sub_140316a60", 33784}, + {"setdronegoalpos", 33785}, + {"hudoutlineenable", 33786}, + {"hudoutlinedisable", 33787}, + {"worldpointtoscreenpos", 33792}, + {"botfirstavailablegrenade", 33795}, + {"emissiveblend", 33801}, + {"sub_1402e66d0", 33804}, + {"sub_1402e66e0", 33805}, + {"sub_1402e66f0", 33806}, + {"physicssetmaxlinvel", 33810}, + {"physicssetmaxangvel", 33811}, + {"physicsgetlinvel", 33812}, + {"physicsgetlinspeed", 33813}, + {"physicsgetangvel", 33814}, + {"physicsgetangspeed", 33815}, + {"disablemissileboosting", 33816}, + {"enablemissileboosting", 33817}, + {"canspawntestclient", 33818}, + {"spawntestclient", 33819}, + {"loadcustomizationplayerview", 33820}, + {"setgrenadethrowscale", 33821}, + {"setgrenadecookscale", 33822}, + {"setplanesplineid", 33823}, + {"hudoutlineenableforclient", 33824}, + {"hudoutlinedisableforclient", 33825}, + {"hudoutlineenableforclients", 33826}, + {"hudoutlinedisableforclients", 33827}, + {"turretsetbarrelspinenabled", 33828}, + {"hasloadedcustomizationplayerview", 33829}, + {"sub_140313420", 33830}, + {"sub_1403136f0", 33831}, + {"doanimrelative", 33832}, + {"getcorpseentity", 33836}, + {"logmatchdatalife", 33838}, + {"logmatchdatadeath", 33839}, + {"queuedialogforplayer", 33840}, + {"setmlgcameradefaults", 33841}, + {"ismlgspectator", 33842}, + {"disableautoreload", 33843}, + {"enableautoreload", 33844}, + {"getlinkedchildren", 33846}, + {"botpredictenemycampspots", 33847}, + {"playsoundonmovingent", 33848}, + {"cancelmantle", 33849}, + {"hasfemalecustomizationmodel", 33850}, + {"sub_1402e6bb0", 33851}, + {"setscriptabledamageowner", 33852}, + {"setfxkilldefondelete", 33853}, + {"sub_1402e1b80", 33856}, + {"sub_140310fb0", 33858}, + {"challengenotification", 33859}, + {"sub_140528300", 33860}, + {"sub_14052bff0", 33861}, + {"linktosynchronizedparent", 33862}, + {"getclientomnvar", 33863}, + {"getcacplayerdataforgroup", 33866}, + {"cloakingenable", 33867}, + {"cloakingdisable", 33868}, + {"getunnormalizedcameramovement", 33869}, + {"sub_14031edf0", 33870}, + {"isturretoverheated", 33871}, + {"sub_14052c170", 33872}, + {"sub_14052c190", 33873}, + {"sub_14052c1b0", 33874}, + {"sub_14052c1d0", 33875}, + {"sub_14052c0b0", 33878}, + {"sub_1402de140", 33879}, + {"getvieworigin", 33884}, + {"setweaponmodelvariant", 33885}, + {"ridevehicle", 33886}, + {"stopridingvehicle", 33887}, + {"autoboltmissileeffects", 33889}, + {"disablemissilestick", 33890}, + {"enablemissilestick", 33891}, + {"setmissileminimapvisible", 33892}, + {"isoffhandweaponreadytothrow", 33893}, + {"makecollidewithitemclip", 33895}, + {"visionsetpostapplyforplayer", 33897}, + {"setlookattarget", 33898}, + {"clearlookattarget", 33899}, + {"sub_14052c250", 33907}, + {"sub_14052c290", 33908}, + {"sub_14052c2f0", 33909}, + {"sub_14052c340", 33910}, + {"sub_14052c360", 33911}, + {"sub_14031c170", 33912}, + {"sub_14031c590", 33913}, + {"setclienttriggervisionset", 33914}, + {"sub_1402e41c0", 33917}, + {"sub_1402e43b0", 33918}, + {"sub_14052b4d0", 33919}, + {"sub_14052b550", 33920}, + {"showviewmodel", 33921}, + {"hideviewmodel", 33922}, + {"setpickupweapon", 33923}, + {"allowpowerslide", 33925}, + {"allowhighjumpdrop", 33926}, + {"sub_1404045e0", 33927}, + {"sub_1405297e0", 33928}, + {"sub_14052c200", 33929}, + {"clearentity", 33930}, + {"sub_140334a40", 33931}, + {"allowdodge", 33933}, + {"sub_140529860", 33934}, + {"setminimapvisible", 33935}, + {"sub_1402e0a90", 33936}, + {"sub_1402e0bc0", 33937}, + {"sub_1402e0cf0", 33938}, + {"setplayermech", 33940}, + {"setdamagecallbackon", 33941}, + {"finishentitydamage", 33942}, + {"designatefoftarget", 33946}, + {"sethintstringvisibleonlytoowner", 33947}, + {"notifyonplayercommandremove", 33948}, + {"sub_1402e3bf0", 33949}, + {"allowboostjump", 33950}, + {"batterydischargebegin", 33951}, + {"batterydischargeend", 33952}, + {"batterydischargeonce", 33953}, + {"batterygetcharge", 33954}, + {"batterysetcharge", 33955}, + {"batteryfullrecharge", 33956}, + {"batterygetsize", 33957}, + {"batterysetdischargescale", 33958}, + {"batterygetdischargerate", 33959}, + {"batteryisinuse", 33960}, + {"enablephysicaldepthoffieldscripting", 33961}, + {"disablephysicaldepthoffieldscripting", 33962}, + {"setphysicaldepthoffield", 33963}, + {"sub_140313860", 33964}, + {"sub_14052a560", 33965}, + {"sub_140321790", 33966}, + {"sub_140321a50", 33967}, + {"sub_1402dda50", 33968}, + {"sub_14052ac50", 33969}, + {"sub_14052ad50", 33970}, + {"setdemigod", 33971}, + {"sub_140310840", 33972}, + {"setcostumemodels", 33978}, + {"sub_140529e00", 33979}, + {"sub_140313510", 33980}, + {"scriptmodelpauseanim", 33981}, + {"digitaldistortsetmaterial", 33982}, + {"disableoffhandsecondaryweapons", 33983}, + {"enableoffhandsecondaryweapons", 33984}, + {"canplaceriotshield", 33985}, + {"setriotshieldfailhint", 33986}, + {"enabledetonate", 33987}, + {"getdetonateenabled", 33988}, + {"playergetuseent", 33989}, + {"refreshshieldmodels", 33990}, + {"sub_14052c3a0", 33991}, + {"locret_140406a70", 33993}, + {"getgravity", 33994}, + {"sub_140529560", 33997}, + {"sub_140529650", 33998}, + {"setcommonplayerdatareservedint", 33999}, + {"getrankedplayerdatareservedint", 34000}, + {"setrankedplayerdatareservedint", 34001}, + {"getcommonplayerdatareservedint", 34002}, + {"sub_1402e8a20", 34003}, + {"sub_14052c3c0", 34004}, + {"addsoundmutedevice", 34005}, + {"removesoundmutedevice", 34006}, + {"clientaddsoundsubmix", 34007}, + {"clientclearsoundsubmix", 34008}, + {"sub_140312520", 34009}, + {"sub_140312ba0", 34010}, + {"sub_140312bf0", 34011}, + {"sub_140312cb0", 34012}, + {"sub_140312df0", 34013}, + {"sub_140312ff0", 34014}, + {"isusingoffhand", 34016}, + {"physicsstop", 34017}, + {"sub_14031b9e0", 34018}, + {"sub_14031e3c0", 34023}, + {"sub_1402ef8a0", 34024}, + {"sub_14052c400", 34025}, + {"initwaterclienttrigger", 34026}, + {"getcurrentweaponmodelname", 34027}, + {"sub_14031f000", 34028}, + {"setignorefoliagesightingme", 34030}, + {"loadcostumemodels", 34031}, + {"sub_14030cd90", 34036}, + {"sub_14030b1c0", 34038}, + {"sub_140322450", 34039}, + {"iscloaked", 34040}, + {"sub_140528bc0", 34041}, + {"sub_140528cf0", 34042}, + {"sub_14031fb80", 34043}, + {"sub_140320180", 34044}, + {"selfieaccessselfievalidflaginplayerdef", 34045}, + {"selfieaccessselfiecustomassetsarestreamed", 34046}, + {"sub_14031ede0", 34048}, + {"selfiescreenshottaken", 34049}, + {"sub_14031f190", 34050}, + {"sub_140319de0", 34052}, + {"setmissilecoasting", 34053}, + {"setmlgspectator", 34054}, + {"gettotalmpxp", 34055}, + {"turretsetgroundaimentity", 34056}, + {"sub_140318610", 34057}, + {"sub_140317760", 34058}, + {"sub_14032e9a0", 34059}, + {"sub_140320830", 34060}, + {"sub_140329bc0", 34061}, + {"sub_14032e370", 34062}, + {"consumereinforcement", 34063}, + {"ghost", 34064}, + {"loadweapons", 34065}, + {"sub_1402e0e80", 34067}, + {"setwaypointiconfadeatcenter", 34068}, + {"setreinforcementhintstrings", 34069}, + {"playgoliathentryanim", 34070}, + {"playgoliathtoidleanim", 34071}, + {"sub_140312210", 34072}, + {"sub_140312280", 34073}, + {"sub_140321660", 34074}, + {"playlocalannouncersound", 34075}, + {"setmissilespecialclipmask", 34076}, + {"sub_140527c40", 34077}, + {"sub_140527c60", 34078}, + {"isdodging", 34079}, + {"ispowersliding", 34080}, + {"sub_140320ab0", 34081}, + {"getcurrentping", 34082}, + {"sub_1402eeb60", 34083}, + {"sub_140329390", 34084}, + {"gethordeplayerdata", 34085}, + {"sethordeplayerdata", 34086}, + {"sub_1402dcbc0", 34087}, + {"sub_14031a0b0", 34088}, + {"sub_1403198a0", 34089}, + {"sub_1403345e0", 34090}, + {"sub_1402e7d80", 34092}, + {"sub_140404f00", 34093}, + {"issplitscreenplayer2", 34095}, + {"setowneroriginal", 34096}, + {"getlinkedtagname", 34097}, + {"sub_14032de80", 34098}, + {"sub_14032dfb0", 34099}, + {"setwaypointaerialtargeting", 34100}, + {"worldweaponsloaded", 34101}, + {"sub_140320aa0", 34102}, + {"usetriggertouchcheckstance", 34103}, + {"onlystreamactiveweapon", 34104}, + {"precachekillcamiconforweapon", 34105}, + {"selfierequestupdate", 34106}, + {"getclanwarsbonus", 34107}, + {"sub_140406810", 34108}, + {"sub_1404051d0", 34109}, + {"sub_140406340", 34110}, + {"sub_1402e72a0", 34111}, + {"sub_140404c70", 34112}, + {"sub_1404065c0", 34113}, + {"sub_140405c60", 34114}, + {"sub_140406400", 34115}, + {"sub_140406230", 34116}, + {"sub_140406650", 34117}, + {"sub_1402e7de0", 34118}, + {"sub_140333550", 34119}, + {"sub_140403fe0", 34120}, + {"sub_140320360", 34121}, + {"canhighjump", 34122}, + {"setprestigemastery", 34123}, + {"sub_140403f50", 34124}, + {"sub_14030c7b0", 34125}, + {"sub_1403206b0", 34126}, + {"sub_140329960", 34127}, + {"sub_140328100", 34128}, + {"sub_140405990", 34129}, + {"sub_1402e70c0", 34130}, + {"sub_1403335f0", 34131}, + {"getcoopplayerdatareservedint", 34132}, + {"setcoopplayerdatareservedint", 34133}, + {"sub_140406b50", 34134}, + {"sub_1402de070", 34135}, + {"sub_1402e7e40", 34136}, + {"sub_140329ba0", 34137}, + {"sub_140405af0", 34138}, + {"sub_1402e7240", 34139}, + {"sub_14031a370", 34140}, + {"sub_140406970", 34141}, + {"sub_140405b60", 34142}, + {"sub_140334e10", 34143}, + {"sub_140320a90", 34144}, + {"sub_140406c00", 34145}, + {"sub_140328bf0", 34146}, + {"sub_1404053e0", 34147}, + {"sub_140406d20", 34148}, + {"sub_14032c900", 34149}, + {"sub_14032c9e0", 34150}, + {"sub_140044360", 34151}, + {"sub_140333680", 34152}, + {"sub_1402e7130", 34153}, + {"sub_1403294b0", 34154}, + {"sub_140320b40", 34155}, + {"sub_140333710", 34156}, + }; + + std::unordered_map token_map = + { + {"CodeCallback_BulletHitEntity", 180}, + {"CodeCallback_CodeEndGame", 181}, + {"CodeCallback_EntityDamage", 182}, + {"CodeCallback_EntityOutOfWorld", 183}, + {"CodeCallback_HostMigration", 185}, + {"CodeCallback_PartyMembers", 187}, + {"CodeCallback_PlayerConnect", 188}, + {"CodeCallback_PlayerDamage", 189}, + {"CodeCallback_PlayerDisconnect", 190}, + {"CodeCallback_PlayerGrenadeSuicide", 191}, + {"CodeCallback_PlayerKilled", 192}, + {"CodeCallback_PlayerLastStand", 193}, + {"CodeCallback_PlayerMigrated", 194}, + {"CodeCallback_StartGameType", 195}, + {"CodeCallback_VehicleDamage", 196}, + {"CreateStruct", 221}, + {"InitStructs", 522}, + {"main", 619}, + {"AbortLevel", 1727}, + {"callbackVoid", 6662}, + {"CodeCallback_GiveKillstreak", 8192}, + {"SetDefaultCallbacks", 32577}, + {"SetupCallbacks", 33531}, + {"SetupDamageFlags", 33542}, + {"struct", 36698}, + {"codescripts/delete", 0x053D}, + {"codescripts/struct", 0x053E}, + {"maps/mp/gametypes/_callbacksetup", 0x0540}, + {"codescripts/character", 0xA4E5}, + {"common_scripts/_artcommon", 42214}, + {"common_scripts/_bcs_location_trigs", 42215}, + {"common_scripts/_createfx", 42216}, + {"common_scripts/_createfxmenu", 42217}, + {"common_scripts/_destructible", 42218}, + {"common_scripts/_dynamic_world", 42219}, + {"maps/createart/mp_vlobby_room_art", 42735}, + {"maps/createart/mp_vlobby_room_fog", 42736}, + {"maps/createart/mp_vlobby_room_fog_hdr", 42737} + }; +} diff --git a/src/client/game/scripting/functions.cpp b/src/client/game/scripting/functions.cpp new file mode 100644 index 00000000..3452c767 --- /dev/null +++ b/src/client/game/scripting/functions.cpp @@ -0,0 +1,106 @@ +#include +#include "functions.hpp" + +#include + +namespace scripting +{ + namespace + { + std::unordered_map lowercase_map( + const std::unordered_map& old_map) + { + std::unordered_map new_map{}; + for (auto& entry : old_map) + { + new_map[utils::string::to_lower(entry.first)] = entry.second; + } + + return new_map; + } + + const std::unordered_map& get_methods() + { + static auto methods = lowercase_map(method_map); + return methods; + } + + const std::unordered_map& get_functions() + { + static auto function = lowercase_map(function_map); + return function; + } + + int find_function_index(const std::string& name, const bool prefer_global) + { + const auto target = utils::string::to_lower(name); + + const auto& primary_map = prefer_global + ? get_functions() + : get_methods(); + const auto& secondary_map = !prefer_global + ? get_functions() + : get_methods(); + + auto function_entry = primary_map.find(target); + if (function_entry != primary_map.end()) + { + return function_entry->second; + } + + function_entry = secondary_map.find(target); + if (function_entry != secondary_map.end()) + { + return function_entry->second; + } + + return -1; + } + + script_function get_function_by_index(const unsigned index) + { + static const auto function_table = SELECT_VALUE(0x149668F50, 0x147DD1850); + static const auto method_table = SELECT_VALUE(0x14966A670, 0x147DD2F50); + + if (index < 0x2DF) + { + return reinterpret_cast(function_table)[index]; + } + + return reinterpret_cast(method_table)[index - 0x8000]; + } + } + + std::string find_token(unsigned int id) + { + for (const auto& token : token_map) + { + if (token.second == id) + { + return token.first; + } + } + + return utils::string::va("_ID%i", id); + } + + unsigned int find_token_id(const std::string& name) + { + const auto result = token_map.find(name); + + if (result != token_map.end()) + { + return result->second; + } + + return 0; + } + + script_function find_function(const std::string& name, const bool prefer_global) + { + const auto index = find_function_index(name, prefer_global); + if (index < 0) return nullptr; + + return get_function_by_index(index); + } +} diff --git a/src/client/game/scripting/functions.hpp b/src/client/game/scripting/functions.hpp new file mode 100644 index 00000000..0422bcf7 --- /dev/null +++ b/src/client/game/scripting/functions.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "game/game.hpp" + +namespace scripting +{ + extern std::unordered_map method_map; + extern std::unordered_map function_map; + extern std::unordered_map token_map; + + using script_function = void(*)(game::scr_entref_t); + + std::string find_token(unsigned int id); + unsigned int find_token_id(const std::string& name); + + script_function find_function(const std::string& name, const bool prefer_global); +} diff --git a/src/client/game/scripting/lua/context.cpp b/src/client/game/scripting/lua/context.cpp new file mode 100644 index 00000000..462a6628 --- /dev/null +++ b/src/client/game/scripting/lua/context.cpp @@ -0,0 +1,489 @@ +#include +#include "context.hpp" +#include "error.hpp" +#include "value_conversion.hpp" + +#include "../execution.hpp" +#include "../functions.hpp" + +#include "../../../component/command.hpp" +#include "../../../component/logfile.hpp" +#include "../../../component/scripting.hpp" + +#include + +namespace scripting::lua +{ + namespace + { + std::vector load_game_constants() + { + std::vector result{}; + + const auto constants = game::GScr_LoadConsts.get(); + + ud_t ud; + ud_init(&ud); + ud_set_mode(&ud, 64); + ud_set_pc(&ud, uint64_t(constants)); + ud_set_input_buffer(&ud, reinterpret_cast(constants), INT32_MAX); + + while (true) + { + ud_disassemble(&ud); + + if (ud_insn_mnemonic(&ud) == UD_Iret) + { + break; + } + + if (ud_insn_mnemonic(&ud) == UD_Imov) + { + const auto* operand = ud_insn_opr(&ud, 0); + if (operand && operand->type == UD_OP_REG && operand->base == UD_R_ECX) + { + operand = ud_insn_opr(&ud, 1); + if (operand && operand->type == UD_OP_IMM && (operand->base == UD_R_RAX || operand->base == UD_R_EAX)) + { + result.emplace_back(reinterpret_cast(0x1409C1CE0)[operand->lval.udword]); + } + } + } + + if (ud_insn_mnemonic(&ud) == UD_Ilea) + { + const auto* operand = ud_insn_opr(&ud, 0); + if (!operand || operand->type != UD_OP_REG || operand->base != UD_R_RCX) + { + continue; + } + + operand = ud_insn_opr(&ud, 1); + if (operand && operand->type == UD_OP_MEM && operand->base == UD_R_RIP) + { + auto* operand_ptr = reinterpret_cast(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->lval. + sdword); + if (!utils::memory::is_bad_read_ptr(operand_ptr) && utils::memory::is_rdata_ptr(operand_ptr) && + strlen(operand_ptr) > 0) + { + result.emplace_back(operand_ptr); + } + } + } + + if (*reinterpret_cast(ud.pc) == 0xCC) break; // int 3 + } + + return result; + } + + const std::vector& get_game_constants() + { + static auto constants = load_game_constants(); + return constants; + } + + void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler) + { + state["level"] = entity{*game::levelEntityId}; + + auto vector_type = state.new_usertype("vector", sol::constructors()); + vector_type["x"] = sol::property(&vector::get_x, &vector::set_x); + vector_type["y"] = sol::property(&vector::get_y, &vector::set_y); + vector_type["z"] = sol::property(&vector::get_z, &vector::set_z); + + vector_type["r"] = sol::property(&vector::get_x, &vector::set_x); + vector_type["g"] = sol::property(&vector::get_y, &vector::set_y); + vector_type["b"] = sol::property(&vector::get_z, &vector::set_z); + + auto entity_type = state.new_usertype("entity"); + + for (const auto& func : method_map) + { + const auto name = utils::string::to_lower(func.first); + entity_type[name.data()] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, entity.call(name, arguments)); + }; + } + + for (const auto& constant : get_game_constants()) + { + entity_type[constant] = sol::property( + [constant](const entity& entity, const sol::this_state s) + { + return convert(s, entity.get(constant)); + }, + [constant](const entity& entity, const sol::this_state s, const sol::lua_value& value) + { + entity.set(constant, convert({s, value})); + }); + } + + entity_type["set"] = [](const entity& entity, const std::string& field, + const sol::lua_value& value) + { + entity.set(field, convert(value)); + }; + + entity_type["get"] = [](const entity& entity, const sol::this_state s, const std::string& field) + { + return convert(s, entity.get(field)); + }; + + entity_type["notify"] = [](const entity& entity, const sol::this_state s, const std::string& event, + sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + notify(entity, event, arguments); + }; + + entity_type["onnotify"] = [&handler](const entity& entity, const std::string& event, + const event_callback& callback) + { + event_listener listener{}; + listener.callback = callback; + listener.entity = entity; + listener.event = event; + listener.is_volatile = false; + + return handler.add_event_listener(std::move(listener)); + }; + + entity_type["onnotifyonce"] = [&handler](const entity& entity, const std::string& event, + const event_callback& callback) + { + event_listener listener{}; + listener.callback = callback; + listener.entity = entity; + listener.event = event; + listener.is_volatile = true; + + return handler.add_event_listener(std::move(listener)); + }; + + entity_type["call"] = [](const entity& entity, const sol::this_state s, const std::string& function, + sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, entity.call(function, arguments)); + }; + + entity_type[sol::meta_function::new_index] = [](const entity& entity, const std::string& field, + const sol::lua_value& value) + { + entity.set(field, convert(value)); + }; + + entity_type[sol::meta_function::index] = [](const entity& entity, const sol::this_state s, const std::string& field) + { + return convert(s, entity.get(field)); + }; + + entity_type["getstruct"] = [](const entity& entity, const sol::this_state s) + { + const auto id = entity.get_entity_id(); + return scripting::lua::entity_to_struct(s, id); + }; + + entity_type["struct"] = sol::property([](const entity& entity, const sol::this_state s) + { + const auto id = entity.get_entity_id(); + return scripting::lua::entity_to_struct(s, id); + }); + + entity_type["scriptcall"] = [](const entity& entity, const sol::this_state s, const std::string& filename, + const std::string function, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, call_script_function(entity, filename, function, arguments)); + }; + + struct game + { + }; + auto game_type = state.new_usertype("game_"); + state["game"] = game(); + + for (const auto& func : function_map) + { + const auto name = utils::string::to_lower(func.first); + game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, call(name, arguments)); + }; + } + + game_type["call"] = [](const game&, const sol::this_state s, const std::string& function, + sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, call(function, arguments)); + }; + + game_type["ontimeout"] = [&scheduler](const game&, const sol::protected_function& callback, + const long long milliseconds) + { + return scheduler.add(callback, milliseconds, true); + }; + + game_type["oninterval"] = [&scheduler](const game&, const sol::protected_function& callback, + const long long milliseconds) + { + return scheduler.add(callback, milliseconds, false); + }; + + game_type["executecommand"] = [](const game&, const std::string& command) + { + command::execute(command, false); + }; + + game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback) + { + logfile::add_player_damage_callback(callback); + }; + + game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback) + { + logfile::add_player_killed_callback(callback); + }; + + game_type["getgamevar"] = [](const sol::this_state s) + { + const auto id = *reinterpret_cast(0x14815DEB4); + const auto value = ::game::scr_VarGlob->childVariableValue[id]; + + ::game::VariableValue variable{}; + variable.type = value.type; + variable.u.uintValue = value.u.u.uintValue; + + return convert(s, variable); + }; + + game_type["getfunctions"] = [entity_type](const game&, const sol::this_state s, const std::string& filename) + { + if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) + { + throw std::runtime_error("File '" + filename + "' not found"); + } + + auto functions = sol::table::create(s.lua_state()); + + for (const auto& function : scripting::script_function_table[filename]) + { + functions[function.first] = sol::overload( + [filename, function](const entity& entity, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + gsl::finally(&logfile::enable_vm_execute_hook); + logfile::disable_vm_execute_hook(); + + return convert(s, call_script_function(entity, filename, function.first, arguments)); + }, + [filename, function](const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + gsl::finally(&logfile::enable_vm_execute_hook); + logfile::disable_vm_execute_hook(); + + return convert(s, call_script_function(*::game::levelEntityId, filename, function.first, arguments)); + } + ); + } + + return functions; + }; + + game_type["scriptcall"] = [](const game&, const sol::this_state s, const std::string& filename, + const std::string function, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + gsl::finally(&logfile::enable_vm_execute_hook); + logfile::disable_vm_execute_hook(); + + return convert(s, call_script_function(*::game::levelEntityId, filename, function, arguments)); + }; + + game_type["detour"] = [](const game&, const sol::this_state s, const std::string& filename, + const std::string function_name, const sol::protected_function& function) + { + const auto pos = get_function_pos(filename, function_name); + logfile::vm_execute_hooks[pos] = function; + + auto detour = sol::table::create(function.lua_state()); + + detour["disable"] = [pos]() + { + logfile::vm_execute_hooks.erase(pos); + }; + + detour["enable"] = [pos, function]() + { + logfile::vm_execute_hooks[pos] = function; + }; + + detour["invoke"] = sol::overload( + [filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + gsl::finally(&logfile::enable_vm_execute_hook); + logfile::disable_vm_execute_hook(); + + return convert(s, call_script_function(entity, filename, function_name, arguments)); + }, + [filename, function_name](const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + gsl::finally(&logfile::enable_vm_execute_hook); + logfile::disable_vm_execute_hook(); + + return convert(s, call_script_function(*::game::levelEntityId, filename, function_name, arguments)); + } + ); + + return detour; + }; + } + } + + context::context(std::string folder) + : folder_(std::move(folder)) + , scheduler_(state_) + , event_handler_(state_) + + { + this->state_.open_libraries(sol::lib::base, + sol::lib::package, + sol::lib::io, + sol::lib::string, + sol::lib::os, + sol::lib::math, + sol::lib::table); + + this->state_["include"] = [this](const std::string& file) + { + this->load_script(file); + }; + + sol::function old_require = this->state_["require"]; + auto base_path = utils::string::replace(this->folder_, "/", ".") + "."; + this->state_["require"] = [base_path, old_require](const std::string& path) + { + return old_require(base_path + path); + }; + + this->state_["scriptdir"] = [this]() + { + return this->folder_; + }; + + setup_entity_type(this->state_, this->event_handler_, this->scheduler_); + + printf("Loading script '%s'\n", this->folder_.data()); + this->load_script("__init__"); + } + + context::~context() + { + this->collect_garbage(); + this->scheduler_.clear(); + this->event_handler_.clear(); + this->state_ = {}; + } + + void context::run_frame() + { + this->scheduler_.run_frame(); + this->collect_garbage(); + } + + void context::notify(const event& e) + { + this->scheduler_.dispatch(e); + this->event_handler_.dispatch(e); + } + + void context::collect_garbage() + { + this->state_.collect_garbage(); + } + + void context::load_script(const std::string& script) + { + if (!this->loaded_scripts_.emplace(script).second) + { + return; + } + + const auto file = (std::filesystem::path{this->folder_} / (script + ".lua")).generic_string(); + handle_error(this->state_.safe_script_file(file, &sol::script_pass_on_error)); + } +} diff --git a/src/client/game/scripting/lua/context.hpp b/src/client/game/scripting/lua/context.hpp new file mode 100644 index 00000000..79a5e905 --- /dev/null +++ b/src/client/game/scripting/lua/context.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "../event.hpp" + +#pragma warning(push) +#pragma warning(disable: 4702) + +#define SOL_ALL_SAFETIES_ON 1 +#define SOL_PRINT_ERRORS 0 +#include + +#pragma warning(pop) + +#include "scheduler.hpp" +#include "event_handler.hpp" + +namespace scripting::lua +{ + class context + { + public: + context(std::string folder); + ~context(); + + context(context&&) noexcept = delete; + context& operator=(context&&) noexcept = delete; + + context(const context&) = delete; + context& operator=(const context&) = delete; + + void run_frame(); + void notify(const event& e); + void collect_garbage(); + + private: + sol::state state_{}; + std::string folder_; + std::unordered_set loaded_scripts_; + + scheduler scheduler_; + event_handler event_handler_; + + void load_script(const std::string& script); + }; +} diff --git a/src/client/game/scripting/lua/engine.cpp b/src/client/game/scripting/lua/engine.cpp new file mode 100644 index 00000000..15863c1c --- /dev/null +++ b/src/client/game/scripting/lua/engine.cpp @@ -0,0 +1,75 @@ +#include +#include "engine.hpp" +#include "context.hpp" + +#include "../execution.hpp" +#include "../../../component/logfile.hpp" +#include "../../../component/game_module.hpp" + +#include + +namespace scripting::lua::engine +{ + namespace + { + auto& get_scripts() + { + static std::vector> scripts{}; + return scripts; + } + + void load_scripts(const std::string& script_dir) + { + if (!utils::io::directory_exists(script_dir)) + { + return; + } + + const auto scripts = utils::io::list_files(script_dir); + + for (const auto& script : scripts) + { + if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua")) + { + get_scripts().push_back(std::make_unique(script)); + } + } + } + } + + void stop() + { + logfile::clear_callbacks(); + get_scripts().clear(); + } + + void start() + { + // No SP until there is a concept + if (game::environment::is_sp()) + { + return; + } + + stop(); + load_scripts(game_module::get_host_module().get_folder() + "/data/scripts/"); + load_scripts("s1x/scripts/"); + load_scripts("data/scripts/"); + } + + void notify(const event& e) + { + for (auto& script : get_scripts()) + { + script->notify(e); + } + } + + void run_frame() + { + for (auto& script : get_scripts()) + { + script->run_frame(); + } + } +} diff --git a/src/client/game/scripting/lua/engine.hpp b/src/client/game/scripting/lua/engine.hpp new file mode 100644 index 00000000..471316cd --- /dev/null +++ b/src/client/game/scripting/lua/engine.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../event.hpp" + +namespace scripting::lua::engine +{ + void start(); + void stop(); + void notify(const event& e); + void run_frame(); +} diff --git a/src/client/game/scripting/lua/error.cpp b/src/client/game/scripting/lua/error.cpp new file mode 100644 index 00000000..935db0f0 --- /dev/null +++ b/src/client/game/scripting/lua/error.cpp @@ -0,0 +1,37 @@ +#include +#include "error.hpp" +#include "../execution.hpp" + +#include "component/console.hpp" + +namespace scripting::lua +{ + namespace + { + void notify_error() + { + try + { + call("iprintln", {"^1Script execution error!"}); + } + catch (...) + { + } + } + } + + void handle_error(const sol::protected_function_result& result) + { + if (!result.valid()) + { + console::error("************** Script execution error **************\n"); + + const sol::error err = result; + console::error("%s\n", err.what()); + + console::error("****************************************************\n"); + + notify_error(); + } + } +} diff --git a/src/client/game/scripting/lua/error.hpp b/src/client/game/scripting/lua/error.hpp new file mode 100644 index 00000000..dab56bee --- /dev/null +++ b/src/client/game/scripting/lua/error.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "context.hpp" + +namespace scripting::lua +{ + void handle_error(const sol::protected_function_result& result); +} diff --git a/src/client/game/scripting/lua/event_handler.cpp b/src/client/game/scripting/lua/event_handler.cpp new file mode 100644 index 00000000..7121ea63 --- /dev/null +++ b/src/client/game/scripting/lua/event_handler.cpp @@ -0,0 +1,174 @@ +#include "std_include.hpp" +#include "context.hpp" +#include "error.hpp" +#include "value_conversion.hpp" + +namespace scripting::lua +{ + event_handler::event_handler(sol::state& state) + : state_(state) + { + auto event_listener_handle_type = state.new_usertype("event_listener_handle"); + + event_listener_handle_type["clear"] = [this](const event_listener_handle& handle) + { + this->remove(handle); + }; + + event_listener_handle_type["endon"] = [this](const event_listener_handle& handle, const entity& entity, const std::string& event) + { + this->add_endon_condition(handle, entity, event); + }; + } + + void event_handler::dispatch(const event& event) + { + bool has_built_arguments = false; + event_arguments arguments{}; + + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + this->handle_endon_conditions(event); + + for (auto i = tasks.begin(); i != tasks.end();) + { + if (i->event != event.name || i->entity != event.entity) + { + ++i; + continue; + } + + if (!i->is_deleted) + { + if(!has_built_arguments) + { + has_built_arguments = true; + arguments = this->build_arguments(event); + } + + handle_error(i->callback(sol::as_args(arguments))); + } + + if (i->is_volatile || i->is_deleted) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + event_listener_handle event_handler::add_event_listener(event_listener&& listener) + { + const uint64_t id = ++this->current_listener_id_; + listener.id = id; + listener.is_deleted = false; + + new_callbacks_.access([&listener](task_list& tasks) + { + tasks.emplace_back(std::move(listener)); + }); + + return {id}; + } + + void event_handler::add_endon_condition(const event_listener_handle& handle, const entity& entity, + const std::string& event) + { + auto merger = [&](task_list& tasks) + { + for(auto& task : tasks) + { + if(task.id == handle.id) + { + task.endon_conditions.emplace_back(entity, event); + } + } + }; + + callbacks_.access([&](task_list& tasks) + { + merger(tasks); + new_callbacks_.access(merger); + }); + } + + void event_handler::clear() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + new_tasks.clear(); + tasks.clear(); + }); + }); + } + + void event_handler::remove(const event_listener_handle& handle) + { + auto mask_as_deleted = [&](task_list& tasks) + { + for (auto& task : tasks) + { + if (task.id == handle.id) + { + task.is_deleted = true; + break; + } + } + }; + + callbacks_.access(mask_as_deleted); + new_callbacks_.access(mask_as_deleted); + } + + void event_handler::merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), + std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } + + void event_handler::handle_endon_conditions(const event& event) + { + auto deleter = [&](task_list& tasks) + { + for(auto& task : tasks) + { + for(auto& condition : task.endon_conditions) + { + if(condition.first == event.entity && condition.second == event.name) + { + task.is_deleted = true; + break; + } + } + } + }; + + callbacks_.access(deleter); + } + + event_arguments event_handler::build_arguments(const event& event) const + { + event_arguments arguments; + + for (const auto& argument : event.arguments) + { + arguments.emplace_back(convert(this->state_, argument)); + } + + return arguments; + } +} diff --git a/src/client/game/scripting/lua/event_handler.hpp b/src/client/game/scripting/lua/event_handler.hpp new file mode 100644 index 00000000..fc95b704 --- /dev/null +++ b/src/client/game/scripting/lua/event_handler.hpp @@ -0,0 +1,58 @@ +#pragma once + +namespace scripting::lua +{ + using event_arguments = std::vector; + using event_callback = sol::protected_function; + + class event_listener_handle + { + public: + uint64_t id = 0; + }; + + class event_listener final : public event_listener_handle + { + public: + std::string event = {}; + entity entity{}; + event_callback callback = {}; + bool is_volatile = false; + bool is_deleted = false; + std::vector> endon_conditions{}; + }; + + class event_handler final + { + public: + event_handler(sol::state& state); + + event_handler(event_handler&&) noexcept = delete; + event_handler& operator=(event_handler&&) noexcept = delete; + + event_handler(const scheduler&) = delete; + event_handler& operator=(const event_handler&) = delete; + + void dispatch(const event& event); + + event_listener_handle add_event_listener(event_listener&& listener); + + void clear(); + + private: + sol::state& state_; + std::atomic_int64_t current_listener_id_ = 0; + + using task_list = std::vector; + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + + void remove(const event_listener_handle& handle); + void merge_callbacks(); + void handle_endon_conditions(const event& event); + + void add_endon_condition(const event_listener_handle& handle, const entity& entity, const std::string& event); + + event_arguments build_arguments(const event& event) const; + }; +} diff --git a/src/client/game/scripting/lua/scheduler.cpp b/src/client/game/scripting/lua/scheduler.cpp new file mode 100644 index 00000000..1afb7df2 --- /dev/null +++ b/src/client/game/scripting/lua/scheduler.cpp @@ -0,0 +1,171 @@ +#include "std_include.hpp" +#include "context.hpp" +#include "error.hpp" + +namespace scripting::lua +{ + scheduler::scheduler(sol::state& state) + { + auto task_handle_type = state.new_usertype("task_handle"); + + task_handle_type["clear"] = [this](const task_handle& handle) + { + this->remove(handle); + }; + + task_handle_type["endon"] = [this](const task_handle& handle, const entity& entity, const std::string& event) + { + this->add_endon_condition(handle, entity, event); + }; + } + + void scheduler::dispatch(const event& event) + { + auto deleter = [&](task_list& tasks) + { + for(auto& task : tasks) + { + for(auto& condition : task.endon_conditions) + { + if(condition.first == event.entity && condition.second == event.name) + { + task.is_deleted = true; + break; + } + } + } + }; + + callbacks_.access([&](task_list& tasks) + { + deleter(tasks); + new_callbacks_.access(deleter); + }); + } + + void scheduler::run_frame() + { + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + + for (auto i = tasks.begin(); i != tasks.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - i->last_call; + + if (diff < i->delay) + { + ++i; + continue; + } + + i->last_call = now; + + if (!i->is_deleted) + { + handle_error(i->callback()); + } + + if (i->is_volatile || i->is_deleted) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + void scheduler::clear() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + new_tasks.clear(); + tasks.clear(); + }); + }); + } + + task_handle scheduler::add(const sol::protected_function& callback, const long long milliseconds, + const bool is_volatile) + { + return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); + } + + task_handle scheduler::add(const sol::protected_function& callback, const std::chrono::milliseconds delay, + const bool is_volatile) + { + const uint64_t id = ++this->current_task_id_; + + task task; + task.is_volatile = is_volatile; + task.callback = callback; + task.delay = delay; + task.last_call = std::chrono::steady_clock::now(); + task.id = id; + task.is_deleted = false; + + new_callbacks_.access([&task](task_list& tasks) + { + tasks.emplace_back(std::move(task)); + }); + + return {id}; + } + + void scheduler::add_endon_condition(const task_handle& handle, const entity& entity, const std::string& event) + { + auto merger = [&](task_list& tasks) + { + for(auto& task : tasks) + { + if(task.id == handle.id) + { + task.endon_conditions.emplace_back(entity, event); + } + } + }; + + callbacks_.access([&](task_list& tasks) + { + merger(tasks); + new_callbacks_.access(merger); + }); + } + + void scheduler::remove(const task_handle& handle) + { + auto mask_as_deleted = [&](task_list& tasks) + { + for (auto& task : tasks) + { + if (task.id == handle.id) + { + task.is_deleted = true; + break; + } + } + }; + + callbacks_.access(mask_as_deleted); + new_callbacks_.access(mask_as_deleted); + } + + void scheduler::merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), + std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } +} diff --git a/src/client/game/scripting/lua/scheduler.hpp b/src/client/game/scripting/lua/scheduler.hpp new file mode 100644 index 00000000..17c90797 --- /dev/null +++ b/src/client/game/scripting/lua/scheduler.hpp @@ -0,0 +1,54 @@ +#pragma once +#include + +namespace scripting::lua +{ + class context; + + class task_handle + { + public: + uint64_t id = 0; + }; + + class task final : public task_handle + { + public: + std::chrono::steady_clock::time_point last_call{}; + sol::protected_function callback{}; + std::chrono::milliseconds delay{}; + bool is_volatile = false; + bool is_deleted = false; + std::vector> endon_conditions{}; + }; + + class scheduler final + { + public: + scheduler(sol::state& state); + + scheduler(scheduler&&) noexcept = delete; + scheduler& operator=(scheduler&&) noexcept = delete; + + scheduler(const scheduler&) = delete; + scheduler& operator=(const scheduler&) = delete; + + void dispatch(const event& event); + void run_frame(); + void clear(); + + task_handle add(const sol::protected_function& callback, long long milliseconds, bool is_volatile); + task_handle add(const sol::protected_function& callback, std::chrono::milliseconds delay, bool is_volatile); + + private: + using task_list = std::vector; + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + std::atomic_int64_t current_task_id_ = 0; + + void add_endon_condition(const task_handle& handle, const entity& entity, const std::string& event); + + void remove(const task_handle& handle); + void merge_callbacks(); + }; +} diff --git a/src/client/game/scripting/lua/value_conversion.cpp b/src/client/game/scripting/lua/value_conversion.cpp new file mode 100644 index 00000000..defbe14d --- /dev/null +++ b/src/client/game/scripting/lua/value_conversion.cpp @@ -0,0 +1,319 @@ +#include +#include "value_conversion.hpp" +#include "../functions.hpp" +#include "../execution.hpp" +#include ".../../component/logfile.hpp" + +namespace scripting::lua +{ + namespace + { + struct array_value + { + int index; + script_value value; + }; + + sol::lua_value entity_to_array(lua_State* state, unsigned int id) + { + auto table = sol::table::create(state); + auto metatable = sol::table::create(state); + + std::unordered_map values; + + const auto offset = 64000 * (id & 3); + + auto current = game::scr_VarGlob->objectVariableChildren[id].firstChild; + auto idx = 1; + + for (auto i = offset + current; current; i = offset + current) + { + const auto var = game::scr_VarGlob->childVariableValue[i]; + + if (var.type == game::SCRIPT_NONE) + { + current = var.nextSibling; + continue; + } + + const auto string_value = (game::scr_string_t)((unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8)); + const auto* str = game::SL_ConvertToString(string_value); + + std::string key = string_value < 0x40000 && str + ? str + : std::to_string(idx++); + + game::VariableValue variable{}; + variable.type = var.type; + variable.u = var.u.u; + + array_value value; + value.index = i; + value.value = variable; + + values[key] = value; + + current = var.nextSibling; + } + + table["getkeys"] = [values]() + { + std::vector _keys; + + for (const auto& entry : values) + { + _keys.push_back(entry.first); + } + + return _keys; + }; + + metatable[sol::meta_function::new_index] = [values](const sol::table t, const sol::this_state s, + const sol::lua_value& key_value, const sol::lua_value& value) + { + const auto key = key_value.is() + ? std::to_string(key_value.as()) + : key_value.as(); + + if (values.find(key) == values.end()) + { + return; + } + + const auto i = values.at(key).index; + const auto variable = &game::scr_VarGlob->childVariableValue[i]; + + const auto new_variable = convert({s, value}).get_raw(); + + game::AddRefToValue(new_variable.type, new_variable.u); + game::RemoveRefToValue(variable->type, variable->u.u); + + variable->type = (char)new_variable.type; + variable->u.u = new_variable.u; + }; + + metatable[sol::meta_function::index] = [values](const sol::table t, const sol::this_state s, + const sol::lua_value& key_value) + { + const auto key = key_value.is() + ? std::to_string(key_value.as()) + : key_value.as(); + + if (values.find(key) == values.end()) + { + return sol::lua_value{s, sol::lua_nil}; + } + + return convert(s, values.at(key).value); + }; + + metatable[sol::meta_function::length] = [values]() + { + return values.size(); + }; + + table[sol::metatable_key] = metatable; + + return {state, table}; + } + + game::VariableValue convert_function(sol::lua_value value) + { + const auto function = value.as(); + const auto index = reinterpret_cast(logfile::vm_execute_hooks.size()); + + logfile::vm_execute_hooks[index] = function; + + game::VariableValue func; + func.type = game::SCRIPT_FUNCTION; + func.u.codePosValue = index; + + return func; + } + + sol::lua_value convert_function(lua_State* state, const char* pos) + { + return sol::overload( + [pos](const entity& entity, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, exec_ent_thread(entity, pos, arguments)); + }, + [pos](const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + return convert(s, exec_ent_thread(*game::levelEntityId, pos, arguments)); + } + ); + } + } + + sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id) + { + auto table = sol::table::create(state); + auto metatable = sol::table::create(state); + + const auto offset = 64000 * (parent_id & 3); + + metatable[sol::meta_function::new_index] = [offset, parent_id](const sol::table t, const sol::this_state s, + const sol::lua_value& field, const sol::lua_value& value) + { + const auto id = field.is() + ? scripting::find_token_id(field.as()) + : field.as(); + + if (!id) + { + return; + } + + const auto variable_id = game::GetVariable(parent_id, id); + const auto variable = &game::scr_VarGlob->childVariableValue[variable_id + offset]; + const auto new_variable = convert({s, value}).get_raw(); + + game::AddRefToValue(new_variable.type, new_variable.u); + game::RemoveRefToValue(variable->type, variable->u.u); + + variable->type = (char)new_variable.type; + variable->u.u = new_variable.u; + }; + + metatable[sol::meta_function::index] = [offset, parent_id](const sol::table t, const sol::this_state s, + const sol::lua_value& field) + { + const auto id = field.is() + ? scripting::find_token_id(field.as()) + : field.as(); + + if (!id) + { + return sol::lua_value{s, sol::lua_nil}; + } + + const auto variable_id = game::FindVariable(parent_id, id); + if (!variable_id) + { + return sol::lua_value{s, sol::lua_nil}; + } + + const auto variable = game::scr_VarGlob->childVariableValue[variable_id + offset]; + + game::VariableValue result{}; + result.u = variable.u.u; + result.type = (game::scriptType_e)variable.type; + + return convert(s, result); + }; + + table[sol::metatable_key] = metatable; + + return {state, table}; + } + + script_value convert(const sol::lua_value& value) + { + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return convert_function(value); + } + + return {}; + } + + sol::lua_value convert(lua_State* state, const script_value& value) + { + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is>()) + { + return entity_to_struct(state, value.get_raw().u.uintValue); + } + + if (value.is>()) + { + return entity_to_array(state, value.get_raw().u.uintValue); + } + + if (value.is>()) + { + return convert_function(state, value.get_raw().u.codePosValue); + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + return {state, sol::lua_nil}; + } +} diff --git a/src/client/game/scripting/lua/value_conversion.hpp b/src/client/game/scripting/lua/value_conversion.hpp new file mode 100644 index 00000000..93256f80 --- /dev/null +++ b/src/client/game/scripting/lua/value_conversion.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "context.hpp" + +namespace scripting::lua +{ + sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id); + + script_value convert(const sol::lua_value& value); + sol::lua_value convert(lua_State* state, const script_value& value); +} diff --git a/src/client/game/scripting/safe_execution.cpp b/src/client/game/scripting/safe_execution.cpp new file mode 100644 index 00000000..92daa3b7 --- /dev/null +++ b/src/client/game/scripting/safe_execution.cpp @@ -0,0 +1,72 @@ +#include +#include "safe_execution.hpp" + +#pragma warning(push) +#pragma warning(disable: 4611) + +namespace scripting::safe_execution +{ + namespace + { + bool execute_with_seh(const script_function function, const game::scr_entref_t& entref) + { + __try + { + function(entref); + return true; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + } + } + + bool call(const script_function function, const game::scr_entref_t& entref) + { + *game::g_script_error_level += 1; + if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) + { + *game::g_script_error_level -= 1; + return false; + } + + const auto result = execute_with_seh(function, entref); + *game::g_script_error_level -= 1; + return result; + } + + bool set_entity_field(const game::scr_entref_t& entref, const int offset) + { + *game::g_script_error_level += 1; + if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) + { + *game::g_script_error_level -= 1; + return false; + } + + game::Scr_SetObjectField(entref.classnum, entref.entnum, offset); + + *game::g_script_error_level -= 1; + return true; + } + + bool get_entity_field(const game::scr_entref_t& entref, const int offset, game::VariableValue* value) + { + *game::g_script_error_level += 1; + if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) + { + value->type = game::SCRIPT_NONE; + value->u.intValue = 0; + *game::g_script_error_level -= 1; + return false; + } + + game::GetEntityFieldValue(value, entref.classnum, entref.entnum, offset); + + *game::g_script_error_level -= 1; + return true; + } +} + +#pragma warning(pop) diff --git a/src/client/game/scripting/safe_execution.hpp b/src/client/game/scripting/safe_execution.hpp new file mode 100644 index 00000000..6eea59d2 --- /dev/null +++ b/src/client/game/scripting/safe_execution.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "functions.hpp" + +namespace scripting::safe_execution +{ + bool call(script_function function, const game::scr_entref_t& entref); + + bool set_entity_field(const game::scr_entref_t& entref, int offset); + bool get_entity_field(const game::scr_entref_t& entref, int offset, game::VariableValue* value); +} diff --git a/src/client/game/scripting/script_value.cpp b/src/client/game/scripting/script_value.cpp new file mode 100644 index 00000000..7d334f17 --- /dev/null +++ b/src/client/game/scripting/script_value.cpp @@ -0,0 +1,278 @@ +#include +#include "script_value.hpp" +#include "entity.hpp" + + +namespace scripting +{ + /*************************************************************** + * Constructors + **************************************************************/ + + script_value::script_value(const game::VariableValue& value) + : value_(value) + { + } + + script_value::script_value(const int value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_INTEGER; + variable.u.intValue = value; + + this->value_ = variable; + } + + script_value::script_value(const unsigned int value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_INTEGER; + variable.u.uintValue = value; + + this->value_ = variable; + } + + script_value::script_value(const bool value) + : script_value(static_cast(value)) + { + } + + script_value::script_value(const float value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_FLOAT; + variable.u.floatValue = value; + + this->value_ = variable; + } + + script_value::script_value(const double value) + : script_value(static_cast(value)) + { + } + + script_value::script_value(const char* value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_STRING; + variable.u.stringValue = game::SL_GetString(value, 0); + + const auto _ = gsl::finally([&variable]() + { + game::RemoveRefToValue(variable.type, variable.u); + }); + + this->value_ = variable; + } + + script_value::script_value(const std::string& value) + : script_value(value.data()) + { + } + + script_value::script_value(const entity& value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_OBJECT; + variable.u.pointerValue = value.get_entity_id(); + + this->value_ = variable; + } + + script_value::script_value(const vector& value) + { + game::VariableValue variable{}; + variable.type = game::SCRIPT_VECTOR; + variable.u.vectorValue = game::Scr_AllocVector(value); + + const auto _ = gsl::finally([&variable]() + { + game::RemoveRefToValue(variable.type, variable.u); + }); + + this->value_ = variable; + } + + /*************************************************************** + * Integer + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().type == game::SCRIPT_INTEGER; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + int script_value::get() const + { + return this->get_raw().u.intValue; + } + + template <> + unsigned int script_value::get() const + { + return this->get_raw().u.uintValue; + } + + template <> + bool script_value::get() const + { + return this->get_raw().u.uintValue != 0; + } + + /*************************************************************** + * Float + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().type == game::SCRIPT_FLOAT; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + float script_value::get() const + { + return this->get_raw().u.floatValue; + } + + template <> + double script_value::get() const + { + return static_cast(this->get_raw().u.floatValue); + } + + /*************************************************************** + * String + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().type == game::SCRIPT_STRING; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + const char* script_value::get() const + { + return game::SL_ConvertToString(static_cast(this->get_raw().u.stringValue)); + } + + template <> + std::string script_value::get() const + { + return this->get(); + } + + /*************************************************************** + * Array + **************************************************************/ + + template <> + bool script_value::is>() const + { + if (this->get_raw().type != game::SCRIPT_OBJECT) + { + return false; + } + + const auto id = this->get_raw().u.uintValue; + const auto type = game::scr_VarGlob->objectVariableValue[id].w.type; + + return type == game::SCRIPT_ARRAY; + } + + /*************************************************************** + * Struct + **************************************************************/ + + template <> + bool script_value::is>() const + { + if (this->get_raw().type != game::SCRIPT_OBJECT) + { + return false; + } + + const auto id = this->get_raw().u.uintValue; + const auto type = game::scr_VarGlob->objectVariableValue[id].w.type; + + return type == game::SCRIPT_STRUCT; + } + + /*************************************************************** + * Function + **************************************************************/ + + template <> + bool script_value::is>() const + { + return this->get_raw().type == game::SCRIPT_FUNCTION; + } + + /*************************************************************** + * Entity + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().type == game::SCRIPT_OBJECT; + } + + template <> + entity script_value::get() const + { + return entity(this->get_raw().u.pointerValue); + } + + /*************************************************************** + * Vector + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().type == game::SCRIPT_VECTOR; + } + + template <> + vector script_value::get() const + { + return this->get_raw().u.vectorValue; + } + + /*************************************************************** + * + **************************************************************/ + + const game::VariableValue& script_value::get_raw() const + { + return this->value_.get(); + } +} diff --git a/src/client/game/scripting/script_value.hpp b/src/client/game/scripting/script_value.hpp new file mode 100644 index 00000000..df8a95b6 --- /dev/null +++ b/src/client/game/scripting/script_value.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "game/game.hpp" +#include "variable_value.hpp" +#include "vector.hpp" + +namespace scripting +{ + class entity; + + class script_value + { + public: + script_value() = default; + script_value(const game::VariableValue& value); + + script_value(int value); + script_value(unsigned int value); + script_value(bool value); + + script_value(float value); + script_value(double value); + + script_value(const char* value); + script_value(const std::string& value); + + script_value(const entity& value); + + script_value(const vector& value); + + template + bool is() const; + + template + T as() const + { + if (!this->is()) + { + throw std::runtime_error("Invalid type"); + } + + return get(); + } + + const game::VariableValue& get_raw() const; + + private: + template + T get() const; + + variable_value value_{}; + }; +} diff --git a/src/client/game/scripting/stack_isolation.cpp b/src/client/game/scripting/stack_isolation.cpp new file mode 100644 index 00000000..646e2584 --- /dev/null +++ b/src/client/game/scripting/stack_isolation.cpp @@ -0,0 +1,27 @@ +#include +#include "stack_isolation.hpp" + +namespace scripting +{ + stack_isolation::stack_isolation() + { + this->in_param_count_ = game::scr_VmPub->inparamcount; + this->out_param_count_ = game::scr_VmPub->outparamcount; + this->top_ = game::scr_VmPub->top; + this->max_stack_ = game::scr_VmPub->maxstack; + + game::scr_VmPub->top = this->stack_; + game::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1]; + game::scr_VmPub->inparamcount = 0; + game::scr_VmPub->outparamcount = 0; + } + + stack_isolation::~stack_isolation() + { + game::Scr_ClearOutParams(); + game::scr_VmPub->inparamcount = this->in_param_count_; + game::scr_VmPub->outparamcount = this->out_param_count_; + game::scr_VmPub->top = this->top_; + game::scr_VmPub->maxstack = this->max_stack_; + } +} diff --git a/src/client/game/scripting/stack_isolation.hpp b/src/client/game/scripting/stack_isolation.hpp new file mode 100644 index 00000000..8dffd4bc --- /dev/null +++ b/src/client/game/scripting/stack_isolation.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "game/game.hpp" + +namespace scripting +{ + class stack_isolation final + { + public: + stack_isolation(); + ~stack_isolation(); + + stack_isolation(stack_isolation&&) = delete; + stack_isolation(const stack_isolation&) = delete; + stack_isolation& operator=(stack_isolation&&) = delete; + stack_isolation& operator=(const stack_isolation&) = delete; + + private: + game::VariableValue stack_[512]{}; + + game::VariableValue* max_stack_; + game::VariableValue* top_; + unsigned int in_param_count_; + unsigned int out_param_count_; + }; +} diff --git a/src/client/game/scripting/variable_value.cpp b/src/client/game/scripting/variable_value.cpp new file mode 100644 index 00000000..69a20023 --- /dev/null +++ b/src/client/game/scripting/variable_value.cpp @@ -0,0 +1,68 @@ +#include +#include "variable_value.hpp" + +namespace scripting +{ + variable_value::variable_value(const game::VariableValue& value) + { + this->assign(value); + } + + variable_value::variable_value(const variable_value& other) noexcept + { + this->operator=(other); + } + + variable_value::variable_value(variable_value&& other) noexcept + { + this->operator=(std::move(other)); + } + + variable_value& variable_value::operator=(const variable_value& other) noexcept + { + if (this != &other) + { + this->release(); + this->assign(other.value_); + } + + return *this; + } + + variable_value& variable_value::operator=(variable_value&& other) noexcept + { + if (this != &other) + { + this->release(); + this->value_ = other.value_; + other.value_.type = game::SCRIPT_NONE; + } + + return *this; + } + + variable_value::~variable_value() + { + this->release(); + } + + const game::VariableValue& variable_value::get() const + { + return this->value_; + } + + void variable_value::assign(const game::VariableValue& value) + { + this->value_ = value; + game::AddRefToValue(this->value_.type, this->value_.u); + } + + void variable_value::release() + { + if (this->value_.type != game::SCRIPT_NONE) + { + game::RemoveRefToValue(this->value_.type, this->value_.u); + this->value_.type = game::SCRIPT_NONE; + } + } +} diff --git a/src/client/game/scripting/variable_value.hpp b/src/client/game/scripting/variable_value.hpp new file mode 100644 index 00000000..7a962612 --- /dev/null +++ b/src/client/game/scripting/variable_value.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "game/game.hpp" + +namespace scripting +{ + class variable_value + { + public: + variable_value() = default; + variable_value(const game::VariableValue& value); + variable_value(const variable_value& other) noexcept; + variable_value(variable_value&& other) noexcept; + + variable_value& operator=(const variable_value& other) noexcept; + variable_value& operator=(variable_value&& other) noexcept; + + ~variable_value(); + + const game::VariableValue& get() const; + + private: + void assign(const game::VariableValue& value); + void release(); + + game::VariableValue value_{{0}, game::SCRIPT_NONE}; + }; +} diff --git a/src/client/game/scripting/vector.cpp b/src/client/game/scripting/vector.cpp new file mode 100644 index 00000000..e3b66dcd --- /dev/null +++ b/src/client/game/scripting/vector.cpp @@ -0,0 +1,85 @@ +#include +#include "vector.hpp" + +namespace scripting +{ + vector::vector(const float* value) + { + for (auto i = 0; i < 3; ++i) + { + this->value_[i] = value[i]; + } + } + + vector::vector(const game::vec3_t& value) + : vector(&value[0]) + { + } + + vector::vector(const float x, const float y, const float z) + { + this->value_[0] = x; + this->value_[1] = y; + this->value_[2] = z; + } + + vector::operator game::vec3_t&() + { + return this->value_; + } + + vector::operator const game::vec3_t&() const + { + return this->value_; + } + + game::vec_t& vector::operator[](const size_t i) + { + if (i >= 3) + { + throw std::runtime_error("Out of bounds."); + } + + return this->value_[i]; + } + + const game::vec_t& vector::operator[](const size_t i) const + { + if (i >= 3) + { + throw std::runtime_error("Out of bounds."); + } + + return this->value_[i]; + } + + float vector::get_x() const + { + return this->operator[](0); + } + + float vector::get_y() const + { + return this->operator[](1); + } + + float vector::get_z() const + { + return this->operator[](2); + } + + void vector::set_x(const float value) + { + this->operator[](0) = value; + } + + void vector::set_y(const float value) + { + this->operator[](1) = value; + } + + void vector::set_z(const float value) + { + this->operator[](2) = value; + } +} diff --git a/src/client/game/scripting/vector.hpp b/src/client/game/scripting/vector.hpp new file mode 100644 index 00000000..70b146d6 --- /dev/null +++ b/src/client/game/scripting/vector.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "game/game.hpp" + +namespace scripting +{ + class vector final + { + public: + vector() = default; + vector(const float* value); + vector(const game::vec3_t& value); + vector(float x, float y, float z); + + operator game::vec3_t&(); + operator const game::vec3_t&() const; + + game::vec_t& operator[](size_t i); + const game::vec_t& operator[](size_t i) const; + + float get_x() const; + float get_y() const; + float get_z() const; + + void set_x(float value); + void set_y(float value); + void set_z(float value); + + private: + game::vec3_t value_{0}; + }; +} diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp new file mode 100644 index 00000000..5004de2b --- /dev/null +++ b/src/client/game/structs.hpp @@ -0,0 +1,1634 @@ +#pragma once +#include + +#define PROTOCOL 1 + +namespace game +{ + typedef float vec_t; + typedef vec_t vec2_t[2]; + typedef vec_t vec3_t[3]; + typedef vec_t vec4_t[4]; + + // * scripting + enum scr_string_t + { + scr_string_t_dummy = 0x0, + }; + + struct scr_entref_t + { + unsigned short entnum; + unsigned short classnum; + }; + + enum scriptType_e + { + SCRIPT_NONE = 0, + SCRIPT_OBJECT = 1, + SCRIPT_STRING = 2, + SCRIPT_ISTRING = 3, + SCRIPT_VECTOR = 4, + SCRIPT_FLOAT = 5, + SCRIPT_INTEGER = 6, + SCRIPT_END = 8, + SCRIPT_FUNCTION = 9, + SCRIPT_STRUCT = 19, + SCRIPT_ARRAY = 22 + }; + + struct VariableStackBuffer + { + const char* pos; + unsigned __int16 size; + unsigned __int16 bufLen; + unsigned __int16 localId; + char time; + char buf[1]; + }; + + union VariableUnion + { + int intValue; + unsigned int uintValue; + float floatValue; + unsigned int stringValue; + const float* vectorValue; + const char* codePosValue; + unsigned int pointerValue; + VariableStackBuffer* stackValue; + unsigned int entityOffset; + }; + + struct VariableValue + { + VariableUnion u; + int type; + }; + + struct function_stack_t + { + const char* pos; + unsigned int localId; + unsigned int localVarCount; + VariableValue* top; + VariableValue* startTop; + }; + + struct function_frame_t + { + function_stack_t fs; + int topType; + }; + + struct scrVmPub_t + { + unsigned int* localVars; + VariableValue* maxstack; + int function_count; + function_frame_t* function_frame; + VariableValue* top; + unsigned int inparamcount; + unsigned int outparamcount; + function_frame_t function_frame_start[32]; + VariableValue stack[2048]; + }; + + struct scr_classStruct_t + { + unsigned __int16 id; + unsigned __int16 entArrayId; + char charId; + const char* name; + }; + + struct ObjectVariableChildren + { + unsigned __int16 firstChild; + unsigned __int16 lastChild; + }; + + struct ObjectVariableValue_u_f + { + unsigned __int16 prev; + unsigned __int16 next; + }; + + union ObjectVariableValue_u_o_u + { + unsigned __int16 size; + unsigned __int16 entnum; + unsigned __int16 nextEntId; + unsigned __int16 self; + }; + + struct ObjectVariableValue_u_o + { + unsigned __int16 refCount; + ObjectVariableValue_u_o_u u; + }; + + union ObjectVariableValue_w + { + unsigned int type; + unsigned int classnum; + unsigned int notifyName; + unsigned int waitTime; + unsigned int parentLocalId; + }; + + struct ChildVariableValue_u_f + { + unsigned __int16 prev; + unsigned __int16 next; + }; + + union ChildVariableValue_u + { + ChildVariableValue_u_f f; + VariableUnion u; + }; + + struct ChildBucketMatchKeys_keys + { + unsigned __int16 name_hi; + unsigned __int16 parentId; + }; + + union ChildBucketMatchKeys + { + ChildBucketMatchKeys_keys keys; + unsigned int match; + }; + + struct ChildVariableValue + { + ChildVariableValue_u u; + unsigned __int16 next; + char type; + char name_lo; + ChildBucketMatchKeys k; + unsigned __int16 nextSibling; + unsigned __int16 prevSibling; + }; + + union ObjectVariableValue_u + { + ObjectVariableValue_u_f f; + ObjectVariableValue_u_o o; + }; + + struct ObjectVariableValue + { + ObjectVariableValue_u u; + ObjectVariableValue_w w; + }; + + struct scrVarGlob_t + { + ObjectVariableValue objectVariableValue[40960]; + ObjectVariableChildren objectVariableChildren[40960]; + unsigned __int16 childVariableBucket[65536]; + ChildVariableValue childVariableValue[384000]; + }; + // * + + enum Sys_Folder + { + SF_ZONE = 0x0, + SF_ZONE_LOC = 0x1, + SF_VIDEO = 0x2, + SF_VIDEO_LOC = 0x3, + SF_PAKFILE = 0x4, + SF_PAKFILE_LOC = 0x5, + SF_COUNT = 0x6, + }; + + enum CodPlayMode + { + CODPLAYMODE_NONE = 0x0, + CODPLAYMODE_SP = 0x1, + CODPLAYMODE_CORE = 0x2, + CODPLAYMODE_SURVIVAL = 0x5, + CODPLAYMODE_ZOMBIES = 0x6, + }; + + enum DWOnlineStatus + { + DW_LIVE_DISCONNECTED = 0x0, + DW_LIVE_CONNECTING = 0x1, + DW_LIVE_CONNECTED = 0x2, + }; + + enum DWNetStatus + { + DW_NET_ERROR_START_FAILED = 0x0, + DW_NET_ERROR_NO_LOCAL_IP = 0x1, + DW_NET_NOT_STARTED = 0x2, + DW_NET_STARTING_LAN = 0x3, + DW_NET_STARTED_LAN = 0x4, + DW_NET_STARTING_ONLINE = 0x5, + DW_NET_STARTED_ONLINE = 0x6, + }; + + enum DWLogonStatus + { + DW_LOGON_ERROR = 0x0, + DW_NP_CONNECTING = 0x1, + DW_NO_ACCOUNT_SIGNED_IN = 0x2, + DW_DNS_NOT_RESOLVED = 0x3, + DW_PC_STEAM_ACQUIRE_DEDICATED_LICENSE = 0x4, + DW_PC_STEAM_ACQUIRING_DEDICATED_LICENSE = 0x5, + DW_PC_STEAM_AUTHORIZING_DEDICATED_LICENSE = 0x6, + DW_PC_STATIC_LICENSE = 0x7, + DW_PC_AUTHORIZING_STATIC_LICENSE = 0x8, + DW_LOBBY_CONNECT = 0x9, + DW_LOBBY_CONNECTING = 0xA, + DW_LOGON_COMPLETE = 0xB, + }; + + enum bdLobbyErrorCode : uint32_t + { + BD_NO_ERROR = 0x0, + BD_TOO_MANY_TASKS = 0x1, + BD_NOT_CONNECTED = 0x2, + BD_SEND_FAILED = 0x3, + BD_HANDLE_TASK_FAILED = 0x4, + BD_START_TASK_FAILED = 0x5, + BD_RESULT_EXCEEDS_BUFFER_SIZE = 0x64, + BD_ACCESS_DENIED = 0x65, + BD_EXCEPTION_IN_DB = 0x66, + BD_MALFORMED_TASK_HEADER = 0x67, + BD_INVALID_ROW = 0x68, + BD_EMPTY_ARG_LIST = 0x69, + BD_PARAM_PARSE_ERROR = 0x6A, + BD_PARAM_MISMATCHED_TYPE = 0x6B, + BD_SERVICE_NOT_AVAILABLE = 0x6C, + BD_CONNECTION_RESET = 0x6D, + BD_INVALID_USER_ID = 0x6E, + BD_LOBBY_PROTOCOL_VERSION_FAILURE = 0x6F, + BD_LOBBY_INTERNAL_FAILURE = 0x70, + BD_LOBBY_PROTOCOL_ERROR = 0x71, + BD_LOBBY_FAILED_TO_DECODE_UTF8 = 0x72, + BD_LOBBY_ASCII_EXPECTED = 0x73, + BD_ASYNCHRONOUS_ERROR = 0xC8, + BD_STREAMING_COMPLETE = 0xC9, + BD_MEMBER_NO_PROPOSAL = 0x12C, + BD_TEAMNAME_ALREADY_EXISTS = 0x12D, + BD_MAX_TEAM_MEMBERSHIPS_LIMITED = 0x12E, + BD_MAX_TEAM_OWNERSHIPS_LIMITED = 0x12F, + BD_NOT_A_TEAM_MEMBER = 0x130, + BD_INVALID_TEAM_ID = 0x131, + BD_INVALID_TEAM_NAME = 0x132, + BD_NOT_A_TEAM_OWNER = 0x133, + BD_NOT_AN_ADMIN_OR_OWNER = 0x134, + BD_MEMBER_PROPOSAL_EXISTS = 0x135, + BD_MEMBER_EXISTS = 0x136, + BD_TEAM_FULL = 0x137, + BD_VULGAR_TEAM_NAME = 0x138, + BD_TEAM_USERID_BANNED = 0x139, + BD_TEAM_EMPTY = 0x13A, + BD_INVALID_TEAM_PROFILE_QUERY_ID = 0x13B, + BD_TEAMNAME_TOO_SHORT = 0x13C, + BD_UNIQUE_PROFILE_DATA_EXISTS_ALREADY = 0x13D, + BD_INVALID_LEADERBOARD_ID = 0x190, + BD_INVALID_STATS_SET = 0x191, + BD_EMPTY_STATS_SET_IGNORED = 0x193, + BD_NO_DIRECT_ACCESS_TO_ARBITRATED_LBS = 0x194, + BD_STATS_WRITE_PERMISSION_DENIED = 0x195, + BD_STATS_WRITE_TYPE_DATA_TYPE_MISMATCH = 0x196, + BD_NO_STATS_FOR_USER = 0x197, + BD_INVALID_ACCESS_TO_UNRANKED_LB = 0x198, + BD_INVALID_EXTERNAL_TITLE_ID = 0x199, + BD_DIFFERENT_LEADERBOARD_SCHEMAS = 0x19A, + BD_TOO_MANY_LEADERBOARDS_REQUESTED = 0x19B, + BD_ENTITLEMENTS_ERROR = 0x19C, + BD_ENTITLEMENTS_INVALID_TITLEID = 0x19D, + BD_ENTITLEMENTS_INVALID_LEADERBOARDID = 0x19E, + BD_ENTITLEMENTS_INVALID_GET_MODE_FOR_TITLE = 0x19F, + BD_ENTITLEMENTS_URL_CONNECTION_ERROR = 0x1A0, + BD_ENTITLEMENTS_CONFIG_ERROR = 0x1A1, + BD_ENTITLEMENTS_NAMED_PARENT_ERROR = 0x1A2, + BD_ENTITLEMENTS_NAMED_KEY_ERROR = 0x1A3, + BD_TOO_MANY_ENTITY_IDS_REQUESTED = 0x1A4, + BD_STATS_READ_FAILED = 0x1A5, + BD_INVALID_TITLE_ID = 0x1F4, + BD_MESSAGING_INVALID_MAIL_ID = 0x258, + BD_SELF_BLOCK_NOT_ALLOWED = 0x259, + BD_GLOBAL_MESSAGE_ACCESS_DENIED = 0x25A, + BD_GLOBAL_MESSAGES_USER_LIMIT_EXCEEDED = 0x25B, + BD_MESSAGING_SENDER_DOES_NOT_EXIST = 0x25C, + BD_AUTH_NO_ERROR = 0x2BC, + BD_AUTH_BAD_REQUEST = 0x2BD, + BD_AUTH_SERVER_CONFIG_ERROR = 0x2BE, + BD_AUTH_BAD_TITLE_ID = 0x2BF, + BD_AUTH_BAD_ACCOUNT = 0x2C0, + BD_AUTH_ILLEGAL_OPERATION = 0x2C1, + BD_AUTH_INCORRECT_LICENSE_CODE = 0x2C2, + BD_AUTH_CREATE_USERNAME_EXISTS = 0x2C3, + BD_AUTH_CREATE_USERNAME_ILLEGAL = 0x2C4, + BD_AUTH_CREATE_USERNAME_VULGAR = 0x2C5, + BD_AUTH_CREATE_MAX_ACC_EXCEEDED = 0x2C6, + BD_AUTH_MIGRATE_NOT_SUPPORTED = 0x2C7, + BD_AUTH_TITLE_DISABLED = 0x2C8, + BD_AUTH_ACCOUNT_EXPIRED = 0x2C9, + BD_AUTH_ACCOUNT_LOCKED = 0x2CA, + BD_AUTH_UNKNOWN_ERROR = 0x2CB, + BD_AUTH_INCORRECT_PASSWORD = 0x2CC, + BD_AUTH_IP_NOT_IN_ALLOWED_RANGE = 0x2CD, + BD_AUTH_WII_TOKEN_VERIFICATION_FAILED = 0x2CE, + BD_AUTH_WII_AUTHENTICATION_FAILED = 0x2CF, + BD_AUTH_IP_KEY_LIMIT_REACHED = 0x2D0, + BD_AUTH_INVALID_GSPID = 0x2D1, + BD_AUTH_INVALID_IP_RANGE_ID = 0x2D2, + BD_AUTH_3DS_TOKEN_VERIFICATION_FAILED = 0x2D1, + BD_AUTH_3DS_AUTHENTICATION_FAILED = 0x2D2, + BD_AUTH_STEAM_APP_ID_MISMATCH = 0x2D3, + BD_AUTH_ABACCOUNTS_APP_ID_MISMATCH = 0x2D4, + BD_AUTH_CODO_USERNAME_NOT_SET = 0x2D5, + BD_AUTH_WIIU_TOKEN_VERIFICATION_FAILED = 0x2D6, + BD_AUTH_WIIU_AUTHENTICATION_FAILED = 0x2D7, + BD_AUTH_CODO_USERNAME_NOT_BASE64 = 0x2D8, + BD_AUTH_CODO_USERNAME_NOT_UTF8 = 0x2D9, + BD_AUTH_TENCENT_TICKET_EXPIRED = 0x2DA, + BD_AUTH_PS3_SERVICE_ID_MISMATCH = 0x2DB, + BD_AUTH_CODOID_NOT_WHITELISTED = 0x2DC, + BD_AUTH_PLATFORM_TOKEN_ERROR = 0x2DD, + BD_AUTH_JSON_FORMAT_ERROR = 0x2DE, + BD_AUTH_REPLY_CONTENT_ERROR = 0x2DF, + BD_AUTH_THIRD_PARTY_TOKEN_EXPIRED = 0x2E0, + BD_AUTH_CONTINUING = 0x2E1, + BD_AUTH_PLATFORM_DEVICE_ID_ERROR = 0x2E4, + BD_NO_PROFILE_INFO_EXISTS = 0x320, + BD_FRIENDSHIP_NOT_REQUSTED = 0x384, + BD_NOT_A_FRIEND = 0x385, + BD_SELF_FRIENDSHIP_NOT_ALLOWED = 0x387, + BD_FRIENDSHIP_EXISTS = 0x388, + BD_PENDING_FRIENDSHIP_EXISTS = 0x389, + BD_USERID_BANNED = 0x38A, + BD_FRIENDS_FULL = 0x38C, + BD_FRIENDS_NO_RICH_PRESENCE = 0x38D, + BD_RICH_PRESENCE_TOO_LARGE = 0x38E, + BD_NO_FILE = 0x3E8, + BD_PERMISSION_DENIED = 0x3E9, + BD_FILESIZE_LIMIT_EXCEEDED = 0x3EA, + BD_FILENAME_MAX_LENGTH_EXCEEDED = 0x3EB, + BD_EXTERNAL_STORAGE_SERVICE_ERROR = 0x3EC, + BD_CHANNEL_DOES_NOT_EXIST = 0x44D, + BD_CHANNEL_ALREADY_SUBSCRIBED = 0x44E, + BD_CHANNEL_NOT_SUBSCRIBED = 0x44F, + BD_CHANNEL_FULL = 0x450, + BD_CHANNEL_SUBSCRIPTIONS_FULL = 0x451, + BD_CHANNEL_NO_SELF_WHISPERING = 0x452, + BD_CHANNEL_ADMIN_REQUIRED = 0x453, + BD_CHANNEL_TARGET_NOT_SUBSCRIBED = 0x454, + BD_CHANNEL_REQUIRES_PASSWORD = 0x455, + BD_CHANNEL_TARGET_IS_SELF = 0x456, + BD_CHANNEL_PUBLIC_BAN_NOT_ALLOWED = 0x457, + BD_CHANNEL_USER_BANNED = 0x458, + BD_CHANNEL_PUBLIC_PASSWORD_NOT_ALLOWED = 0x459, + BD_CHANNEL_PUBLIC_KICK_NOT_ALLOWED = 0x45A, + BD_CHANNEL_MUTED = 0x45B, + BD_EVENT_DESC_TRUNCATED = 0x4B0, + BD_CONTENT_UNLOCK_UNKNOWN_ERROR = 0x514, + BD_UNLOCK_KEY_INVALID = 0x515, + BD_UNLOCK_KEY_ALREADY_USED_UP = 0x516, + BD_SHARED_UNLOCK_LIMIT_REACHED = 0x517, + BD_DIFFERENT_HARDWARE_ID = 0x518, + BD_INVALID_CONTENT_OWNER = 0x519, + BD_CONTENT_UNLOCK_INVALID_USER = 0x51A, + BD_CONTENT_UNLOCK_INVALID_CATEGORY = 0x51B, + BD_KEY_ARCHIVE_INVALID_WRITE_TYPE = 0x5DC, + BD_KEY_ARCHIVE_EXCEEDED_MAX_IDS_PER_REQUEST = 0x5DD, + BD_BANDWIDTH_TEST_TRY_AGAIN = 0x712, + BD_BANDWIDTH_TEST_STILL_IN_PROGRESS = 0x713, + BD_BANDWIDTH_TEST_NOT_PROGRESS = 0x714, + BD_BANDWIDTH_TEST_SOCKET_ERROR = 0x715, + BD_INVALID_SESSION_NONCE = 0x76D, + BD_ARBITRATION_FAILURE = 0x76F, + BD_ARBITRATION_USER_NOT_REGISTERED = 0x771, + BD_ARBITRATION_NOT_CONFIGURED = 0x772, + BD_CONTENTSTREAMING_FILE_NOT_AVAILABLE = 0x7D0, + BD_CONTENTSTREAMING_STORAGE_SPACE_EXCEEDED = 0x7D1, + BD_CONTENTSTREAMING_NUM_FILES_EXCEEDED = 0x7D2, + BD_CONTENTSTREAMING_UPLOAD_BANDWIDTH_EXCEEDED = 0x7D3, + BD_CONTENTSTREAMING_FILENAME_MAX_LENGTH_EXCEEDED = 0x7D4, + BD_CONTENTSTREAMING_MAX_THUMB_DATA_SIZE_EXCEEDED = 0x7D5, + BD_CONTENTSTREAMING_DOWNLOAD_BANDWIDTH_EXCEEDED = 0x7D6, + BD_CONTENTSTREAMING_NOT_ENOUGH_DOWNLOAD_BUFFER_SPACE = 0x7D7, + BD_CONTENTSTREAMING_SERVER_NOT_CONFIGURED = 0x7D8, + BD_CONTENTSTREAMING_INVALID_APPLE_RECEIPT = 0x7DA, + BD_CONTENTSTREAMING_APPLE_STORE_NOT_AVAILABLE = 0x7DB, + BD_CONTENTSTREAMING_APPLE_RECEIPT_FILENAME_MISMATCH = 0x7DC, + BD_CONTENTSTREAMING_HTTP_ERROR = 0x7E4, + BD_CONTENTSTREAMING_FAILED_TO_START_HTTP = 0x7E5, + BD_CONTENTSTREAMING_LOCALE_INVALID = 0x7E6, + BD_CONTENTSTREAMING_LOCALE_MISSING = 0x7E7, + BD_VOTERANK_ERROR_EMPTY_RATING_SUBMISSION = 0x7EE, + BD_VOTERANK_ERROR_MAX_VOTES_EXCEEDED = 0x7EF, + BD_VOTERANK_ERROR_INVALID_RATING = 0x7F0, + BD_MAX_NUM_TAGS_EXCEEDED = 0x82A, + BD_TAGGED_COLLECTION_DOES_NOT_EXIST = 0x82B, + BD_EMPTY_TAG_ARRAY = 0x82C, + BD_INVALID_QUERY_ID = 0x834, + BD_NO_ENTRY_TO_UPDATE = 0x835, + BD_SESSION_INVITE_EXISTS = 0x836, + BD_INVALID_SESSION_ID = 0x837, + BD_ATTACHMENT_TOO_LARGE = 0x838, + BD_INVALID_GROUP_ID = 0xAF0, + BD_MAIL_INVALID_MAIL_ID_ERROR = 0xB55, + BD_UCD_SERVICE_ERROR = 0xC80, + BD_UCD_SERVICE_DISABLED = 0xC81, + BD_UCD_UNINTIALIZED_ERROR = 0xC82, + BD_UCD_ACCOUNT_ALREADY_REGISTERED = 0xC83, + BD_UCD_ACCOUNT_NOT_REGISTERED = 0xC84, + BD_UCD_AUTH_ATTEMPT_FAILED = 0xC85, + BD_UCD_ACCOUNT_LINKING_ERROR = 0xC86, + BD_UCD_ENCRYPTION_ERROR = 0xC87, + BD_UCD_ACCOUNT_DATA_INVALID = 0xC88, + BD_UCD_ACCOUNT_DATA_INVALID_FIRSTNAME = 0xC89, + BD_UCD_ACCOUNT_DATA_INVALID_LASTNAME = 0xC8A, + BD_UCD_ACCOUNT_DATA_INVALID_DOB = 0xC8B, + BD_UCD_ACCOUNT_DATA_INVALID_EMAIL = 0xC8C, + BD_UCD_ACCOUNT_DATA_INVALID_COUNTRY = 0xC8D, + BD_UCD_ACCOUNT_DATA_INVALID_POSTCODE = 0xC8E, + BD_UCD_ACCOUNT_DATA_INVALID_PASSWORD = 0xC8F, + BD_UCD_ACCOUNT_NAME_ALREADY_RESISTERED = 0xC94, + BD_UCD_ACCOUNT_EMAIL_ALREADY_RESISTERED = 0xC95, + BD_UCD_GUEST_ACCOUNT_AUTH_CONFLICT = 0xC96, + BD_TWITCH_SERVICE_ERROR = 0xC1D, + BD_TWITCH_ACCOUNT_ALREADY_LINKED = 0xC1E, + BD_TWITCH_NO_LINKED_ACCOUNT = 0xC1F, + BD_YOUTUBE_SERVICE_ERROR = 0xCE5, + BD_YOUTUBE_SERVICE_COMMUNICATION_ERROR = 0xCE6, + BD_YOUTUBE_USER_DENIED_AUTHORIZATION = 0xCE7, + BD_YOUTUBE_AUTH_MAX_TIME_EXCEEDED = 0xCE8, + BD_YOUTUBE_USER_UNAUTHORIZED = 0xCE9, + BD_YOUTUBE_UPLOAD_MAX_TIME_EXCEEDED = 0xCEA, + BD_YOUTUBE_DUPLICATE_UPLOAD = 0xCEB, + BD_YOUTUBE_FAILED_UPLOAD = 0xCEC, + BD_YOUTUBE_ACCOUNT_ALREADY_REGISTERED = 0xCED, + BD_YOUTUBE_ACCOUNT_NOT_REGISTERED = 0xCEE, + BD_YOUTUBE_CONTENT_SERVER_ERROR = 0xCEF, + BD_YOUTUBE_UPLOAD_DOES_NOT_EXIST = 0xCF0, + BD_YOUTUBE_NO_LINKED_ACCOUNT = 0xCF1, + BD_YOUTUBE_DEVELOPER_TAGS_INVALID = 0xCF2, + BD_TWITTER_AUTH_ATTEMPT_FAILED = 0xDAD, + BD_TWITTER_AUTH_TOKEN_INVALID = 0xDAE, + BD_TWITTER_UPDATE_LIMIT_REACHED = 0xDAF, + BD_TWITTER_UNAVAILABLE = 0xDB0, + BD_TWITTER_ERROR = 0xDB1, + BD_TWITTER_TIMED_OUT = 0xDB2, + BD_TWITTER_DISABLED_FOR_USER = 0xDB3, + BD_TWITTER_ACCOUNT_AMBIGUOUS = 0xDB4, + BD_TWITTER_MAXIMUM_ACCOUNTS_REACHED = 0xDB5, + BD_TWITTER_ACCOUNT_NOT_REGISTERED = 0xDB6, + BD_TWITTER_DUPLICATE_STATUS = 0xDB7, + BD_TWITTER_ACCOUNT_ALREADY_REGISTERED = 0xE1C, + BD_FACEBOOK_AUTH_ATTEMPT_FAILED = 0xE11, + BD_FACEBOOK_AUTH_TOKEN_INVALID = 0xE12, + BD_FACEBOOK_PHOTO_DOES_NOT_EXIST = 0xE13, + BD_FACEBOOK_PHOTO_INVALID = 0xE14, + BD_FACEBOOK_PHOTO_ALBUM_FULL = 0xE15, + BD_FACEBOOK_UNAVAILABLE = 0xE16, + BD_FACEBOOK_ERROR = 0xE17, + BD_FACEBOOK_TIMED_OUT = 0xE18, + BD_FACEBOOK_DISABLED_FOR_USER = 0xE19, + BD_FACEBOOK_ACCOUNT_AMBIGUOUS = 0xE1A, + BD_FACEBOOK_MAXIMUM_ACCOUNTS_REACHED = 0xE1B, + BD_FACEBOOK_INVALID_NUM_PICTURES_REQUESTED = 0xE1C, + BD_FACEBOOK_VIDEO_DOES_NOT_EXIST = 0xE1D, + BD_FACEBOOK_ACCOUNT_ALREADY_REGISTERED = 0xE1E, + BD_APNS_INVALID_PAYLOAD = 0xE74, + BD_APNS_INVALID_TOKEN_LENGTH_ERROR = 0xE76, + BD_MAX_CONSOLEID_LENGTH_EXCEEDED = 0xEE1, + BD_MAX_WHITELIST_LENGTH_EXCEEDED = 0xEE2, + BD_USERGROUP_NAME_ALREADY_EXISTS = 0x1770, + BD_INVALID_USERGROUP_ID = 0x1771, + BD_USER_ALREADY_IN_USERGROUP = 0x1772, + BD_USER_NOT_IN_USERGROUP = 0x1773, + BD_INVALID_USERGROUP_MEMBER_TYPE = 0x1774, + BD_TOO_MANY_MEMBERS_REQUESTED = 0x1775, + BD_USERGROUP_NAME_TOO_SHORT = 0x1776, + BD_RICH_PRESENCE_DATA_TOO_LARGE = 0x1A90, + BD_RICH_PRESENCE_TOO_MANY_USERS = 0x1A91, + BD_PRESENCE_DATA_TOO_LARGE = 0x283C, + BD_PRESENCE_TOO_MANY_USERS = 0x283D, + BD_USER_LOGGED_IN_OTHER_TITLE = 0x283E, + BD_USER_NOT_LOGGED_IN = 0x283F, + BD_SUBSCRIPTION_TOO_MANY_USERS = 0x1B58, + BD_SUBSCRIPTION_TICKET_PARSE_ERROR = 0x1B59, + BD_CODO_ID_INVALID_DATA = 0x1BBC, + BD_INVALID_MESSAGE_FORMAT = 0x1BBD, + BD_TLOG_TOO_MANY_MESSAGES = 0x1BBE, + BD_CODO_ID_NOT_IN_WHITELIST = 0x1BBF, + BD_TLOG_MESSAGE_TRANSFORMATION_ERROR = 0x1BC0, + BD_REWARDS_NOT_ENABLED = 0x1BC1, + BD_MARKETPLACE_ERROR = 0x1F40, + BD_MARKETPLACE_RESOURCE_NOT_FOUND = 0x1F41, + BD_MARKETPLACE_INVALID_CURRENCY = 0x1F42, + BD_MARKETPLACE_INVALID_PARAMETER = 0x1F43, + BD_MARKETPLACE_RESOURCE_CONFLICT = 0x1F44, + BD_MARKETPLACE_STORAGE_ERROR = 0x1F45, + BD_MARKETPLACE_INTEGRITY_ERROR = 0x1F46, + BD_MARKETPLACE_INSUFFICIENT_FUNDS_ERROR = 0x1F47, + BD_MARKETPLACE_MMP_SERVICE_ERROR = 0x1F48, + BD_MARKETPLACE_PRECONDITION_REQUIRED = 0x1F49, + BD_MARKETPLACE_ITEM_MULTIPLE_PURCHASE_ERROR = 0x1F4A, + BD_MARKETPLACE_MISSING_REQUIRED_ENTITLEMENT = 0x1F4B, + BD_MARKETPLACE_VALIDATION_ERROR = 0x1F4C, + BD_MARKETPLACE_TENCENT_PAYMENT_ERROR = 0x1F4D, + BD_MARKETPLACE_SKU_NOT_COUPON_ENABLED_ERROR = 0x1F4E, + BD_LEAGUE_INVALID_TEAM_SIZE = 0x1FA4, + BD_LEAGUE_INVALID_TEAM = 0x1FA5, + BD_LEAGUE_INVALID_SUBDIVISION = 0x1FA6, + BD_LEAGUE_INVALID_LEAGUE = 0x1FA7, + BD_LEAGUE_TOO_MANY_RESULTS_REQUESTED = 0x1FA8, + BD_LEAGUE_METADATA_TOO_LARGE = 0x1FA9, + BD_LEAGUE_TEAM_ICON_TOO_LARGE = 0x1FAA, + BD_LEAGUE_TEAM_NAME_TOO_LONG = 0x1FAB, + BD_LEAGUE_ARRAY_SIZE_MISMATCH = 0x1FAC, + BD_LEAGUE_SUBDIVISION_MISMATCH = 0x2008, + BD_LEAGUE_INVALID_WRITE_TYPE = 0x2009, + BD_LEAGUE_INVALID_STATS_DATA = 0x200A, + BD_LEAGUE_SUBDIVISION_UNRANKED = 0x200B, + BD_LEAGUE_CROSS_TEAM_STATS_WRITE_PREVENTED = 0x200C, + BD_LEAGUE_INVALID_STATS_SEASON = 0x200D, + BD_COMMERCE_ERROR = 0x206C, + BD_COMMERCE_RESOURCE_NOT_FOUND = 0x206D, + BD_COMMERCE_STORAGE_INVALID_PARAMETER = 0x206E, + BD_COMMERCE_APPLICATION_INVALID_PARAMETER = 0x206F, + BD_COMMERCE_RESOURCE_CONFLICT = 0x2070, + BD_COMMERCE_STORAGE_ERROR = 0x2071, + BD_COMMERCE_INTEGRITY_ERROR = 0x2072, + BD_COMMERCE_MMP_SERVICE_ERROR = 0x2073, + BD_COMMERCE_PERMISSION_DENIED = 0x2074, + BD_COMMERCE_INSUFFICIENT_FUNDS_ERROR = 0x2075, + BD_COMMERCE_UNKNOWN_CURRENCY = 0x2076, + BD_COMMERCE_INVALID_RECEIPT = 0x2077, + BD_COMMERCE_RECEIPT_USED = 0x2078, + BD_COMMERCE_TRANSACTION_ALREADY_APPLIED = 0x2079, + BD_COMMERCE_INVALID_CURRENCY_TYPE = 0x207A, + BD_CONNECTION_COUNTER_ERROR = 0x20D0, + BD_LINKED_ACCOUNTS_INVALID_CONTEXT = 0x2198, + BD_LINKED_ACCOUNTS_INVALID_PLATFORM = 0x2199, + BD_LINKED_ACCOUNTS_LINKED_ACCOUNTS_FETCH_ERROR = 0x219A, + BD_LINKED_ACCOUNTS_INVALID_ACCOUNT = 0x219B, + BD_GMSG_INVALID_CATEGORY_ID = 0x27D8, + BD_GMSG_CATEGORY_MEMBERSHIPS_LIMIT = 0x27D9, + BD_GMSG_NONMEMBER_POST_DISALLOWED = 0x27DA, + BD_GMSG_CATEGORY_DISALLOWS_CLIENT_TYPE = 0x27DB, + BD_GMSG_PAYLOAD_TOO_BIG = 0x27DC, + BD_GMSG_MEMBER_POST_DISALLOWED = 0x27DD, + BD_GMSG_OVERLOADED = 0x27DE, + BD_GMSG_USER_PERCATEGORY_POST_RATE_EXCEEDED = 0x27DF, + BD_GMSG_USER_GLOBAL_POST_RATE_EXCEEDED = 0x27E0, + BD_GMSG_GROUP_POST_RATE_EXCEEDED = 0x27E1, + BD_MAX_ERROR_CODE = 0x27E2, + }; + + enum bdNATType : uint8_t + { + BD_NAT_UNKNOWN = 0x0, + BD_NAT_OPEN = 0x1, + BD_NAT_MODERATE = 0x2, + BD_NAT_STRICT = 0x3, + }; + +#pragma pack(push, 1) + struct bdAuthTicket + { + unsigned int m_magicNumber; + char m_type; + unsigned int m_titleID; + unsigned int m_timeIssued; + unsigned int m_timeExpires; + unsigned long long m_licenseID; + unsigned long long m_userID; + char m_username[64]; + char m_sessionKey[24]; + char m_usingHashMagicNumber[3]; + char m_hash[4]; + }; +#pragma pack(pop) + + enum keyNum_t + { + K_NONE = 0x0, + K_FIRSTGAMEPADBUTTON_RANGE_1 = 0x1, + K_BUTTON_A = 0x1, + K_BUTTON_B = 0x2, + K_BUTTON_X = 0x3, + K_BUTTON_Y = 0x4, + K_BUTTON_LSHLDR = 0x5, + K_BUTTON_RSHLDR = 0x6, + K_LASTGAMEPADBUTTON_RANGE_1 = 0x6, + K_BS = 0x8, + K_TAB = 0x9, + K_ENTER = 0xD, + K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, + K_BUTTON_START = 0xE, + K_BUTTON_BACK = 0xF, + K_BUTTON_LSTICK = 0x10, + K_BUTTON_RSTICK = 0x11, + K_BUTTON_LTRIG = 0x12, + K_BUTTON_RTRIG = 0x13, + K_DPAD_UP = 0x14, + K_FIRSTDPAD = 0x14, + K_DPAD_DOWN = 0x15, + K_DPAD_LEFT = 0x16, + K_DPAD_RIGHT = 0x17, + K_BUTTON_LSTICK_ALTIMAGE2 = 0x10, + K_BUTTON_RSTICK_ALTIMAGE2 = 0x11, + K_BUTTON_LSTICK_ALTIMAGE = 0xBC, + K_BUTTON_RSTICK_ALTIMAGE = 0xBD, + K_LASTDPAD = 0x17, + K_LASTGAMEPADBUTTON_RANGE_2 = 0x17, + K_ESCAPE = 0x1B, + K_FIRSTGAMEPADBUTTON_RANGE_3 = 0x1C, + K_APAD_UP = 0x1C, + K_FIRSTAPAD = 0x1C, + K_APAD_DOWN = 0x1D, + K_APAD_LEFT = 0x1E, + K_APAD_RIGHT = 0x1F, + K_LASTAPAD = 0x1F, + K_LASTGAMEPADBUTTON_RANGE_3 = 0x1F, + K_SPACE = 0x20, + K_GRAVE = 0x60, + K_TILDE = 0x7E, + K_BACKSPACE = 0x7F, + K_ASCII_FIRST = 0x80, + K_ASCII_181 = 0x80, + K_ASCII_191 = 0x81, + K_ASCII_223 = 0x82, + K_ASCII_224 = 0x83, + K_ASCII_225 = 0x84, + K_ASCII_228 = 0x85, + K_ASCII_229 = 0x86, + K_ASCII_230 = 0x87, + K_ASCII_231 = 0x88, + K_ASCII_232 = 0x89, + K_ASCII_233 = 0x8A, + K_ASCII_236 = 0x8B, + K_ASCII_241 = 0x8C, + K_ASCII_242 = 0x8D, + K_ASCII_243 = 0x8E, + K_ASCII_246 = 0x8F, + K_ASCII_248 = 0x90, + K_ASCII_249 = 0x91, + K_ASCII_250 = 0x92, + K_ASCII_252 = 0x93, + K_END_ASCII_CHARS = 0x94, + K_COMMAND = 0x96, + K_CAPSLOCK = 0x97, + K_POWER = 0x98, + K_PAUSE = 0x99, + K_UPARROW = 0x9A, + K_DOWNARROW = 0x9B, + K_LEFTARROW = 0x9C, + K_RIGHTARROW = 0x9D, + K_ALT = 0x9E, + K_CTRL = 0x9F, + K_SHIFT = 0xA0, + K_INS = 0xA1, + K_DEL = 0xA2, + K_PGDN = 0xA3, + K_PGUP = 0xA4, + K_HOME = 0xA5, + K_END = 0xA6, + K_F1 = 0xA7, + K_F2 = 0xA8, + K_F3 = 0xA9, + K_F4 = 0xAA, + K_F5 = 0xAB, + K_F6 = 0xAC, + K_F7 = 0xAD, + K_F8 = 0xAE, + K_F9 = 0xAF, + K_F10 = 0xB0, + K_F11 = 0xB1, + K_F12 = 0xB2, + K_F13 = 0xB3, + K_F14 = 0xB4, + K_F15 = 0xB5, + K_KP_HOME = 0xB6, + K_KP_UPARROW = 0xB7, + K_KP_PGUP = 0xB8, + K_KP_LEFTARROW = 0xB9, + K_KP_5 = 0xBA, + K_KP_RIGHTARROW = 0xBB, + K_KP_END = 0xBC, + K_KP_DOWNARROW = 0xBD, + K_KP_PGDN = 0xBE, + K_KP_ENTER = 0xBF, + K_KP_INS = 0xC0, + K_KP_DEL = 0xC1, + K_KP_SLASH = 0xC2, + K_KP_MINUS = 0xC3, + K_KP_PLUS = 0xC4, + K_KP_NUMLOCK = 0xC5, + K_KP_STAR = 0xC6, + K_KP_EQUALS = 0xC7, + K_MOUSE1 = 0xC8, + K_MOUSE2 = 0xC9, + K_MOUSE3 = 0xCA, + K_MOUSE4 = 0xCB, + K_MOUSE5 = 0xCC, + K_MWHEELDOWN = 0xCD, + K_MWHEELUP = 0xCE, + K_AUX1 = 0xCF, + K_AUX2 = 0xD0, + K_AUX3 = 0xD1, + K_AUX4 = 0xD2, + K_AUX5 = 0xD3, + K_AUX6 = 0xD4, + K_AUX7 = 0xD5, + K_AUX8 = 0xD6, + K_AUX9 = 0xD7, + K_AUX10 = 0xD8, + K_AUX11 = 0xD9, + K_AUX12 = 0xDA, + K_AUX13 = 0xDB, + K_AUX14 = 0xDC, + K_AUX15 = 0xDD, + K_AUX16 = 0xDE, + K_LAST_KEY = 0xDF + }; + + struct KeyState + { + int down; + int repeats; + int binding; + }; + + struct PlayerKeyState + { + int overstrikeMode; + int anyKeyDown; + KeyState keys[256]; + }; + + struct ScreenPlacement + { + vec2_t scaleVirtualToReal; + vec2_t scaleVirtualToFull; + vec2_t scaleRealToVirtual; + vec2_t realViewportPosition; + vec2_t realViewportSize; + vec2_t virtualViewableMin; + vec2_t virtualViewableMax; + vec2_t realViewableMin; + vec2_t realViewableMax; + vec2_t virtualAdjustableMin; + vec2_t virtualAdjustableMax; + vec2_t realAdjustableMin; + vec2_t realAdjustableMax; + vec2_t subScreenLeft; + }; + + enum netadrtype_t + { + NA_BOT = 0x0, + NA_BAD = 0x1, + NA_LOOPBACK = 0x2, + NA_BROADCAST = 0x3, + NA_IP = 0x4, + }; + + enum netsrc_t + { + NS_CLIENT1 = 0x0, + NS_MAXCLIENTS = 0x1, + NS_SERVER = 0x2, + NS_PACKET = 0x3, + NS_INVALID_NETSRC = 0x4, + }; + + struct netadr_s + { + netadrtype_t type; + unsigned char ip[4]; + unsigned __int16 port; + netsrc_t localNetID; + unsigned int addrHandleIndex; + }; + + struct msg_t + { + int overflowed; + int readOnly; + char* data; + char* splitData; + int maxsize; + int cursize; + int splitSize; + int readcount; + int bit; + int lastEntityRef; + netsrc_t targetLocalNetID; + int useZlib; + }; + + enum errorParm + { + ERR_FATAL = 0, + ERR_DROP = 1, + ERR_SERVERDISCONNECT = 2, + ERR_DISCONNECT = 3, + ERR_SCRIPT = 4, + ERR_SCRIPT_DROP = 5, + ERR_LOCALIZATION = 6, + ERR_MAPLOADERRORSUMMARY = 7, + }; + + struct CmdArgs + { + int nesting; + int localClientNum[8]; + int controllerIndex[8]; + int argc[8]; + const char** argv[8]; + }; + + struct cmd_function_s + { + cmd_function_s* next; + const char* name; + void(__cdecl* function)(); + }; + + enum DvarSetSource : std::uint32_t + { + DVAR_SOURCE_INTERNAL = 0x0, + DVAR_SOURCE_EXTERNAL = 0x1, + DVAR_SOURCE_SCRIPT = 0x2, + DVAR_SOURCE_UISCRIPT = 0x3, + DVAR_SOURCE_SERVERCMD = 0x4, + DVAR_SOURCE_NUM = 0x5, + }; + + enum DvarFlags : std::uint32_t + { + DVAR_FLAG_NONE = 0, + DVAR_FLAG_SAVED = 0x1, + DVAR_FLAG_LATCHED = 0x2, + DVAR_FLAG_CHEAT = 0x4, + DVAR_FLAG_REPLICATED = 0x8, + DVAR_FLAG_WRITE = 0x800, + DVAR_FLAG_READ = 0x2000, + }; + + enum dvar_type : std::int8_t + { + boolean = 0, + value = 1, + vec2 = 2, + vec3 = 3, + vec4 = 4, + integer = 5, + enumeration = 6, + string = 7, + color = 8, + rgb = 9 // Color without alpha + }; + + union dvar_value + { + bool enabled; + int integer; + unsigned int unsignedInt; + float value; + float vector[4]; + const char* string; + char color[4]; + }; + + struct $A37BA207B3DDD6345C554D4661813EDD + { + int stringCount; + const char* const* strings; + }; + + struct $9CA192F9DB66A3CB7E01DE78A0DEA53D + { + int min; + int max; + }; + + struct $251C2428A496074035CACA7AAF3D55BD + { + float min; + float max; + }; + + union dvar_limits + { + $A37BA207B3DDD6345C554D4661813EDD enumeration; + $9CA192F9DB66A3CB7E01DE78A0DEA53D integer; + $251C2428A496074035CACA7AAF3D55BD value; + $251C2428A496074035CACA7AAF3D55BD vector; + }; + + struct dvar_t + { + const char* name; + unsigned int flags; + dvar_type type; + bool modified; + dvar_value current; + dvar_value latched; + dvar_value reset; + dvar_limits domain; + }; + + enum connstate_t + { + CA_DISCONNECTED = 0x0, + CA_CINEMATIC = 0x1, + CA_LOGO = 0x2, + CA_CONNECTING = 0x3, + CA_CHALLENGING = 0x4, + CA_CONNECTED = 0x5, + CA_SENDINGSTATS = 0x6, + CA_SYNCHRONIZING_DATA = 0x7, + CA_LOADING = 0x8, + CA_PRIMED = 0x9, + CA_ACTIVE = 0xA, + }; + + enum svscmd_type + { + SV_CMD_CAN_IGNORE = 0x0, + SV_CMD_RELIABLE = 0x1, + }; + + enum threadType + { + THREAD_CONTEXT_MAIN = 0x0, + THREAD_CONTEXT_BACKEND = 0x1, + THREAD_CONTEXT_WORKER0 = 0x2, + THREAD_CONTEXT_WORKER1 = 0x3, + THREAD_CONTEXT_WORKER2 = 0x4, + THREAD_CONTEXT_WORKER3 = 0x5, + THREAD_CONTEXT_WORKER4 = 0x6, + THREAD_CONTEXT_WORKER5 = 0x7, + THREAD_CONTEXT_WORKER6 = 0x8, + THREAD_CONTEXT_WORKER7 = 0x9, + THREAD_CONTEXT_SERVER = 0xA, + THREAD_CONTEXT_TRACE_COUNT = 0xB, + THREAD_CONTEXT_TRACE_LAST = 0xA, + THREAD_CONTEXT_CINEMATIC = 0xB, + THREAD_CONTEXT_DATABASE = 0xC, + THREAD_CONTEXT_STREAM = 0xD, + THREAD_CONTEXT_SNDSTREAMPACKETCALLBACK = 0xE, + THREAD_CONTEXT_STATS_WRITE = 0xF, + THREAD_CONTEXT_COUNT = 0x10, + }; + + enum DBSyncMode + { + DB_LOAD_ASYNC = 0x0, + DB_LOAD_SYNC = 0x1, + DB_LOAD_ASYNC_WAIT_ALLOC = 0x2, + DB_LOAD_ASYNC_FORCE_FREE = 0x3, + DB_LOAD_ASYNC_NO_SYNC_THREADS = 0x4, + DB_LOAD_SYNC_SKIP_ALWAYS_LOADED = 0x5, + }; + + struct XZoneInfo + { + const char* name; + int allocFlags; + int freeFlags; + }; + + enum XAssetType + { + ASSET_TYPE_PHYSPRESET, + ASSET_TYPE_PHYSCOLLMAP, + ASSET_TYPE_PHYSWATERPRESET, + ASSET_TYPE_PHYSWORLDMAP, + ASSET_TYPE_PHYSCONSTRAINT, + ASSET_TYPE_XANIMPARTS, + ASSET_TYPE_XMODELSURFS, + ASSET_TYPE_XMODEL, + ASSET_TYPE_MATERIAL, + ASSET_TYPE_COMPUTESHADER, + ASSET_TYPE_VERTEXSHADER, + ASSET_TYPE_HULLSHADER, + ASSET_TYPE_DOMAINSHADER, + ASSET_TYPE_PIXELSHADER, + ASSET_TYPE_VERTEXDECL, + ASSET_TYPE_TECHNIQUE_SET, + ASSET_TYPE_IMAGE, + ASSET_TYPE_SOUND, + ASSET_TYPE_SOUND_SUBMIX, + ASSET_TYPE_SOUND_CURVE, + ASSET_TYPE_LPF_CURVE, + ASSET_TYPE_REVERB_CURVE, + ASSET_TYPE_SOUND_CONTEXT, + ASSET_TYPE_LOADED_SOUND, + ASSET_TYPE_CLIPMAP, + ASSET_TYPE_COMWORLD, + ASSET_TYPE_GLASSWORLD, + ASSET_TYPE_PATHDATA, + ASSET_TYPE_VEHICLE_TRACK, + ASSET_TYPE_MAP_ENTS, + ASSET_TYPE_FXWORLD, + ASSET_TYPE_GFXWORLD, + ASSET_TYPE_LIGHT_DEF, + ASSET_TYPE_UI_MAP, + ASSET_TYPE_FONT, + ASSET_TYPE_MENULIST, + ASSET_TYPE_MENU, + ASSET_TYPE_ANIMCLASS, + ASSET_TYPE_LOCALIZE_ENTRY, + ASSET_TYPE_ATTACHMENT, + ASSET_TYPE_WEAPON, + ASSET_TYPE_SNDDRIVER_GLOBALS, + ASSET_TYPE_FX, + ASSET_TYPE_IMPACT_FX, + ASSET_TYPE_SURFACE_FX, + ASSET_TYPE_AITYPE, + ASSET_TYPE_MPTYPE, + ASSET_TYPE_CHARACTER, + ASSET_TYPE_XMODELALIAS, + ASSET_TYPE_RAWFILE, + ASSET_TYPE_SCRIPTFILE, + ASSET_TYPE_STRINGTABLE, + ASSET_TYPE_LEADERBOARD, + ASSET_TYPE_STRUCTURED_DATA_DEF, + ASSET_TYPE_TRACER, + ASSET_TYPE_VEHICLE, + ASSET_TYPE_ADDON_MAP_ENTS, + ASSET_TYPE_NET_CONST_STRINGS, + ASSET_TYPE_REVERB_PRESET, + ASSET_TYPE_LUA_FILE, + ASSET_TYPE_SCRIPTABLE, + ASSET_TYPE_EQUIPMENT_SND_TABLE, + ASSET_TYPE_VECTORFIELD, + ASSET_TYPE_DOPPLER_PRESET, + ASSET_TYPE_PARTICLE_SIM_ANIMATION, + ASSET_TYPE_LASER, + ASSET_TYPE_SKELETON_SCRIPT, + ASSET_TYPE_CLUT, + ASSET_TYPE_COUNT, + }; + + enum GfxDrawSceneMethod + { + GFX_DRAW_SCENE_STANDARD = 0x0, + }; + + enum MaterialTechniqueType + { + TECHNIQUE_UNLIT = 8, + TECHNIQUE_EMISSIVE = 9, + TECHNIQUE_LIT = 13, + }; + + struct GfxDrawMethod_s + { + int drawScene; + int baseTechType; + int emissiveTechType; + int forceTechType; + }; + + struct Material + { + const char* name; + }; + + struct Glyph + { + unsigned short letter; + char x0; + char y0; + char dx; + char pixelWidth; + char pixelHeight; + float s0; + float t0; + float s1; + float t1; + }; + + struct Font_s + { + const char* fontName; + int pixelHeight; + int glyphCount; + Material* material; + Material* glowMaterial; + Glyph* glyphs; + }; + + struct StreamFileNameRaw + { + const char* dir; + const char* name; + }; + + struct StreamFileNamePacked + { + unsigned __int64 offset; + unsigned __int64 length; + }; + + union StreamFileInfo + { + StreamFileNameRaw raw; + StreamFileNamePacked packed; + }; + + struct StreamFileName + { + unsigned __int16 isLocalized; + unsigned __int16 fileIndex; + StreamFileInfo info; + }; + + struct StreamedSound + { + StreamFileName filename; + unsigned int totalMsec; + }; + + union SoundFileRef + { + StreamedSound streamSnd; + }; + + struct SoundFile + { + char type; + char exists; + SoundFileRef u; + }; + + struct snd_alias_t + { + const char* aliasName; + char __pad0[24]; + SoundFile* soundFile; + char __pad1[198]; + // not gonna map this out... + }; + + struct snd_alias_list_t + { + const char* aliasName; + snd_alias_t* head; + void* unk; + unsigned char count; + unsigned char unkCount; + char __pad0[6]; + }; + + struct RawFile + { + const char* name; + int compressedLen; + int len; + const char* buffer; + }; + + struct ScriptFile + { + const char* name; + int compressedLen; + int len; + int bytecodeLen; + const char* buffer; + char* bytecode; + }; + + struct StringTableCell + { + const char* string; + int hash; + }; + + struct StringTable + { + const char* name; + int columnCount; + int rowCount; + StringTableCell* values; + }; + + struct LuaFile + { + const char* name; + int len; + char strippingType; + const char* buffer; + }; + + struct GfxImageLoadDef + { + char levelCount; + char numElements; + char pad[2]; + int flags; + int format; + int resourceSize; + char data[1]; + }; + + union $3FA29451CE6F1FA138A5ABAB84BE9676 + { + ID3D11Texture1D* linemap; + ID3D11Texture2D* map; + ID3D11Texture3D* volmap; + ID3D11Texture2D* cubemap; + GfxImageLoadDef* loadDef; + }; + + + struct GfxTexture + { + $3FA29451CE6F1FA138A5ABAB84BE9676 ___u0; + ID3D11ShaderResourceView* shaderView; + ID3D11ShaderResourceView* shaderViewAlternate; + }; + + struct Picmip + { + char platform[2]; + }; + + struct CardMemory + { + int platform[2]; + }; + + struct GfxImage + { + GfxTexture textures; + int flags; + int imageFormat; + int resourceSize; + char mapType; + char semantic; + char category; + char flags2; + Picmip picmip; + char track; + //CardMemory cardMemory; + unsigned short width; + unsigned short height; + unsigned short depth; + unsigned short numElements; + char pad3[4]; + void* pixelData; + //GfxImageLoadDef *loadDef; + uint64_t streams[4]; + const char* name; + }; + + union XAssetHeader + { + void* data; + Material* material; + Font_s* font; + RawFile* rawfile; + ScriptFile* scriptfile; + StringTable* stringTable; + LuaFile* luaFile; + GfxImage* image; + }; + + struct XAsset + { + XAssetType type; + XAssetHeader header; + }; + + struct XAssetEntry + { + XAsset asset; + char zoneIndex; + volatile char inuseMask; + unsigned int nextHash; + unsigned int nextOverride; + unsigned int nextPoolEntry; + }; + + enum TestClientType + { + TC_NONE = 0x0, + TC_TEST_CLIENT = 0x1, + TC_BOT = 0x2, + TC_COUNT = 0x3, + }; + + enum LiveClientDropType + { + SV_LIVE_DROP_NONE = 0x0, + SV_LIVE_DROP_DISCONNECT = 0x1, + }; + + namespace mp + { + struct cachedSnapshot_t + { + int archivedFrame; + int time; + int num_entities; + int first_entity; + int num_clients; + int first_client; + int num_agents; + int first_agent; + unsigned int scriptableCount; + unsigned int scriptableFirstIndex; + int usesDelta; + }; + + struct gclient_s + { + char __pad0[20708]; + char name[32]; // 20708 + char __pad1[668]; + int flags; // 21408 + }; // size = ? + + struct EntityState + { + char entityNum; + }; // size = ? + + struct gentity_s + { + EntityState s; + char __pad0[343]; + gclient_s* client; + char __pad1[80]; + int flags; + char __pad2[300]; + }; // size = 736 + + struct playerState_s + { + }; + + struct clientHeader_t + { + int state; + char __pad0[36]; + netadr_s remoteAddress; + }; // size = ? + + struct client_t + { + clientHeader_t header; + char __pad0[3044]; + int reliableSequence; + int reliableAcknowledge; + char __pad1[265864]; + gentity_s* gentity; // 268976 + char name[32]; // 268984 + char __pad2[8]; + int nextSnapshotTime; // 269024 + char __pad3[544]; + LiveClientDropType liveDropRequest; //269572 + char __pad4[24]; + TestClientType testClient; // 269600 + char __pad5[391700]; + }; // size = 661304 + } + + namespace sp + { + struct gclient_s + { + char __pad[56135]; + int flags; // 56136 + }; + + struct gentity_s + { + char __pad0[280]; + gclient_s* client; // 280 + char __pad1[76]; + int flags; // 364 + }; + + struct playerState_s + { + }; + } + + union playerState_s + { + sp::playerState_s* sp; + mp::playerState_s* mp; + }; + + namespace hks + { + struct GenericChunkHeader + { + unsigned __int64 m_flags; + }; + + struct ChunkHeader : GenericChunkHeader + { + ChunkHeader* m_next; + }; + + struct UserData : ChunkHeader + { + unsigned __int64 m_envAndSizeOffsetHighBits; + unsigned __int64 m_metaAndSizeOffsetLowBits; + char m_data[8]; + }; + + struct InternString + { + unsigned __int64 m_flags; + unsigned __int64 m_lengthbits; + unsigned int m_hash; + char m_data[30]; + }; + + struct HashTable; + struct cclosure; + + union HksValue + { + cclosure* cClosure; + void* closure; + UserData* userData; + HashTable* table; + void* tstruct; + InternString* str; + void* thread; + void* ptr; + float number; + unsigned int native; + bool boolean; + }; + + enum HksObjectType + { + TANY = 0xFFFFFFFE, + TNONE = 0xFFFFFFFF, + TNIL = 0x0, + TBOOLEAN = 0x1, + TLIGHTUSERDATA = 0x2, + TNUMBER = 0x3, + TSTRING = 0x4, + TTABLE = 0x5, + TFUNCTION = 0x6, // idk + TUSERDATA = 0x7, + TTHREAD = 0x8, + TIFUNCTION = 0x9, // Lua function + TCFUNCTION = 0xA, // C function + TUI64 = 0xB, + TSTRUCT = 0xC, + NUM_TYPE_OBJECTS = 0xE, + }; + + struct HksObject + { + HksObjectType t; + HksValue v; + }; + + const struct hksInstruction + { + unsigned int code; + }; + + struct ActivationRecord + { + HksObject* m_base; + const hksInstruction* m_returnAddress; + __int16 m_tailCallDepth; + __int16 m_numVarargs; + int m_numExpectedReturns; + }; + + struct CallStack + { + ActivationRecord* m_records; + ActivationRecord* m_lastrecord; + ActivationRecord* m_current; + const hksInstruction* m_current_lua_pc; + const hksInstruction* m_hook_return_addr; + int m_hook_level; + }; + + struct ApiStack + { + HksObject* top; + HksObject* base; + HksObject* alloc_top; + HksObject* bottom; + }; + + struct UpValue : ChunkHeader + { + HksObject m_storage; + HksObject* loc; + UpValue* m_next; + }; + + struct CallSite + { + _SETJMP_FLOAT128 m_jumpBuffer[16]; + CallSite* m_prev; + }; + + enum Status + { + NEW = 0x1, + RUNNING = 0x2, + YIELDED = 0x3, + DEAD_ERROR = 0x4, + }; + + enum HksError + { + }; + + struct lua_Debug + { + int event; + const char* name; + const char* namewhat; + const char* what; + const char* source; + int currentline; + int nups; + int nparams; + int ishksfunc; + int linedefined; + int lastlinedefined; + char short_src[512]; + int callstack_level; + int is_tail_call; + }; + + struct lua_State : ChunkHeader + { + void* m_global; + CallStack m_callStack; + ApiStack m_apistack; + UpValue* pending; + HksObject globals; + HksObject m_cEnv; + CallSite* m_callsites; + int m_numberOfCCalls; + void* m_context; + InternString* m_name; + lua_State* m_nextState; + lua_State* m_nextStateStack; + Status m_status; + HksError m_error; + }; + + using lua_function = int(__fastcall*)(lua_State*); + + struct luaL_Reg + { + const char* name; + lua_function function; + }; + + struct Node + { + HksObject m_key; + HksObject m_value; + }; + + struct Metatable + { + }; + + struct HashTable : ChunkHeader + { + Metatable* m_meta; + unsigned int m_version; + unsigned int m_mask; + Node* m_hashPart; + HksObject* m_arrayPart; + unsigned int m_arraySize; + Node* m_freeNode; + }; + + struct cclosure : ChunkHeader + { + lua_function m_function; + HashTable* m_env; + __int16 m_numUpvalues; + __int16 m_flags; + InternString* m_name; + HksObject m_upvalues[1]; + }; + } +} diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp new file mode 100644 index 00000000..20d45bbb --- /dev/null +++ b/src/client/game/symbols.hpp @@ -0,0 +1,226 @@ +#pragma once + +#define WEAK __declspec(selectany) + +namespace game +{ + /*************************************************************** + * Functions + **************************************************************/ + + WEAK symbol Cbuf_AddText{ 0x140342EB0, 0x1404033B0 }; // H1MP64[AYRIA] + WEAK symbol Cmd_ExecuteSingleCommand{ 0x140343980, 0x140343980 }; // H1SP64[CODEX] + + WEAK symbol Cmd_AddCommandInternal{ 0x1403433E0, 0x140403950 }; // H1MP64[AYRIA] + + WEAK symbol Com_Frame_Try_Block_Function{ 0, 0x1400D8310 }; //H1MP MWR TEST + + WEAK symbol BG_GetWeaponNameComplete{ 0x0, 0x140165580 }; + + // wip + WEAK symbol GScr_LoadConsts{ 0x140283970, 0x1403479C0 }; + WEAK symbol GetVariable{ 0x0, 0x1403F3730 }; + WEAK symbol GetVariableName{ 0x1403170E0, 0x1403F37F0 }; + + + WEAK symbol Com_Quit_f{ 0, 0x1400DA640 }; //H1MP64[AYRIA] + + WEAK symbol Cmd_TokenizeString{ 0, 0x1404046F0 }; //H1MP64[AYRIA] + + WEAK symbol Dvar_SetCommand{ 0x1403C72B0, 0x1404FD0A0 }; //H1MP64[AYRIA] NOT_SURE + + WEAK symbol Com_Error{ 0, 0x1400D78A0 }; //H1MP64[AYRIA] + + // WEAK symbol CG_GameMessage{ 0x1389A0 }; // H1SP64[CODEX] + // WEAK symbol CG_GameMessageBold{ 0x138750 }; // H1SP64[CODEX] + + WEAK symbol CG_GameMessage{ 0x1401389A0, 0x140220CC0 }; // H1MP64[AYRIA] + WEAK symbol CG_GameMessageBold{ 0x140138750, 0x140220620 }; // H1MP64[AYRIA] + WEAK symbol Conbuf_AppendText{ 0, 0x140513FF0 }; // H1MP64[AYRIA] + + WEAK symbol ConcatArgs{ 0x14021A7E0, 0x1402E9670 }; + + WEAK symbol Cmd_EndTokenizeString{ 0, 0x140403C20 }; // H1MP64[AYRIA] + + WEAK symbol Dvar_FindVar{ 0x1403C5D50, 0x1404FBB00 }; // H1MP64[AYRIA] + WEAK symbol Dvar_ValueToString{ 0x1403C8560,0x1404FE660 }; // H1MP64[AYRIA]; different typedef from previous titles + //WEAK symbol Dvar_SetCommand{ 0, 0x1404FD0A0 }; // H1MP64[AYRIA] + + WEAK symbol Dvar_RegisterBool{ 0x1403C47E0,0x1404FA540 }; // H1 + //WEAK symbol + //Dvar_RegisterBool{ 0, 0x1404FA540 }; + WEAK symbol Dvar_RegisterInt{ 0, 0x1404FAA20 }; // H1 + //WEAK symbol + //Dvar_RegisterInt{ 0, 0x1404FAA20 }; + WEAK symbol Dvar_RegisterFloat{ 0,0x1404FA910 }; // H1MP64[AYRIA] + WEAK symbol Dvar_RegisterString{ 0,0x1404FAB00 }; // H1MP64[AYRIA] + WEAK symbol Dvar_RegisterVec4{ 0, 0x1404FAF40 }; // H1MP64[AYRIA] + + WEAK symbol generateHashValue{ 0x1400FE8A0, 0x1401B1010 }; // H1MP64[AYRIA] + + //WEAK symbol CL_IsCgameInitialized{ 0x17EE30 }; // H1SP64[CODEX] + WEAK symbol CL_IsCgameInitialized{ 0, 0x140245650 }; //H1MP64[AYRIA] + WEAK symbol Live_SyncOnlineDataFlags{ 0, 0x14059A700 }; //H1MP64[AYRIA] + + WEAK symbol Sys_Milliseconds{ 0, 0x140513710 }; + WEAK symbol Sys_IsDatabaseReady2{ 0, 0x14042B090 }; //H1MP64[AYRIA] + + WEAK symbol SV_DirectConnect{ 0, 0x140480860 }; + WEAK symbol SV_Cmd_TokenizeString{ 0, 0x140404D20 }; + WEAK symbol SV_Cmd_EndTokenizedString{ 0, 0x140404CE0 }; + WEAK symbol Sys_SendPacket{ 0, 0x1405133B0 }; + WEAK symbol NetadrToSockadr{ 0, 0x1404F62F0 }; + WEAK symbol NET_OutOfBandPrint{ 0, 0x1404255D0 }; + WEAK symbol query_socket{ 0, 0x14DDFBF98 }; + WEAK symbol NET_SendLoopPacket{ 0, 0x140425790 }; + + //WEAK symbol + //Dvar_RegisterInt{ 0, 0x140 }; + + WEAK symbol SV_BotIsBot{ 0, 0x14046E6C0 }; + + WEAK symbol I_CleanStr{ 0, 0x1403CD230 }; // H1SP64[CODEX] + WEAK symbol ScrPlace_GetViewPlacement{ 0, 0x140288550 }; // H1MP64[AYRIA] + + WEAK symbol Material_RegisterHandle{ 0, 0x1405EAB30 }; // H1MP64[AYRIA] + + WEAK symbol R_AddCmdDrawStretchPic{ 0, 0x1402443A0 }; // H1MP64[AYRIA] + + WEAK symbol R_RegisterFont{ 0, 0x1405D91E0 }; // H1MP64[AYRIA] + WEAK symbol R_GetFontHeight{ 0, 0x1405D92C0 }; // H1MP64[AYRIA] + WEAK symbol JUST_DO_OUR_DIRTY_WORK{ 0, 0x1405D8890 }; // H1MP64[AYRIA] + + WEAK symbol G_GetClientScore{ 0, 0x140342F90 }; // H1MP64[AYRIA] + WEAK symbol SV_GetGuid{ 0, 0x140484B90 }; // H1MP64[AYRIA] + WEAK symbol SV_GetClientPing{ 0, 0x140484B70 }; // H1MP64[AYRIA] + + WEAK symbol H1_AddBaseDrawTextCmd{ 0,0x1405FB1F0 }; // H1MP64[AYRIA] + +#define R_AddCmdDrawText(TXT,MC,F,X,Y,XS,YS,R,C,S) H1_AddBaseDrawTextCmd(TXT,MC,F,game::R_GetFontHeight(F),X,Y,XS,YS,R,C,S,-1,0,game::JUST_DO_OUR_DIRTY_WORK(S)) + +#define R_AddCmdDrawTextWithCursor(TXT,MC,F,UNK,X,Y,XS,YS,R,C,S,CP,CC) H1_AddBaseDrawTextCmd(TXT,MC,F,game::R_GetFontHeight(F),X,Y,XS,YS,R,C,S,CP,CC,game::JUST_DO_OUR_DIRTY_WORK(S)) + + WEAK symbol R_TextWidth{ 0, 0x1405D94A0 }; // H1MP64[AYRIA] + + //WEAK symbol Com_Quit_f{ 0x352BE0 }; //H1SP64[CODEX] + + WEAK symbol cmd_functions{ 0,0x14946BAC8 }; //H1MP64[AYRIA] + WEAK symbol keyCatchers{ 0,0x142D0BA9C }; //H1MP64[AYRIA] + WEAK symbol playerKeys{ 0,0x142C19AFC }; //H1MP64[AYRIA] + WEAK symbol cmd_args{ 0, 0x140000000 }; //H1SP64[CODEX] + + //WEAK symbol g_entities{ 0, 0x621E530 }; //H1MP64[ARYIA] + //WEAK symbol g_entities{ 0x550DD90 }; //H1SP64[CODEX] + + //########################################################################################################################################################################### + //########################################################################################################################################################################### + //########################################################################################################################################################################### + + WEAK symbol G_Glass_Update{ 0, 0x14033A640 }; // H1MP64[AYRIA] + + WEAK symbol AddRefToValue{ 0, 0x1405C0EB0 }; + WEAK symbol AddRefToObject{ 0,0x1405C0EA0 }; + WEAK symbol AllocThread{ 0,0x1405C1200 }; + WEAK symbol RemoveRefToValue{ 0, 0x1405C29B0 }; + WEAK symbol RemoveRefToObject{ 0,0x1405C28A0 }; + + + WEAK symbol + DB_EnumXAssets_Internal{ 0, 0x1404129F0 }; + WEAK symbol DB_GetXAssetName{ 0,0x1403E4090 }; + WEAK symbol DB_LoadXAssets{ 0,0x140414FF0 }; + WEAK symbol DB_FindXAssetHeader{ 0, 0x140412F60 }; + WEAK symbol DB_GetRawFileLen{ 0,0x140413D80 }; + WEAK symbol DB_GetRawBuffer{ 0,0x140413C40 }; + + WEAK symbol FindVariable{ 0,0x1405C1D50 }; + WEAK symbol FindEntityId{ 0, 0x1405C1C50 }; + WEAK symbol GetEntityFieldValue{ 0, 0x1405C6100 }; + + WEAK symbol G_GetWeaponForName{ 0, 0x14051B260 }; + WEAK symbol + G_GivePlayerWeapon{ 0, 0x14051B660 }; + WEAK symbol G_InitializeAmmo{ 0, 0x1404C4110 }; + WEAK symbol G_SelectWeapon{ 0,0x14051C0D0 }; + + WEAK symbol Image_Setup{ 0, 0x14074B2A0 }; + + WEAK symbol LUI_OpenMenu{ 0, 0x1405F0EE0 }; + WEAK symbol Menu_IsMenuOpenAndVisible{ 0, 0x1405EE1A0 }; + + WEAK symbol Scr_AllocVector{ 0, 0x1405C3220 }; + WEAK symbol Scr_ClearOutParams{ 0, 0x1405C6E50 }; + WEAK symbol Scr_GetEntityIdRef{ 0, 0x1405C56C0 }; + WEAK symbol Scr_SetObjectField{ 0,0x140512190 }; + WEAK symbol Scr_NotifyId{ 0,0x1405C8240 }; + + WEAK symbol VM_Execute{ 0, 0x1405C8DB0 }; + + WEAK symbol R_SyncRenderThread{ 0,0x14076E7D0 }; + WEAK symbol R_AddDObjToScene{ 0, 0x140775C40 }; + + WEAK symbol SL_ConvertToString{ 0,0x1405BFBB0 }; + WEAK symbol SL_GetString{ 0, 0x1405C0170 }; + + WEAK symbol SV_Loaded{ 0,0x140442F60 }; + + WEAK symbol Sys_ShowConsole{ 0,0x140514910 }; + + WEAK symbol UI_SafeTranslateString{ 0, 0x5A2930 }; + + WEAK symbol longjmp{ 0, 0x14089EED0 }; + WEAK symbol _setjmp{ 0, 0x1408EC2E0 }; + + WEAK symbol SV_Cmd_ArgvBuffer{ 0x1402EEFD0, 0x1403B05C0 }; + + // Variables + WEAK symbol sv_cmd_args{ 0, 0x14946BA20 }; // mwr maybe + + + WEAK symbol g_assetNames{ 0, 0x140BEF280 }; + WEAK symbol g_poolSize{ 0, 0x140BF2E40 }; + + WEAK symbol gfxDrawMethod{ 0,0x14EDF9E00 }; + + WEAK symbol dvarCount{ 0, 0x14BFBB310 }; + WEAK symbol sortedDvars{ 0,0x14BFBB320 }; + + WEAK symbol levelEntityId{ 0,0x14B5E0B30 }; + WEAK symbol g_script_error_level{ 0,0x14BA9CC24 }; + WEAK symbol g_script_error{ 0,0x14BA9CD40 }; + WEAK symbol g_classMap{ 0, 0x140BF95C0 }; + + WEAK symbol scr_VarGlob{ 0, 0x14B617C00 }; + WEAK symbol scr_VmPub{ 0,0x14BA9EE40 }; + WEAK symbol scr_function_stack{ 0,0x14BAA93C0 }; + + namespace mp + { + WEAK symbol g_entities{ 0, 0x14621E530 }; // H1MP64[AYRIA] + WEAK symbol svs_clients{ 0, 0x14B204A10 }; // H1MP64[AYRIA] + } + + namespace sp + { + WEAK symbol g_entities{ 0x14550DD90 , 0 }; + } + + namespace hks + { + WEAK symbol lua_state{0, 0x1412E2B50}; + WEAK symbol hksi_lua_pushlstring{0, 0x1400290B0}; + WEAK symbol hks_obj_getfield{0, 0x14009D3C0}; + WEAK symbol hks_obj_settable{0, 0x14009E480}; + WEAK symbol hks_obj_gettable{0, 0x14009D800}; + WEAK symbol vm_call_internal{0, 0x1400C9EC0}; + WEAK symbol Hashtable_Create{0, 0x14008AAE0}; + WEAK symbol cclosure_Create{0, 0x14008AD00}; + WEAK symbol hksi_luaL_ref{0, 0x1400A7D60}; + WEAK symbol hksi_luaL_unref{0, 0x1400A0660}; + } +} diff --git a/src/client/game/ui_scripting/execution.cpp b/src/client/game/ui_scripting/execution.cpp new file mode 100644 index 00000000..fff6b88e --- /dev/null +++ b/src/client/game/ui_scripting/execution.cpp @@ -0,0 +1,161 @@ +#include +#include "execution.hpp" +#include "component/ui_scripting.hpp" + +#include + +namespace ui_scripting +{ + void push_value(const script_value& value) + { + const auto state = *game::hks::lua_state; + const auto value_ = value.get_raw(); + *state->m_apistack.top = value_; + state->m_apistack.top++; + } + + script_value get_return_value(int offset) + { + const auto state = *game::hks::lua_state; + return state->m_apistack.top[-1 - offset]; + } + + arguments get_return_values(int count) + { + arguments values; + + for (auto i = count - 1; i >= 0; i--) + { + values.push_back(get_return_value(i)); + } + + if (values.size() == 0) + { + values.push_back({}); + } + + return values; + } + + arguments call_script_function(const function& function, const arguments& arguments) + { + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(function); + for (auto i = arguments.begin(); i != arguments.end(); ++i) + { + push_value(*i); + } + + const auto _1 = gsl::finally(&disable_error_hook); + enable_error_hook(); + + try + { + game::hks::vm_call_internal(state, static_cast(arguments.size()), -1, 0); + const auto count = static_cast(state->m_apistack.top - state->m_apistack.base); + return get_return_values(count); + } + catch (const std::exception& e) + { + throw std::runtime_error(std::string("Error executing script function: ") + e.what()); + } + } + + script_value get_field(const userdata& self, const script_value& key) + { + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(key); + + const auto _1 = gsl::finally(&disable_error_hook); + enable_error_hook(); + + game::hks::HksObject value{}; + game::hks::HksObject userdata{}; + userdata.t = game::hks::TUSERDATA; + userdata.v.ptr = self.ptr; + + try + { + game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); + return value; + } + catch (const std::exception& e) + { + throw std::runtime_error(std::string("Error getting userdata field: ") + e.what()); + } + } + + script_value get_field(const table& self, const script_value& key) + { + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(key); + + const auto _1 = gsl::finally(&disable_error_hook); + enable_error_hook(); + + game::hks::HksObject value{}; + game::hks::HksObject userdata{}; + userdata.t = game::hks::TTABLE; + userdata.v.ptr = self.ptr; + + try + { + game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); + return value; + } + catch (const std::exception& e) + { + throw std::runtime_error(std::string("Error getting table field: ") + e.what()); + } + } + + void set_field(const userdata& self, const script_value& key, const script_value& value) + { + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + const auto _1 = gsl::finally(&disable_error_hook); + enable_error_hook(); + + game::hks::HksObject userdata{}; + userdata.t = game::hks::TUSERDATA; + userdata.v.ptr = self.ptr; + + try + { + game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw()); + } + catch (const std::exception& e) + { + throw std::runtime_error(std::string("Error setting userdata field: ") + e.what()); + } + } + + void set_field(const table& self, const script_value& key, const script_value& value) + { + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + const auto _1 = gsl::finally(&disable_error_hook); + enable_error_hook(); + + game::hks::HksObject userdata{}; + userdata.t = game::hks::TTABLE; + userdata.v.ptr = self.ptr; + + try + { + game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw()); + } + catch (const std::exception& e) + { + throw std::runtime_error(std::string("Error setting table field: ") + e.what()); + } + } +} diff --git a/src/client/game/ui_scripting/execution.hpp b/src/client/game/ui_scripting/execution.hpp new file mode 100644 index 00000000..24f4dd72 --- /dev/null +++ b/src/client/game/ui_scripting/execution.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "game/game.hpp" +#include "types.hpp" +#include "script_value.hpp" + +namespace ui_scripting +{ + void push_value(const script_value& value); + script_value get_return_value(int offset); + arguments get_return_values(int count); + + arguments call_script_function(const function& function, const arguments& arguments); + + script_value get_field(const userdata& self, const script_value& key); + script_value get_field(const table& self, const script_value& key); + void set_field(const userdata& self, const script_value& key, const script_value& value); + void set_field(const table& self, const script_value& key, const script_value& value); +} diff --git a/src/client/game/ui_scripting/lua/context.cpp b/src/client/game/ui_scripting/lua/context.cpp new file mode 100644 index 00000000..d6d05f1d --- /dev/null +++ b/src/client/game/ui_scripting/lua/context.cpp @@ -0,0 +1,205 @@ +#include +#include "context.hpp" +#include "error.hpp" +#include "value_conversion.hpp" +#include "../script_value.hpp" +#include "../execution.hpp" + +#include "../../../component/ui_scripting.hpp" +#include "../../../component/command.hpp" + +#include "component/game_console.hpp" +#include "component/scheduler.hpp" + +#include +#include +#include + +namespace ui_scripting::lua +{ + namespace + { + void setup_types(sol::state& state, scheduler& scheduler) + { + struct game + { + }; + auto game_type = state.new_usertype("game_"); + state["game"] = game(); + + game_type["ontimeout"] = [&scheduler](const game&, const sol::protected_function& callback, + const long long milliseconds) + { + return scheduler.add(callback, milliseconds, true); + }; + + game_type["oninterval"] = [&scheduler](const game&, const sol::protected_function& callback, + const long long milliseconds) + { + return scheduler.add(callback, milliseconds, false); + }; + + auto userdata_type = state.new_usertype("userdata_"); + + userdata_type["new"] = sol::property( + [](const userdata& userdata, const sol::this_state s) + { + return convert(s, userdata.get("new")); + }, + [](const userdata& userdata, const sol::this_state s, const sol::lua_value& value) + { + userdata.set("new", convert({s, value})); + } + ); + + + userdata_type["get"] = [](const userdata& userdata, const sol::this_state s, + const sol::lua_value& key) + { + return convert(s, userdata.get(convert({s, key}))); + }; + + userdata_type["set"] = [](const userdata& userdata, const sol::this_state s, + const sol::lua_value& key, const sol::lua_value& value) + { + userdata.set(convert({s, key}), convert({s, value})); + }; + + userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s, + const sol::lua_value& key) + { + return convert(s, userdata.get(convert({s, key}))); + }; + + userdata_type[sol::meta_function::new_index] = [](const userdata& userdata, const sol::this_state s, + const sol::lua_value& key, const sol::lua_value& value) + { + userdata.set(convert({s, key }), convert({s, value})); + }; + + auto table_type = state.new_usertype("table_"); + + table_type["new"] = sol::property( + [](const table& table, const sol::this_state s) + { + return convert(s, table.get("new")); + }, + [](const table& table, const sol::this_state s, const sol::lua_value& value) + { + table.set("new", convert({s, value})); + } + ); + + table_type["get"] = [](const table& table, const sol::this_state s, + const sol::lua_value& key) + { + return convert(s, table.get(convert({s, key}))); + }; + + table_type["set"] = [](const table& table, const sol::this_state s, + const sol::lua_value& key, const sol::lua_value& value) + { + table.set(convert({s, key}), convert({s, value})); + }; + + table_type[sol::meta_function::index] = [](const table& table, const sol::this_state s, + const sol::lua_value& key) + { + return convert(s, table.get(convert({s, key}))); + }; + + table_type[sol::meta_function::new_index] = [](const table& table, const sol::this_state s, + const sol::lua_value& key, const sol::lua_value& value) + { + table.set(convert({s, key}), convert({s, value})); + }; + + auto function_type = state.new_usertype("function_"); + + function_type[sol::meta_function::call] = [](const function& function, const sol::this_state s, sol::variadic_args va) + { + arguments arguments{}; + + for (auto arg : va) + { + arguments.push_back(convert({s, arg})); + } + + const auto values = function.call(arguments); + std::vector returns; + + for (const auto& value : values) + { + returns.push_back(convert(s, value)); + } + + return sol::as_returns(returns); + }; + + state["luiglobals"] = table((*::game::hks::lua_state)->globals.v.table); + state["CoD"] = state["luiglobals"]["CoD"]; + state["LUI"] = state["luiglobals"]["LUI"]; + state["Engine"] = state["luiglobals"]["Engine"]; + state["Game"] = state["luiglobals"]["Game"]; + } + } + + context::context(std::string folder) + : folder_(std::move(folder)) + , scheduler_(state_) + { + this->state_.open_libraries(sol::lib::base, + sol::lib::package, + sol::lib::io, + sol::lib::string, + sol::lib::os, + sol::lib::math, + sol::lib::table); + + this->state_["include"] = [this](const std::string& file) + { + this->load_script(file); + }; + + sol::function old_require = this->state_["require"]; + auto base_path = utils::string::replace(this->folder_, "/", ".") + "."; + this->state_["require"] = [base_path, old_require](const std::string& path) + { + return old_require(base_path + path); + }; + + this->state_["scriptdir"] = [this]() + { + return this->folder_; + }; + + setup_types(this->state_, this->scheduler_); + + printf("Loading ui script '%s'\n", this->folder_.data()); + this->load_script("__init__"); + } + + context::~context() + { + this->state_.collect_garbage(); + this->scheduler_.clear(); + this->state_ = {}; + } + + void context::run_frame() + { + this->scheduler_.run_frame(); + this->state_.collect_garbage(); + } + + void context::load_script(const std::string& script) + { + if (!this->loaded_scripts_.emplace(script).second) + { + return; + } + + const auto file = (std::filesystem::path{this->folder_} / (script + ".lua")).generic_string(); + handle_error(this->state_.safe_script_file(file, &sol::script_pass_on_error)); + } +} diff --git a/src/client/game/ui_scripting/lua/context.hpp b/src/client/game/ui_scripting/lua/context.hpp new file mode 100644 index 00000000..0876d3df --- /dev/null +++ b/src/client/game/ui_scripting/lua/context.hpp @@ -0,0 +1,36 @@ +#pragma once +#pragma warning(push) +#pragma warning(disable: 4702) + +#define SOL_ALL_SAFETIES_ON 1 +#define SOL_PRINT_ERRORS 0 +#include + +#include "scheduler.hpp" + +namespace ui_scripting::lua +{ + class context + { + public: + context(std::string folder); + ~context(); + + context(context&&) noexcept = delete; + context& operator=(context&&) noexcept = delete; + + context(const context&) = delete; + context& operator=(const context&) = delete; + + void run_frame(); + + private: + sol::state state_{}; + std::string folder_; + std::unordered_set loaded_scripts_; + + scheduler scheduler_; + + void load_script(const std::string& script); + }; +} diff --git a/src/client/game/ui_scripting/lua/engine.cpp b/src/client/game/ui_scripting/lua/engine.cpp new file mode 100644 index 00000000..ee8e29ac --- /dev/null +++ b/src/client/game/ui_scripting/lua/engine.cpp @@ -0,0 +1,61 @@ +#include +#include "engine.hpp" +#include "context.hpp" + +#include "../../../component/ui_scripting.hpp" +#include "../../../component/game_module.hpp" + +#include + +namespace ui_scripting::lua::engine +{ + namespace + { + auto& get_scripts() + { + static std::vector> scripts{}; + return scripts; + } + + void load_scripts(const std::string& script_dir) + { + if (!utils::io::directory_exists(script_dir)) + { + return; + } + + const auto scripts = utils::io::list_files(script_dir); + + for (const auto& script : scripts) + { + if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua")) + { + get_scripts().push_back(std::make_unique(script)); + } + } + } + } + + void start() + { + clear_converted_functions(); + get_scripts().clear(); + load_scripts(game_module::get_host_module().get_folder() + "/data/ui_scripts/"); + load_scripts("s1x/ui_scripts/"); + load_scripts("data/ui_scripts/"); + } + + void stop() + { + clear_converted_functions(); + get_scripts().clear(); + } + + void run_frame() + { + for (auto& script : get_scripts()) + { + script->run_frame(); + } + } +} diff --git a/src/client/game/ui_scripting/lua/engine.hpp b/src/client/game/ui_scripting/lua/engine.hpp new file mode 100644 index 00000000..bbcf427c --- /dev/null +++ b/src/client/game/ui_scripting/lua/engine.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace ui_scripting::lua::engine +{ + void start(); + void stop(); + void run_frame(); +} diff --git a/src/client/game/ui_scripting/lua/error.cpp b/src/client/game/ui_scripting/lua/error.cpp new file mode 100644 index 00000000..d13b4896 --- /dev/null +++ b/src/client/game/ui_scripting/lua/error.cpp @@ -0,0 +1,18 @@ +#include +#include "error.hpp" + +namespace ui_scripting::lua +{ + void handle_error(const sol::protected_function_result& result) + { + if (!result.valid()) + { + printf("************** UI Script execution error **************\n"); + + const sol::error err = result; + printf("%s\n", err.what()); + + printf("****************************************************\n"); + } + } +} diff --git a/src/client/game/ui_scripting/lua/error.hpp b/src/client/game/ui_scripting/lua/error.hpp new file mode 100644 index 00000000..28a5c453 --- /dev/null +++ b/src/client/game/ui_scripting/lua/error.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "context.hpp" + +namespace ui_scripting::lua +{ + void handle_error(const sol::protected_function_result& result); +} diff --git a/src/client/game/ui_scripting/lua/scheduler.cpp b/src/client/game/ui_scripting/lua/scheduler.cpp new file mode 100644 index 00000000..18e779b6 --- /dev/null +++ b/src/client/game/ui_scripting/lua/scheduler.cpp @@ -0,0 +1,122 @@ +#include "std_include.hpp" +#include "context.hpp" +#include "error.hpp" + +namespace ui_scripting::lua +{ + scheduler::scheduler(sol::state& state) + { + auto task_handle_type = state.new_usertype("task_handle"); + + task_handle_type["clear"] = [this](const task_handle& handle) + { + this->remove(handle); + }; + } + + void scheduler::run_frame() + { + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + + for (auto i = tasks.begin(); i != tasks.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - i->last_call; + + if (diff < i->delay) + { + ++i; + continue; + } + + i->last_call = now; + + if (!i->is_deleted) + { + handle_error(i->callback()); + } + + if (i->is_volatile || i->is_deleted) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + void scheduler::clear() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + new_tasks.clear(); + tasks.clear(); + }); + }); + } + + task_handle scheduler::add(const sol::protected_function& callback, const long long milliseconds, + const bool is_volatile) + { + return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); + } + + task_handle scheduler::add(const sol::protected_function& callback, const std::chrono::milliseconds delay, + const bool is_volatile) + { + const uint64_t id = ++this->current_task_id_; + + task task; + task.is_volatile = is_volatile; + task.callback = callback; + task.delay = delay; + task.last_call = std::chrono::steady_clock::now(); + task.id = id; + task.is_deleted = false; + + new_callbacks_.access([&task](task_list& tasks) + { + tasks.emplace_back(std::move(task)); + }); + + return {id}; + } + + void scheduler::remove(const task_handle& handle) + { + auto mask_as_deleted = [&](task_list& tasks) + { + for (auto& task : tasks) + { + if (task.id == handle.id) + { + task.is_deleted = true; + break; + } + } + }; + + callbacks_.access(mask_as_deleted); + new_callbacks_.access(mask_as_deleted); + } + + void scheduler::merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), + std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } +} diff --git a/src/client/game/ui_scripting/lua/scheduler.hpp b/src/client/game/ui_scripting/lua/scheduler.hpp new file mode 100644 index 00000000..1935e25e --- /dev/null +++ b/src/client/game/ui_scripting/lua/scheduler.hpp @@ -0,0 +1,50 @@ +#pragma once +#include + +namespace ui_scripting::lua +{ + class context; + + class task_handle + { + public: + uint64_t id = 0; + }; + + class task final : public task_handle + { + public: + std::chrono::steady_clock::time_point last_call{}; + sol::protected_function callback{}; + std::chrono::milliseconds delay{}; + bool is_volatile = false; + bool is_deleted = false; + }; + + class scheduler final + { + public: + scheduler(sol::state& state); + + scheduler(scheduler&&) noexcept = delete; + scheduler& operator=(scheduler&&) noexcept = delete; + + scheduler(const scheduler&) = delete; + scheduler& operator=(const scheduler&) = delete; + + void run_frame(); + void clear(); + + task_handle add(const sol::protected_function& callback, long long milliseconds, bool is_volatile); + task_handle add(const sol::protected_function& callback, std::chrono::milliseconds delay, bool is_volatile); + + private: + using task_list = std::vector; + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + std::atomic_int64_t current_task_id_ = 0; + + void remove(const task_handle& handle); + void merge_callbacks(); + }; +} diff --git a/src/client/game/ui_scripting/lua/value_conversion.cpp b/src/client/game/ui_scripting/lua/value_conversion.cpp new file mode 100644 index 00000000..38376cdf --- /dev/null +++ b/src/client/game/ui_scripting/lua/value_conversion.cpp @@ -0,0 +1,144 @@ +#include +#include "value_conversion.hpp" +#include "../execution.hpp" +#include "../../../component/ui_scripting.hpp" + +namespace ui_scripting::lua +{ + namespace + { + table convert_table(const sol::table& t) + { + table res{}; + + t.for_each([res](const sol::object& key, const sol::object& value) + { + res.set(convert(key), convert(value)); + }); + + return res; + } + + script_value convert_function(const sol::protected_function& function) + { + const auto closure = game::hks::cclosure_Create(*game::hks::lua_state, main_function_handler, 0, 0, 0); + add_converted_function(closure, function); + + game::hks::HksObject value{}; + value.t = game::hks::TCFUNCTION; + value.v.cClosure = closure; + + return value; + } + } + + script_value convert(const sol::lua_value& value) + { + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is
()) + { + return {value.as
()}; + } + + if (value.is()) + { + return {value.as()}; + } + + if (value.is()) + { + return {convert_table(value.as())}; + } + + if (value.is()) + { + return {convert_function(value.as())}; + } + + return {}; + } + + sol::lua_value convert(lua_State* state, const script_value& value) + { + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + if (value.is
()) + { + return {state, value.as
()}; + } + + if (value.is()) + { + return {state, value.as()}; + } + + return {state, sol::lua_nil}; + } +} diff --git a/src/client/game/ui_scripting/lua/value_conversion.hpp b/src/client/game/ui_scripting/lua/value_conversion.hpp new file mode 100644 index 00000000..21a67e33 --- /dev/null +++ b/src/client/game/ui_scripting/lua/value_conversion.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "context.hpp" +#include "../script_value.hpp" + +namespace ui_scripting::lua +{ + script_value convert(const sol::lua_value& value); + sol::lua_value convert(lua_State* state, const script_value& value); +} diff --git a/src/client/game/ui_scripting/script_value.cpp b/src/client/game/ui_scripting/script_value.cpp new file mode 100644 index 00000000..34d17020 --- /dev/null +++ b/src/client/game/ui_scripting/script_value.cpp @@ -0,0 +1,274 @@ +#include +#include "execution.hpp" +#include "types.hpp" +#include "script_value.hpp" + +namespace ui_scripting +{ + /*************************************************************** + * Constructors + **************************************************************/ + + script_value::script_value(const game::hks::HksObject& value) + : value_(value) + { + } + + script_value::script_value(const int value) + { + game::hks::HksObject obj{}; + obj.t = game::hks::TNUMBER; + obj.v.number = static_cast(value); + + this->value_ = obj; + } + + script_value::script_value(const unsigned int value) + { + game::hks::HksObject obj{}; + obj.t = game::hks::TNUMBER; + obj.v.number = static_cast(value); + + this->value_ = obj; + } + + script_value::script_value(const bool value) + { + game::hks::HksObject obj{}; + obj.t = game::hks::TBOOLEAN; + obj.v.boolean = value; + + this->value_ = obj; + } + + script_value::script_value(const float value) + { + game::hks::HksObject obj{}; + obj.t = game::hks::TNUMBER; + obj.v.number = static_cast(value); + + this->value_ = obj; + } + + script_value::script_value(const double value) + : script_value(static_cast(value)) + { + } + + script_value::script_value(const char* value) + { + game::hks::HksObject obj{}; + + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + game::hks::hksi_lua_pushlstring(state, value, (unsigned int)strlen(value)); + obj = state->m_apistack.top[-1]; + + this->value_ = obj; + } + + script_value::script_value(const std::string& value) + : script_value(value.data()) + { + } + + script_value::script_value(const lightuserdata& value) + { + this->value_.t = game::hks::TLIGHTUSERDATA; + this->value_.v.ptr = value.ptr; + } + + script_value::script_value(const userdata& value) + { + this->value_.t = game::hks::TUSERDATA; + this->value_.v.ptr = value.ptr; + } + + script_value::script_value(const table& value) + { + this->value_.t = game::hks::TTABLE; + this->value_.v.ptr = value.ptr; + } + + script_value::script_value(const function& value) + { + this->value_.t = value.type; + this->value_.v.ptr = value.ptr; + } + + /*************************************************************** + * Integer + **************************************************************/ + + template <> + bool script_value::is() const + { + const auto number = this->get_raw().v.number; + return this->get_raw().t == game::hks::TNUMBER && static_cast(number) == number; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + int script_value::get() const + { + return static_cast(this->get_raw().v.number); + } + + template <> + unsigned int script_value::get() const + { + return static_cast(this->get_raw().v.number); + } + + /*************************************************************** + * Boolean + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TBOOLEAN; + } + + template <> + bool script_value::get() const + { + return this->get_raw().v.boolean; + } + + /*************************************************************** + * Float + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TNUMBER; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + float script_value::get() const + { + return this->get_raw().v.number; + } + + template <> + double script_value::get() const + { + return static_cast(this->get_raw().v.number); + } + + /*************************************************************** + * String + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TSTRING; + } + + template <> + bool script_value::is() const + { + return this->is(); + } + + template <> + const char* script_value::get() const + { + return this->get_raw().v.str->m_data; + } + + template <> + std::string script_value::get() const + { + return this->get(); + } + + /*************************************************************** + * Lightuserdata + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TLIGHTUSERDATA; + } + + template <> + lightuserdata script_value::get() const + { + return this->get_raw().v.ptr; + } + + /*************************************************************** + * Userdata + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TUSERDATA; + } + + template <> + userdata script_value::get() const + { + return this->get_raw().v.ptr; + } + + /*************************************************************** + * Table + **************************************************************/ + + template <> + bool script_value::is
() const + { + return this->get_raw().t == game::hks::TTABLE; + } + + template <> + table script_value::get() const + { + return this->get_raw().v.table; + } + + /*************************************************************** + * Function + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TIFUNCTION + || this->get_raw().t == game::hks::TCFUNCTION; + } + + template <> + function script_value::get() const + { + return { this->get_raw().v.cClosure, this->get_raw().t }; + } + + /*************************************************************** + * + **************************************************************/ + + const game::hks::HksObject& script_value::get_raw() const + { + return this->value_; + } +} diff --git a/src/client/game/ui_scripting/script_value.hpp b/src/client/game/ui_scripting/script_value.hpp new file mode 100644 index 00000000..3de52ddf --- /dev/null +++ b/src/client/game/ui_scripting/script_value.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "game/game.hpp" + +namespace ui_scripting +{ + class lightuserdata; + class userdata; + class table; + class function; + + class script_value + { + public: + script_value() = default; + script_value(const game::hks::HksObject& value); + + script_value(int value); + script_value(unsigned int value); + script_value(bool value); + + script_value(float value); + script_value(double value); + + script_value(const char* value); + script_value(const std::string& value); + + script_value(const lightuserdata& value); + script_value(const userdata& value); + script_value(const table& value); + script_value(const function& value); + + template + bool is() const; + + template + T as() const + { + if (!this->is()) + { + throw std::runtime_error("Invalid type"); + } + + return get(); + } + + const game::hks::HksObject& get_raw() const; + + private: + template + T get() const; + + game::hks::HksObject value_{}; + }; + + using arguments = std::vector; +} diff --git a/src/client/game/ui_scripting/types.cpp b/src/client/game/ui_scripting/types.cpp new file mode 100644 index 00000000..37032b1b --- /dev/null +++ b/src/client/game/ui_scripting/types.cpp @@ -0,0 +1,276 @@ +#include +#include "types.hpp" +#include "execution.hpp" + +namespace ui_scripting +{ + /*************************************************************** + * Lightuserdata + **************************************************************/ + + lightuserdata::lightuserdata(void* ptr_) + : ptr(ptr_) + { + } + + /*************************************************************** + * Userdata + **************************************************************/ + + userdata::userdata(void* ptr_) + : ptr(ptr_) + { + this->add(); + } + + userdata::userdata(const userdata& other) + { + this->operator=(other); + } + + userdata::userdata(userdata&& other) noexcept + { + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + userdata::~userdata() + { + this->release(); + } + + userdata& userdata::operator=(const userdata& other) + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + this->add(); + } + + return *this; + } + + userdata& userdata::operator=(userdata&& other) noexcept + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + return *this; + } + + void userdata::add() + { + game::hks::HksObject value{}; + value.v.ptr = this->ptr; + value.t = game::hks::TUSERDATA; + + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(value); + + this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); + } + + void userdata::release() + { + if (this->ref) + { + game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); + } + } + + void userdata::set(const script_value& key, const script_value& value) const + { + set_field(*this, key, value); + } + + script_value userdata::get(const script_value& key) const + { + return get_field(*this, key); + } + + /*************************************************************** + * Table + **************************************************************/ + + table::table() + { + const auto state = *game::hks::lua_state; + this->ptr = game::hks::Hashtable_Create(state, 0, 0); + this->add(); + } + + table::table(game::hks::HashTable* ptr_) + : ptr(ptr_) + { + this->add(); + } + + table::table(const table& other) + { + this->operator=(other); + } + + table::table(table&& other) noexcept + { + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + table::~table() + { + this->release(); + } + + table& table::operator=(const table& other) + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + this->add(); + } + + return *this; + } + + table& table::operator=(table&& other) noexcept + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + return *this; + } + + void table::add() + { + game::hks::HksObject value{}; + value.v.table = this->ptr; + value.t = game::hks::TTABLE; + + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(value); + + this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); + } + + void table::release() + { + if (this->ref) + { + game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); + } + } + + void table::set(const script_value& key, const script_value& value) const + { + set_field(*this, key, value); + } + + script_value table::get(const script_value& key) const + { + return get_field(*this, key); + } + + /*************************************************************** + * Function + **************************************************************/ + + function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_) + : ptr(ptr_) + , type(type_) + { + this->add(); + } + + function::function(const function& other) + { + this->operator=(other); + } + + function::function(function&& other) noexcept + { + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + other.ref = 0; + } + + function::~function() + { + this->release(); + } + + function& function::operator=(const function& other) + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + this->add(); + } + + return *this; + } + + function& function::operator=(function&& other) noexcept + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + other.ref = 0; + } + + return *this; + } + + void function::add() + { + game::hks::HksObject value{}; + value.v.cClosure = this->ptr; + value.t = this->type; + + const auto state = *game::hks::lua_state; + state->m_apistack.top = state->m_apistack.base; + + push_value(value); + + this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); + } + + void function::release() + { + if (this->ref) + { + game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); + } + } + + arguments function::call(const arguments& arguments) const + { + return call_script_function(*this, arguments); + } +} diff --git a/src/client/game/ui_scripting/types.hpp b/src/client/game/ui_scripting/types.hpp new file mode 100644 index 00000000..1924407f --- /dev/null +++ b/src/client/game/ui_scripting/types.hpp @@ -0,0 +1,89 @@ +#pragma once +#include "game/game.hpp" +#include "script_value.hpp" + +namespace ui_scripting +{ + class lightuserdata + { + public: + lightuserdata(void*); + void* ptr; + }; + + class userdata + { + public: + userdata(void*); + + userdata(const userdata& other); + userdata(userdata&& other) noexcept; + + ~userdata(); + + userdata& operator=(const userdata& other); + userdata& operator=(userdata&& other) noexcept; + + script_value get(const script_value& key) const; + void set(const script_value& key, const script_value& value) const; + + void* ptr; + + private: + void add(); + void release(); + + int ref{}; + }; + + class table + { + public: + table(); + table(game::hks::HashTable* ptr_); + + table(const table& other); + table(table&& other) noexcept; + + ~table(); + + table& operator=(const table& other); + table& operator=(table&& other) noexcept; + + script_value get(const script_value& key) const; + void set(const script_value& key, const script_value& value) const; + + game::hks::HashTable* ptr; + + private: + void add(); + void release(); + + int ref{}; + }; + + class function + { + public: + function(game::hks::cclosure*, game::hks::HksObjectType); + + function(const function& other); + function(function&& other) noexcept; + + ~function(); + + function& operator=(const function& other); + function& operator=(function&& other) noexcept; + + arguments call(const arguments& arguments) const; + + game::hks::cclosure* ptr; + game::hks::HksObjectType type; + + private: + void add(); + void release(); + + int ref{}; + }; +} diff --git a/src/client/launcher/html/doc_host_ui_handler.cpp b/src/client/launcher/html/doc_host_ui_handler.cpp new file mode 100644 index 00000000..2ec43a22 --- /dev/null +++ b/src/client/launcher/html/doc_host_ui_handler.cpp @@ -0,0 +1,115 @@ +#include +#include "html_frame.hpp" + +doc_host_ui_handler::doc_host_ui_handler(html_frame* frame): frame_(frame) +{ +} + +HRESULT doc_host_ui_handler::QueryInterface(REFIID riid, LPVOID* ppvObj) +{ + auto client_site = this->frame_->get_client_site(); + if (client_site) + { + return client_site->QueryInterface(riid, ppvObj); + } + + return E_NOINTERFACE; +} + +ULONG doc_host_ui_handler::AddRef() +{ + return 1; +} + +ULONG doc_host_ui_handler::Release() +{ + return 1; +} + +HRESULT doc_host_ui_handler::ShowContextMenu(DWORD /*dwID*/, POINT* /*ppt*/, IUnknown* /*pcmdtReserved*/, + IDispatch* /*pdispReserved*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::ShowUI(DWORD /*dwID*/, IOleInPlaceActiveObject* /*pActiveObject*/, + IOleCommandTarget* /*pCommandTarget*/, + IOleInPlaceFrame* /*pFrame*/, IOleInPlaceUIWindow* /*pDoc*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::HideUI() +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::UpdateUI() +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::EnableModeless(BOOL /*fEnable*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::OnDocWindowActivate(BOOL /*fActivate*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::OnFrameWindowActivate(BOOL /*fActivate*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::ResizeBorder(LPCRECT /*prcBorder*/, IOleInPlaceUIWindow* /*pUIWindow*/, + BOOL /*fRameWindow*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::TranslateAcceleratorA(LPMSG /*lpMsg*/, const GUID* pguidCmdGroup, DWORD /*nCmdID*/) +{ + pguidCmdGroup = nullptr; + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetOptionKeyPath(LPOLESTR* /*pchKey*/, DWORD /*dw*/) +{ + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetDropTarget(IDropTarget* /*pDropTarget*/, IDropTarget** /*ppDropTarget*/) +{ + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetExternal(IDispatch** ppDispatch) +{ + *ppDispatch = this->frame_->get_html_dispatch(); + return (*ppDispatch) ? S_OK : S_FALSE; +} + +HRESULT doc_host_ui_handler::FilterDataObject(IDataObject* /*pDO*/, IDataObject** ppDORet) +{ + *ppDORet = nullptr; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE doc_host_ui_handler::TranslateUrl(DWORD /*dwTranslate*/, OLECHAR __RPC_FAR* /*pchURLIn*/, + OLECHAR __RPC_FAR* __RPC_FAR* ppchURLOut) +{ + *ppchURLOut = nullptr; + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo) +{ + pInfo->cbSize = sizeof(DOCHOSTUIINFO); + pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_DPI_AWARE /*| DOCHOSTUIFLAG_SCROLL_NO*/; + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; + + return S_OK; +} diff --git a/src/client/launcher/html/doc_host_ui_handler.hpp b/src/client/launcher/html/doc_host_ui_handler.hpp new file mode 100644 index 00000000..0b538b41 --- /dev/null +++ b/src/client/launcher/html/doc_host_ui_handler.hpp @@ -0,0 +1,47 @@ +#pragma once + +class html_frame; + +class doc_host_ui_handler final : public IDocHostUIHandler +{ +public: + doc_host_ui_handler(html_frame* frame); + virtual ~doc_host_ui_handler() = default; + +private: + html_frame* frame_; + +public: // IDocHostUIHandler interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE ShowContextMenu( + DWORD dwID, + POINT __RPC_FAR * ppt, + IUnknown __RPC_FAR * pcmdtReserved, + IDispatch __RPC_FAR * pdispReserved) override; + HRESULT STDMETHODCALLTYPE ShowUI( + DWORD dwID, + IOleInPlaceActiveObject __RPC_FAR * pActiveObject, + IOleCommandTarget __RPC_FAR * pCommandTarget, + IOleInPlaceFrame __RPC_FAR * pFrame, + IOleInPlaceUIWindow __RPC_FAR * pDoc) override; + HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo) override; + HRESULT STDMETHODCALLTYPE HideUI() override; + HRESULT STDMETHODCALLTYPE UpdateUI() override; + HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override; + HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL fActivate) override; + HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL fActivate) override; + HRESULT STDMETHODCALLTYPE ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR * pUIWindow, + BOOL fRameWindow) override; + HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpMsg, const GUID __RPC_FAR * pguidCmdGroup, DWORD nCmdID) + override; + HRESULT STDMETHODCALLTYPE GetOptionKeyPath(LPOLESTR __RPC_FAR * pchKey, DWORD dw) override; + HRESULT STDMETHODCALLTYPE GetDropTarget(IDropTarget __RPC_FAR * pDropTarget, + IDropTarget __RPC_FAR *__RPC_FAR * ppDropTarget) override; + HRESULT STDMETHODCALLTYPE GetExternal(IDispatch __RPC_FAR *__RPC_FAR * ppDispatch) override; + HRESULT STDMETHODCALLTYPE TranslateUrl(DWORD dwTranslate, OLECHAR __RPC_FAR * pchURLIn, + OLECHAR __RPC_FAR *__RPC_FAR * ppchURLOut) override; + HRESULT STDMETHODCALLTYPE FilterDataObject(IDataObject __RPC_FAR * pDO, IDataObject __RPC_FAR *__RPC_FAR * ppDORet) + override; +}; diff --git a/src/client/launcher/html/html_argument.cpp b/src/client/launcher/html/html_argument.cpp new file mode 100644 index 00000000..181dc6e5 --- /dev/null +++ b/src/client/launcher/html/html_argument.cpp @@ -0,0 +1,48 @@ +#include +#include "html_argument.hpp" + +html_argument::html_argument(VARIANT* val) : value_(val) +{ +} + +bool html_argument::is_empty() const +{ + return this->value_ == nullptr || this->value_->vt == VT_EMPTY; +} + +bool html_argument::is_string() const +{ + if (this->is_empty()) return false; + return this->value_->vt == VT_BSTR; +} + +bool html_argument::is_number() const +{ + if (this->is_empty()) return false; + return this->value_->vt == VT_I4; +} + +bool html_argument::is_bool() const +{ + if (this->is_empty()) return false; + return this->value_->vt == VT_BOOL; +} + +std::string html_argument::get_string() const +{ + if (!this->is_string()) return {}; + std::wstring wide_string(this->value_->bstrVal); + return std::string(wide_string.begin(), wide_string.end()); +} + +int html_argument::get_number() const +{ + if (!this->is_number()) return 0; + return this->value_->intVal; +} + +bool html_argument::get_bool() const +{ + if (!this->is_bool()) return false; + return this->value_->boolVal != FALSE; +} diff --git a/src/client/launcher/html/html_argument.hpp b/src/client/launcher/html/html_argument.hpp new file mode 100644 index 00000000..6e460e29 --- /dev/null +++ b/src/client/launcher/html/html_argument.hpp @@ -0,0 +1,20 @@ +#pragma once + +class html_argument final +{ +public: + html_argument(VARIANT* val); + + bool is_empty() const; + + bool is_string() const; + bool is_number() const; + bool is_bool() const; + + std::string get_string() const; + int get_number() const; + bool get_bool() const; + +private: + VARIANT* value_; +}; diff --git a/src/client/launcher/html/html_dispatch.cpp b/src/client/launcher/html/html_dispatch.cpp new file mode 100644 index 00000000..0cbea58d --- /dev/null +++ b/src/client/launcher/html/html_dispatch.cpp @@ -0,0 +1,61 @@ +#include +#include "html_frame.hpp" + +html_dispatch::html_dispatch(html_frame* frame) : frame_(frame) +{ +} + +HRESULT html_dispatch::QueryInterface(const IID& riid, LPVOID* ppvObj) +{ + if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) || + !memcmp(&riid, &IID_IDispatch, sizeof(GUID))) + { + *ppvObj = this; + this->AddRef(); + return S_OK; + } + + *ppvObj = nullptr; + return E_NOINTERFACE; +} + +ULONG html_dispatch::AddRef() +{ + return 1; +} + +ULONG html_dispatch::Release() +{ + return 1; +} + +HRESULT html_dispatch::GetTypeInfoCount(UINT* pctinfo) +{ + return S_FALSE; +} + +HRESULT html_dispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + return S_FALSE; +} + +HRESULT html_dispatch::GetIDsOfNames(const IID& riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) +{ + for (unsigned int i = 0; i < cNames; ++i) + { + std::wstring wide_name(rgszNames[i]); + std::string name(wide_name.begin(), wide_name.end()); + + rgDispId[i] = this->frame_->get_callback_id(name); + } + + return S_OK; +} + +HRESULT html_dispatch::Invoke(DISPID dispIdMember, const IID& riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + html_frame::callback_params params(pDispParams, pVarResult); + this->frame_->invoke_callback(dispIdMember, ¶ms); + return S_OK; +} diff --git a/src/client/launcher/html/html_dispatch.hpp b/src/client/launcher/html/html_dispatch.hpp new file mode 100644 index 00000000..869af7a8 --- /dev/null +++ b/src/client/launcher/html/html_dispatch.hpp @@ -0,0 +1,24 @@ +#pragma once + +class html_frame; + +class html_dispatch final : public IDispatch +{ +public: + html_dispatch(html_frame* frame); + virtual ~html_dispatch() = default; + +private: + html_frame* frame_; + +public: // IDispatch interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override; + HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override; + HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) + override; + HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override; +}; diff --git a/src/client/launcher/html/html_frame.cpp b/src/client/launcher/html/html_frame.cpp new file mode 100644 index 00000000..d844ffec --- /dev/null +++ b/src/client/launcher/html/html_frame.cpp @@ -0,0 +1,295 @@ +#include +#include "html_frame.hpp" + +#include + +std::atomic html_frame::frame_count_ = 0; + +html_frame::callback_params::callback_params(DISPPARAMS* params, VARIANT* res) : result(res) +{ + for (auto i = params->cArgs; i > 0; --i) + { + auto* param = ¶ms->rgvarg[i - 1]; + this->arguments.emplace_back(param); + } +} + +html_frame::html_frame() + : in_place_frame_(this) + , in_place_site_(this) + , ui_handler_(this) + , client_site_(this) + , html_dispatch_(this) +{ + if (frame_count_++ == 0 && OleInitialize(nullptr) != S_OK) + { + throw std::runtime_error("Unable to initialize the OLE library"); + } + + auto needs_restart = false; + needs_restart |= set_browser_feature("FEATURE_BROWSER_EMULATION", 11000); + needs_restart |= set_browser_feature("FEATURE_GPU_RENDERING", 1); + + if (needs_restart) + { + utils::nt::relaunch_self(); + utils::nt::terminate(0); + } +} + +html_frame::~html_frame() +{ + if (--frame_count_ <= 0) + { + frame_count_ = 0; + OleUninitialize(); + } +} + +void html_frame::object_deleter(IUnknown* object) +{ + if (object) + { + object->Release(); + } +} + +HWND html_frame::get_window() const +{ + return this->window_; +} + +std::shared_ptr html_frame::get_browser_object() const +{ + return this->browser_object_; +} + +ole_in_place_frame* html_frame::get_in_place_frame() +{ + return &this->in_place_frame_; +} + +ole_in_place_site* html_frame::get_in_place_site() +{ + return &this->in_place_site_; +} + +doc_host_ui_handler* html_frame::get_ui_handler() +{ + return &this->ui_handler_; +} + +ole_client_site* html_frame::get_client_site() +{ + return &this->client_site_; +} + +html_dispatch* html_frame::get_html_dispatch() +{ + return &this->html_dispatch_; +} + +std::shared_ptr html_frame::get_web_browser() const +{ + if (!this->browser_object_) return {}; + + IWebBrowser2* web_browser = nullptr; + if (FAILED(this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast(&web_browser))) + || !web_browser) + return {}; + + return std::shared_ptr(web_browser, object_deleter); +} + +std::shared_ptr html_frame::get_dispatch() const +{ + const auto web_browser = this->get_web_browser(); + if (!web_browser) return {}; + + IDispatch* dispatch = nullptr; + if (FAILED(web_browser->get_Document(&dispatch)) || !dispatch) return {}; + + return std::shared_ptr(dispatch, object_deleter); +} + +std::shared_ptr html_frame::get_document() const +{ + const auto dispatch = this->get_dispatch(); + if (!dispatch) return {}; + + IHTMLDocument2* document = nullptr; + if (FAILED(dispatch->QueryInterface(IID_IHTMLDocument2, reinterpret_cast(&document))) + || !document) + return {}; + + return std::shared_ptr(document, object_deleter); +} + +void html_frame::initialize(const HWND window) +{ + if (this->window_) return; + this->window_ = window; + + this->create_browser(); + this->initialize_browser(); +} + +void html_frame::create_browser() +{ + LPCLASSFACTORY class_factory = nullptr; + if (FAILED( + CoGetClassObject(CLSID_WebBrowser, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, nullptr, IID_IClassFactory, + reinterpret_cast(&class_factory))) || !class_factory) + { + throw std::runtime_error("Unable to get the class factory"); + } + + IOleObject* browser_object = nullptr; + class_factory->CreateInstance(nullptr, IID_IOleObject, reinterpret_cast(&browser_object)); + class_factory->Release(); + + if (!browser_object) + { + throw std::runtime_error("Unable to create browser object"); + } + + this->browser_object_ = std::shared_ptr(browser_object, [](IOleObject* browser_object) + { + if (browser_object) + { + browser_object->Close(OLECLOSE_NOSAVE); + object_deleter(browser_object); + } + }); +} + +void html_frame::initialize_browser() +{ + this->browser_object_->SetClientSite(this->get_client_site()); + this->browser_object_->SetHostNames(L"Hostname", nullptr); + + RECT rect; + GetClientRect(this->get_window(), &rect); + OleSetContainedObject(this->browser_object_.get(), TRUE); + + this->browser_object_->DoVerb(OLEIVERB_SHOW, nullptr, this->get_client_site(), -1, this->get_window(), &rect); + this->resize(rect.right, rect.bottom); +} + +bool html_frame::set_browser_feature(const std::string& feature, DWORD value) +{ + const auto registry_path = R"(SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\)" + feature; + + HKEY key = nullptr; + if (RegCreateKeyA(HKEY_CURRENT_USER, registry_path.data(), &key) == ERROR_SUCCESS) + { + RegCloseKey(key); + } + + key = nullptr; + if (RegOpenKeyExA( + HKEY_CURRENT_USER, registry_path.data(), 0, + KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) + { + return false; // Error :( + } + + const utils::nt::library self; + const auto name = self.get_name(); + + DWORD type{}; + auto is_new = true; + if (RegQueryValueExA(key, name.data(), nullptr, &type, nullptr, nullptr) == ERROR_SUCCESS) + { + is_new = false; + } + + RegSetValueExA(key, name.data(), 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + RegCloseKey(key); + + return is_new; +} + +void html_frame::resize(const DWORD width, const DWORD height) const +{ + auto web_browser = this->get_web_browser(); + if (web_browser) + { + web_browser->put_Left(0); + web_browser->put_Top(0); + web_browser->put_Width(width); + web_browser->put_Height(height); + } +} + +bool html_frame::load_url(const std::string& url) const +{ + auto web_browser = this->get_web_browser(); + if (!web_browser) return false; + + std::wstring wide_url(url.begin(), url.end()); + + VARIANT my_url; + VariantInit(&my_url); + my_url.vt = VT_BSTR; + my_url.bstrVal = SysAllocString(wide_url.data()); + + const auto _ = gsl::finally([&my_url]() { VariantClear(&my_url); }); + if (!my_url.bstrVal) return false; + + return SUCCEEDED(web_browser->Navigate2(&my_url, nullptr, nullptr, nullptr, nullptr)); +} + +bool html_frame::load_html(const std::string& html) const +{ + if (!this->load_url("about:blank")) return false; + + const auto document = this->get_document(); + if (!document) return false; + + SAFEARRAYBOUND safe_array_bound = {1, 0}; + auto safe_array = SafeArrayCreate(VT_VARIANT, 1, &safe_array_bound); + if (!safe_array) return false; + + const auto _ = gsl::finally([safe_array]() { SafeArrayDestroy(safe_array); }); + + VARIANT* variant = nullptr; + if (FAILED(SafeArrayAccessData(safe_array, reinterpret_cast(&variant))) || !variant) return false; + + std::wstring wide_html(html.begin(), html.end()); + + variant->vt = VT_BSTR; + variant->bstrVal = SysAllocString(wide_html.data()); + if (!variant->bstrVal) return false; + + document->write(safe_array); + document->close(); + + return true; +} + +int html_frame::get_callback_id(const std::string& name) +{ + for (auto i = 0u; i < this->callbacks_.size(); ++i) + { + if (this->callbacks_[i].first == name) + { + return i; + } + } + + return -1; +} + +void html_frame::invoke_callback(const int id, callback_params* params) +{ + if (id >= 0 && static_cast(id) < this->callbacks_.size()) + { + this->callbacks_[id].second(params); + } +} + +void html_frame::register_callback(const std::string& name, const std::function& callback) +{ + this->callbacks_.emplace_back(name, callback); +} diff --git a/src/client/launcher/html/html_frame.hpp b/src/client/launcher/html/html_frame.hpp new file mode 100644 index 00000000..04d8108c --- /dev/null +++ b/src/client/launcher/html/html_frame.hpp @@ -0,0 +1,67 @@ +#pragma once +#include "ole_in_place_frame.hpp" +#include "ole_in_place_site.hpp" +#include "doc_host_ui_handler.hpp" +#include "ole_client_site.hpp" +#include "html_dispatch.hpp" +#include "html_argument.hpp" + +class html_frame +{ +public: + class callback_params final + { + public: + callback_params(DISPPARAMS* params, VARIANT* res); + + std::vector arguments; + html_argument result; + }; + + html_frame(); + virtual ~html_frame(); + + void initialize(HWND window); + + void resize(DWORD width, DWORD height) const; + bool load_url(const std::string& url) const; + bool load_html(const std::string& html) const; + + HWND get_window() const; + + std::shared_ptr get_browser_object() const; + std::shared_ptr get_web_browser() const; + std::shared_ptr get_dispatch() const; + std::shared_ptr get_document() const; + + ole_in_place_frame* get_in_place_frame(); + ole_in_place_site* get_in_place_site(); + doc_host_ui_handler* get_ui_handler(); + ole_client_site* get_client_site(); + html_dispatch* get_html_dispatch(); + + int get_callback_id(const std::string& name); + void invoke_callback(int id, callback_params* params); + + void register_callback(const std::string& name, const std::function& callback); + +private: + HWND window_ = nullptr; + std::shared_ptr browser_object_; + + ole_in_place_frame in_place_frame_; + ole_in_place_site in_place_site_; + doc_host_ui_handler ui_handler_; + ole_client_site client_site_; + html_dispatch html_dispatch_; + + std::vector>> callbacks_; + + void create_browser(); + void initialize_browser(); + + static bool set_browser_feature(const std::string& feature, DWORD value); + static void object_deleter(IUnknown* object); + + static std::atomic frame_count_; +}; diff --git a/src/client/launcher/html/html_window.cpp b/src/client/launcher/html/html_window.cpp new file mode 100644 index 00000000..bf01098c --- /dev/null +++ b/src/client/launcher/html/html_window.cpp @@ -0,0 +1,29 @@ +#include +#include "html_window.hpp" + +window* html_window::get_window() +{ + return this; +} + +html_frame* html_window::get_html_frame() +{ + return this; +} + +LRESULT html_window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param) +{ + if (message == WM_SIZE) + { + this->resize(LOWORD(l_param), HIWORD(l_param)); + return 0; + } + + if (message == WM_CREATE) + { + this->initialize(*this); + return 0; + } + + return window::processor(message, w_param, l_param); +} diff --git a/src/client/launcher/html/html_window.hpp b/src/client/launcher/html/html_window.hpp new file mode 100644 index 00000000..5b9f25be --- /dev/null +++ b/src/client/launcher/html/html_window.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "../window.hpp" +#include "html_frame.hpp" + +class html_window final : public window, public html_frame +{ +public: + ~html_window() = default; + + window* get_window(); + html_frame* get_html_frame(); + +private: + LRESULT processor(UINT message, WPARAM w_param, LPARAM l_param) override; +}; diff --git a/src/client/launcher/html/ole_client_site.cpp b/src/client/launcher/html/ole_client_site.cpp new file mode 100644 index 00000000..6e3914ea --- /dev/null +++ b/src/client/launcher/html/ole_client_site.cpp @@ -0,0 +1,77 @@ +#include +#include "html_frame.hpp" + +ole_client_site::ole_client_site(html_frame* frame): frame_(frame) +{ +} + +HRESULT ole_client_site::QueryInterface(REFIID riid, LPVOID* ppvObject) +{ + if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) || + !memcmp(&riid, &IID_IOleClientSite, sizeof(GUID))) + { + *ppvObject = this; + this->AddRef(); + return S_OK; + } + + if (!memcmp(&riid, &IID_IOleInPlaceSite, sizeof(GUID))) + { + auto in_place_site = this->frame_->get_in_place_site(); + in_place_site->AddRef(); + *ppvObject = in_place_site; + return S_OK; + } + + if (!memcmp(&riid, &IID_IDocHostUIHandler, sizeof(GUID))) + { + auto ui_handler = this->frame_->get_ui_handler(); + ui_handler->AddRef(); + *ppvObject = ui_handler; + return S_OK; + } + + *ppvObject = nullptr; + return E_NOINTERFACE; +} + +ULONG ole_client_site::AddRef() +{ + return 1; +} + +ULONG ole_client_site::Release() +{ + return 1; +} + +HRESULT ole_client_site::SaveObject() +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::GetMoniker(DWORD /*dwAssign*/, DWORD /*dwWhichMoniker*/, IMoniker** /*ppmk*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::GetContainer(LPOLECONTAINER* ppContainer) +{ + *ppContainer = nullptr; + return E_NOINTERFACE; +} + +HRESULT ole_client_site::ShowObject() +{ + return NOERROR; +} + +HRESULT ole_client_site::OnShowWindow(BOOL /*fShow*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::RequestNewObjectLayout() +{ + return E_NOTIMPL; +} diff --git a/src/client/launcher/html/ole_client_site.hpp b/src/client/launcher/html/ole_client_site.hpp new file mode 100644 index 00000000..d0adc80d --- /dev/null +++ b/src/client/launcher/html/ole_client_site.hpp @@ -0,0 +1,24 @@ +#pragma once + +class html_frame; + +class ole_client_site final : public IOleClientSite +{ +public: + ole_client_site(html_frame* frame); + virtual ~ole_client_site() = default; + +private: + html_frame* frame_; + +public: + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObject) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE SaveObject() override; + HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk) override; + HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER FAR* ppContainer) override; + HRESULT STDMETHODCALLTYPE ShowObject() override; + HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow) override; + HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() override; +}; diff --git a/src/client/launcher/html/ole_in_place_frame.cpp b/src/client/launcher/html/ole_in_place_frame.cpp new file mode 100644 index 00000000..172e5db0 --- /dev/null +++ b/src/client/launcher/html/ole_in_place_frame.cpp @@ -0,0 +1,82 @@ +#include +#include "html_frame.hpp" + +ole_in_place_frame::ole_in_place_frame(html_frame* frame): frame_(frame) +{ +} + +HRESULT ole_in_place_frame::QueryInterface(REFIID /*riid*/, LPVOID* /*ppvObj*/) +{ + return E_NOTIMPL; +} + +ULONG ole_in_place_frame::AddRef() +{ + return 1; +} + +ULONG ole_in_place_frame::Release() +{ + return 1; +} + +HRESULT ole_in_place_frame::GetWindow(HWND* lphwnd) +{ + *lphwnd = this->frame_->get_window(); + return S_OK; +} + +HRESULT ole_in_place_frame::ContextSensitiveHelp(BOOL /*fEnterMode*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::GetBorder(LPRECT /*lprectBorder*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::RequestBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetActiveObject(IOleInPlaceActiveObject* /*pActiveObject*/, LPCOLESTR /*pszObjName*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS /*lpMenuWidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetMenu(HMENU /*hmenuShared*/, HOLEMENU /*holemenu*/, HWND /*hwndActiveObject*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::RemoveMenus(HMENU /*hmenuShared*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetStatusText(LPCOLESTR /*pszStatusText*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::EnableModeless(BOOL /*fEnable*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::TranslateAcceleratorA(LPMSG /*lpmsg*/, WORD /*wID*/) +{ + return E_NOTIMPL; +} diff --git a/src/client/launcher/html/ole_in_place_frame.hpp b/src/client/launcher/html/ole_in_place_frame.hpp new file mode 100644 index 00000000..4a39d7f3 --- /dev/null +++ b/src/client/launcher/html/ole_in_place_frame.hpp @@ -0,0 +1,30 @@ +#pragma once + +class html_frame; + +class ole_in_place_frame final : public IOleInPlaceFrame +{ +public: + ole_in_place_frame(html_frame* frame); + virtual ~ole_in_place_frame() = default; + +private: + html_frame* frame_; + +public: // IOleInPlaceFrame interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override; + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override; + HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder) override; + HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) override; + HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS pborderwidths) override; + HRESULT STDMETHODCALLTYPE SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR pszObjName) override; + HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) override; + HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) override; + HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared) override; + HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR pszStatusText) override; + HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override; + HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID) override; +}; diff --git a/src/client/launcher/html/ole_in_place_site.cpp b/src/client/launcher/html/ole_in_place_site.cpp new file mode 100644 index 00000000..d6cd3d82 --- /dev/null +++ b/src/client/launcher/html/ole_in_place_site.cpp @@ -0,0 +1,105 @@ +#include +#include "html_frame.hpp" + +ole_in_place_site::ole_in_place_site(html_frame* frame) : frame_(frame) +{ +} + +HRESULT ole_in_place_site::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + auto client_site = this->frame_->get_client_site(); + if (client_site) + { + return client_site->QueryInterface(riid, ppvObj); + } + + return E_NOINTERFACE; +} + +ULONG ole_in_place_site::AddRef() +{ + return 1; +} + +ULONG ole_in_place_site::Release() +{ + return 1; +} + +HRESULT ole_in_place_site::GetWindow(HWND* lphwnd) +{ + *lphwnd = this->frame_->get_window(); + return S_OK; +} + +HRESULT ole_in_place_site::ContextSensitiveHelp(BOOL /*fEnterMode*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::CanInPlaceActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnInPlaceActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnUIActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::GetWindowContext(LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, + LPRECT /*lprcPosRect*/, LPRECT /*lprcClipRect*/, + LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + *lplpFrame = this->frame_->get_in_place_frame(); + *lplpDoc = nullptr; + + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = this->frame_->get_window(); + lpFrameInfo->haccel = nullptr; + lpFrameInfo->cAccelEntries = 0; + + return S_OK; +} + +HRESULT ole_in_place_site::Scroll(SIZE /*scrollExtent*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::OnUIDeactivate(BOOL /*fUndoable*/) +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnInPlaceDeactivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::DiscardUndoState() +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::DeactivateAndUndo() +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::OnPosRectChange(LPCRECT lprcPosRect) +{ + IOleInPlaceObject* in_place = nullptr; + if (!this->frame_->get_browser_object()->QueryInterface(IID_IOleInPlaceObject, reinterpret_cast(&in_place))) + { + in_place->SetObjectRects(lprcPosRect, lprcPosRect); + in_place->Release(); + } + + return S_OK; +} diff --git a/src/client/launcher/html/ole_in_place_site.hpp b/src/client/launcher/html/ole_in_place_site.hpp new file mode 100644 index 00000000..3dad18cf --- /dev/null +++ b/src/client/launcher/html/ole_in_place_site.hpp @@ -0,0 +1,32 @@ +#pragma once + +class html_frame; + +class ole_in_place_site final : public IOleInPlaceSite +{ +public: + ole_in_place_site(html_frame* frame); + virtual ~ole_in_place_site() = default; + +private: + html_frame* frame_; + +public: // IOleInPlaceSite interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override; + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override; + HRESULT STDMETHODCALLTYPE CanInPlaceActivate() override; + HRESULT STDMETHODCALLTYPE OnInPlaceActivate() override; + HRESULT STDMETHODCALLTYPE OnUIActivate() override; + HRESULT STDMETHODCALLTYPE GetWindowContext(LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, + LPRECT lprcPosRect, LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo) override; + HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtent) override; + HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable) override; + HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() override; + HRESULT STDMETHODCALLTYPE DiscardUndoState() override; + HRESULT STDMETHODCALLTYPE DeactivateAndUndo() override; + HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect) override; +}; diff --git a/src/client/launcher/launcher.cpp b/src/client/launcher/launcher.cpp new file mode 100644 index 00000000..270ad799 --- /dev/null +++ b/src/client/launcher/launcher.cpp @@ -0,0 +1,66 @@ +#include +#include "launcher.hpp" + +#include + +launcher::launcher() +{ + this->create_main_menu(); +} + +void launcher::create_main_menu() +{ + this->main_window_.register_callback("openUrl", [](html_frame::callback_params* params) + { + if (params->arguments.empty()) return; + + const auto param = params->arguments[0]; + if (!param.is_string()) return; + + const auto url = param.get_string(); + ShellExecuteA(nullptr, "open", url.data(), nullptr, nullptr, SW_SHOWNORMAL); + }); + + this->main_window_.register_callback("selectMode", [this](html_frame::callback_params* params) + { + if (params->arguments.empty()) return; + + const auto param = params->arguments[0]; + if (!param.is_number()) return; + + const auto number = static_cast(param.get_number()); + this->select_mode(number); + }); + + this->main_window_.set_callback( + [](window* window, const UINT message, const WPARAM w_param, const LPARAM l_param) -> LRESULT + { + if (message == WM_CLOSE) + { + window::close_all(); + } + + return DefWindowProcA(*window, message, w_param, l_param); + }); + + this->main_window_.create("S1x", 750, 420); + this->main_window_.load_html(load_content(MENU_MAIN)); + this->main_window_.show(); +} + +launcher::mode launcher::run() const +{ + window::run(); + return this->mode_; +} + +void launcher::select_mode(const mode mode) +{ + this->mode_ = mode; + this->main_window_.close(); +} + +std::string launcher::load_content(const int res) +{ + return utils::nt::load_resource(res); +} diff --git a/src/client/launcher/launcher.hpp b/src/client/launcher/launcher.hpp new file mode 100644 index 00000000..1808376c --- /dev/null +++ b/src/client/launcher/launcher.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "html/html_window.hpp" + +class launcher final +{ +public: + enum class mode + { + none, + singleplayer, + multiplayer, + server, + // Surrogates + survival, + zombies, + }; + + launcher(); + + mode run() const; + +private: + mode mode_ = mode::none; + + html_window main_window_; + + void select_mode(mode mode); + + void create_main_menu(); + + static std::string load_content(int res); +}; diff --git a/src/client/launcher/window.cpp b/src/client/launcher/window.cpp new file mode 100644 index 00000000..b9390612 --- /dev/null +++ b/src/client/launcher/window.cpp @@ -0,0 +1,208 @@ +#include +#include "window.hpp" + +#include + +std::mutex window::mutex_; +std::vector window::windows_; + +window::window() +{ + ZeroMemory(&this->wc_, sizeof(this->wc_)); + + this->classname_ = "window-base-" + std::to_string(time(nullptr)); + + this->wc_.cbSize = sizeof(this->wc_); + this->wc_.style = CS_HREDRAW | CS_VREDRAW; + this->wc_.lpfnWndProc = static_processor; + this->wc_.hInstance = GetModuleHandle(nullptr); + this->wc_.hCursor = LoadCursor(nullptr, IDC_ARROW); + this->wc_.hIcon = LoadIcon(this->wc_.hInstance, MAKEINTRESOURCE(102)); + this->wc_.hIconSm = this->wc_.hIcon; + this->wc_.hbrBackground = HBRUSH(COLOR_WINDOW); + this->wc_.lpszClassName = this->classname_.data(); + RegisterClassEx(&this->wc_); +} + +void window::create(const std::string& title, const int width, const int height, const long flags) +{ + { + std::lock_guard _(mutex_); + windows_.push_back(this); + } + + const auto x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; + const auto y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; + + this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(), flags, x, y, width, height, nullptr, + nullptr, this->wc_.hInstance, this); + + SendMessageA(this->handle_, WM_DPICHANGED, 0, 0); +} + +window::~window() +{ + this->close(); + UnregisterClass(this->wc_.lpszClassName, this->wc_.hInstance); +} + +void window::close() +{ + if (!this->handle_) return; + + SendMessageA(this->handle_, WM_KILL_WINDOW, NULL, NULL); + this->handle_ = nullptr; +} + +void window::run() +{ + MSG msg; + while (GetMessage(&msg, nullptr, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void window::close_all() +{ + std::unique_lock lock(mutex_); + auto window_list = windows_; + lock.unlock(); + + const auto current_thread_id = GetCurrentThreadId(); + for (auto& window : window_list) + { + const auto thread_id = GetWindowThreadProcessId(*window, nullptr); + + if (thread_id == current_thread_id) + { + window->close(); + } + } +} + +void window::remove_window(const window* window) +{ + std::lock_guard _(mutex_); + + for (auto i = windows_.begin(); i != windows_.end(); ++i) + { + if (*i == window) + { + windows_.erase(i); + break; + } + } +} + +int window::get_window_count() +{ + std::lock_guard _(mutex_); + + auto count = 0; + const auto current_thread_id = GetCurrentThreadId(); + + for (const auto& window : windows_) + { + const auto thread_id = GetWindowThreadProcessId(*window, nullptr); + + if (thread_id == current_thread_id) + { + ++count; + } + } + + return count; +} + +void window::show() const +{ + ShowWindow(this->handle_, SW_SHOW); + UpdateWindow(this->handle_); +} + +void window::hide() const +{ + ShowWindow(this->handle_, SW_HIDE); + UpdateWindow(this->handle_); +} + +void window::set_callback(const std::function& callback) +{ + this->callback_ = callback; +} + +LRESULT window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param) +{ + if (message == WM_DPICHANGED) + { + const utils::nt::library user32{"user32.dll"}; + const auto get_dpi = user32 ? user32.get_proc("GetDpiForWindow") : nullptr; + + if (get_dpi) + { + const auto dpi = get_dpi(*this); + if (dpi != this->last_dpi_) + { + RECT rect; + GetWindowRect(*this, &rect); + + const auto scale = dpi * 1.0 / this->last_dpi_; + this->last_dpi_ = dpi; + + const auto width = rect.right - rect.left; + const auto height = rect.bottom - rect.top; + + MoveWindow(*this, rect.left, rect.top, int(width * scale), int(height * scale), TRUE); + } + } + } + + if (message == WM_DESTROY) + { + remove_window(this); + + if (get_window_count() == 0) + { + PostQuitMessage(0); + } + + return TRUE; + } + + if (message == WM_KILL_WINDOW) + { + DestroyWindow(*this); + return 0; + } + + if (this->callback_) + { + return this->callback_(this, message, w_param, l_param); + } + + return DefWindowProc(*this, message, w_param, l_param); +} + +LRESULT CALLBACK window::static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) +{ + if (message == WM_CREATE) + { + auto data = reinterpret_cast(l_param); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, LONG_PTR(data->lpCreateParams)); + + static_cast(data->lpCreateParams)->handle_ = hwnd; + } + + const auto self = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + if (self) return self->processor(message, w_param, l_param); + + return DefWindowProc(hwnd, message, w_param, l_param); +} + + +window::operator HWND() const +{ + return this->handle_; +} diff --git a/src/client/launcher/window.hpp b/src/client/launcher/window.hpp new file mode 100644 index 00000000..4dea45d6 --- /dev/null +++ b/src/client/launcher/window.hpp @@ -0,0 +1,44 @@ +#pragma once + +#define WM_KILL_WINDOW (WM_USER+0) + +class window +{ +public: + window(); + virtual ~window(); + + void create(const std::string& title, int width, int height, + long flags = (WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX))); + + void close(); + + void show() const; + void hide() const; + + void set_callback(const std::function& callback); + + operator HWND() const; + + static void run(); + static void close_all(); + +protected: + virtual LRESULT processor(UINT message, WPARAM w_param, LPARAM l_param); + +private: + uint32_t last_dpi_ = 96; + + WNDCLASSEX wc_{}; + HWND handle_ = nullptr; + std::string classname_; + std::function callback_; + + static LRESULT CALLBACK static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param); + + static std::mutex mutex_; + static std::vector windows_; + + static void remove_window(const window* window); + static int get_window_count(); +}; diff --git a/src/client/loader/component_interface.hpp b/src/client/loader/component_interface.hpp new file mode 100644 index 00000000..e1ee433f --- /dev/null +++ b/src/client/loader/component_interface.hpp @@ -0,0 +1,35 @@ +#pragma once + +class component_interface +{ +public: + virtual ~component_interface() + { + } + + virtual void post_start() + { + } + + virtual void post_load() + { + } + + virtual void pre_destroy() + { + } + + virtual void post_unpack() + { + } + + virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function) + { + return nullptr; + } + + virtual bool is_supported() + { + return true; + } +}; diff --git a/src/client/loader/component_loader.cpp b/src/client/loader/component_loader.cpp new file mode 100644 index 00000000..60418086 --- /dev/null +++ b/src/client/loader/component_loader.cpp @@ -0,0 +1,127 @@ +#include +#include "component_loader.hpp" + +void component_loader::register_component(std::unique_ptr&& component_) +{ + get_components().push_back(std::move(component_)); +} + +bool component_loader::post_start() +{ + static auto handled = false; + if (handled) return true; + handled = true; + + try + { + for (const auto& component_ : get_components()) + { + component_->post_start(); + } + } + catch (premature_shutdown_trigger&) + { + return false; + } + + return true; +} + +bool component_loader::post_load() +{ + static auto handled = false; + if (handled) return true; + handled = true; + + clean(); + + try + { + for (const auto& component_ : get_components()) + { + component_->post_load(); + } + } + catch (premature_shutdown_trigger&) + { + return false; + } + + return true; +} + +void component_loader::post_unpack() +{ + static auto handled = false; + if (handled) return; + handled = true; + + for (const auto& component_ : get_components()) + { + component_->post_unpack(); + } +} + +void component_loader::pre_destroy() +{ + static auto handled = false; + if (handled) return; + handled = true; + + for (const auto& component_ : get_components()) + { + component_->pre_destroy(); + } +} + +void component_loader::clean() +{ + auto& components = get_components(); + for (auto i = components.begin(); i != components.end();) + { + if (!(*i)->is_supported()) + { + (*i)->pre_destroy(); + i = components.erase(i); + } + else + { + ++i; + } + } +} + +void* component_loader::load_import(const std::string& library, const std::string& function) +{ + void* function_ptr = nullptr; + + for (const auto& component_ : get_components()) + { + auto* const component_function_ptr = component_->load_import(library, function); + if (component_function_ptr) + { + function_ptr = component_function_ptr; + } + } + + return function_ptr; +} + +void component_loader::trigger_premature_shutdown() +{ + throw premature_shutdown_trigger(); +} + +std::vector>& component_loader::get_components() +{ + using component_vector = std::vector>; + using component_vector_container = std::unique_ptr>; + + static component_vector_container components(new component_vector, [](component_vector* component_vector) + { + pre_destroy(); + delete component_vector; + }); + + return *components; +} diff --git a/src/client/loader/component_loader.hpp b/src/client/loader/component_loader.hpp new file mode 100644 index 00000000..4ff8f3c4 --- /dev/null +++ b/src/client/loader/component_loader.hpp @@ -0,0 +1,61 @@ +#pragma once +#include "component_interface.hpp" + +class component_loader final +{ +public: + class premature_shutdown_trigger final : public std::exception + { + [[nodiscard]] const char* what() const noexcept override + { + return "Premature shutdown requested"; + } + }; + + template + class installer final + { + static_assert(std::is_base_of::value, "component has invalid base class"); + + public: + installer() + { + register_component(std::make_unique()); + } + }; + + template + static T* get() + { + for (const auto& component_ : get_components()) + { + if (typeid(*component_.get()) == typeid(T)) + { + return reinterpret_cast(component_.get()); + } + } + + return nullptr; + } + + static void register_component(std::unique_ptr&& component); + + static bool post_start(); + static bool post_load(); + static void post_unpack(); + static void pre_destroy(); + static void clean(); + + static void* load_import(const std::string& library, const std::string& function); + + static void trigger_premature_shutdown(); + +private: + static std::vector>& get_components(); +}; + +#define REGISTER_COMPONENT(name) \ +namespace \ +{ \ + static component_loader::installer __component; \ +} diff --git a/src/client/loader/loader.cpp b/src/client/loader/loader.cpp new file mode 100644 index 00000000..1bc7b41c --- /dev/null +++ b/src/client/loader/loader.cpp @@ -0,0 +1,211 @@ +#include +#include "loader.hpp" +#include "seh.hpp" +#include "tls.hpp" + +#include +#include + +FARPROC loader::load(const utils::nt::library& library, const std::string& buffer) const +{ + if (buffer.empty()) return nullptr; + + const utils::nt::library source(HMODULE(buffer.data())); + if (!source) return nullptr; + + this->load_sections(library, source); + this->load_imports(library, source); + this->load_exception_table(library, source); + this->load_tls(library, source); + + DWORD old_protect; + VirtualProtect(library.get_nt_headers(), 0x1000, PAGE_EXECUTE_READWRITE, &old_protect); + + library.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] = source + .get_optional_header()->DataDirectory[ + IMAGE_DIRECTORY_ENTRY_IMPORT]; + std::memmove(library.get_nt_headers(), source.get_nt_headers(), + sizeof(IMAGE_NT_HEADERS) + source.get_nt_headers()->FileHeader.NumberOfSections * sizeof( + IMAGE_SECTION_HEADER)); + + return FARPROC(library.get_ptr() + source.get_relative_entry_point()); +} + +FARPROC loader::load_library(const std::string& filename) const +{ + const auto target = utils::nt::library::load(filename); + if (!target) + { + throw std::runtime_error{"Failed to map binary!"}; + } + + const auto base = size_t(target.get_ptr()); + if(base != 0x140000000) + { + throw std::runtime_error{utils::string::va("Binary was mapped at 0x%llX (instead of 0x%llX). Something is severely broken :(", base, 0x140000000)}; + } + + this->load_imports(target, target); + this->load_tls(target, target); + + return FARPROC(target.get_ptr() + target.get_relative_entry_point()); +} + +void loader::set_import_resolver(const std::function& resolver) +{ + this->import_resolver_ = resolver; +} + +void loader::load_section(const utils::nt::library& target, const utils::nt::library& source, + IMAGE_SECTION_HEADER* section) +{ + void* target_ptr = target.get_ptr() + section->VirtualAddress; + const void* source_ptr = source.get_ptr() + section->PointerToRawData; + + if (PBYTE(target_ptr) >= (target.get_ptr() + BINARY_PAYLOAD_SIZE)) + { + throw std::runtime_error("Section exceeds the binary payload size, please increase it!"); + } + + if (section->SizeOfRawData > 0) + { + std::memmove(target_ptr, source_ptr, section->SizeOfRawData); + + DWORD old_protect; + VirtualProtect(target_ptr, section->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &old_protect); + } +} + +void loader::load_sections(const utils::nt::library& target, const utils::nt::library& source) const +{ + for (auto& section : source.get_section_headers()) + { + this->load_section(target, source, section); + } +} + +void loader::load_imports(const utils::nt::library& target, const utils::nt::library& source) const +{ + auto* const import_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; + + auto* descriptor = PIMAGE_IMPORT_DESCRIPTOR(target.get_ptr() + import_directory->VirtualAddress); + + while (descriptor->Name) + { + std::string name = LPSTR(target.get_ptr() + descriptor->Name); + + auto* name_table_entry = reinterpret_cast(target.get_ptr() + descriptor->OriginalFirstThunk); + auto* address_table_entry = reinterpret_cast(target.get_ptr() + descriptor->FirstThunk); + + if (!descriptor->OriginalFirstThunk) + { + name_table_entry = reinterpret_cast(target.get_ptr() + descriptor->FirstThunk); + } + + while (*name_table_entry) + { + FARPROC function = nullptr; + std::string function_name; + const char* function_procname; + + if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry)) + { + function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry)); + function_procname = MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry)); + } + else + { + auto* import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry); + function_name = import->Name; + function_procname = function_name.data(); + } + + if (this->import_resolver_) function = FARPROC(this->import_resolver_(name, function_name)); + if (!function) + { + auto library = utils::nt::library::load(name); + if (library) + { + function = GetProcAddress(library, function_procname); + } + } + + if (!function) + { + throw std::runtime_error(utils::string::va("Unable to load import '%s' from library '%s'", + function_name.data(), name.data())); + } + + utils::hook::set(address_table_entry, reinterpret_cast(function)); + + name_table_entry++; + address_table_entry++; + } + + descriptor++; + } +} + +void loader::load_exception_table(const utils::nt::library& target, const utils::nt::library& source) const +{ + auto* exception_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; + + auto* function_list = PRUNTIME_FUNCTION(target.get_ptr() + exception_directory->VirtualAddress); + const auto entry_count = ULONG(exception_directory->Size / sizeof(RUNTIME_FUNCTION)); + + if (!RtlAddFunctionTable(function_list, entry_count, DWORD64(target.get_ptr()))) + { + MessageBoxA(nullptr, "Setting exception handlers failed.", "Error", MB_OK | MB_ICONERROR); + } + + { + const utils::nt::library ntdll("ntdll.dll"); + + auto* const table_list_head = ntdll.invoke_pascal("RtlGetFunctionTableListHead"); + auto* table_list_entry = table_list_head->Flink; + + while (table_list_entry != table_list_head) + { + auto* const function_table = CONTAINING_RECORD(table_list_entry, DYNAMIC_FUNCTION_TABLE, Links); + + if (function_table->BaseAddress == ULONG_PTR(target.get_handle())) + { + function_table->EntryCount = entry_count; + function_table->FunctionTable = function_list; + } + + table_list_entry = function_table->Links.Flink; + } + } + + seh::setup_handler(target.get_ptr(), target.get_ptr() + source.get_optional_header()->SizeOfImage, function_list, + entry_count); +} + +void loader::load_tls(const utils::nt::library& target, const utils::nt::library& source) const +{ + if (source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) + { + auto* target_tls = tls::allocate_tls_index(); + /* target_tls = reinterpret_cast(library.get_ptr() + library.get_optional_header() + ->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); */ + auto* const source_tls = reinterpret_cast(target.get_ptr() + source.get_optional_header() + ->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + + const auto tls_size = source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData; + const auto tls_index = *reinterpret_cast(target_tls->AddressOfIndex); + utils::hook::set(source_tls->AddressOfIndex, tls_index); + + DWORD old_protect; + VirtualProtect(PVOID(target_tls->StartAddressOfRawData), + source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData, PAGE_READWRITE, + &old_protect); + + auto* const tls_base = *reinterpret_cast(__readgsqword(0x58) + 8ull * tls_index); + std::memmove(tls_base, PVOID(source_tls->StartAddressOfRawData), tls_size); + std::memmove(PVOID(target_tls->StartAddressOfRawData), PVOID(source_tls->StartAddressOfRawData), tls_size); + + VirtualProtect(target_tls, sizeof(*target_tls), PAGE_READWRITE, &old_protect); + *target_tls = *source_tls; + } +} diff --git a/src/client/loader/loader.hpp b/src/client/loader/loader.hpp new file mode 100644 index 00000000..2c5d86f9 --- /dev/null +++ b/src/client/loader/loader.hpp @@ -0,0 +1,21 @@ +#pragma once +#include + +class loader final +{ +public: + FARPROC load(const utils::nt::library& library, const std::string& buffer) const; + FARPROC load_library(const std::string& filename) const; + + void set_import_resolver(const std::function& resolver); + +private: + std::function import_resolver_; + + static void load_section(const utils::nt::library& target, const utils::nt::library& source, + IMAGE_SECTION_HEADER* section); + void load_sections(const utils::nt::library& target, const utils::nt::library& source) const; + void load_imports(const utils::nt::library& target, const utils::nt::library& source) const; + void load_exception_table(const utils::nt::library& target, const utils::nt::library& source) const; + void load_tls(const utils::nt::library& target, const utils::nt::library& source) const; +}; diff --git a/src/client/loader/seh.cpp b/src/client/loader/seh.cpp new file mode 100644 index 00000000..a3364a8f --- /dev/null +++ b/src/client/loader/seh.cpp @@ -0,0 +1,151 @@ +#include + +#include +#include + +#include "seh.hpp" + +namespace seh +{ + namespace + { + void*(*rtlpx_lookup_function_table)(void*, FUNCTION_TABLE_DATA*); + void*(*rtlpx_lookup_function_table_down_level)(void*, PDWORD64, PULONG); + + FUNCTION_TABLE_DATA overridden_table; + + DWORD64 override_end; + DWORD64 override_start; + + void* find_call_from_address(void* method_ptr, ud_mnemonic_code mnemonic = UD_Icall) + { + ud_t ud; + ud_init(&ud); + ud_set_mode(&ud, 64); + ud_set_pc(&ud, reinterpret_cast(method_ptr)); + ud_set_input_buffer(&ud, static_cast(method_ptr), INT32_MAX); + + void* retval = nullptr; + while (true) + { + ud_disassemble(&ud); + + if (ud_insn_mnemonic(&ud) == UD_Iint3) break; + if (ud_insn_mnemonic(&ud) == mnemonic) + { + const auto* const operand = ud_insn_opr(&ud, 0); + if (operand->type == UD_OP_JIMM) + { + if (!retval) retval = reinterpret_cast(ud_insn_len(&ud) + ud_insn_off(&ud) + operand-> + lval.sdword); + else + { + retval = nullptr; + break; + } + } + } + } + + return retval; + } + + void* rtlpx_lookup_function_table_override(void* exception_address, FUNCTION_TABLE_DATA* out_data) + { + ZeroMemory(out_data, sizeof(*out_data)); + + auto* retval = seh::rtlpx_lookup_function_table(exception_address, out_data); + + const auto address_num = DWORD64(exception_address); + if (address_num >= seh::override_start && address_num <= seh::override_end) + { + if (address_num != 0) + { + *out_data = seh::overridden_table; + retval = PVOID(seh::overridden_table.TableAddress); + } + } + + return retval; + } + + void* rtlpx_lookup_function_table_override_down_level(void* exception_address, const PDWORD64 image_base, + const PULONG length) + { + auto* retval = seh::rtlpx_lookup_function_table_down_level(exception_address, image_base, length); + + const auto address_num = DWORD64(exception_address); + if (address_num >= seh::override_start && address_num <= seh::override_end) + { + if (address_num != 0) + { + *image_base = seh::overridden_table.ImageBase; + *length = seh::overridden_table.Size; + + retval = PVOID(seh::overridden_table.TableAddress); + } + } + + return retval; + } + } + + void setup_handler(void* module_base, void* module_end, PRUNTIME_FUNCTION runtime_functions, const DWORD entryCount) + { + const utils::nt::library ntdll("ntdll.dll"); + + seh::override_start = DWORD64(module_base); + seh::override_end = DWORD64(module_end); + + seh::overridden_table.ImageBase = seh::override_start; + seh::overridden_table.TableAddress = DWORD64(runtime_functions); + seh::overridden_table.Size = entryCount * sizeof(RUNTIME_FUNCTION); + + if (IsWindows8Point1OrGreater()) + { + struct + { + DWORD64 field0; + DWORD imageSize; + DWORD fieldC; + DWORD64 field10; + } query_result = {0, 0, 0, 0}; + + ntdll.invoke_pascal("NtQueryVirtualMemory", GetCurrentProcess(), module_base, 6, &query_result, + sizeof(query_result), nullptr); + seh::overridden_table.ImageSize = query_result.imageSize; + } + + auto* base_address = ntdll.get_proc("RtlLookupFunctionTable"); + auto* internal_address = find_call_from_address(base_address); + + void* patch_function = rtlpx_lookup_function_table_override; + auto** patch_original = reinterpret_cast(&seh::rtlpx_lookup_function_table); + + if (!internal_address) + { + if (!IsWindows8Point1OrGreater()) + { + internal_address = find_call_from_address(base_address, UD_Ijmp); + patch_function = rtlpx_lookup_function_table_override_down_level; + patch_original = reinterpret_cast(&seh::rtlpx_lookup_function_table_down_level); + } + + if (!internal_address) + { + if (IsWindows8OrGreater()) + { + // TODO: Catch the error + } + + internal_address = base_address; + patch_function = rtlpx_lookup_function_table_override_down_level; + patch_original = reinterpret_cast(&seh::rtlpx_lookup_function_table_down_level); + } + } + + static utils::hook::detour hook{}; + hook = utils::hook::detour(internal_address, patch_function); + *patch_original = hook.get_original(); + } +} diff --git a/src/client/loader/seh.hpp b/src/client/loader/seh.hpp new file mode 100644 index 00000000..232dca47 --- /dev/null +++ b/src/client/loader/seh.hpp @@ -0,0 +1,38 @@ +#pragma once + +struct FUNCTION_TABLE_DATA +{ + DWORD64 TableAddress; + DWORD64 ImageBase; + DWORD ImageSize; // field +8 in ZwQueryVirtualMemory class 6 + DWORD Size; +}; + +typedef enum _FUNCTION_TABLE_TYPE +{ + RF_SORTED, + RF_UNSORTED, + RF_CALLBACK +} FUNCTION_TABLE_TYPE; + +typedef struct _DYNAMIC_FUNCTION_TABLE +{ + LIST_ENTRY Links; + PRUNTIME_FUNCTION FunctionTable; + LARGE_INTEGER TimeStamp; + + ULONG_PTR MinimumAddress; + ULONG_PTR MaximumAddress; + ULONG_PTR BaseAddress; + + PGET_RUNTIME_FUNCTION_CALLBACK Callback; + PVOID Context; + PWSTR OutOfProcessCallbackDll; + FUNCTION_TABLE_TYPE Type; + ULONG EntryCount; +} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE; + +namespace seh +{ + void setup_handler(void* module_base, void* module_end, PRUNTIME_FUNCTION runtime_functions, DWORD entryCount); +} diff --git a/src/client/loader/tls.cpp b/src/client/loader/tls.cpp new file mode 100644 index 00000000..61195e16 --- /dev/null +++ b/src/client/loader/tls.cpp @@ -0,0 +1,34 @@ +#include +#include "tls.hpp" + +#include +#include + +namespace tls +{ + namespace + { + utils::binary_resource tls_dll_file(TLS_DLL, "s1x-tlsdll.dll"); + } + + PIMAGE_TLS_DIRECTORY allocate_tls_index() + { + static auto already_allocated = false; + if (already_allocated) + { + throw std::runtime_error("Currently only a single allocation is supported!"); + } + + already_allocated = true; + + const auto dll_path = tls_dll_file.get_extracted_file(); + const auto tls_dll = utils::nt::library::load(dll_path); + if (!tls_dll) + { + throw std::runtime_error("Failed to load TLS DLL"); + } + + return reinterpret_cast(tls_dll.get_ptr() + tls_dll.get_optional_header() + ->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + } +} diff --git a/src/client/loader/tls.hpp b/src/client/loader/tls.hpp new file mode 100644 index 00000000..1b7c68d2 --- /dev/null +++ b/src/client/loader/tls.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace tls +{ + PIMAGE_TLS_DIRECTORY allocate_tls_index(); +} diff --git a/src/client/main.cpp b/src/client/main.cpp new file mode 100644 index 00000000..07d6ad8a --- /dev/null +++ b/src/client/main.cpp @@ -0,0 +1,224 @@ +#include +#include "launcher/launcher.hpp" +#include "loader/loader.hpp" +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include +#include + +DECLSPEC_NORETURN void WINAPI exit_hook(const int code) +{ + component_loader::pre_destroy(); + exit(code); +} + + +BOOL WINAPI system_parameters_info_a(const UINT uiAction, const UINT uiParam, const PVOID pvParam, const UINT fWinIni) +{ + component_loader::post_unpack(); + return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni); +} + +FARPROC WINAPI get_proc_address(const HMODULE hModule, const LPCSTR lpProcName) +{ + if (lpProcName == "GlobalMemoryStatusEx"s) + { + component_loader::post_unpack(); + } + + return GetProcAddress(hModule, lpProcName); +} + +launcher::mode detect_mode_from_arguments() +{ + if (utils::flags::has_flag("dedicated")) + { + return launcher::mode::server; + } + + if (utils::flags::has_flag("multiplayer")) + { + return launcher::mode::multiplayer; + } + + if (utils::flags::has_flag("singleplayer")) + { + return launcher::mode::singleplayer; + } + + return launcher::mode::none; +} + + +FARPROC load_binary(const launcher::mode mode) +{ + loader loader; + utils::nt::library self; + + loader.set_import_resolver([self](const std::string& library, const std::string& function) -> void* + { + if (library == "steam_api64.dll") + { + return self.get_proc(function); + } + else if (function == "ExitProcess") + { + return exit_hook; + } + else if (function == "SystemParametersInfoA") + { + return system_parameters_info_a; + } + else if (function == "GetProcAddress") + { + return get_proc_address; + } + + return component_loader::load_import(library, function); + }); + + std::string binary; + switch (mode) + { + case launcher::mode::server: + case launcher::mode::multiplayer: + binary = "h1_mp64_ship.exe"; + break; + case launcher::mode::singleplayer: + binary = "h1_sp64_ship.exe"; + break; + case launcher::mode::none: + default: + throw std::runtime_error("Invalid game mode!"); + } + + std::string data; + if (!utils::io::read_file(binary, &data)) + { + throw std::runtime_error(utils::string::va( + "Failed to read game binary (%s)!\nPlease copy the h1x.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", + binary.data())); + } + + return loader.load_library(binary); +} + +void remove_crash_file() +{ + utils::io::remove_file("__h1Exe"); +} + +void verify_mwr_version() +{ + const auto BuildNumMp = *reinterpret_cast(0x1403F6280); + const auto BuildNumSp = *reinterpret_cast(0x140335370); + + if (BuildNumMp != 814118 && BuildNumSp != 814118) + { + throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version"s); + } +} + +void enable_dpi_awareness() +{ + const utils::nt::library user32{"user32.dll"}; + const auto set_dpi = user32 + ? user32.get_proc("SetProcessDpiAwarenessContext") + : nullptr; + if (set_dpi) + { + set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + } +} + +void limit_parallel_dll_loading() +{ + const utils::nt::library self; + const auto registry_path = R"(Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)" + self. + get_name(); + + HKEY key = nullptr; + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, registry_path.data(), &key) == ERROR_SUCCESS) + { + RegCloseKey(key); + } + + key = nullptr; + if (RegOpenKeyExA( + HKEY_LOCAL_MACHINE, registry_path.data(), 0, + KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) + { + return; + } + + DWORD value = 1; + RegSetValueExA(key, "MaxLoaderThreads", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + + RegCloseKey(key); +} + +int main() +{ + FARPROC entry_point; + enable_dpi_awareness(); + + // This requires admin privilege, but I suppose many + // people will start with admin rights if it crashes. + limit_parallel_dll_loading(); + + srand(uint32_t(time(nullptr))); + + { + auto premature_shutdown = true; + const auto _ = gsl::finally([&premature_shutdown]() + { + if (premature_shutdown) + { + component_loader::pre_destroy(); + } + }); + + try + { + remove_crash_file(); + + if (!component_loader::post_start()) return 0; + + auto mode = detect_mode_from_arguments(); + if (mode == launcher::mode::none) + { + const launcher launcher; + mode = launcher.run(); + if (mode == launcher::mode::none) return 0; + } + + game::environment::set_mode(mode); + + entry_point = load_binary(mode); + if (!entry_point) + { + throw std::runtime_error("Unable to load binary into memory"); + } + + if (!component_loader::post_load()) return 0; + + verify_mwr_version(); + + premature_shutdown = false; + } + catch (std::exception& e) + { + MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); + return 1; + } + } + + return static_cast(entry_point()); +} + +int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int) +{ + return main(); +} diff --git a/src/client/proto/auth.proto b/src/client/proto/auth.proto new file mode 100644 index 00000000..2c77e4f4 --- /dev/null +++ b/src/client/proto/auth.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package proto.network; + +message connect_info +{ + bytes infostring = 1; + bytes publickey = 2; + bytes signature = 3; +} diff --git a/src/client/resource.hpp b/src/client/resource.hpp new file mode 100644 index 00000000..c2ce9b6a --- /dev/null +++ b/src/client/resource.hpp @@ -0,0 +1,22 @@ +#pragma once + +#define ID_ICON 102 + +#define IMAGE_SPLASH 300 +#define IMAGE_LOGO 301 + +#define DW_ENTITLEMENT_CONFIG 302 +#define DW_SOCIAL_CONFIG 303 +#define DW_MM_CONFIG 304 +#define DW_LOOT_CONFIG 305 +#define DW_STORE_CONFIG 306 +#define DW_MOTD 307 +#define DW_FASTFILE 308 +#define DW_PLAYLISTS 309 + +#define MENU_MAIN 310 + +#define TLS_DLL 311 +#define RUNNER 312 + +#define ICON_IMAGE 313 diff --git a/src/client/resource.rc b/src/client/resource.rc new file mode 100644 index 00000000..62ba38f8 --- /dev/null +++ b/src/client/resource.rc @@ -0,0 +1,136 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" +#include "version.h" +#include "resource.hpp" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_FILE_RC + PRODUCTVERSION VERSION_PRODUCT_RC + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else +#ifdef PRERELEASE + FILEFLAGS VS_FF_PRERELEASE +#else +#ifndef CI + FILEFLAGS VS_FF_PRIVATEBUILD +#else + FILEFLAGS 0x0L +#endif +#endif +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "X Labs" + VALUE "FileDescription", "S1x" + VALUE "FileVersion", VERSION_FILE + VALUE "InternalName", "S1x" + VALUE "LegalCopyright", "Copyright (C) 2021 X Labs Project. All rights reserved." + VALUE "Licence", "GPLv3" + VALUE "Info", "https://github.com/XLabsProject/s1x-client" + VALUE "OriginalFilename", "s1x.exe" + VALUE "ProductName", "s1x" + VALUE "ProductVersion", VERSION_PRODUCT + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +ID_ICON ICON "resources/icon.ico" + +IMAGE_SPLASH BITMAP "resources/splash.bmp" +IMAGE_LOGO BITMAP "resources/logo.bmp" + +DW_STORE_CONFIG RCDATA "resources/dw/winStoreConfig_tu22.csv" +DW_FASTFILE RCDATA "resources/dw/ffotd-1.15.1.ff" +DW_MOTD RCDATA "resources/dw/motd-english.txt" +DW_PLAYLISTS RCDATA "resources/dw/playlists_tu12.aggr" + +MENU_MAIN RCDATA "resources/main.html" + +#ifdef _DEBUG +TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll" +#else +TLS_DLL RCDATA "../../build/bin/x64/Release/tlsdll.dll" +#endif + +#ifdef _DEBUG +RUNNER RCDATA "../../build/bin/x64/Debug/runner.exe" +#else +RUNNER RCDATA "../../build/bin/x64/Release/runner.exe" +#endif + +ICON_IMAGE RCDATA "resources/icon.png" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/client/resources/dw/ffotd-1.15.1.ff b/src/client/resources/dw/ffotd-1.15.1.ff new file mode 100644 index 00000000..3aaf5e7f Binary files /dev/null and b/src/client/resources/dw/ffotd-1.15.1.ff differ diff --git a/src/client/resources/dw/motd-english.txt b/src/client/resources/dw/motd-english.txt new file mode 100644 index 00000000..1ad6121b --- /dev/null +++ b/src/client/resources/dw/motd-english.txt @@ -0,0 +1 @@ +Welcome to H1-Mod. \ No newline at end of file diff --git a/src/client/resources/dw/playlists_tu12.aggr b/src/client/resources/dw/playlists_tu12.aggr new file mode 100644 index 00000000..4b7240a6 Binary files /dev/null and b/src/client/resources/dw/playlists_tu12.aggr differ diff --git a/src/client/resources/dw/winStoreConfig_tu22.csv b/src/client/resources/dw/winStoreConfig_tu22.csv new file mode 100644 index 00000000..4ccc8e11 --- /dev/null +++ b/src/client/resources/dw/winStoreConfig_tu22.csv @@ -0,0 +1,10 @@ +version,version_id,5,,,,,,,,,,, +product,product_1,134217732,store_codpoints_200,consumable,CODPOINTS,all,0,,,DEPOT_200_COD_POINTS,DEPOT_200_COD_POINTS_DESC_SHORT,DEPOT_200_COD_POINTS_DESC_LONG, +product,product_2,134217736,store_codpoints_1100,consumable,CODPOINTS,all,0,,,DEPOT_1100_COD_POINTS,DEPOT_1100_COD_POINTS_DESC_SHORT,DEPOT_1100_COD_POINTS_DESC_LONG, +product,product_3,134217740,store_codpoints_2400,consumable,CODPOINTS,all,0,,,DEPOT_2400_COD_POINTS,DEPOT_2400_COD_POINTS_DESC_SHORT,DEPOT_2400_COD_POINTS_DESC_LONG, +product,product_4,134217744,store_codpoints_5000,consumable,CODPOINTS,all,0,,,DEPOT_5000_COD_POINTS,DEPOT_5000_COD_POINTS_DESC_SHORT,DEPOT_5000_COD_POINTS_DESC_LONG, +product,product_5,134217748,store_codpoints_9500,consumable,CODPOINTS,all,0,,,DEPOT_9500_COD_POINTS,DEPOT_9500_COD_POINTS_DESC_SHORT,DEPOT_9500_COD_POINTS_DESC_LONG, +product,product_6,134217752,store_codpoints_13000,consumable,CODPOINTS,all,0,,,DEPOT_13000_COD_POINTS,DEPOT_13000_COD_POINTS_DESC_SHORT,DEPOT_13000_COD_POINTS_DESC_LONG, +product,product_7,594970,store_mappack1,mappack1,MAPPACKS,all,0,,,DEPOT_MAP_PACK_1,DEPOT_MAP_PACK_1_DESC_SHORT,DEPOT_MAP_PACK_1_DESC_LONG, +category,category_1,1,CODPOINTS,DEPOT_COD_POINTS,all,0,,,,,,, +category,category_2,2,MAPPACKS,DEPOT_STORE_MAP_PACKS,all,0,,,,,,, diff --git a/src/client/resources/icon.ico b/src/client/resources/icon.ico new file mode 100644 index 00000000..b6c8943d Binary files /dev/null and b/src/client/resources/icon.ico differ diff --git a/src/client/resources/icon.png b/src/client/resources/icon.png new file mode 100644 index 00000000..c7f4980a Binary files /dev/null and b/src/client/resources/icon.png differ diff --git a/src/client/resources/logo.bmp b/src/client/resources/logo.bmp new file mode 100644 index 00000000..c8054d21 Binary files /dev/null and b/src/client/resources/logo.bmp differ diff --git a/src/client/resources/main.html b/src/client/resources/main.html new file mode 100644 index 00000000..7c77e8f6 --- /dev/null +++ b/src/client/resources/main.html @@ -0,0 +1,531 @@ + + + + + + + H1-Mod + + + + + + +
+
+ + + + +
+
+ + + + + diff --git a/src/client/resources/splash.bmp b/src/client/resources/splash.bmp new file mode 100644 index 00000000..f19b71b0 Binary files /dev/null and b/src/client/resources/splash.bmp differ diff --git a/src/client/std_include.cpp b/src/client/std_include.cpp new file mode 100644 index 00000000..efe6cd64 --- /dev/null +++ b/src/client/std_include.cpp @@ -0,0 +1,32 @@ +#include + +#pragma comment(linker, "/base:0x160000000") + +extern "C" +{ + __declspec(dllexport) DWORD NvOptimusEnablement = 1; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +}; + +extern "C" +{ + int s_read_arc4random(void*, size_t) + { + return -1; + } + + int s_read_getrandom(void*, size_t) + { + return -1; + } + + int s_read_urandom(void*, size_t) + { + return -1; + } + + int s_read_ltm_rng(void*, size_t) + { + return -1; + } +} diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp new file mode 100644 index 00000000..a0d25e91 --- /dev/null +++ b/src/client/std_include.hpp @@ -0,0 +1,102 @@ +#pragma once + +#define BINARY_PAYLOAD_SIZE 0x12000000 + +#pragma warning(push) +#pragma warning(disable: 4100) +#pragma warning(disable: 4127) +#pragma warning(disable: 4244) +#pragma warning(disable: 4458) +#pragma warning(disable: 4702) +#pragma warning(disable: 4996) +#pragma warning(disable: 5054) +#pragma warning(disable: 6011) +#pragma warning(disable: 6297) +#pragma warning(disable: 6385) +#pragma warning(disable: 6386) +#pragma warning(disable: 6387) +#pragma warning(disable: 26110) +#pragma warning(disable: 26451) +#pragma warning(disable: 26444) +#pragma warning(disable: 26451) +#pragma warning(disable: 26489) +#pragma warning(disable: 26495) +#pragma warning(disable: 26498) +#pragma warning(disable: 26812) +#pragma warning(disable: 28020) + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#pragma warning(pop) +#pragma warning(disable: 4100) + +#pragma comment(lib, "ntdll.lib") +#pragma comment(lib, "ws2_32.lib") +#pragma comment(lib, "urlmon.lib" ) +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "Crypt32.lib") + +#include "resource.hpp" + +using namespace std::literals; diff --git a/src/client/steam/interface.cpp b/src/client/steam/interface.cpp new file mode 100644 index 00000000..75ca922a --- /dev/null +++ b/src/client/steam/interface.cpp @@ -0,0 +1,98 @@ +#include +#include "interface.hpp" + +#include +#include + +namespace steam +{ + interface::interface() : interface(nullptr) + { + } + + interface::interface(void* interface_ptr) : interface_ptr_(static_cast(interface_ptr)) + { + } + + interface::operator bool() const + { + return this->interface_ptr_ != nullptr; + } + + void* interface::find_method(const std::string& name) + { + const auto method_entry = this->methods_.find(name); + if (method_entry != this->methods_.end()) + { + return method_entry->second; + } + + return this->search_method(name); + } + + void* interface::search_method(const std::string& name) + { + if (!utils::memory::is_bad_read_ptr(this->interface_ptr_)) + { + auto vftbl = *this->interface_ptr_; + + while (!utils::memory::is_bad_read_ptr(vftbl) && !utils::memory::is_bad_code_ptr(*vftbl)) + { + const auto ptr = *vftbl; + const auto result = this->analyze_method(ptr); + if (!result.empty()) + { + this->methods_[result] = ptr; + + if (result == name) + { + return ptr; + } + } + + ++vftbl; + } + } + + return {}; + } + + std::string interface::analyze_method(const void* method_ptr) + { + if (utils::memory::is_bad_code_ptr(method_ptr)) return {}; + + ud_t ud; + ud_init(&ud); + ud_set_mode(&ud, 64); + ud_set_pc(&ud, uint64_t(method_ptr)); + ud_set_input_buffer(&ud, static_cast(method_ptr), INT32_MAX); + + while (true) + { + ud_disassemble(&ud); + + if (ud_insn_mnemonic(&ud) == UD_Iret) + { + break; + } + + if (ud_insn_mnemonic(&ud) == UD_Ilea) + { + const auto* operand = ud_insn_opr(&ud, 1); + if (operand && operand->type == UD_OP_MEM && operand->base == UD_R_RIP) + { + auto* operand_ptr = reinterpret_cast(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->lval. + sdword); + if (!utils::memory::is_bad_read_ptr(operand_ptr) && utils::memory::is_rdata_ptr(operand_ptr)) + { + return operand_ptr; + } + } + } + + if (*reinterpret_cast(ud.pc) == 0xCC) break; // int 3 + } + + return {}; + } +} diff --git a/src/client/steam/interface.hpp b/src/client/steam/interface.hpp new file mode 100644 index 00000000..c118c80e --- /dev/null +++ b/src/client/steam/interface.hpp @@ -0,0 +1,85 @@ +#pragma once + +#ifdef interface +#undef interface +#endif + +namespace steam +{ + struct raw_steam_id final + { + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; + }; + + typedef union + { + raw_steam_id raw; + unsigned long long bits; + } steam_id; + +#pragma pack( push, 1 ) + struct raw_game_id final + { + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; + }; + + typedef union + { + raw_game_id raw; + unsigned long long bits; + } game_id; +#pragma pack( pop ) + + class interface final + { + public: + + interface(); + interface(void* interface_ptr); + + operator bool() const; + + template + T invoke(const std::string& method_name, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + const auto method = this->find_method(method_name); + if (!method) + { + throw std::runtime_error("Unable to find method: " + method_name); + } + + return static_cast(method)(this->interface_ptr_, args...); + } + + template + T invoke(const size_t table_entry, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + return static_cast((*this->interface_ptr_)[table_entry])( + this->interface_ptr_, args...); + } + + private: + void*** interface_ptr_; + std::unordered_map methods_; + + void* find_method(const std::string& name); + void* search_method(const std::string& name); + + std::string analyze_method(const void* method_ptr); + }; +} diff --git a/src/client/steam/interfaces/apps.cpp b/src/client/steam/interfaces/apps.cpp new file mode 100644 index 00000000..44350e5e --- /dev/null +++ b/src/client/steam/interfaces/apps.cpp @@ -0,0 +1,104 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool apps::BIsSubscribed() + { + return true; + } + + bool apps::BIsLowViolence() + { + return false; + } + + bool apps::BIsCybercafe() + { + return false; + } + + bool apps::BIsVACBanned() + { + return false; + } + + const char* apps::GetCurrentGameLanguage() + { + return "english"; + } + + const char* apps::GetAvailableGameLanguages() + { + return "english"; + } + + bool apps::BIsSubscribedApp(unsigned int appID) + { + return true; + } + + bool apps::BIsDlcInstalled(unsigned int appID) + { + return true; + } + + unsigned int apps::GetEarliestPurchaseUnixTime(unsigned int nAppID) + { + return 0; + } + + bool apps::BIsSubscribedFromFreeWeekend() + { + return false; + } + + int apps::GetDLCCount() + { + return 0; + } + + bool apps::BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize) + { + return false; + } + + void apps::InstallDLC(unsigned int nAppID) + { + } + + void apps::UninstallDLC(unsigned int nAppID) + { + } + + void apps::RequestAppProofOfPurchaseKey(unsigned int nAppID) + { + } + + bool apps::GetCurrentBetaName(char* pchName, int cchNameBufferSize) + { + strncpy_s(pchName, cchNameBufferSize, "public", cchNameBufferSize); + return true; + } + + bool apps::MarkContentCorrupt(bool bMissingFilesOnly) + { + return false; + } + + unsigned int apps::GetInstalledDepots(int* pvecDepots, unsigned int cMaxDepots) + { + return 0; + } + + unsigned int apps::GetAppInstallDir(unsigned int appID, char* pchFolder, unsigned int cchFolderBufferSize) + { + return 0; + } + + bool apps::BIsAppInstalled(unsigned int appID) + { + return false; + } +} \ No newline at end of file diff --git a/src/client/steam/interfaces/apps.hpp b/src/client/steam/interfaces/apps.hpp new file mode 100644 index 00000000..07298080 --- /dev/null +++ b/src/client/steam/interfaces/apps.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace steam +{ + class apps + { + public: + ~apps() = default; + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char* GetCurrentGameLanguage(); + virtual const char* GetAvailableGameLanguages(); + virtual bool BIsSubscribedApp(unsigned int appID); + virtual bool BIsDlcInstalled(unsigned int appID); + virtual unsigned int GetEarliestPurchaseUnixTime(unsigned int nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize); + virtual void InstallDLC(unsigned int nAppID); + virtual void UninstallDLC(unsigned int nAppID); + virtual void RequestAppProofOfPurchaseKey(unsigned int nAppID); + virtual bool GetCurrentBetaName(char* pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual unsigned int GetInstalledDepots(int* pvecDepots, unsigned int cMaxDepots); + virtual unsigned int GetAppInstallDir(unsigned int appID, char* pchFolder, unsigned int cchFolderBufferSize); + virtual bool BIsAppInstalled(unsigned int appID); + }; +} diff --git a/src/client/steam/interfaces/friends.cpp b/src/client/steam/interfaces/friends.cpp new file mode 100644 index 00000000..5f3d5ab5 --- /dev/null +++ b/src/client/steam/interfaces/friends.cpp @@ -0,0 +1,313 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + const char* friends::GetPersonaName() + { + return "1337"; + } + + unsigned long long friends::SetPersonaName(const char* pchPersonaName) + { + return 0; + } + + int friends::GetPersonaState() + { + return 1; + } + + int friends::GetFriendCount(int eFriendFlags) + { + return 0; + } + + steam_id friends::GetFriendByIndex(int iFriend, int iFriendFlags) + { + return steam_id(); + } + + int friends::GetFriendRelationship(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetFriendPersonaState(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendPersonaName(steam_id steamIDFriend) + { + return ""; + } + + bool friends::GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo) + { + return false; + } + + const char* friends::GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName) + { + return ""; + } + + bool friends::HasFriend(steam_id steamIDFriend, int eFriendFlags) + { + return false; + } + + int friends::GetClanCount() + { + return 0; + } + + steam_id friends::GetClanByIndex(int iClan) + { + return steam_id(); + } + + const char* friends::GetClanName(steam_id steamIDClan) + { + return "3arc"; + } + + const char* friends::GetClanTag(steam_id steamIDClan) + { + return this->GetClanName(steamIDClan); + } + + bool friends::GetClanActivityCounts(steam_id steamID, int* pnOnline, int* pnInGame, int* pnChatting) + { + return false; + } + + unsigned long long friends::DownloadClanActivityCounts(steam_id groupIDs[], int nIds) + { + return 0; + } + + int friends::GetFriendCountFromSource(steam_id steamIDSource) + { + return 0; + } + + steam_id friends::GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend) + { + return steam_id(); + } + + bool friends::IsUserInSource(steam_id steamIDUser, steam_id steamIDSource) + { + return false; + } + + void friends::SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking) + { + } + + void friends::ActivateGameOverlay(const char* pchDialog) + { + } + + void friends::ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID) + { + } + + void friends::ActivateGameOverlayToWebPage(const char* pchURL) + { + } + + void friends::ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag) + { + } + + void friends::SetPlayedWith(steam_id steamIDUserPlayedWith) + { + } + + void friends::ActivateGameOverlayInviteDialog(steam_id steamIDLobby) + { + } + + int friends::GetSmallFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetMediumFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetLargeFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + bool friends::RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly) + { + return false; + } + + unsigned long long friends::RequestClanOfficerList(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOwner(steam_id steamIDClan) + { + return steam_id(); + } + + int friends::GetClanOfficerCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer) + { + return steam_id(); + } + + int friends::GetUserRestrictions() + { + return 0; + } + + bool friends::SetRichPresence(const char* pchKey, const char* pchValue) + { + return true; + } + + void friends::ClearRichPresence() + { + } + + const char* friends::GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey) + { + return ""; + } + + int friends::GetFriendRichPresenceKeyCount(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey) + { + return "a"; + } + + void friends::RequestFriendRichPresence(steam_id steamIDFriend) + { + } + + bool friends::InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString) + { + return false; + } + + int friends::GetCoplayFriendCount() + { + return 0; + } + + steam_id friends::GetCoplayFriend(int iCoplayFriend) + { + return steam_id(); + } + + int friends::GetFriendCoplayTime(steam_id steamIDFriend) + { + return 0; + } + + unsigned int friends::GetFriendCoplayGame(steam_id steamIDFriend) + { + return 0; + } + + unsigned long long friends::JoinClanChatRoom(steam_id steamIDClan) + { + return 0; + } + + bool friends::LeaveClanChatRoom(steam_id steamIDClan) + { + return false; + } + + int friends::GetClanChatMemberCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetChatMemberByIndex(steam_id steamIDClan, int iUser) + { + return steam_id(); + } + + bool friends::SendClanChatMessage(steam_id steamIDClanChat, const char* pchText) + { + return false; + } + + int friends::GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void* prgchText, int cchTextMax, + unsigned int* peChatEntryType, steam_id* pSteamIDChatter) + { + return 0; + } + + bool friends::IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser) + { + return false; + } + + bool friends::IsClanChatWindowOpenInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::OpenClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::CloseClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::SetListenForFriendsMessages(bool bInterceptEnabled) + { + return false; + } + + bool friends::ReplyToFriendMessage(steam_id steamIDFriend, const char* pchMsgToSend) + { + return false; + } + + int friends::GetFriendMessage(steam_id steamIDFriend, int iMessageID, void* pvData, int cubData, + unsigned int* peChatEntryType) + { + return 0; + } + + unsigned long long friends::GetFollowerCount(steam_id steamID) + { + return 0; + } + + unsigned long long friends::IsFollowing(steam_id steamID) + { + return 0; + } + + unsigned long long friends::EnumerateFollowingList(unsigned int unStartIndex) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/friends.hpp b/src/client/steam/interfaces/friends.hpp new file mode 100644 index 00000000..f7cb2a2e --- /dev/null +++ b/src/client/steam/interfaces/friends.hpp @@ -0,0 +1,76 @@ +#pragma once + +namespace steam +{ + class friends + { + public: + ~friends() = default; + + virtual const char* GetPersonaName(); + virtual unsigned long long SetPersonaName(const char* pchPersonaName); + virtual int GetPersonaState(); + virtual int GetFriendCount(int eFriendFlags); + virtual steam_id GetFriendByIndex(int iFriend, int iFriendFlags); + virtual int GetFriendRelationship(steam_id steamIDFriend); + virtual int GetFriendPersonaState(steam_id steamIDFriend); + virtual const char* GetFriendPersonaName(steam_id steamIDFriend); + virtual bool GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo); + virtual const char* GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName); + virtual bool HasFriend(steam_id steamIDFriend, int eFriendFlags); + virtual int GetClanCount(); + virtual steam_id GetClanByIndex(int iClan); + virtual const char* GetClanName(steam_id steamIDClan); + virtual const char* GetClanTag(steam_id steamIDClan); + virtual bool GetClanActivityCounts(steam_id steamID, int* pnOnline, int* pnInGame, int* pnChatting); + virtual unsigned long long DownloadClanActivityCounts(steam_id groupIDs[], int nIds); + virtual int GetFriendCountFromSource(steam_id steamIDSource); + virtual steam_id GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend); + virtual bool IsUserInSource(steam_id steamIDUser, steam_id steamIDSource); + virtual void SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking); + virtual void ActivateGameOverlay(const char* pchDialog); + virtual void ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID); + virtual void ActivateGameOverlayToWebPage(const char* pchURL); + virtual void ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag); + virtual void SetPlayedWith(steam_id steamIDUserPlayedWith); + virtual void ActivateGameOverlayInviteDialog(steam_id steamIDLobby); + virtual int GetSmallFriendAvatar(steam_id steamIDFriend); + virtual int GetMediumFriendAvatar(steam_id steamIDFriend); + virtual int GetLargeFriendAvatar(steam_id steamIDFriend); + virtual bool RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly); + virtual unsigned long long RequestClanOfficerList(steam_id steamIDClan); + virtual steam_id GetClanOwner(steam_id steamIDClan); + virtual int GetClanOfficerCount(steam_id steamIDClan); + virtual steam_id GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer); + virtual int GetUserRestrictions(); + virtual bool SetRichPresence(const char* pchKey, const char* pchValue); + virtual void ClearRichPresence(); + virtual const char* GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey); + virtual int GetFriendRichPresenceKeyCount(steam_id steamIDFriend); + virtual const char* GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey); + virtual void RequestFriendRichPresence(steam_id steamIDFriend); + virtual bool InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString); + virtual int GetCoplayFriendCount(); + virtual steam_id GetCoplayFriend(int iCoplayFriend); + virtual int GetFriendCoplayTime(steam_id steamIDFriend); + virtual unsigned int GetFriendCoplayGame(steam_id steamIDFriend); + virtual unsigned long long JoinClanChatRoom(steam_id steamIDClan); + virtual bool LeaveClanChatRoom(steam_id steamIDClan); + virtual int GetClanChatMemberCount(steam_id steamIDClan); + virtual steam_id GetChatMemberByIndex(steam_id steamIDClan, int iUser); + virtual bool SendClanChatMessage(steam_id steamIDClanChat, const char* pchText); + virtual int GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void* prgchText, int cchTextMax, + unsigned int* peChatEntryType, steam_id* pSteamIDChatter); + virtual bool IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser); + virtual bool IsClanChatWindowOpenInSteam(steam_id steamIDClanChat); + virtual bool OpenClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool CloseClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool SetListenForFriendsMessages(bool bInterceptEnabled); + virtual bool ReplyToFriendMessage(steam_id steamIDFriend, const char* pchMsgToSend); + virtual int GetFriendMessage(steam_id steamIDFriend, int iMessageID, void* pvData, int cubData, + unsigned int* peChatEntryType); + virtual unsigned long long GetFollowerCount(steam_id steamID); + virtual unsigned long long IsFollowing(steam_id steamID); + virtual unsigned long long EnumerateFollowingList(unsigned int unStartIndex); + }; +} diff --git a/src/client/steam/interfaces/game_server.cpp b/src/client/steam/interfaces/game_server.cpp new file mode 100644 index 00000000..11e7a79d --- /dev/null +++ b/src/client/steam/interfaces/game_server.cpp @@ -0,0 +1,204 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool game_server::InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, + unsigned int unServerFlags, unsigned int nAppID, const char* pchVersion) + { + return true; + } + + void game_server::SetProduct(const char* pchProductName) + { + } + + void game_server::SetGameDescription(const char* pchGameDescription) + { + } + + void game_server::SetModDir(const char* pchModDir) + { + } + + void game_server::SetDedicatedServer(bool bDedicatedServer) + { + } + + void game_server::LogOn(const char* pszAccountName, const char* pszPassword) + { + } + + void game_server::LogOnAnonymous() + { + auto* const retvals = calloc(1, 1); + const auto result = callbacks::register_call(); + callbacks::return_call(retvals, 0, 101, result); + } + + void game_server::LogOff() + { + } + + bool game_server::BLoggedOn() + { + return true; + } + + bool game_server::BSecure() + { + return false; + } + + steam_id game_server::GetSteamID() + { + return SteamUser()->GetSteamID(); + } + + bool game_server::WasRestartRequested() + { + return false; + } + + void game_server::SetMaxPlayerCount(int cPlayersMax) + { + } + + void game_server::SetBotPlayerCount(int cBotPlayers) + { + } + + void game_server::SetServerName(const char* pszServerName) + { + } + + void game_server::SetMapName(const char* pszMapName) + { + } + + void game_server::SetPasswordProtected(bool bPasswordProtected) + { + } + + void game_server::SetSpectatorPort(unsigned short unSpectatorPort) + { + } + + void game_server::SetSpectatorServerName(const char* pszSpectatorServerName) + { + } + + void game_server::ClearAllKeyValues() + { + } + + void game_server::SetKeyValue(const char* pKey, const char* pValue) + { + } + + void game_server::SetGameTags(const char* pchGameTags) + { + } + + void game_server::SetGameData(const char* pchGameData) + { + } + + void game_server::SetRegion(const char* pchRegionName) + { + } + + int game_server::SendUserConnectAndAuthenticate(unsigned int unIPClient, const void* pvAuthBlob, + unsigned int cubAuthBlobSize, steam_id* pSteamIDUser) + { + return 0; + } + + steam_id game_server::CreateUnauthenticatedUserConnection() + { + return SteamUser()->GetSteamID(); + } + + void game_server::SendUserDisconnect(steam_id steamIDUser) + { + } + + bool game_server::BUpdateUserData(steam_id steamIDUser, const char* pchPlayerName, unsigned int uScore) + { + return false; + } + + int game_server::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + return 0; + } + + int game_server::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void game_server::EndAuthSession(steam_id steamID) + { + } + + void game_server::CancelAuthTicket(int hAuthTicket) + { + } + + int game_server::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool game_server::RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup) + { + return false; + } + + void game_server::GetGameplayStats() + { + } + + unsigned long long game_server::GetServerReputation() + { + return 0; + } + + unsigned int game_server::GetPublicIP() + { + return 0; + } + + bool game_server::HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort) + { + return false; + } + + int game_server::GetNextOutgoingPacket(void* pOut, int cbMaxOut, unsigned int* pNetAdr, unsigned short* pPort) + { + return 0; + } + + void game_server::EnableHeartbeats(bool bActive) + { + } + + void game_server::SetHeartbeatInterval(int iHeartbeatInterval) + { + } + + void game_server::ForceHeartbeat() + { + } + + unsigned long long game_server::AssociateWithClan(steam_id clanID) + { + return 0; + } + + unsigned long long game_server::ComputeNewPlayerCompatibility(steam_id steamID) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/game_server.hpp b/src/client/steam/interfaces/game_server.hpp new file mode 100644 index 00000000..3f7f7c71 --- /dev/null +++ b/src/client/steam/interfaces/game_server.hpp @@ -0,0 +1,57 @@ +#pragma once + +namespace steam +{ + class game_server + { + public: + ~game_server() = default; + + virtual bool InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, + unsigned int unServerFlags, unsigned int nAppID, const char* pchVersion); + virtual void SetProduct(const char* pchProductName); + virtual void SetGameDescription(const char* pchGameDescription); + virtual void SetModDir(const char* pchModDir); + virtual void SetDedicatedServer(bool bDedicatedServer); + virtual void LogOn(const char* pszAccountName, const char* pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual steam_id GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotPlayers); + virtual void SetServerName(const char* pszServerName); + virtual void SetMapName(const char* pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(unsigned short unSpectatorPort); + virtual void SetSpectatorServerName(const char* pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char* pKey, const char* pValue); + virtual void SetGameTags(const char* pchGameTags); + virtual void SetGameData(const char* pchGameData); + virtual void SetRegion(const char* pchRegionName); + virtual int SendUserConnectAndAuthenticate(unsigned int unIPClient, const void* pvAuthBlob, + unsigned int cubAuthBlobSize, steam_id* pSteamIDUser); + virtual steam_id CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(steam_id steamIDUser); + virtual bool BUpdateUserData(steam_id steamIDUser, const char* pchPlayerName, unsigned int uScore); + virtual int GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + virtual int BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(int hAuthTicket); + virtual int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup); + virtual void GetGameplayStats(); + virtual unsigned long long GetServerReputation(); + virtual unsigned int GetPublicIP(); + virtual bool HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort); + virtual int GetNextOutgoingPacket(void* pOut, int cbMaxOut, unsigned int* pNetAdr, unsigned short* pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual unsigned long long AssociateWithClan(steam_id clanID); + virtual unsigned long long ComputeNewPlayerCompatibility(steam_id steamID); + }; +} diff --git a/src/client/steam/interfaces/matchmaking.cpp b/src/client/steam/interfaces/matchmaking.cpp new file mode 100644 index 00000000..8b8dec7b --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.cpp @@ -0,0 +1,230 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + int matchmaking::GetFavoriteGameCount() + { + return 0; + } + + bool matchmaking::GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer) + { + return false; + } + + int matchmaking::AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer) + { + return 0; + } + + bool matchmaking::RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags) + { + return false; + } + + unsigned long long matchmaking::RequestLobbyList() + { + return 0; + } + + void matchmaking::AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo) + { + } + + void matchmaking::AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable) + { + } + + void matchmaking::AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter) + { + } + + void matchmaking::AddRequestLobbyListResultCountFilter(int cMaxResults) + { + } + + void matchmaking::AddRequestLobbyListCompatibleMembersFilter(steam_id steamID) + { + } + + steam_id matchmaking::GetLobbyByIndex(int iLobby) + { + steam_id id; + + id.raw.account_id = SteamUser()->GetSteamID().raw.account_id; + id.raw.universe = 1; + id.raw.account_type = 8; + id.raw.account_instance = 0x40000; + + return id; + } + + unsigned long long matchmaking::CreateLobby(int eLobbyType, int cMaxMembers) + { + const auto result = callbacks::register_call(); + auto retvals = static_cast(calloc(1, sizeof(lobby_created))); + //::Utils::Memory::AllocateArray(); + steam_id id; + + id.raw.account_id = SteamUser()->GetSteamID().raw.account_id; + id.raw.universe = 1; + id.raw.account_type = 8; + id.raw.account_instance = 0x40000; + + retvals->m_e_result = 1; + retvals->m_ul_steam_id_lobby = id; + + callbacks::return_call(retvals, sizeof(lobby_created), lobby_created::callback_id, result); + + matchmaking::JoinLobby(id); + + return result; + } + + unsigned long long matchmaking::JoinLobby(steam_id steamIDLobby) + { + const auto result = callbacks::register_call(); + auto* retvals = static_cast(calloc(1, sizeof(lobby_enter))); + //::Utils::Memory::AllocateArray(); + retvals->m_b_locked = false; + retvals->m_e_chat_room_enter_response = 1; + retvals->m_rgf_chat_permissions = 0xFFFFFFFF; + retvals->m_ul_steam_id_lobby = steamIDLobby; + + callbacks::return_call(retvals, sizeof(lobby_enter), lobby_enter::callback_id, result); + + return result; + } + + void matchmaking::LeaveLobby(steam_id steamIDLobby) + { + } + + bool matchmaking::InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee) + { + return true; + } + + int matchmaking::GetNumLobbyMembers(steam_id steamIDLobby) + { + return 1; + } + + steam_id matchmaking::GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember) + { + return SteamUser()->GetSteamID(); + } + + const char* matchmaking::GetLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return ""; + } + + bool matchmaking::SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + return true; + } + + int matchmaking::GetLobbyDataCount(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize) + { + return true; + } + + bool matchmaking::DeleteLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return true; + } + + const char* matchmaking::GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey) + { + return ""; + } + + void matchmaking::SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + } + + bool matchmaking::SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody) + { + return true; + } + + int matchmaking::GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType) + { + return 0; + } + + bool matchmaking::RequestLobbyData(steam_id steamIDLobby) + { + return true; + } + + void matchmaking::SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer) + { + } + + bool matchmaking::GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer) + { + return true; + } + + bool matchmaking::SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers) + { + return true; + } + + int matchmaking::GetLobbyMemberLimit(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::SetLobbyType(steam_id steamIDLobby, int eLobbyType) + { + return true; + } + + bool matchmaking::SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable) + { + return true; + } + + steam_id matchmaking::GetLobbyOwner(steam_id steamIDLobby) + { + return SteamUser()->GetSteamID(); + } + + bool matchmaking::SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner) + { + return true; + } + + bool matchmaking::SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2) + { + return true; + } +} diff --git a/src/client/steam/interfaces/matchmaking.hpp b/src/client/steam/interfaces/matchmaking.hpp new file mode 100644 index 00000000..88923212 --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace steam +{ + struct lobby_created final + { + enum { callback_id = 513 }; + + int m_e_result; + int m_pad; + steam_id m_ul_steam_id_lobby; + }; + + struct lobby_enter final + { + enum { callback_id = 504 }; + + steam_id m_ul_steam_id_lobby; + int m_rgf_chat_permissions; + bool m_b_locked; + int m_e_chat_room_enter_response; + }; + + class matchmaking + { + public: + ~matchmaking() = default; + + virtual int GetFavoriteGameCount(); + virtual bool GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer); + virtual int AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer); + virtual bool RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags); + virtual unsigned long long RequestLobbyList(); + virtual void AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo); + virtual void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable); + virtual void AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter); + virtual void AddRequestLobbyListResultCountFilter(int cMaxResults); + virtual void AddRequestLobbyListCompatibleMembersFilter(steam_id steamID); + virtual steam_id GetLobbyByIndex(int iLobby); + virtual unsigned long long CreateLobby(int eLobbyType, int cMaxMembers); + virtual unsigned long long JoinLobby(steam_id steamIDLobby); + virtual void LeaveLobby(steam_id steamIDLobby); + virtual bool InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee); + virtual int GetNumLobbyMembers(steam_id steamIDLobby); + virtual steam_id GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember); + virtual const char* GetLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual bool SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual int GetLobbyDataCount(steam_id steamIDLobby); + virtual bool GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize); + virtual bool DeleteLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual const char* GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey); + virtual void SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual bool SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody); + virtual int GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType); + virtual bool RequestLobbyData(steam_id steamIDLobby); + virtual void SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer); + virtual bool GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer); + virtual bool SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers); + virtual int GetLobbyMemberLimit(steam_id steamIDLobby); + virtual bool SetLobbyType(steam_id steamIDLobby, int eLobbyType); + virtual bool SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable); + virtual steam_id GetLobbyOwner(steam_id steamIDLobby); + virtual bool SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner); + virtual bool SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2); + }; +} diff --git a/src/client/steam/interfaces/networking.cpp b/src/client/steam/interfaces/networking.cpp new file mode 100644 index 00000000..d0ee6e0e --- /dev/null +++ b/src/client/steam/interfaces/networking.cpp @@ -0,0 +1,121 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool networking::SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType) + { + return false; + } + + bool networking::IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk) + { + return false; + } + + bool networking::ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote) + { + return false; + } + + bool networking::AcceptP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort) + { + return false; + } + + bool networking::GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState) + { + return false; + } + + bool networking::AllowP2PPacketRelay(bool bAllow) + { + return false; + } + + unsigned int networking::CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec) + { + return NULL; + } + + bool networking::DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable) + { + return false; + } + + bool networking::IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote) + { + return false; + } + + bool networking::GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort) + { + return false; + } + + int networking::GetSocketConnectionType(unsigned int hSocket) + { + return 0; + } + + int networking::GetMaxPacketSize(unsigned int hSocket) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/networking.hpp b/src/client/steam/interfaces/networking.hpp new file mode 100644 index 00000000..bb1b29dd --- /dev/null +++ b/src/client/steam/interfaces/networking.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace steam +{ + class networking + { + public: + ~networking() = default; + + virtual bool SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType); + virtual bool IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk); + virtual bool ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote); + virtual bool AcceptP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort); + virtual bool GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState); + virtual bool AllowP2PPacketRelay(bool bAllow); + virtual unsigned int CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec); + virtual bool DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable); + virtual bool IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize); + virtual bool RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize); + virtual bool IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote); + virtual bool GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort); + virtual int GetSocketConnectionType(unsigned int hSocket); + virtual int GetMaxPacketSize(unsigned int hSocket); + }; +} diff --git a/src/client/steam/interfaces/remote_storage.cpp b/src/client/steam/interfaces/remote_storage.cpp new file mode 100644 index 00000000..02bc968f --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.cpp @@ -0,0 +1,283 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool remote_storage::FileWrite(const char* pchFile, const void* pvData, int cubData) + { + return true; + } + + int remote_storage::FileRead(const char* pchFile, void* pvData, int cubDataToRead) + { + return 0; + } + + bool remote_storage::FileForget(const char* pchFile) + { + return true; + } + + bool remote_storage::FileDelete(const char* pchFile) + { + return true; + } + + unsigned long long remote_storage::FileShare(const char* pchFile) + { + return 0; + } + + bool remote_storage::SetSyncPlatforms(const char* pchFile, unsigned int eRemoteStoragePlatform) + { + return true; + } + + unsigned long long remote_storage::FileWriteStreamOpen(const char* pchFile) + { + return 0; + } + + int remote_storage::FileWriteStreamWriteChunk(unsigned long long hStream, const void* pvData, int cubData) + { + return 1; + } + + int remote_storage::FileWriteStreamClose(unsigned long long hStream) + { + return 1; + } + + int remote_storage::FileWriteStreamCancel(unsigned long long hStream) + { + return 1; + } + + bool remote_storage::FileExists(const char* pchFile) + { + return true; + } + + bool remote_storage::FilePersisted(const char* pchFile) + { + return true; + } + + int remote_storage::GetFileSize(const char* pchFile) + { + return 0; + } + + long long remote_storage::GetFileTimestamp(const char* pchFile) + { + return 0; + } + + unsigned remote_storage::GetSyncPlatforms(const char* pchFile) + { + return 0; + } + + int remote_storage::GetFileCount() + { + return 0; + } + + const char* remote_storage::GetFileNameAndSize(int iFile, int* pnFileSizeInBytes) + { + *pnFileSizeInBytes = 0; + return ""; + } + + bool remote_storage::GetQuota(int* pnTotalBytes, int* puAvailableBytes) + { + *pnTotalBytes = 0x10000000; + *puAvailableBytes = 0x10000000; + return false; + } + + bool remote_storage::IsCloudEnabledForAccount() + { + return false; + } + + bool remote_storage::IsCloudEnabledForApp() + { + return false; + } + + void remote_storage::SetCloudEnabledForApp(bool bEnabled) + { + } + + unsigned long long remote_storage::UGCDownload(unsigned long long hContent, unsigned int uUnk) + { + return 0; + } + + bool remote_storage::GetUGCDownloadProgress(unsigned long long hContent, unsigned int* puDownloadedBytes, + unsigned int* puTotalBytes) + { + return false; + } + + bool remote_storage::GetUGCDetails(unsigned long long hContent, unsigned int* pnAppID, char** ppchName, + int* pnFileSizeInBytes, steam_id* pSteamIDOwner) + { + return false; + } + + int remote_storage::UGCRead(unsigned long long hContent, void* pvData, int cubDataToRead, unsigned int uOffset) + { + return 0; + } + + int remote_storage::GetCachedUGCCount() + { + return 0; + } + + unsigned long long remote_storage::GetCachedUGCHandle(int iCachedContent) + { + return 0; + } + + unsigned long long remote_storage::PublishWorkshopFile(const char* pchFile, const char* pchPreviewFile, + unsigned int nConsumerAppId, const char* pchTitle, + const char* pchDescription, unsigned int eVisibility, + int* pTags, unsigned int eWorkshopFileType) + { + return 0; + } + + unsigned long long remote_storage::CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char* pchFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char* pchPreviewFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char* pchTitle) + { + return false; + } + + bool remote_storage::UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char* pchDescription) + { + return false; + } + + bool remote_storage::UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTags(unsigned long long hUpdateRequest, int* pTags) + { + return false; + } + + unsigned long long remote_storage::CommitPublishedFileUpdate(unsigned long long hUpdateRequest) + { + return 0; + } + + unsigned long long remote_storage::GetPublishedFileDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::DeletePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserPublishedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::SubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSubscribedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::UnsubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, + const char* cszDescription) + { + return false; + } + + unsigned long long remote_storage::GetPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp) + { + return 0; + } + + unsigned long long remote_storage::GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, + unsigned int uStartIndex, int* pRequiredTags, + int* pExcludedTags) + { + return 0; + } + + unsigned long long remote_storage::PublishVideo(unsigned int eVideoProvider, const char* cszVideoAccountName, + const char* cszVideoIdentifier, const char* cszFileName, + unsigned int nConsumerAppId, const char* cszTitle, + const char* cszDescription, unsigned int eVisibility, int* pTags) + { + return 0; + } + + unsigned long long remote_storage::SetUserPublishedFileAction(unsigned long long unPublishedFileId, + unsigned int eAction) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedFilesByUserAction( + unsigned int eAction, unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, + unsigned int cDays, unsigned int cCount, + int* pTags, int* pUserTags) + { + return 0; + } + + unsigned long long remote_storage::UGCDownloadToLocation(unsigned long long hContent, const char* cszLocation, + unsigned int uUnk) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/remote_storage.hpp b/src/client/steam/interfaces/remote_storage.hpp new file mode 100644 index 00000000..ec0d64ea --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.hpp @@ -0,0 +1,78 @@ +#pragma once + +namespace steam +{ + class remote_storage + { + public: + ~remote_storage() = default; + + virtual bool FileWrite(const char* pchFile, const void* pvData, int cubData); + virtual int FileRead(const char* pchFile, void* pvData, int cubDataToRead); + virtual bool FileForget(const char* pchFile); + virtual bool FileDelete(const char* pchFile); + virtual unsigned long long FileShare(const char* pchFile); + virtual bool SetSyncPlatforms(const char* pchFile, unsigned int eRemoteStoragePlatform); + virtual unsigned long long FileWriteStreamOpen(const char* pchFile); + virtual int FileWriteStreamWriteChunk(unsigned long long hStream, const void* pvData, int cubData); + virtual int FileWriteStreamClose(unsigned long long hStream); + virtual int FileWriteStreamCancel(unsigned long long hStream); + virtual bool FileExists(const char* pchFile); + virtual bool FilePersisted(const char* pchFile); + virtual int GetFileSize(const char* pchFile); + virtual long long GetFileTimestamp(const char* pchFile); + virtual unsigned int GetSyncPlatforms(const char* pchFile); + virtual int GetFileCount(); + virtual const char* GetFileNameAndSize(int iFile, int* pnFileSizeInBytes); + virtual bool GetQuota(int* pnTotalBytes, int* puAvailableBytes); + virtual bool IsCloudEnabledForAccount(); + virtual bool IsCloudEnabledForApp(); + virtual void SetCloudEnabledForApp(bool bEnabled); + virtual unsigned long long UGCDownload(unsigned long long hContent, unsigned int uUnk); + virtual bool GetUGCDownloadProgress(unsigned long long hContent, unsigned int* puDownloadedBytes, + unsigned int* puTotalBytes); + virtual bool GetUGCDetails(unsigned long long hContent, unsigned int* pnAppID, char** ppchName, + int* pnFileSizeInBytes, steam_id* pSteamIDOwner); + virtual int UGCRead(unsigned long long hContent, void* pvData, int cubDataToRead, unsigned int uOffset); + virtual int GetCachedUGCCount(); + virtual unsigned long long GetCachedUGCHandle(int iCachedContent); + virtual unsigned long long PublishWorkshopFile(const char* pchFile, const char* pchPreviewFile, + unsigned int nConsumerAppId, const char* pchTitle, + const char* pchDescription, unsigned int eVisibility, int* pTags, + unsigned int eWorkshopFileType); + virtual unsigned long long CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char* pchFile); + virtual bool UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char* pchPreviewFile); + virtual bool UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char* pchTitle); + virtual bool UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char* pchDescription); + virtual bool UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility); + virtual bool UpdatePublishedFileTags(unsigned long long hUpdateRequest, int* pTags); + virtual unsigned long long CommitPublishedFileUpdate(unsigned long long hUpdateRequest); + virtual unsigned long long GetPublishedFileDetails(unsigned long long unPublishedFileId); + virtual unsigned long long DeletePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserPublishedFiles(unsigned int uStartIndex); + virtual unsigned long long SubscribePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSubscribedFiles(unsigned int uStartIndex); + virtual unsigned long long UnsubscribePublishedFile(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, + const char* cszDescription); + virtual unsigned long long GetPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp); + virtual unsigned long long GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, + unsigned int uStartIndex, int* pRequiredTags, + int* pExcludedTags); + virtual unsigned long long PublishVideo(unsigned int eVideoProvider, const char* cszVideoAccountName, + const char* cszVideoIdentifier, const char* cszFileName, + unsigned int nConsumerAppId, const char* cszTitle, + const char* cszDescription, unsigned int eVisibility, int* pTags); + virtual unsigned long long SetUserPublishedFileAction(unsigned long long unPublishedFileId, + unsigned int eAction); + virtual unsigned long long EnumeratePublishedFilesByUserAction(unsigned int eAction, unsigned int uStartIndex); + virtual unsigned long long EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, + unsigned int cDays, unsigned int cCount, int* pTags, + int* pUserTags); + virtual unsigned long long UGCDownloadToLocation(unsigned long long hContent, const char* cszLocation, + unsigned int uUnk); + }; +} diff --git a/src/client/steam/interfaces/user.cpp b/src/client/steam/interfaces/user.cpp new file mode 100644 index 00000000..752007ba --- /dev/null +++ b/src/client/steam/interfaces/user.cpp @@ -0,0 +1,164 @@ +#include +#include "../steam.hpp" + +#include "component/auth.hpp" + +namespace steam +{ + namespace + { + std::string auth_ticket; + + steam_id generate_steam_id() + { + steam_id id{}; + id.bits = auth::get_guid(); + return id; + } + } + + int user::GetHSteamUser() + { + return NULL; + } + + bool user::LoggedOn() + { + return true; + } + + steam_id user::GetSteamID() + { + static auto id = generate_steam_id(); + return id; + } + + int user::InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure) + { + return 0; + } + + void user::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer) + { + } + + void user::TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo) + { + } + + bool user::GetUserDataFolder(char* pchBuffer, int cubBuffer) + { + return false; + } + + void user::StartVoiceRecording() + { + } + + void user::StopVoiceRecording() + { + } + + int user::GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten) + { + return 0; + } + + unsigned int user::GetVoiceOptimalSampleRate() + { + return 0; + } + + unsigned int user::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + static uint32_t ticket = 0; + *pcbTicket = 1; + + const auto result = callbacks::register_call(); + auto* response = static_cast(calloc( + 1, sizeof(get_auth_session_ticket_response))); + response->m_h_auth_ticket = ++ticket; + response->m_e_result = 1; // k_EResultOK; + + callbacks::return_call(response, sizeof(get_auth_session_ticket_response), + get_auth_session_ticket_response::callback_id, result); + return response->m_h_auth_ticket; + } + + int user::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void user::EndAuthSession(steam_id steamID) + { + } + + void user::CancelAuthTicket(unsigned int hAuthTicket) + { + } + + unsigned int user::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool user::BIsBehindNAT() + { + return false; + } + + void user::AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer) + { + } + + unsigned long long user::RequestEncryptedAppTicket(void* pUserData, int cbUserData) + { + const auto id = this->GetSteamID(); + + auth_ticket = "S1"; + auth_ticket.resize(32); + auth_ticket.append(static_cast(pUserData), 24); // key + auth_ticket.append(reinterpret_cast(&id.bits), sizeof(id.bits)); // user id + auth_ticket.append(&static_cast(pUserData)[24], 64); // user name + + // Create the call response + const auto result = callbacks::register_call(); + const auto retvals = static_cast(calloc(1, sizeof(encrypted_app_ticket_response))); + //::Utils::Memory::AllocateArray(); + retvals->m_e_result = 1; + + // Return the call response + callbacks::return_call(retvals, sizeof(encrypted_app_ticket_response), + encrypted_app_ticket_response::callback_id, result); + + return result; + } + + bool user::GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + if (cbMaxTicket < 0 || auth_ticket.empty()) return false; + + const auto size = std::min(size_t(cbMaxTicket), auth_ticket.size()); + std::memcpy(pTicket, auth_ticket.data(), size); + *pcbTicket = static_cast(size); + + return true; + } +} diff --git a/src/client/steam/interfaces/user.hpp b/src/client/steam/interfaces/user.hpp new file mode 100644 index 00000000..07cd8018 --- /dev/null +++ b/src/client/steam/interfaces/user.hpp @@ -0,0 +1,55 @@ +#pragma once + +namespace steam +{ + struct encrypted_app_ticket_response final + { + enum { callback_id = 154 }; + + int m_e_result; + }; + + struct get_auth_session_ticket_response + { + enum { callback_id = 163 }; + + unsigned int m_h_auth_ticket; + int m_e_result; + }; + + class user + { + public: + ~user() = default; + + virtual int GetHSteamUser(); + virtual bool LoggedOn(); + virtual steam_id GetSteamID(); + + virtual int InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure); + virtual void TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer); + virtual void TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo = ""); + virtual bool GetUserDataFolder(char* pchBuffer, int cubBuffer); + virtual void StartVoiceRecording(); + virtual void StopVoiceRecording(); + virtual int GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten); + virtual unsigned int GetVoiceOptimalSampleRate(); + virtual unsigned int GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + virtual int BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(unsigned int hAuthTicket); + virtual unsigned int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool BIsBehindNAT(); + virtual void AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer); + virtual unsigned long long RequestEncryptedAppTicket(void* pUserData, int cbUserData); + virtual bool GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + }; +} diff --git a/src/client/steam/interfaces/user_stats.cpp b/src/client/steam/interfaces/user_stats.cpp new file mode 100644 index 00000000..13d4ccc0 --- /dev/null +++ b/src/client/steam/interfaces/user_stats.cpp @@ -0,0 +1,231 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool user_stats::RequestCurrentStats() + { + return true; + } + + bool user_stats::GetStat(const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetStat(const char* pchName, float* pData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, int nData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, float fData) + { + return false; + } + + bool user_stats::UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength) + { + return false; + } + + bool user_stats::GetAchievement(const char* pchName, bool* pbAchieved) + { + return true; + } + + bool user_stats::SetAchievement(const char* pchName) + { + return true; + } + + bool user_stats::ClearAchievement(const char* pchName) + { + return true; + } + + bool user_stats::GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime) + { + return true; + } + + bool user_stats::StoreStats() + { + return true; + } + + int user_stats::GetAchievementIcon(const char* pchName) + { + return 0; + } + + const char* user_stats::GetAchievementDisplayAttribute(const char* pchName, const char* pchKey) + { + return ""; + } + + bool user_stats::IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress) + { + return true; + } + + unsigned int user_stats::GetNumAchievements() + { + return 0; + } + + const char* user_stats::GetAchievementName(unsigned int iAchievement) + { + return ""; + } + + unsigned long long user_stats::RequestUserStats(steam_id steamIDUser) + { + return 0; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, float* pData) + { + return false; + } + + bool user_stats::GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved) + { + return true; + } + + bool user_stats::GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime) + { + return true; + } + + bool user_stats::ResetAllStats(bool bAchievementsToo) + { + return false; + } + + unsigned long long user_stats::FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType) + { + return 0; + } + + unsigned long long user_stats::FindLeaderboard(const char* pchLeaderboardName) + { + return 0; + } + + const char* user_stats::GetLeaderboardName(unsigned long long hSteamLeaderboard) + { + return ""; + } + + int user_stats::GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, + int nRangeEnd) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers) + { + return 0; + } + + bool user_stats::GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax) + { + return false; + } + + unsigned long long user_stats::UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount) + { + return 0; + } + + unsigned long long user_stats::AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC) + { + return 0; + } + + unsigned long long user_stats::GetNumberOfCurrentPlayers() + { + return 0; + } + + unsigned long long user_stats::RequestGlobalAchievementPercentages() + { + return 0; + } + + int user_stats::GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved) + { + return 0; + } + + int user_stats::GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved) + { + return 0; + } + + bool user_stats::GetAchievementAchievedPercent(const char* pchName, float* pflPercent) + { + return true; + } + + unsigned long long user_stats::RequestGlobalStats(int nHistoryDays) + { + return 0; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, long long* pData) + { + return false; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, double* pData) + { + return false; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData) + { + return 0; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/user_stats.hpp b/src/client/steam/interfaces/user_stats.hpp new file mode 100644 index 00000000..c49c79d4 --- /dev/null +++ b/src/client/steam/interfaces/user_stats.hpp @@ -0,0 +1,65 @@ +#pragma once + +namespace steam +{ + class user_stats + { + public: + ~user_stats() = default; + + virtual bool RequestCurrentStats(); + virtual bool GetStat(const char* pchName, int* pData); + virtual bool GetStat(const char* pchName, float* pData); + virtual bool SetStat(const char* pchName, int nData); + virtual bool SetStat(const char* pchName, float fData); + virtual bool UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength); + virtual bool GetAchievement(const char* pchName, bool* pbAchieved); + virtual bool SetAchievement(const char* pchName); + virtual bool ClearAchievement(const char* pchName); + virtual bool GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime); + virtual bool StoreStats(); + virtual int GetAchievementIcon(const char* pchName); + virtual const char* GetAchievementDisplayAttribute(const char* pchName, const char* pchKey); + virtual bool IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress); + virtual unsigned int GetNumAchievements(); + virtual const char* GetAchievementName(unsigned int iAchievement); + virtual unsigned long long RequestUserStats(steam_id steamIDUser); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, int* pData); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, float* pData); + virtual bool GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved); + virtual bool GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime); + virtual bool ResetAllStats(bool bAchievementsToo); + virtual unsigned long long FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType); + virtual unsigned long long FindLeaderboard(const char* pchLeaderboardName); + virtual const char* GetLeaderboardName(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard); + virtual unsigned long long DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, + int nRangeEnd); + virtual unsigned long long DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers); + virtual bool GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax); + virtual unsigned long long UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount); + virtual unsigned long long AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC); + virtual unsigned long long GetNumberOfCurrentPlayers(); + virtual unsigned long long RequestGlobalAchievementPercentages(); + virtual int GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved); + virtual int GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved); + virtual bool GetAchievementAchievedPercent(const char* pchName, float* pflPercent); + virtual unsigned long long RequestGlobalStats(int nHistoryDays); + virtual bool GetGlobalStat(const char* pchStatName, long long* pData); + virtual bool GetGlobalStat(const char* pchStatName, double* pData); + virtual int GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData); + virtual int GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData); + }; +} diff --git a/src/client/steam/interfaces/utils.cpp b/src/client/steam/interfaces/utils.cpp new file mode 100644 index 00000000..95f923aa --- /dev/null +++ b/src/client/steam/interfaces/utils.cpp @@ -0,0 +1,123 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + unsigned int utils::GetSecondsSinceAppActive() + { + return 0; + } + + unsigned int utils::GetSecondsSinceComputerActive() + { + return (uint32_t)GetTickCount64() / 1000; + } + + int utils::GetConnectedUniverse() + { + return 1; + } + + unsigned int utils::GetServerRealTime() + { + return (uint32_t)time(NULL); + } + + const char* utils::GetIPCountry() + { + return "US"; + } + + bool utils::GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight) + { + return false; + } + + bool utils::GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize) + { + return false; + } + + bool utils::GetCSERIPPort(unsigned int* unIP, unsigned short* usPort) + { + return false; + } + + unsigned char utils::GetCurrentBatteryPower() + { + return 255; + } + + unsigned int utils::GetAppID() + { + return 209660; + } + + void utils::SetOverlayNotificationPosition(int eNotificationPosition) + { + //const auto& overlay = steam_proxy::get_overlay_module(); + //if (overlay) + //{ + // overlay.invoke("SetNotificationPosition", eNotificationPosition); + //} + } + + bool utils::IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed) + { + return false; + } + + int utils::GetAPICallFailureReason(unsigned long long hSteamAPICall) + { + return -1; + } + + bool utils::GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed) + { + return false; + } + + void utils::RunFrame() + { + } + + unsigned int utils::GetIPCCallCount() + { + return 0; + } + + void utils::SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)) + { + } + + bool utils::IsOverlayEnabled() + { + return false; + } + + bool utils::BOverlayNeedsPresent() + { + return false; + } + + unsigned long long utils::CheckFileSignature(const char* szFileName) + { + return 0; + } + + bool utils::ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char* szText, unsigned int uMaxLength) + { + return false; + } + + unsigned int utils::GetEnteredGamepadTextLength() + { + return 0; + } + + bool utils::GetEnteredGamepadTextInput(char* pchValue, unsigned int cchValueMax) + { + return false; + } +} diff --git a/src/client/steam/interfaces/utils.hpp b/src/client/steam/interfaces/utils.hpp new file mode 100644 index 00000000..d42a27f9 --- /dev/null +++ b/src/client/steam/interfaces/utils.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace steam +{ + class utils + { + public: + ~utils() = default; + + virtual unsigned int GetSecondsSinceAppActive(); + virtual unsigned int GetSecondsSinceComputerActive(); + virtual int GetConnectedUniverse(); + virtual unsigned int GetServerRealTime(); + virtual const char* GetIPCountry(); + virtual bool GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight); + virtual bool GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize); + virtual bool GetCSERIPPort(unsigned int* unIP, unsigned short* usPort); + virtual unsigned char GetCurrentBatteryPower(); + virtual unsigned int GetAppID(); + virtual void SetOverlayNotificationPosition(int eNotificationPosition); + virtual bool IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed); + virtual int GetAPICallFailureReason(unsigned long long hSteamAPICall); + virtual bool GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed); + virtual void RunFrame(); + virtual unsigned int GetIPCCallCount(); + virtual void SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)); + virtual bool IsOverlayEnabled(); + virtual bool BOverlayNeedsPresent(); + virtual unsigned long long CheckFileSignature(const char* szFileName); + + virtual bool ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char* szText, + unsigned int uMaxLength); + virtual unsigned int GetEnteredGamepadTextLength(); + virtual bool GetEnteredGamepadTextInput(char* pchValue, unsigned int cchValueMax); + }; +} diff --git a/src/client/steam/steam.cpp b/src/client/steam/steam.cpp new file mode 100644 index 00000000..b6fb0dbe --- /dev/null +++ b/src/client/steam/steam.cpp @@ -0,0 +1,238 @@ +#include +#include "steam.hpp" + +namespace steam +{ + uint64_t callbacks::call_id_ = 0; + std::recursive_mutex callbacks::mutex_; + std::map callbacks::calls_; + std::map callbacks::result_handlers_; + std::vector callbacks::results_; + std::vector callbacks::callback_list_; + + uint64_t callbacks::register_call() + { + std::lock_guard _(mutex_); + calls_[++call_id_] = false; + return call_id_; + } + + void callbacks::register_callback(base* handler, const int callback) + { + std::lock_guard _(mutex_); + handler->set_i_callback(callback); + callback_list_.push_back(handler); + } + + void callbacks::unregister_callback(base* handler) + { + std::lock_guard _(mutex_); + for (auto i = callback_list_.begin(); i != callback_list_.end();) + { + if (*i == handler) + { + i = callback_list_.erase(i); + } + else + { + ++i; + } + } + } + + void callbacks::register_call_result(const uint64_t call, base* result) + { + std::lock_guard _(mutex_); + result_handlers_[call] = result; + } + + void callbacks::unregister_call_result(const uint64_t call, base* /*result*/) + { + std::lock_guard _(mutex_); + const auto i = result_handlers_.find(call); + if (i != result_handlers_.end()) + { + result_handlers_.erase(i); + } + } + + void callbacks::return_call(void* data, const int size, const int type, const uint64_t call) + { + std::lock_guard _(mutex_); + + result result{}; + result.call = call; + result.data = data; + result.size = size; + result.type = type; + + calls_[call] = true; + + results_.emplace_back(result); + } + + void callbacks::run_callbacks() + { + std::lock_guard _(mutex_); + + for (const auto& result : results_) + { + if (result_handlers_.find(result.call) != result_handlers_.end()) + { + result_handlers_[result.call]->run(result.data, false, result.call); + } + + for (const auto& callback : callback_list_) + { + if (callback && callback->get_i_callback() == result.type) + { + callback->run(result.data, false, 0); + } + } + + if (result.data) + { + free(result.data); + } + } + + results_.clear(); + } + + extern "C" { + + bool SteamAPI_RestartAppIfNecessary() + { + return false; + } + + bool SteamAPI_Init() + { + return true; + } + + void SteamAPI_RegisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::register_call_result(call, result); + } + + void SteamAPI_RegisterCallback(callbacks::base* handler, const int callback) + { + callbacks::register_callback(handler, callback); + } + + void SteamAPI_RunCallbacks() + { + callbacks::run_callbacks(); + } + + void SteamAPI_Shutdown() + { + } + + void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::unregister_call_result(call, result); + } + + void SteamAPI_UnregisterCallback(callbacks::base* handler) + { + callbacks::unregister_callback(handler); + } + + const char* SteamAPI_GetSteamInstallPath() + { + static std::string install_path{}; + if (!install_path.empty()) + { + return install_path.data(); + } + + HKEY reg_key; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\WOW6432Node\\Valve\\Steam", 0, KEY_QUERY_VALUE, + ®_key) == + ERROR_SUCCESS) + { + char path[MAX_PATH] = {0}; + DWORD length = sizeof(path); + RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), + &length); + RegCloseKey(reg_key); + + install_path = path; + } + + return install_path.data(); + } + + + bool SteamGameServer_Init() + { + return true; + } + + void SteamGameServer_RunCallbacks() + { + } + + void SteamGameServer_Shutdown() + { + } + + + friends* SteamFriends() + { + static friends friends; + return &friends; + } + + matchmaking* SteamMatchmaking() + { + static matchmaking matchmaking; + return &matchmaking; + } + + game_server* SteamGameServer() + { + static game_server game_server; + return &game_server; + } + + networking* SteamNetworking() + { + static networking networking; + return &networking; + } + + remote_storage* SteamRemoteStorage() + { + static remote_storage remote_storage; + return &remote_storage; + } + + user* SteamUser() + { + static user user; + return &user; + } + + utils* SteamUtils() + { + static utils utils; + return &utils; + } + + apps* SteamApps() + { + static apps apps; + return &apps; + } + + user_stats* SteamUserStats() + { + static user_stats user_stats; + return &user_stats; + } + + } +} diff --git a/src/client/steam/steam.hpp b/src/client/steam/steam.hpp new file mode 100644 index 00000000..3018921f --- /dev/null +++ b/src/client/steam/steam.hpp @@ -0,0 +1,121 @@ +#pragma once + +#define STEAM_EXPORT extern "C" __declspec(dllexport) + +struct raw_steam_id final +{ + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; +}; + +typedef union +{ + raw_steam_id raw; + unsigned long long bits; +} steam_id; + +#pragma pack( push, 1 ) +struct raw_game_id final +{ + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; +}; + +typedef union +{ + raw_game_id raw; + unsigned long long bits; +} game_id; +#pragma pack( pop ) + +#include "interfaces/apps.hpp" +#include "interfaces/user.hpp" +#include "interfaces/utils.hpp" +#include "interfaces/friends.hpp" +#include "interfaces/user_stats.hpp" +#include "interfaces/game_server.hpp" +#include "interfaces/networking.hpp" +#include "interfaces/matchmaking.hpp" +#include "interfaces/remote_storage.hpp" + +namespace steam +{ + class callbacks + { + public: + class base + { + public: + base() : flags_(0), callback_(0) + { + } + + virtual void run(void* pv_param) = 0; + virtual void run(void* pv_param, bool failure, uint64_t handle) = 0; + virtual int get_callback_size_bytes() = 0; + + int get_i_callback() const { return callback_; } + void set_i_callback(const int i_callback) { callback_ = i_callback; } + + protected: + ~base() = default; + + unsigned char flags_; + int callback_; + }; + + struct result final + { + void* data{}; + int size{}; + int type{}; + uint64_t call{}; + }; + + static uint64_t register_call(); + + static void register_callback(base* handler, int callback); + static void unregister_callback(base* handler); + + static void register_call_result(uint64_t call, base* result); + static void unregister_call_result(uint64_t call, base* result); + + static void return_call(void* data, int size, int type, uint64_t call); + static void run_callbacks(); + + private: + static uint64_t call_id_; + static std::recursive_mutex mutex_; + static std::map calls_; + static std::map result_handlers_; + static std::vector results_; + static std::vector callback_list_; + }; + + STEAM_EXPORT bool SteamAPI_RestartAppIfNecessary(); + STEAM_EXPORT bool SteamAPI_Init(); + STEAM_EXPORT void SteamAPI_RegisterCallResult(callbacks::base* result, uint64_t call); + STEAM_EXPORT void SteamAPI_RegisterCallback(callbacks::base* handler, int callback); + STEAM_EXPORT void SteamAPI_RunCallbacks(); + STEAM_EXPORT void SteamAPI_Shutdown(); + STEAM_EXPORT void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call); + STEAM_EXPORT void SteamAPI_UnregisterCallback(callbacks::base* handler); + STEAM_EXPORT const char* SteamAPI_GetSteamInstallPath(); + + STEAM_EXPORT bool SteamGameServer_Init(); + STEAM_EXPORT void SteamGameServer_RunCallbacks(); + STEAM_EXPORT void SteamGameServer_Shutdown(); + + STEAM_EXPORT friends* SteamFriends(); + STEAM_EXPORT matchmaking* SteamMatchmaking(); + STEAM_EXPORT game_server* SteamGameServer(); + STEAM_EXPORT networking* SteamNetworking(); + STEAM_EXPORT remote_storage* SteamRemoteStorage(); + STEAM_EXPORT user* SteamUser(); + STEAM_EXPORT utils* SteamUtils(); + STEAM_EXPORT apps* SteamApps(); + STEAM_EXPORT user_stats* SteamUserStats(); +} diff --git a/src/common/exception/minidump.cpp b/src/common/exception/minidump.cpp new file mode 100644 index 00000000..164cd628 --- /dev/null +++ b/src/common/exception/minidump.cpp @@ -0,0 +1,93 @@ +#include "minidump.hpp" + +#include +#pragma comment(lib, "dbghelp.lib") + +#include + +namespace exception +{ + namespace + { + constexpr MINIDUMP_TYPE get_minidump_type() + { + const auto type = MiniDumpIgnoreInaccessibleMemory // + | MiniDumpWithHandleData // + | MiniDumpScanMemory // + | MiniDumpWithProcessThreadData // + | MiniDumpWithFullMemoryInfo // + | MiniDumpWithThreadInfo // + | MiniDumpWithUnloadedModules; + + return static_cast(type); + } + + std::string get_temp_filename() + { + char filename[MAX_PATH] = {0}; + char pathname[MAX_PATH] = {0}; + + GetTempPathA(sizeof(pathname), pathname); + GetTempFileNameA(pathname, "S1x-", 0, filename); + return filename; + } + + HANDLE write_dump_to_temp_file(const LPEXCEPTION_POINTERS exceptioninfo) + { + MINIDUMP_EXCEPTION_INFORMATION minidump_exception_info = {GetCurrentThreadId(), exceptioninfo, FALSE}; + + auto* const file_handle = CreateFileA(get_temp_filename().data(), GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + nullptr); + + if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file_handle, get_minidump_type(), + &minidump_exception_info, + nullptr, + nullptr)) + { + MessageBoxA(nullptr, "There was an error creating the minidump! Hit OK to close the program.", + "Minidump Error", MB_OK | MB_ICONERROR); + TerminateProcess(GetCurrentProcess(), 123); + } + + return file_handle; + } + + std::string read_file(HANDLE file_handle) + { + FlushFileBuffers(file_handle); + SetFilePointer(file_handle, 0, nullptr, FILE_BEGIN); + + std::string buffer{}; + + DWORD bytes_read = 0; + char temp_bytes[0x2000]; + + do + { + if (!ReadFile(file_handle, temp_bytes, sizeof(temp_bytes), &bytes_read, nullptr)) + { + return {}; + } + + buffer.append(temp_bytes, bytes_read); + } + while (bytes_read == sizeof(temp_bytes)); + + return buffer; + } + } + + std::string create_minidump(const LPEXCEPTION_POINTERS exceptioninfo) + { + auto* const file_handle = write_dump_to_temp_file(exceptioninfo); + + const auto _ = gsl::finally([file_handle]() + { + CloseHandle(file_handle); + }); + + return read_file(file_handle); + } +} diff --git a/src/common/exception/minidump.hpp b/src/common/exception/minidump.hpp new file mode 100644 index 00000000..42b3a46a --- /dev/null +++ b/src/common/exception/minidump.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../utils/nt.hpp" + +namespace exception +{ + std::string create_minidump(LPEXCEPTION_POINTERS exceptioninfo); +} diff --git a/src/common/utils/binary_resource.cpp b/src/common/utils/binary_resource.cpp new file mode 100644 index 00000000..eed83b0d --- /dev/null +++ b/src/common/utils/binary_resource.cpp @@ -0,0 +1,75 @@ +#include "binary_resource.hpp" + +#include +#include "nt.hpp" +#include "io.hpp" + +namespace utils +{ + namespace + { + std::string get_temp_folder() + { + char path[MAX_PATH] = {0}; + if (!GetTempPathA(sizeof(path), path)) + { + throw std::runtime_error("Unable to get temp path"); + } + + return path; + } + + std::string write_existing_temp_file(const std::string& file, const std::string& data, + const bool fatal_if_overwrite_fails) + { + const auto temp = get_temp_folder(); + auto file_path = temp + file; + + std::string current_data; + if (!io::read_file(file_path, ¤t_data)) + { + if (!io::write_file(file_path, data)) + { + throw std::runtime_error("Failed to write file: " + file_path); + } + + return file_path; + } + + if (current_data == data || io::write_file(file_path, data) || !fatal_if_overwrite_fails) + { + return file_path; + } + + throw std::runtime_error( + "Temporary file was already written, but differs. It can't be overwritten as it's still in use: " + + file_path); + } + } + + binary_resource::binary_resource(const int id, std::string file) + : filename_(std::move(file)) + { + this->resource_ = nt::load_resource(id); + + if (this->resource_.empty()) + { + throw std::runtime_error("Unable to load resource: " + std::to_string(id)); + } + } + + std::string binary_resource::get_extracted_file(const bool fatal_if_overwrite_fails) + { + if (this->path_.empty()) + { + this->path_ = write_existing_temp_file(this->filename_, this->resource_, fatal_if_overwrite_fails); + } + + return this->path_; + } + + const std::string& binary_resource::get_data() const + { + return this->resource_; + } +} diff --git a/src/common/utils/binary_resource.hpp b/src/common/utils/binary_resource.hpp new file mode 100644 index 00000000..da19af1a --- /dev/null +++ b/src/common/utils/binary_resource.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace utils +{ + class binary_resource + { + public: + binary_resource(int id, std::string file); + + std::string get_extracted_file(bool fatal_if_overwrite_fails = false); + const std::string& get_data() const; + + private: + std::string resource_; + std::string filename_; + std::string path_; + }; +} diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp new file mode 100644 index 00000000..1688cee5 --- /dev/null +++ b/src/common/utils/compression.cpp @@ -0,0 +1,169 @@ +#include "memory.hpp" +#include "compression.hpp" + +#include +#include + +#include + +#include "io.hpp" + +namespace utils::compression +{ + namespace zlib + { + namespace + { + class zlib_stream + { + public: + zlib_stream() + { + memset(&stream_, 0, sizeof(stream_)); + valid_ = inflateInit(&stream_) == Z_OK; + } + + zlib_stream(zlib_stream&&) = delete; + zlib_stream(const zlib_stream&) = delete; + zlib_stream& operator=(zlib_stream&&) = delete; + zlib_stream& operator=(const zlib_stream&) = delete; + + ~zlib_stream() + { + if (valid_) + { + inflateEnd(&stream_); + } + } + + z_stream& get() + { + return stream_; // + } + + bool is_valid() const + { + return valid_; + } + + private: + bool valid_{false}; + z_stream stream_{}; + }; + } + + std::string decompress(const std::string& data) + { + std::string buffer{}; + zlib_stream stream_container{}; + if (!stream_container.is_valid()) + { + return {}; + } + + int ret{}; + size_t offset = 0; + static thread_local uint8_t dest[CHUNK] = {0}; + auto& stream = stream_container.get(); + + do + { + const auto input_size = std::min(sizeof(dest), data.size() - offset); + stream.avail_in = static_cast(input_size); + stream.next_in = reinterpret_cast(data.data()) + offset; + offset += stream.avail_in; + + do + { + stream.avail_out = sizeof(dest); + stream.next_out = dest; + + ret = inflate(&stream, Z_NO_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + return {}; + } + + buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out); + } + while (stream.avail_out == 0); + } + while (ret != Z_STREAM_END); + + return buffer; + } + + std::string compress(const std::string& data) + { + std::string result{}; + auto length = compressBound(static_cast(data.size())); + result.resize(length); + + if (compress2(reinterpret_cast(result.data()), &length, + reinterpret_cast(data.data()), static_cast(data.size()), + Z_BEST_COMPRESSION) != Z_OK) + { + return {}; + } + + result.resize(length); + return result; + } + } + + namespace zip + { + namespace + { + bool add_file(zipFile& zip_file, const std::string& filename, const std::string& data) + { + const auto zip_64 = data.size() > 0xffffffff ? 1 : 0; + if (ZIP_OK != zipOpenNewFileInZip64(zip_file, filename.data(), nullptr, nullptr, 0, nullptr, 0, nullptr, + Z_DEFLATED, Z_BEST_COMPRESSION, zip_64)) + { + return false; + } + + const auto _ = gsl::finally([&zip_file]() + { + zipCloseFileInZip(zip_file); + }); + + return ZIP_OK == zipWriteInFileInZip(zip_file, data.data(), static_cast(data.size())); + } + } + + void archive::add(std::string filename, std::string data) + { + this->files_[std::move(filename)] = std::move(data); + } + + bool archive::write(const std::string& filename, const std::string& comment) + { + // Hack to create the directory :3 + io::write_file(filename, {}); + io::remove_file(filename); + + auto* zip_file = zipOpen64(filename.data(), 0); + if (!zip_file) + { + return false; + } + + const auto _ = gsl::finally([&zip_file, &comment]() + { + zipClose(zip_file, comment.empty() ? nullptr : comment.data()); + }); + + for (const auto& file : this->files_) + { + if (!add_file(zip_file, file.first, file.second)) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp new file mode 100644 index 00000000..dfe36ada --- /dev/null +++ b/src/common/utils/compression.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#define CHUNK 16384u + +namespace utils::compression +{ + namespace zlib + { + std::string compress(const std::string& data); + std::string decompress(const std::string& data); + } + + namespace zip + { + class archive + { + public: + void add(std::string filename, std::string data); + bool write(const std::string& filename, const std::string& comment = {}); + + private: + std::unordered_map files_; + }; + } +}; diff --git a/src/common/utils/concurrency.hpp b/src/common/utils/concurrency.hpp new file mode 100644 index 00000000..05c5d3ad --- /dev/null +++ b/src/common/utils/concurrency.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace utils::concurrency +{ + template + class container + { + public: + template + R access(F&& accessor) const + { + std::lock_guard _{mutex_}; + return accessor(object_); + } + + template + R access(F&& accessor) + { + std::lock_guard _{mutex_}; + return accessor(object_); + } + + template + R access_with_lock(F&& accessor) const + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } + + template + R access_with_lock(F&& accessor) + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } + + T& get_raw() { return object_; } + const T& get_raw() const { return object_; } + + private: + mutable MutexType mutex_{}; + T object_{}; + }; +} diff --git a/src/common/utils/cryptography.cpp b/src/common/utils/cryptography.cpp new file mode 100644 index 00000000..2e2065a6 --- /dev/null +++ b/src/common/utils/cryptography.cpp @@ -0,0 +1,640 @@ +#include "string.hpp" +#include "cryptography.hpp" +#include "nt.hpp" +#include + +#undef max +using namespace std::string_literals; + +/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf + +namespace utils::cryptography +{ + namespace + { + struct __ + { + __() + { + ltc_mp = ltm_desc; + + register_cipher(&aes_desc); + register_cipher(&des3_desc); + + register_prng(&sprng_desc); + register_prng(&fortuna_desc); + register_prng(&yarrow_desc); + + register_hash(&sha1_desc); + register_hash(&sha256_desc); + register_hash(&sha512_desc); + } + } ___; + + [[maybe_unused]] const char* cs(const uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] char* cs(uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] const uint8_t* cs(const char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] uint8_t* cs(char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] unsigned long ul(const size_t value) + { + return static_cast(value); + } + + class prng + { + public: + prng(const ltc_prng_descriptor& descriptor, const bool autoseed = true) + : state_(std::make_unique()) + , descriptor_(descriptor) + { + this->id_ = register_prng(&descriptor); + if (this->id_ == -1) + { + throw std::runtime_error("PRNG "s + this->descriptor_.name + " could not be registered!"); + } + + if (autoseed) + { + this->auto_seed(); + } + else + { + this->descriptor_.start(this->state_.get()); + } + } + + ~prng() + { + this->descriptor_.done(this->state_.get()); + } + + prng_state* get_state() const + { + this->descriptor_.ready(this->state_.get()); + return this->state_.get(); + } + + int get_id() const + { + return this->id_; + } + + void add_entropy(const void* data, const size_t length) const + { + this->descriptor_.add_entropy(static_cast(data), ul(length), this->state_.get()); + } + + void read(void* data, const size_t length) const + { + this->descriptor_.read(static_cast(data), ul(length), this->get_state()); + } + + private: + int id_; + std::unique_ptr state_; + const ltc_prng_descriptor& descriptor_; + + void auto_seed() const + { + rng_make_prng(128, this->id_, this->state_.get(), nullptr); + + int i[4]; // uninitialized data + auto* i_ptr = &i; + this->add_entropy(reinterpret_cast(&i), sizeof(i)); + this->add_entropy(reinterpret_cast(&i_ptr), sizeof(i_ptr)); + + auto t = time(nullptr); + this->add_entropy(reinterpret_cast(&t), sizeof(t)); + } + }; + + const prng prng_(fortuna_desc); + } + + ecc::key::key() + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + ecc::key::~key() + { + this->free(); + } + + ecc::key::key(key&& obj) noexcept + : key() + { + this->operator=(std::move(obj)); + } + + ecc::key::key(const key& obj) + : key() + { + this->operator=(obj); + } + + ecc::key& ecc::key::operator=(key&& obj) noexcept + { + if (this != &obj) + { + std::memmove(&this->key_storage_, &obj.key_storage_, sizeof(this->key_storage_)); + ZeroMemory(&obj.key_storage_, sizeof(obj.key_storage_)); + } + + return *this; + } + + ecc::key& ecc::key::operator=(const key& obj) + { + if (this != &obj && obj.is_valid()) + { + this->deserialize(obj.serialize(obj.key_storage_.type)); + } + + return *this; + } + + bool ecc::key::is_valid() const + { + return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); + } + + ecc_key& ecc::key::get() + { + return this->key_storage_; + } + + const ecc_key& ecc::key::get() const + { + return this->key_storage_; + } + + std::string ecc::key::get_public_key() const + { + uint8_t buffer[512] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return {}; + } + + void ecc::key::set(const std::string& pub_key_buffer) + { + this->free(); + + if (ecc_ansi_x963_import(cs(pub_key_buffer.data()), + ul(pub_key_buffer.size()), + &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + void ecc::key::deserialize(const std::string& key) + { + this->free(); + + if (ecc_import(cs(key.data()), ul(key.size()), + &this->key_storage_) != CRYPT_OK + ) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + std::string ecc::key::serialize(const int type) const + { + uint8_t buffer[4096] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return ""; + } + + void ecc::key::free() + { + if (this->is_valid()) + { + ecc_free(&this->key_storage_); + } + + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + bool ecc::key::operator==(key& key) const + { + return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); + } + + uint64_t ecc::key::get_hash() const + { + const auto hash = sha1::compute(this->get_public_key()); + if (hash.size() >= 8) + { + return *reinterpret_cast(hash.data()); + } + + return 0; + } + + ecc::key ecc::generate_key(const int bits) + { + key key; + ecc_make_key(prng_.get_state(), prng_.get_id(), bits / 8, &key.get()); + + return key; + } + + ecc::key ecc::generate_key(const int bits, const std::string& entropy) + { + key key{}; + const prng yarrow(yarrow_desc, false); + yarrow.add_entropy(entropy.data(), entropy.size()); + + ecc_make_key(yarrow.get_state(), yarrow.get_id(), bits / 8, &key.get()); + + return key; + } + + std::string ecc::sign_message(const key& key, const std::string& message) + { + if (!key.is_valid()) return ""; + + uint8_t buffer[512]; + unsigned long length = sizeof(buffer); + + ecc_sign_hash(cs(message.data()), ul(message.size()), buffer, &length, prng_.get_state(), prng_.get_id(), + &key.get()); + + return std::string(cs(buffer), length); + } + + bool ecc::verify_message(const key& key, const std::string& message, const std::string& signature) + { + if (!key.is_valid()) return false; + + auto result = 0; + return (ecc_verify_hash(cs(signature.data()), + ul(signature.size()), + cs(message.data()), + ul(message.size()), &result, + &key.get()) == CRYPT_OK && result != 0); + } + + bool ecc::encrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, + prng_.get_state(), prng_.get_id(), find_hash("sha512"), &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + bool ecc::decrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_decrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) + { + rsa_key new_key; + rsa_import(cs(key.data()), ul(key.size()), &new_key); + const auto _ = gsl::finally([&]() + { + rsa_free(&new_key); + }); + + + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return rsa_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, cs(hash.data()), + ul(hash.size()), prng_.get_state(), prng_.get_id(), find_hash("sha512"), &new_key); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res == CRYPT_OK) + { + out_data.resize(out_len); + return out_data; + } + + return {}; + } + + std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), cs(enc_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), cs(dec_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string tiger::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[24] = {0}; + + hash_state state; + tiger_init(&state); + tiger_process(&state, data, ul(length)); + tiger_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string aes::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), + cs(enc_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string aes::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), + cs(dec_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string hmac_sha1::compute(const std::string& data, const std::string& key) + { + std::string buffer; + buffer.resize(20); + + hmac_state state; + hmac_init(&state, find_hash("sha1"), cs(key.data()), ul(key.size())); + hmac_process(&state, cs(data.data()), static_cast(data.size())); + + auto out_len = ul(buffer.size()); + hmac_done(&state, cs(buffer.data()), &out_len); + + buffer.resize(out_len); + return buffer; + } + + std::string sha1::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[20] = {0}; + + hash_state state; + sha1_init(&state); + sha1_process(&state, data, ul(length)); + sha1_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha256::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[32] = {0}; + + hash_state state; + sha256_init(&state); + sha256_process(&state, data, ul(length)); + sha256_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha512::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[64] = {0}; + + hash_state state; + sha512_init(&state); + sha512_process(&state, data, ul(length)); + sha512_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string base64::encode(const uint8_t* data, const size_t len) + { + std::string result; + result.resize((len + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_encode(data, ul(len), result.data(), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + std::string base64::encode(const std::string& data) + { + return base64::encode(cs(data.data()), static_cast(data.size())); + } + + std::string base64::decode(const std::string& data) + { + std::string result; + result.resize((data.size() + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_decode(data.data(), ul(data.size()), cs(result.data()), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + unsigned int jenkins_one_at_a_time::compute(const std::string& data) + { + return compute(data.data(), data.size()); + } + + unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) + { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } + + uint32_t random::get_integer() + { + uint32_t result; + random::get_data(&result, sizeof(result)); + return result; + } + + std::string random::get_challenge() + { + std::string result; + result.resize(sizeof(uint32_t)); + random::get_data(result.data(), result.size()); + return string::dump_hex(result, ""); + } + + void random::get_data(void* data, const size_t size) + { + prng_.read(data, size); + } +} diff --git a/src/common/utils/cryptography.hpp b/src/common/utils/cryptography.hpp new file mode 100644 index 00000000..9538c5eb --- /dev/null +++ b/src/common/utils/cryptography.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include + +namespace utils::cryptography +{ + namespace ecc + { + class key final + { + public: + key(); + ~key(); + + key(key&& obj) noexcept; + key(const key& obj); + key& operator=(key&& obj) noexcept; + key& operator=(const key& obj); + + bool is_valid() const; + + ecc_key& get(); + const ecc_key& get() const; + + std::string get_public_key() const; + + void set(const std::string& pub_key_buffer); + + void deserialize(const std::string& key); + + std::string serialize(int type = PK_PRIVATE) const; + + void free(); + + bool operator==(key& key) const; + + uint64_t get_hash() const; + + private: + ecc_key key_storage_{}; + }; + + key generate_key(int bits); + key generate_key(int bits, const std::string& entropy); + std::string sign_message(const key& key, const std::string& message); + bool verify_message(const key& key, const std::string& message, const std::string& signature); + + bool encrypt(const key& key, std::string& data); + bool decrypt(const key& key, std::string& data); + } + + namespace rsa + { + std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); + } + + namespace des3 + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace tiger + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace aes + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace hmac_sha1 + { + std::string compute(const std::string& data, const std::string& key); + } + + namespace sha1 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha256 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha512 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace base64 + { + std::string encode(const uint8_t* data, size_t len); + std::string encode(const std::string& data); + std::string decode(const std::string& data); + } + + namespace jenkins_one_at_a_time + { + unsigned int compute(const std::string& data); + unsigned int compute(const char* key, size_t len); + }; + + namespace random + { + uint32_t get_integer(); + std::string get_challenge(); + void get_data(void* data, size_t size); + } +} diff --git a/src/common/utils/flags.cpp b/src/common/utils/flags.cpp new file mode 100644 index 00000000..cbada183 --- /dev/null +++ b/src/common/utils/flags.cpp @@ -0,0 +1,52 @@ +#include "flags.hpp" +#include "string.hpp" +#include "nt.hpp" + +#include + +namespace utils::flags +{ + void parse_flags(std::vector& flags) + { + int num_args; + auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args); + + flags.clear(); + + if (argv) + { + for (auto i = 0; i < num_args; ++i) + { + std::wstring wide_flag(argv[i]); + if (wide_flag[0] == L'-') + { + wide_flag.erase(wide_flag.begin()); + flags.emplace_back(string::convert(wide_flag)); + } + } + + LocalFree(argv); + } + } + + bool has_flag(const std::string& flag) + { + static auto parsed = false; + static std::vector enabled_flags; + + if (!parsed) + { + parse_flags(enabled_flags); + } + + for (const auto& entry : enabled_flags) + { + if (string::to_lower(entry) == string::to_lower(flag)) + { + return true; + } + } + + return false; + } +} diff --git a/src/common/utils/flags.hpp b/src/common/utils/flags.hpp new file mode 100644 index 00000000..cf304b20 --- /dev/null +++ b/src/common/utils/flags.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::flags +{ + bool has_flag(const std::string& flag); +} diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp new file mode 100644 index 00000000..be05cb96 --- /dev/null +++ b/src/common/utils/hook.cpp @@ -0,0 +1,310 @@ +#include "hook.hpp" +#include "string.hpp" + +#include + +namespace utils::hook +{ + namespace + { + [[maybe_unused]] class _ + { + public: + _() + { + if (MH_Initialize() != MH_OK) + { + throw std::runtime_error("Failed to initialize MinHook"); + } + } + + ~_() + { + MH_Uninitialize(); + } + } __; + } + + void assembler::pushad64() + { + this->push(rax); + this->push(rcx); + this->push(rdx); + this->push(rbx); + this->push(rsp); + this->push(rbp); + this->push(rsi); + this->push(rdi); + + this->sub(rsp, 0x40); + } + + void assembler::popad64() + { + this->add(rsp, 0x40); + + this->pop(rdi); + this->pop(rsi); + this->pop(rbp); + this->pop(rsp); + this->pop(rbx); + this->pop(rdx); + this->pop(rcx); + this->pop(rax); + } + + void assembler::prepare_stack_for_call() + { + const auto reserve_callee_space = this->newLabel(); + const auto stack_unaligned = this->newLabel(); + + this->test(rsp, 0xF); + this->jnz(stack_unaligned); + + this->sub(rsp, 0x8); + this->push(rsp); + + this->push(rax); + this->mov(rax, ptr(rsp, 8, 8)); + this->add(rax, 0x8); + this->mov(ptr(rsp, 8, 8), rax); + this->pop(rax); + + this->jmp(reserve_callee_space); + + this->bind(stack_unaligned); + this->push(rsp); + + this->bind(reserve_callee_space); + this->sub(rsp, 0x40); + } + + void assembler::restore_stack_after_call() + { + this->lea(rsp, ptr(rsp, 0x40)); + this->pop(rsp); + } + + asmjit::Error assembler::call(void* target) + { + return Assembler::call(size_t(target)); + } + + asmjit::Error assembler::jmp(void* target) + { + return Assembler::jmp(size_t(target)); + } + + detour::detour(const size_t place, void* target) : detour(reinterpret_cast(place), target) + { + } + + detour::detour(void* place, void* target) + { + this->create(place, target); + } + + detour::~detour() + { + this->clear(); + } + + void detour::enable() const + { + MH_EnableHook(this->place_); + } + + void detour::disable() const + { + MH_DisableHook(this->place_); + } + + void detour::create(void* place, void* target) + { + this->clear(); + this->place_ = place; + + if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) + { + throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_)); + } + + this->enable(); + } + + void detour::create(const size_t place, void* target) + { + this->create(reinterpret_cast(place), target); + } + + void detour::clear() + { + if (this->place_) + { + MH_RemoveHook(this->place_); + } + + this->place_ = nullptr; + this->original_ = nullptr; + } + + void* detour::get_original() const + { + return this->original_; + } + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub) + { + if (!library.is_valid()) return false; + + auto* const ptr = library.get_iat_entry(target_library, process); + if (!ptr) return false; + + DWORD protect; + VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); + + *ptr = stub; + + VirtualProtect(ptr, sizeof(*ptr), protect, &protect); + return true; + } + + void nop(void* place, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memset(place, 0x90, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void nop(const size_t place, const size_t length) + { + nop(reinterpret_cast(place), length); + } + + void copy(void* place, const void* data, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memmove(place, data, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void copy(const size_t place, const void* data, const size_t length) + { + copy(reinterpret_cast(place), data, length); + } + + bool is_relatively_far(const void* pointer, const void* data, const int offset) + { + const int64_t diff = size_t(data) - (size_t(pointer) + offset); + const auto small_diff = int32_t(diff); + return diff != int64_t(small_diff); + } + + void call(void* pointer, void* data) + { + if (is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + set(patch_pointer, 0xE8); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + + void call(const size_t pointer, void* data) + { + return call(reinterpret_cast(pointer), data); + } + + void call(const size_t pointer, const size_t data) + { + return call(pointer, reinterpret_cast(data)); + } + + void jump(void* pointer, void* data, const bool use_far) + { + static const unsigned char jump_data[] = { + 0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0 + }; + + if (!use_far && is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + + if (use_far) + { + copy(patch_pointer, jump_data, sizeof(jump_data)); + copy(patch_pointer + 2, &data, sizeof(data)); + } + else + { + set(patch_pointer, 0xE9); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + } + + void jump(const size_t pointer, void* data, const bool use_far) + { + return jump(reinterpret_cast(pointer), data, use_far); + } + + void jump(const size_t pointer, const size_t data, const bool use_far) + { + return jump(pointer, reinterpret_cast(data), use_far); + } + + void* assemble(const std::function& asm_function) + { + static asmjit::JitRuntime runtime; + + asmjit::CodeHolder code; + code.init(runtime.environment()); + + assembler a(&code); + + asm_function(a); + + void* result = nullptr; + runtime.add(&result, &code); + + return result; + } + + void inject(void* pointer, const void* data) + { + if (is_relatively_far(pointer, data, 4)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + set(pointer, int32_t(size_t(data) - (size_t(pointer) + 4))); + } + + void inject(const size_t pointer, const void* data) + { + return inject(reinterpret_cast(pointer), data); + } + + void* follow_branch(void* address) + { + auto* const data = static_cast(address); + if (*data != 0xE8 && *data != 0xE9) + { + throw std::runtime_error("No branch instruction found"); + } + + return extract(data + 1); + } +} diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp new file mode 100644 index 00000000..bb24f8ce --- /dev/null +++ b/src/common/utils/hook.hpp @@ -0,0 +1,205 @@ +#pragma once +#include "signature.hpp" + +#include +#include + +using namespace asmjit::x86; + +namespace utils::hook +{ + namespace detail + { + template + std::vector get_iota_functions() + { + if constexpr (entries == 0) + { + std::vector functions; + return functions; + } + else + { + auto functions = get_iota_functions(); + functions.emplace_back([]() + { + return entries - 1; + }); + return functions; + } + } + } + + // Gets the pointer to the entry in the v-table. + // It seems otherwise impossible to get this. + // This is ugly as fuck and only safely works on x64 + // Example: + // ID3D11Device* device = ... + // auto entry = get_vtable_entry(device, &ID3D11Device::CreateTexture2D); + template + void** get_vtable_entry(Class* obj, T (Class::* entry)(Args ...)) + { + union + { + decltype(entry) func; + void* pointer; + }; + + func = entry; + + auto iota_functions = detail::get_iota_functions(); + auto* object = iota_functions.data(); + + using FakeFunc = size_t(__thiscall*)(void* self); + auto index = static_cast(pointer)(&object); + + void** obj_v_table = *reinterpret_cast(obj); + return &obj_v_table[index]; + } + + class assembler : public Assembler + { + public: + using Assembler::Assembler; + using Assembler::call; + using Assembler::jmp; + + void pushad64(); + void popad64(); + + void prepare_stack_for_call(); + void restore_stack_after_call(); + + template + void call_aligned(T&& target) + { + this->prepare_stack_for_call(); + this->call(std::forward(target)); + this->restore_stack_after_call(); + } + + asmjit::Error call(void* target); + asmjit::Error jmp(void* target); + }; + + class detour + { + public: + detour() = default; + detour(void* place, void* target); + detour(size_t place, void* target); + ~detour(); + + detour(detour&& other) noexcept + { + this->operator=(std::move(other)); + } + + detour& operator=(detour&& other) noexcept + { + if (this != &other) + { + this->~detour(); + + this->place_ = other.place_; + this->original_ = other.original_; + + other.place_ = nullptr; + other.original_ = nullptr; + } + + return *this; + } + + detour(const detour&) = delete; + detour& operator=(const detour&) = delete; + + void enable() const; + void disable() const; + + void create(void* place, void* target); + void create(size_t place, void* target); + void clear(); + + template + T* get() const + { + return static_cast(this->get_original()); + } + + template + T invoke(Args ... args) + { + return static_cast(this->get_original())(args...); + } + + [[nodiscard]] void* get_original() const; + + private: + void* place_{}; + void* original_{}; + }; + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub); + + void nop(void* place, size_t length); + void nop(size_t place, size_t length); + + void copy(void* place, const void* data, size_t length); + void copy(size_t place, const void* data, size_t length); + + bool is_relatively_far(const void* pointer, const void* data, int offset = 5); + + void call(void* pointer, void* data); + void call(size_t pointer, void* data); + void call(size_t pointer, size_t data); + + void jump(void* pointer, void* data, bool use_far = false); + void jump(size_t pointer, void* data, bool use_far = false); + void jump(size_t pointer, size_t data, bool use_far = false); + + void* assemble(const std::function& asm_function); + + void inject(void* pointer, const void* data); + void inject(size_t pointer, const void* data); + + template + T extract(void* address) + { + auto* const data = static_cast(address); + const auto offset = *reinterpret_cast(data); + return reinterpret_cast(data + offset + 4); + } + + void* follow_branch(void* address); + + template + static void set(void* place, T value) + { + DWORD old_protect; + VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); + + *static_cast(place) = value; + + VirtualProtect(place, sizeof(T), old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); + } + + template + static void set(const size_t place, T value) + { + return set(reinterpret_cast(place), value); + } + + template + static T invoke(size_t func, Args ... args) + { + return reinterpret_cast(func)(args...); + } + + template + static T invoke(void* func, Args ... args) + { + return static_cast(func)(args...); + } +} diff --git a/src/common/utils/http.cpp b/src/common/utils/http.cpp new file mode 100644 index 00000000..3cb59991 --- /dev/null +++ b/src/common/utils/http.cpp @@ -0,0 +1,48 @@ +#include "http.hpp" +#include "nt.hpp" +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url) + { + CComPtr stream; + + if (FAILED(URLOpenBlockingStreamA(nullptr, url.data(), &stream, 0, nullptr))) + { + return {}; + } + + char buffer[0x1000]; + std::string result; + + HRESULT status{}; + + do + { + DWORD bytes_read = 0; + status = stream->Read(buffer, sizeof(buffer), &bytes_read); + + if (bytes_read > 0) + { + result.append(buffer, bytes_read); + } + } + while (SUCCEEDED(status) && status != S_FALSE); + + if (FAILED(status)) + { + return {}; + } + + return {result}; + } + + std::future> get_data_async(const std::string& url) + { + return std::async(std::launch::async, [url]() + { + return get_data(url); + }); + } +} diff --git a/src/common/utils/http.hpp b/src/common/utils/http.hpp new file mode 100644 index 00000000..65628a9f --- /dev/null +++ b/src/common/utils/http.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url); + std::future> get_data_async(const std::string& url); +} diff --git a/src/common/utils/image.cpp b/src/common/utils/image.cpp new file mode 100644 index 00000000..33f865e2 --- /dev/null +++ b/src/common/utils/image.cpp @@ -0,0 +1,53 @@ +#include "image.hpp" + +#define STB_IMAGE_IMPLEMENTATION +#include +#include + +namespace utils +{ + image::image(const std::string& image_data) + { + int channels{}; + auto* rgb_image = stbi_load_from_memory(reinterpret_cast(image_data.data()), static_cast(image_data.size()), &this->width, &this->height, &channels, 4); + if(!rgb_image) + { + throw std::runtime_error("Unable to load image"); + } + + auto _ = gsl::finally([rgb_image]() + { + stbi_image_free(rgb_image); + }); + + const auto size = this->width * this->height * 4; + this->data.resize(size); + + std::memmove(this->data.data(), rgb_image, size); + } + + int image::get_width() const + { + return this->width; + } + + int image::get_height() const + { + return this->height; + } + + const void* image::get_buffer() const + { + return this->data.data(); + } + + size_t image::get_size() const + { + return this->data.size(); + } + + const std::string& image::get_data() const + { + return this->data; + } +} diff --git a/src/common/utils/image.hpp b/src/common/utils/image.hpp new file mode 100644 index 00000000..a617df76 --- /dev/null +++ b/src/common/utils/image.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace utils +{ + class image + { + public: + image(const std::string& data); + + int get_width() const; + int get_height() const; + const void* get_buffer() const; + size_t get_size() const; + + const std::string& get_data() const; + + private: + int width{}; + int height{}; + std::string data{}; + }; +} diff --git a/src/common/utils/info_string.cpp b/src/common/utils/info_string.cpp new file mode 100644 index 00000000..3b0287e3 --- /dev/null +++ b/src/common/utils/info_string.cpp @@ -0,0 +1,65 @@ +#include "info_string.hpp" +#include "string.hpp" + +namespace utils +{ + info_string::info_string(const std::string& buffer) + { + this->parse(buffer); + } + + info_string::info_string(const std::string_view& buffer) + : info_string(std::string{buffer}) + { + } + + void info_string::set(const std::string& key, const std::string& value) + { + this->key_value_pairs_[key] = value; + } + + std::string info_string::get(const std::string& key) const + { + const auto value = this->key_value_pairs_.find(key); + if (value != this->key_value_pairs_.end()) + { + return value->second; + } + + return ""; + } + + void info_string::parse(std::string buffer) + { + if (buffer[0] == '\\') + { + buffer = buffer.substr(1); + } + + auto key_values = string::split(buffer, '\\'); + for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2) + { + const auto& key = key_values[i]; + const auto& value = key_values[i + 1]; + this->key_value_pairs_[key] = value; + } + } + + std::string info_string::build() const + { + //auto first = true; + std::string info_string; + for (auto i = this->key_value_pairs_.begin(); i != this->key_value_pairs_.end(); ++i) + { + //if (first) first = false; + /*else*/ + info_string.append("\\"); + + info_string.append(i->first); // Key + info_string.append("\\"); + info_string.append(i->second); // Value + } + + return info_string; + } +} diff --git a/src/common/utils/info_string.hpp b/src/common/utils/info_string.hpp new file mode 100644 index 00000000..73910411 --- /dev/null +++ b/src/common/utils/info_string.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace utils +{ + class info_string + { + public: + info_string() = default; + info_string(const std::string& buffer); + info_string(const std::string_view& buffer); + + void set(const std::string& key, const std::string& value); + std::string get(const std::string& key) const; + std::string build() const; + + private: + std::unordered_map key_value_pairs_{}; + + void parse(std::string buffer); + }; +} diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp new file mode 100644 index 00000000..4968f449 --- /dev/null +++ b/src/common/utils/io.cpp @@ -0,0 +1,125 @@ +#include "io.hpp" +#include "nt.hpp" +#include + +namespace utils::io +{ + bool remove_file(const std::string& file) + { + return DeleteFileA(file.data()) == TRUE; + } + + bool move_file(const std::string& src, const std::string& target) + { + return MoveFileA(src.data(), target.data()) == TRUE; + } + + bool file_exists(const std::string& file) + { + return std::ifstream(file).good(); + } + + bool write_file(const std::string& file, const std::string& data, const bool append) + { + const auto pos = file.find_last_of("/\\"); + if (pos != std::string::npos) + { + create_directory(file.substr(0, pos)); + } + + std::ofstream stream( + file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0)); + + if (stream.is_open()) + { + stream.write(data.data(), data.size()); + stream.close(); + return true; + } + + return false; + } + + std::string read_file(const std::string& file) + { + std::string data; + read_file(file, &data); + return data; + } + + bool read_file(const std::string& file, std::string* data) + { + if (!data) return false; + data->clear(); + + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + if (!stream.is_open()) return false; + + stream.seekg(0, std::ios::end); + const std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + if (size > -1) + { + data->resize(static_cast(size)); + stream.read(const_cast(data->data()), size); + stream.close(); + return true; + } + } + + return false; + } + + size_t file_size(const std::string& file) + { + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + + if (stream.good()) + { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } + } + + return 0; + } + + bool create_directory(const std::string& directory) + { + return std::filesystem::create_directories(directory); + } + + bool directory_exists(const std::string& directory) + { + return std::filesystem::is_directory(directory); + } + + bool directory_is_empty(const std::string& directory) + { + return std::filesystem::is_empty(directory); + } + + std::vector list_files(const std::string& directory) + { + std::vector files; + + for (auto& file : std::filesystem::directory_iterator(directory)) + { + files.push_back(file.path().generic_string()); + } + + return files; + } + + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) + { + std::filesystem::copy(src, target, + std::filesystem::copy_options::overwrite_existing | + std::filesystem::copy_options::recursive); + } +} diff --git a/src/common/utils/io.hpp b/src/common/utils/io.hpp new file mode 100644 index 00000000..ab4ebaa4 --- /dev/null +++ b/src/common/utils/io.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +namespace utils::io +{ + bool remove_file(const std::string& file); + bool move_file(const std::string& src, const std::string& target); + bool file_exists(const std::string& file); + bool write_file(const std::string& file, const std::string& data, bool append = false); + bool read_file(const std::string& file, std::string* data); + std::string read_file(const std::string& file); + size_t file_size(const std::string& file); + bool create_directory(const std::string& directory); + bool directory_exists(const std::string& directory); + bool directory_is_empty(const std::string& directory); + std::vector list_files(const std::string& directory); + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); +} diff --git a/src/common/utils/memory.cpp b/src/common/utils/memory.cpp new file mode 100644 index 00000000..52d46771 --- /dev/null +++ b/src/common/utils/memory.cpp @@ -0,0 +1,165 @@ +#include "memory.hpp" +#include "nt.hpp" + +namespace utils +{ + memory::allocator memory::mem_allocator_; + + memory::allocator::~allocator() + { + this->clear(); + } + + void memory::allocator::clear() + { + std::lock_guard _(this->mutex_); + + for (auto& data : this->pool_) + { + memory::free(data); + } + + this->pool_.clear(); + } + + void memory::allocator::free(void* data) + { + std::lock_guard _(this->mutex_); + + const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); + if (j != this->pool_.end()) + { + memory::free(data); + this->pool_.erase(j); + } + } + + void memory::allocator::free(const void* data) + { + this->free(const_cast(data)); + } + + void* memory::allocator::allocate(const size_t length) + { + std::lock_guard _(this->mutex_); + + const auto data = memory::allocate(length); + this->pool_.push_back(data); + return data; + } + + bool memory::allocator::empty() const + { + return this->pool_.empty(); + } + + char* memory::allocator::duplicate_string(const std::string& string) + { + std::lock_guard _(this->mutex_); + + const auto data = memory::duplicate_string(string); + this->pool_.push_back(data); + return data; + } + + void* memory::allocate(const size_t length) + { + return calloc(length, 1); + } + + char* memory::duplicate_string(const std::string& string) + { + const auto new_string = allocate_array(string.size() + 1); + std::memcpy(new_string, string.data(), string.size()); + return new_string; + } + + void memory::free(void* data) + { + if (data) + { + ::free(data); + } + } + + void memory::free(const void* data) + { + free(const_cast(data)); + } + + bool memory::is_set(const void* mem, const char chr, const size_t length) + { + const auto mem_arr = static_cast(mem); + + for (size_t i = 0; i < length; ++i) + { + if (mem_arr[i] != chr) + { + return false; + } + } + + return true; + } + + bool memory::is_bad_read_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + return true; + } + + bool memory::is_bad_code_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + return true; + } + + bool memory::is_rdata_ptr(void* pointer) + { + const std::string rdata = ".rdata"; + const auto pointer_lib = utils::nt::library::get_by_address(pointer); + + for (const auto& section : pointer_lib.get_section_headers()) + { + const auto size = sizeof(section->Name); + char name[size + 1]; + name[size] = 0; + std::memcpy(name, section->Name, size); + + if (name == rdata) + { + const auto target = size_t(pointer); + const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData; + const size_t source_end = source_start + section->SizeOfRawData; + + return target >= source_start && target <= source_end; + } + } + + return false; + } + + memory::allocator* memory::get_allocator() + { + return &memory::mem_allocator_; + } +} diff --git a/src/common/utils/memory.hpp b/src/common/utils/memory.hpp new file mode 100644 index 00000000..5af5645e --- /dev/null +++ b/src/common/utils/memory.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +namespace utils +{ + class memory final + { + public: + class allocator final + { + public: + ~allocator(); + + void clear(); + + void free(void* data); + + void free(const void* data); + + void* allocate(size_t length); + + template + inline T* allocate() + { + return this->allocate_array(1); + } + + template + inline T* allocate_array(const size_t count = 1) + { + return static_cast(this->allocate(count * sizeof(T))); + } + + bool empty() const; + + char* duplicate_string(const std::string& string); + + private: + std::mutex mutex_; + std::vector pool_; + }; + + static void* allocate(size_t length); + + template + static inline T* allocate() + { + return allocate_array(1); + } + + template + static inline T* allocate_array(const size_t count = 1) + { + return static_cast(allocate(count * sizeof(T))); + } + + static char* duplicate_string(const std::string& string); + + static void free(void* data); + static void free(const void* data); + + static bool is_set(const void* mem, char chr, size_t length); + + static bool is_bad_read_ptr(const void* ptr); + static bool is_bad_code_ptr(const void* ptr); + static bool is_rdata_ptr(void* ptr); + + static allocator* get_allocator(); + + private: + static allocator mem_allocator_; + }; +} diff --git a/src/common/utils/nt.cpp b/src/common/utils/nt.cpp new file mode 100644 index 00000000..5fc5273c --- /dev/null +++ b/src/common/utils/nt.cpp @@ -0,0 +1,254 @@ +#include "nt.hpp" + +namespace utils::nt +{ + library library::load(const std::string& name) + { + return library(LoadLibraryA(name.data())); + } + + library library::load(const std::filesystem::path& path) + { + return library::load(path.generic_string()); + } + + library library::get_by_address(void* address) + { + HMODULE handle = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast(address), &handle); + return library(handle); + } + + library::library() + { + this->module_ = GetModuleHandleA(nullptr); + } + + library::library(const std::string& name) + { + this->module_ = GetModuleHandleA(name.data()); + } + + library::library(const HMODULE handle) + { + this->module_ = handle; + } + + bool library::operator==(const library& obj) const + { + return this->module_ == obj.module_; + } + + library::operator bool() const + { + return this->is_valid(); + } + + library::operator HMODULE() const + { + return this->get_handle(); + } + + PIMAGE_NT_HEADERS library::get_nt_headers() const + { + if (!this->is_valid()) return nullptr; + return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); + } + + PIMAGE_DOS_HEADER library::get_dos_header() const + { + return reinterpret_cast(this->get_ptr()); + } + + PIMAGE_OPTIONAL_HEADER library::get_optional_header() const + { + if (!this->is_valid()) return nullptr; + return &this->get_nt_headers()->OptionalHeader; + } + + std::vector library::get_section_headers() const + { + std::vector headers; + + auto nt_headers = this->get_nt_headers(); + auto section = IMAGE_FIRST_SECTION(nt_headers); + + for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) + { + if (section) headers.push_back(section); + else OutputDebugStringA("There was an invalid section :O"); + } + + return headers; + } + + std::uint8_t* library::get_ptr() const + { + return reinterpret_cast(this->module_); + } + + void library::unprotect() const + { + if (!this->is_valid()) return; + + DWORD protection; + VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, + &protection); + } + + size_t library::get_relative_entry_point() const + { + if (!this->is_valid()) return 0; + return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; + } + + void* library::get_entry_point() const + { + if (!this->is_valid()) return nullptr; + return this->get_ptr() + this->get_relative_entry_point(); + } + + bool library::is_valid() const + { + return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; + } + + std::string library::get_name() const + { + if (!this->is_valid()) return ""; + + auto path = this->get_path(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) return path; + + return path.substr(pos + 1); + } + + std::string library::get_path() const + { + if (!this->is_valid()) return ""; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof name); + + return name; + } + + std::string library::get_folder() const + { + if (!this->is_valid()) return ""; + + const auto path = std::filesystem::path(this->get_path()); + return path.parent_path().generic_string(); + } + + void library::free() + { + if (this->is_valid()) + { + FreeLibrary(this->module_); + this->module_ = nullptr; + } + } + + HMODULE library::get_handle() const + { + return this->module_; + } + + void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const + { + if (!this->is_valid()) return nullptr; + + const library other_module(module_name); + if (!other_module.is_valid()) return nullptr; + + auto* const target_function = other_module.get_proc(proc_name); + if (!target_function) return nullptr; + + auto* header = this->get_optional_header(); + if (!header) return nullptr; + + auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory + [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + while (import_descriptor->Name) + { + if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) + { + auto* original_thunk_data = reinterpret_cast(import_descriptor-> + OriginalFirstThunk + this->get_ptr()); + auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> + get_ptr()); + + while (original_thunk_data->u1.AddressOfData) + { + const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; + + if (ordinal_number > 0xFFFF) continue; + + if (GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)) == + target_function) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + + ++original_thunk_data; + ++thunk_data; + } + + //break; + } + + ++import_descriptor; + } + + return nullptr; + } + + void raise_hard_exception() + { + int data = false; + const library ntdll("ntdll.dll"); + ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); + ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); + } + + std::string load_resource(const int id) + { + auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); + if (!res) return {}; + + auto* const handle = LoadResource(nullptr, res); + if (!handle) return {}; + + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); + } + + void relaunch_self() + { + const utils::nt::library self; + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + char current_dir[MAX_PATH]; + GetCurrentDirectoryA(sizeof(current_dir), current_dir); + auto* const command_line = GetCommandLineA(); + + CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); + } + + void terminate(const uint32_t code) + { + TerminateProcess(GetCurrentProcess(), code); + } +} diff --git a/src/common/utils/nt.hpp b/src/common/utils/nt.hpp new file mode 100644 index 00000000..86001bea --- /dev/null +++ b/src/common/utils/nt.hpp @@ -0,0 +1,110 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include +#include + +namespace utils::nt +{ + class library final + { + public: + static library load(const std::string& name); + static library load(const std::filesystem::path& path); + static library get_by_address(void* address); + + library(); + explicit library(const std::string& name); + explicit library(HMODULE handle); + + library(const library& a) : module_(a.module_) + { + } + + bool operator!=(const library& obj) const { return !(*this == obj); }; + bool operator==(const library& obj) const; + + operator bool() const; + operator HMODULE() const; + + void unprotect() const; + void* get_entry_point() const; + size_t get_relative_entry_point() const; + + bool is_valid() const; + std::string get_name() const; + std::string get_path() const; + std::string get_folder() const; + std::uint8_t* get_ptr() const; + void free(); + + HMODULE get_handle() const; + + template + T get_proc(const std::string& process) const + { + if (!this->is_valid()) T{}; + return reinterpret_cast(GetProcAddress(this->module_, process.data())); + } + + template + std::function get(const std::string& process) const + { + if (!this->is_valid()) return std::function(); + return static_cast(this->get_proc(process)); + } + + template + T invoke(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_pascal(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_this(const std::string& process, void* this_ptr, Args ... args) const + { + auto method = this->get(this_ptr, process); + if (method) return method(args...); + return T(); + } + + std::vector get_section_headers() const; + + PIMAGE_NT_HEADERS get_nt_headers() const; + PIMAGE_DOS_HEADER get_dos_header() const; + PIMAGE_OPTIONAL_HEADER get_optional_header() const; + + void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const; + + private: + HMODULE module_; + }; + + __declspec(noreturn) void raise_hard_exception(); + std::string load_resource(int id); + + void relaunch_self(); + __declspec(noreturn) void terminate(uint32_t code = 0); +} diff --git a/src/common/utils/signature.cpp b/src/common/utils/signature.cpp new file mode 100644 index 00000000..9bb8c621 --- /dev/null +++ b/src/common/utils/signature.cpp @@ -0,0 +1,212 @@ +#include "signature.hpp" +#include +#include + +#include + +namespace utils::hook +{ + void signature::load_pattern(const std::string& pattern) + { + this->mask_.clear(); + this->pattern_.clear(); + + uint8_t nibble = 0; + auto has_nibble = false; + + for (auto val : pattern) + { + if (val == ' ') continue; + if (val == '?') + { + this->mask_.push_back(val); + this->pattern_.push_back(0); + } + else + { + if ((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val > 'f')) + { + throw std::runtime_error("Invalid pattern"); + } + + char str[] = {val, 0}; + const auto current_nibble = static_cast(strtol(str, nullptr, 16)); + + if (!has_nibble) + { + has_nibble = true; + nibble = current_nibble; + } + else + { + has_nibble = false; + const uint8_t byte = current_nibble | (nibble << 4); + + this->mask_.push_back('x'); + this->pattern_.push_back(byte); + } + } + } + + while (!this->mask_.empty() && this->mask_.back() == '?') + { + this->mask_.pop_back(); + this->pattern_.pop_back(); + } + + if (this->has_sse_support()) + { + while (this->pattern_.size() < 16) + { + this->pattern_.push_back(0); + } + } + + if (has_nibble) + { + throw std::runtime_error("Invalid pattern"); + } + } + + std::vector signature::process_range(uint8_t* start, const size_t length) const + { + if (this->has_sse_support()) return this->process_range_vectorized(start, length); + return this->process_range_linear(start, length); + } + + std::vector signature::process_range_linear(uint8_t* start, const size_t length) const + { + std::vector result; + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + + size_t j = 0; + for (; j < this->mask_.size(); ++j) + { + if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) + { + break; + } + } + + if (j == this->mask_.size()) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + std::vector signature::process_range_vectorized(uint8_t* start, const size_t length) const + { + std::vector result; + __declspec(align(16)) char desired_mask[16] = {0}; + + for (size_t i = 0; i < this->mask_.size(); i++) + { + desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; + } + + const auto mask = _mm_load_si128(reinterpret_cast(desired_mask)); + const auto comparand = _mm_loadu_si128(reinterpret_cast(this->pattern_.data())); + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + const auto value = _mm_loadu_si128(reinterpret_cast(address)); + const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast(this->mask_.size()), + _SIDD_CMP_EQUAL_EACH); + + const auto matches = _mm_and_si128(mask, comparison); + const auto equivalence = _mm_xor_si128(mask, matches); + + if (_mm_test_all_zeros(equivalence, equivalence)) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + signature::signature_result signature::process() const + { + const auto range = this->length_ - this->mask_.size(); + const auto cores = std::max(1u, std::thread::hardware_concurrency()); + + if (range <= cores * 10ull) return this->process_serial(); + return this->process_parallel(); + } + + signature::signature_result signature::process_serial() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + return {this->process_range(this->start_, this->length_ - sub)}; + } + + signature::signature_result signature::process_parallel() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + const auto range = this->length_ - sub; + const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); + // Only use half of the available cores + const auto grid = range / cores; + + std::mutex mutex; + std::vector result; + std::vector threads; + + for (auto i = 0u; i < cores; ++i) + { + const auto start = this->start_ + (grid * i); + const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; + threads.emplace_back([&, start, length]() + { + auto local_result = this->process_range(start, length); + if (local_result.empty()) return; + + std::lock_guard _(mutex); + for (const auto& address : local_result) + { + result.push_back(address); + } + }); + } + + for (auto& t : threads) + { + if (t.joinable()) + { + t.join(); + } + } + + std::sort(result.begin(), result.end()); + return {std::move(result)}; + } + + bool signature::has_sse_support() const + { + if (this->mask_.size() <= 16) + { + int cpu_id[4]; + __cpuid(cpu_id, 0); + + if (cpu_id[0] >= 1) + { + __cpuidex(cpu_id, 1, 0); + return (cpu_id[2] & (1 << 20)) != 0; + } + } + + return false; + } +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len) +{ + return utils::hook::signature(std::string(str, len)).process(); +} diff --git a/src/common/utils/signature.hpp b/src/common/utils/signature.hpp new file mode 100644 index 00000000..a3728327 --- /dev/null +++ b/src/common/utils/signature.hpp @@ -0,0 +1,73 @@ +#pragma once +#include "nt.hpp" +#include + +namespace utils::hook +{ + class signature final + { + public: + class signature_result + { + public: + signature_result(std::vector&& matches) : matches_(std::move(matches)) + { + } + + [[nodiscard]] uint8_t* get(const size_t index) const + { + if (index >= this->count()) + { + throw std::runtime_error("Invalid index"); + } + + return reinterpret_cast(this->matches_[index]); + } + + [[nodiscard]] size_t count() const + { + return this->matches_.size(); + } + + private: + std::vector matches_; + }; + + explicit signature(const std::string& pattern, const nt::library library = {}) + : signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) + { + } + + signature(const std::string& pattern, void* start, void* end) + : signature(pattern, start, size_t(end) - size_t(start)) + { + } + + signature(const std::string& pattern, void* start, const size_t length) + : start_(static_cast(start)), length_(length) + { + this->load_pattern(pattern); + } + + signature_result process() const; + + private: + std::string mask_; + std::basic_string pattern_; + + uint8_t* start_; + size_t length_; + + void load_pattern(const std::string& pattern); + + signature_result process_parallel() const; + signature_result process_serial() const; + std::vector process_range(uint8_t* start, size_t length) const; + std::vector process_range_linear(uint8_t* start, size_t length) const; + std::vector process_range_vectorized(uint8_t* start, size_t length) const; + + bool has_sse_support() const; + }; +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, size_t len); diff --git a/src/common/utils/smbios.cpp b/src/common/utils/smbios.cpp new file mode 100644 index 00000000..a3282c28 --- /dev/null +++ b/src/common/utils/smbios.cpp @@ -0,0 +1,94 @@ +#include "smbios.hpp" +#include "memory.hpp" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +namespace utils::smbios +{ + namespace + { +#pragma warning(push) +#pragma warning(disable: 4200) + struct RawSMBIOSData + { + BYTE Used20CallingMethod; + BYTE SMBIOSMajorVersion; + BYTE SMBIOSMinorVersion; + BYTE DmiRevision; + DWORD Length; + BYTE SMBIOSTableData[]; + }; + + typedef struct + { + BYTE type; + BYTE length; + WORD handle; + } dmi_header; +#pragma warning(pop) + + std::vector get_smbios_data() + { + DWORD size = 0; + std::vector data{}; + + size = GetSystemFirmwareTable('RSMB', 0, nullptr, size); + data.resize(size); + GetSystemFirmwareTable('RSMB', 0, data.data(), size); + + return data; + } + + std::string parse_uuid(const uint8_t* data) + { + if (utils::memory::is_set(data, 0, 16) || utils::memory::is_set(data, -1, 16)) + { + return {}; + } + + char uuid[16] = {0}; + *reinterpret_cast(uuid + 0) = + _byteswap_ulong(*reinterpret_cast(data + 0)); + *reinterpret_cast(uuid + 4) = + _byteswap_ushort(*reinterpret_cast(data + 4)); + *reinterpret_cast(uuid + 6) = + _byteswap_ushort(*reinterpret_cast(data + 6)); + memcpy(uuid + 8, data + 8, 8); + + return std::string(uuid, sizeof(uuid)); + } + } + + std::string get_uuid() + { + auto smbios_data = get_smbios_data(); + auto* raw_data = reinterpret_cast(smbios_data.data()); + + auto* data = raw_data->SMBIOSTableData; + for (DWORD i = 0; i + sizeof(dmi_header) < raw_data->Length;) + { + auto* header = reinterpret_cast(data + i); + if (header->length < 4) + { + return {}; + } + + if (header->type == 0x01 && header->length >= 0x19) + { + return parse_uuid(data + i + 0x8); + } + + i += header->length; + while ((i + 1) < raw_data->Length && *reinterpret_cast(data + i) != 0) + { + ++i; + } + + i += 2; + } + + return {}; + } +} diff --git a/src/common/utils/smbios.hpp b/src/common/utils/smbios.hpp new file mode 100644 index 00000000..bbd1939d --- /dev/null +++ b/src/common/utils/smbios.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::smbios +{ + std::string get_uuid(); +} diff --git a/src/common/utils/string.cpp b/src/common/utils/string.cpp new file mode 100644 index 00000000..653ecff2 --- /dev/null +++ b/src/common/utils/string.cpp @@ -0,0 +1,179 @@ +#include "string.hpp" +#include +#include +#include + +#include "nt.hpp" + +namespace utils::string +{ + const char* va(const char* fmt, ...) + { + static thread_local va_provider<8, 256> provider; + + va_list ap; + va_start(ap, fmt); + + const char* result = provider.get(fmt, ap); + + va_end(ap); + return result; + } + + std::vector split(const std::string& s, const char delim) + { + std::stringstream ss(s); + std::string item; + std::vector elems; + + while (std::getline(ss, item, delim)) + { + elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) + } + + return elems; + } + + std::string to_lower(std::string text) + { + std::transform(text.begin(), text.end(), text.begin(), [](const char input) + { + return static_cast(tolower(input)); + }); + + return text; + } + + std::string to_upper(std::string text) + { + std::transform(text.begin(), text.end(), text.begin(), [](const char input) + { + return static_cast(toupper(input)); + }); + + return text; + } + + bool starts_with(const std::string& text, const std::string& substring) + { + return text.find(substring) == 0; + } + + bool ends_with(const std::string& text, const std::string& substring) + { + if (substring.size() > text.size()) return false; + return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); + } + + std::string dump_hex(const std::string& data, const std::string& separator) + { + std::string result; + + for (unsigned int i = 0; i < data.size(); ++i) + { + if (i > 0) + { + result.append(separator); + } + + result.append(va("%02X", data[i] & 0xFF)); + } + + return result; + } + + std::string get_clipboard_data() + { + if (OpenClipboard(nullptr)) + { + std::string data; + + auto* const clipboard_data = GetClipboardData(1u); + if (clipboard_data) + { + auto* const cliptext = static_cast(GlobalLock(clipboard_data)); + if (cliptext) + { + data.append(cliptext); + GlobalUnlock(clipboard_data); + } + } + CloseClipboard(); + + return data; + } + return {}; + } + + void strip(const char* in, char* out, int max) + { + if (!in || !out) return; + + max--; + auto current = 0; + while (*in != 0 && current < max) + { + const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48); + + if (*in == '^' && (color_index != 7 || *(in + 1) == '7')) + { + ++in; + } + else + { + *out = *in; + ++out; + ++current; + } + + ++in; + } + *out = '\0'; + } + +#pragma warning(push) +#pragma warning(disable: 4100) + std::string convert(const std::wstring& wstr) + { + std::string result; + result.reserve(wstr.size()); + + for (const auto& chr : wstr) + { + result.push_back(static_cast(chr)); + } + + return result; + } + + std::wstring convert(const std::string& str) + { + std::wstring result; + result.reserve(str.size()); + + for (const auto& chr : str) + { + result.push_back(static_cast(chr)); + } + + return result; + } +#pragma warning(pop) + + std::string replace(std::string str, const std::string& from, const std::string& to) + { + if (from.empty()) + { + return str; + } + + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + return str; + } +} diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp new file mode 100644 index 00000000..20fa4827 --- /dev/null +++ b/src/common/utils/string.hpp @@ -0,0 +1,100 @@ +#pragma once +#include "memory.hpp" +#include + +#ifndef ARRAYSIZE +template +size_t ARRAYSIZE(Type (&)[n]) { return n; } +#endif + +namespace utils::string +{ + template + class va_provider final + { + public: + static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); + + va_provider() : current_buffer_(0) + { + } + + char* get(const char* format, const va_list ap) + { + ++this->current_buffer_ %= ARRAYSIZE(this->string_pool_); + auto entry = &this->string_pool_[this->current_buffer_]; + + if (!entry->size || !entry->buffer) + { + throw std::runtime_error("String pool not initialized"); + } + + while (true) + { + const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + if (res > 0) break; // Success + if (res == 0) return nullptr; // Error + + entry->double_size(); + } + + return entry->buffer; + } + + private: + class entry final + { + public: + explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr) + { + if (this->size < MinBufferSize) this->size = MinBufferSize; + this->allocate(); + } + + ~entry() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->size = 0; + this->buffer = nullptr; + } + + void allocate() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->buffer = memory::get_allocator()->allocate_array(this->size + 1); + } + + void double_size() + { + this->size *= 2; + this->allocate(); + } + + size_t size; + char* buffer; + }; + + size_t current_buffer_; + entry string_pool_[Buffers]; + }; + + const char* va(const char* fmt, ...); + + std::vector split(const std::string& s, char delim); + + std::string to_lower(std::string text); + std::string to_upper(std::string text); + bool starts_with(const std::string& text, const std::string& substring); + bool ends_with(const std::string& text, const std::string& substring); + + std::string dump_hex(const std::string& data, const std::string& separator = " "); + + std::string get_clipboard_data(); + + void strip(const char* in, char* out, int max); + + std::string convert(const std::wstring& wstr); + std::wstring convert(const std::string& str); + + std::string replace(std::string str, const std::string& from, const std::string& to); +} diff --git a/src/common/utils/thread.cpp b/src/common/utils/thread.cpp new file mode 100644 index 00000000..7239b536 --- /dev/null +++ b/src/common/utils/thread.cpp @@ -0,0 +1,128 @@ +#include "thread.hpp" +#include "string.hpp" + +#include + +#include + +namespace utils::thread +{ + bool set_name(const HANDLE t, const std::string& name) + { + const nt::library kernel32("kernel32.dll"); + if (!kernel32) + { + return false; + } + + const auto set_description = kernel32.get_proc("SetThreadDescription"); + if (!set_description) + { + return false; + } + + return SUCCEEDED(set_description(t, string::convert(name).data())); + } + + bool set_name(const DWORD id, const std::string& name) + { + auto* const t = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, id); + if (!t) return false; + + const auto _ = gsl::finally([t]() + { + CloseHandle(t); + }); + + return set_name(t, name); + } + + bool set_name(std::thread& t, const std::string& name) + { + return set_name(t.native_handle(), name); + } + + bool set_name(const std::string& name) + { + return set_name(GetCurrentThread(), name); + } + + std::vector get_thread_ids() + { + auto* const h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId()); + if (h == INVALID_HANDLE_VALUE) + { + return {}; + } + + const auto _ = gsl::finally([h]() + { + CloseHandle(h); + }); + + THREADENTRY32 entry{}; + entry.dwSize = sizeof(entry); + if (!Thread32First(h, &entry)) + { + return {}; + } + + std::vector ids{}; + + do + { + const auto check_size = entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + + sizeof(entry.th32OwnerProcessID); + entry.dwSize = sizeof(entry); + + if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId()) + { + ids.emplace_back(entry.th32ThreadID); + } + } + while (Thread32Next(h, &entry)); + + return ids; + } + + void for_each_thread(const std::function& callback) + { + const auto ids = get_thread_ids(); + + for (const auto& id : ids) + { + auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id); + if (thread != nullptr) + { + const auto _ = gsl::finally([thread]() + { + CloseHandle(thread); + }); + + callback(thread); + } + } + } + + void suspend_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + SuspendThread(thread); + } + }); + } + + void resume_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + ResumeThread(thread); + } + }); + } +} diff --git a/src/common/utils/thread.hpp b/src/common/utils/thread.hpp new file mode 100644 index 00000000..4ea3598c --- /dev/null +++ b/src/common/utils/thread.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include "nt.hpp" + +namespace utils::thread +{ + bool set_name(HANDLE t, const std::string& name); + bool set_name(DWORD id, const std::string& name); + bool set_name(std::thread& t, const std::string& name); + bool set_name(const std::string& name); + + template + std::thread create_named_thread(const std::string& name, Args&&... args) + { + auto t = std::thread(std::forward(args)...); + set_name(t, name); + return t; + } + + std::vector get_thread_ids(); + void for_each_thread(const std::function& callback); + + void suspend_other_threads(); + void resume_other_threads(); +} diff --git a/src/common/utils/toast.cpp b/src/common/utils/toast.cpp new file mode 100644 index 00000000..8d23af25 --- /dev/null +++ b/src/common/utils/toast.cpp @@ -0,0 +1,109 @@ +#include "toast.hpp" +#include "string.hpp" + +#pragma warning(push) +#pragma warning(disable: 6387) +#include +#pragma warning(pop) + +namespace utils +{ + namespace + { + bool initialize() + { + static bool initialized = false; + static bool success = false; + if (initialized) + { + return success; + } + + initialized = true; + auto* instance = WinToastLib::WinToast::instance(); + if (!instance) + { + success = false; + return success; + } + + instance->setAppName(L"S1x"); + instance->setAppUserModelId( + WinToastLib::WinToast::configureAUMI(L"X Labs", L"s1x", L"", L"20201212")); + + WinToastLib::WinToast::WinToastError error; + success = instance->initialize(&error); + + return success; + } + + class toast_handler : public WinToastLib::IWinToastHandler + { + public: + void toastActivated() const override + { + } + + void toastActivated(const int /*actionIndex*/) const override + { + } + + void toastFailed() const override + { + } + + void toastDismissed(WinToastDismissalReason /*state*/) const override + { + } + }; + } + + toast::toast(const int64_t id) + : id_(id) + { + } + + toast::operator bool() const + { + return this->id_ >= 0; + } + + void toast::hide() const + { + if (this->operator bool()) + { + WinToastLib::WinToast::instance()->hideToast(this->id_); + } + } + + toast toast::show(const std::string& title, const std::string& text) + { + if (!initialize()) + { + return toast{-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::Text02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + + return toast{WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } + + toast toast::show(const std::string& title, const std::string& text, const std::string& image) + { + if (!initialize()) + { + return {-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::ImageAndText02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + toast_template.setImagePath(string::convert(image)); + + return {WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } +} diff --git a/src/common/utils/toast.hpp b/src/common/utils/toast.hpp new file mode 100644 index 00000000..739c5c86 --- /dev/null +++ b/src/common/utils/toast.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace utils +{ + class toast + { + public: + static toast show(const std::string& title, const std::string& text); + static toast show(const std::string& title, const std::string& text, const std::string& image); + + operator bool() const; + void hide() const; + + private: + toast(int64_t id); + int64_t id_; + }; +} diff --git a/src/runner/debugger.cpp b/src/runner/debugger.cpp new file mode 100644 index 00000000..d58149b7 --- /dev/null +++ b/src/runner/debugger.cpp @@ -0,0 +1,95 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include "debugger.hpp" + +namespace +{ + bool acquire_debug_privilege() + { + TOKEN_PRIVILEGES token_privileges; + ZeroMemory(&token_privileges, sizeof(token_privileges)); + token_privileges.PrivilegeCount = 1; + + HANDLE token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) + { + return false; + } + + if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid)) + { + CloseHandle(token); + return false; + } + + token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + DWORD size; + if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, nullptr, &size)) + { + CloseHandle(token); + return false; + } + + return CloseHandle(token) != FALSE; + } +} + +debugger::debugger(const unsigned long process_id, const bool start) +{ + if (!start) + { + return; + } + + this->runner_ = std::thread([this, process_id]() + { + this->terminate_ = false; + this->run(process_id); + }); +} + +debugger::~debugger() +{ + this->terminate_ = true; + if (this->runner_.joinable()) + { + this->runner_.join(); + } +} + +void debugger::run(const unsigned long process_id) const +{ + acquire_debug_privilege(); + if (!DebugActiveProcess(process_id)) + { + return; + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + + DEBUG_EVENT event; + while (!this->terminate_ && WaitForDebugEvent(&event,INFINITE)) + { + if (event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + continue; + } + + if (event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + break; + } + +#ifdef DEV_BUILD + if (event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + OutputDebugStringA("Debugger attached!\n"); + } +#endif + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + } +} diff --git a/src/runner/debugger.hpp b/src/runner/debugger.hpp new file mode 100644 index 00000000..99d1073e --- /dev/null +++ b/src/runner/debugger.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +class debugger +{ +public: + debugger(unsigned long process_id, bool start); + ~debugger(); + +private: + volatile bool terminate_ = false; + std::thread runner_; + + void run(unsigned long process_id) const; +}; diff --git a/src/runner/resource.rc b/src/runner/resource.rc new file mode 100644 index 00000000..ba86c6f4 --- /dev/null +++ b/src/runner/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "X Labs" + VALUE "FileDescription", "Steam mod runner" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "Runner" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "runner.exe" + VALUE "ProductName", "runner" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +102 ICON "../client/resources/icon.ico" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/runner/runner.cpp b/src/runner/runner.cpp new file mode 100644 index 00000000..01c32d2e --- /dev/null +++ b/src/runner/runner.cpp @@ -0,0 +1,26 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "debugger.hpp" + +int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int) +{ + const auto* const command = "-proc "; + const char* parent_proc = strstr(GetCommandLineA(), command); + + if (parent_proc) + { + const auto pid = DWORD(atoi(parent_proc + strlen(command))); + auto* const process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid); + if (process_handle) + { + //debugger _(pid, strstr(GetCommandLineA(), "-debug ") != nullptr); + WaitForSingleObject(process_handle, INFINITE); + CloseHandle(process_handle); + return 0; + } + } + + return 1; +} diff --git a/src/tlsdll/dllmain.cpp b/src/tlsdll/dllmain.cpp new file mode 100644 index 00000000..56d31a66 --- /dev/null +++ b/src/tlsdll/dllmain.cpp @@ -0,0 +1,7 @@ +#define TLS_PAYLOAD_SIZE 0x2000 +thread_local char tls_data[TLS_PAYLOAD_SIZE]; + +__declspec(dllexport) void* get_tls_data() +{ + return &tls_data[0]; +} diff --git a/src/tlsdll/resource.rc b/src/tlsdll/resource.rc new file mode 100644 index 00000000..2a778f5f --- /dev/null +++ b/src/tlsdll/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "X Labs" + VALUE "FileDescription", "TLS index allocation dll" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "TLS DLL" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "tlsdll.dll" + VALUE "ProductName", "tlsdll" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +// Nothing here + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/premake5.exe b/tools/premake5.exe new file mode 100644 index 00000000..0e4954fd Binary files /dev/null and b/tools/premake5.exe differ diff --git a/tools/protoc.exe b/tools/protoc.exe new file mode 100644 index 00000000..87bf60b6 Binary files /dev/null and b/tools/protoc.exe differ