mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-23 04:52:29 +00:00
Compare commits
818 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d3ddcb574 | |||
| ed09281f66 | |||
| 8e51bf8b19 | |||
| 844efa7e20 | |||
| fa3a5c7a72 | |||
| 93db35658a | |||
| d45a57056a | |||
| ff40dbc710 | |||
| 7523c972fa | |||
| 4320c1429e | |||
| dc8bfddd7a | |||
| a8cdfb07e6 | |||
| 011de2692e | |||
| 0cc76ab489 | |||
| c5c9985e0d | |||
| a7e95d7818 | |||
| 933d856b5b | |||
| 285cc3af29 | |||
| de8ae7afa6 | |||
| 1b272cba50 | |||
| e35e38b039 | |||
| 9215ba7a8a | |||
| 3f4334985b | |||
| 21002c2e8a | |||
| 445f967ed6 | |||
| 57a15d473f | |||
| df92c578d2 | |||
| 3af43a8e8d | |||
| 647bcce30b | |||
| 25b527156c | |||
| b3ab7deb80 | |||
| 4a9cb07132 | |||
| 8f1b62d166 | |||
| 7e9994b5d4 | |||
| f2f8fae58b | |||
| 3a1e88f9ed | |||
| 4e101aa6d6 | |||
| ef411ee154 | |||
| 93b3f97f24 | |||
| c1d4cb90b9 | |||
| e939c82717 | |||
| 7d03479f41 | |||
| ff440e16b6 | |||
| c6bb0f6495 | |||
| d142bc552a | |||
| 7dc57c3b05 | |||
| ea9b09cf1f | |||
| 968278d8f8 | |||
| aa910864c8 | |||
| 1499f3338e | |||
| fef2f9fc61 | |||
| 8afbc585da | |||
| 457ce85746 | |||
| 49c093dc62 | |||
| beccd557a8 | |||
| e11610b9fa | |||
| 3e652b98bc | |||
| d43af28de4 | |||
| f5106b6af6 | |||
| 3386d13d2d | |||
| d1b7c675f9 | |||
| a40e1cf893 | |||
| c81ab00764 | |||
| 025ef5e1d6 | |||
| 1f29a40e6d | |||
| 66cadd599b | |||
| aa0345c1f1 | |||
| 73b11c5036 | |||
| efbeb2dbb7 | |||
| 8c97c20727 | |||
| f2d07e5c69 | |||
| 64d5b54e65 | |||
| 89b3a04eb3 | |||
| 1bafe0b6b3 | |||
| 82762c3f5a | |||
| 2742eca119 | |||
| 8fc7f3a732 | |||
| 39ce0178f9 | |||
| 3d2f560436 | |||
| a0768d2d28 | |||
| 9009a7aa23 | |||
| 67b03b4e31 | |||
| b08975aefb | |||
| ea3a7cae0b | |||
| 81314a3315 | |||
| d33cfad567 | |||
| c1698a5bdd | |||
| 2a094e8792 | |||
| 4a0725e278 | |||
| 218ffbb2c5 | |||
| 3e30e78158 | |||
| ff2af0c49e | |||
| cd5697bc81 | |||
| b1571cd062 | |||
| 3e5d0a0601 | |||
| 6a80a061dd | |||
| 509fd0615e | |||
| da5e672a28 | |||
| 7090382074 | |||
| 26eabcd7a4 | |||
| 60091015d3 | |||
| 470392021b | |||
| 90984c3215 | |||
| da2296d416 | |||
| c9221f239c | |||
| f4edc69a87 | |||
| 7d04608c4d | |||
| 32be049d96 | |||
| 26fd52fb06 | |||
| 5dd849ac75 | |||
| f484fe4176 | |||
| 3d20c0d6aa | |||
| 0297045cc5 | |||
| cb90d00832 | |||
| f752b57a55 | |||
| 2bb15271c5 | |||
| 6976e27501 | |||
| c9f27d6f90 | |||
| cb129efcad | |||
| d653989b03 | |||
| ea9b373180 | |||
| a4e006fbfb | |||
| 1ffdd4cb34 | |||
| 7f7ba2e6c2 | |||
| 090086f50c | |||
| 407b003f7d | |||
| b6d315d803 | |||
| 6927177291 | |||
| 31ede355a8 | |||
| 0df84e1ee6 | |||
| 0d509a7f3a | |||
| 4c2271ff69 | |||
| ca2072e7bf | |||
| e1eb1ff738 | |||
| 25f5898bae | |||
| 934ff3dadf | |||
| e4ff76dceb | |||
| 6960a1a682 | |||
| d4174ca236 | |||
| 7854130a93 | |||
| e9c63c7d94 | |||
| 27e0665aae | |||
| ea2f431fce | |||
| 8bdcf7cb94 | |||
| 87cb74b851 | |||
| 26c267db1b | |||
| 99f8e6cef5 | |||
| b6917ec782 | |||
| eb51550109 | |||
| 9d1ace627c | |||
| ec3ef411a1 | |||
| 1394b6a4d2 | |||
| 7f41547963 | |||
| 2e4071cdcf | |||
| dc475a1bd7 | |||
| 59ad91a140 | |||
| abc27ab423 | |||
| c975dc2412 | |||
| e085f271f5 | |||
| 5a6314e1a9 | |||
| dc45e0d280 | |||
| 2e2c4d64fe | |||
| c5add503ab | |||
| fe2dcb6544 | |||
| 4fe44f4cb6 | |||
| 63a8d2d641 | |||
| abcb5d069f | |||
| d6b954a4b9 | |||
| 2415645b86 | |||
| e77a83f8c3 | |||
| a5d564a6fb | |||
| 2f4c91824e | |||
| 53e6f931c9 | |||
| a6efb1e8b5 | |||
| b2757143a8 | |||
| 6e5da0e558 | |||
| 6b8e74a29f | |||
| 203e63101a | |||
| 91257d599b | |||
| 491b358e28 | |||
| 180c3088ca | |||
| 97e4547192 | |||
| 0caee9026a | |||
| 0be7ead1d1 | |||
| 950489bc34 | |||
| 45da8cab61 | |||
| e778041198 | |||
| 97e50ced93 | |||
| 4491bb9a70 | |||
| 04fba27467 | |||
| fa47dd7f93 | |||
| b3fb5f00ab | |||
| e17fad9ae0 | |||
| bbdaacd3b0 | |||
| 61bd485449 | |||
| 4b405fe9fe | |||
| d5aaf7cee5 | |||
| 12e9e0f71d | |||
| 0a64e26672 | |||
| 11fc5a9e93 | |||
| 7bbcdfb479 | |||
| 3a530eb43b | |||
| 48a60114b7 | |||
| 06f1f36c95 | |||
| ccd9bd7d4c | |||
| fea6cbf633 | |||
| 460739d35c | |||
| 11e1edc99f | |||
| 7374660045 | |||
| 9e8d365ca7 | |||
| 14d69a0a14 | |||
| fe063637e9 | |||
| 232b1028d7 | |||
| 3624307385 | |||
| c0055cf357 | |||
| f9c1683d36 | |||
| 64df993c10 | |||
| 890ef696fe | |||
| 3f1848b01a | |||
| f7c4f1ff75 | |||
| dcb127f4b6 | |||
| 669b068978 | |||
| db2aeca38f | |||
| 1b3ca95f8c | |||
| c05baac551 | |||
| 939fc79d19 | |||
| a0e6fce057 | |||
| 452389b7a5 | |||
| dd184fa8b6 | |||
| 4a3e6b5edc | |||
| 7961d7afa8 | |||
| cc6bcf3295 | |||
| b73c2016cf | |||
| db7e8241ac | |||
| b7747b07db | |||
| 02ada0e496 | |||
| 7c819539c8 | |||
| e670c89163 | |||
| 9ecdf057db | |||
| b6448c840f | |||
| 0ba90df1f1 | |||
| 12dcbd0871 | |||
| b0be4ca8bd | |||
| 412eb5deaa | |||
| f030461bc7 | |||
| 8f5e7978ab | |||
| 2e55da2b2d | |||
| 16a8f88ae5 | |||
| 22d7ef6763 | |||
| 457e800c73 | |||
| 8393e50aa8 | |||
| b6497cdd6a | |||
| 218ef80f96 | |||
| a90d41480a | |||
| 67df6f62b7 | |||
| 4572dbc426 | |||
| e8cc160572 | |||
| 8c9adca852 | |||
| b53310e23b | |||
| 14f01dc2d7 | |||
| a4d6509e6d | |||
| fc835bfb0e | |||
| 9ec4e5ade0 | |||
| 6b65e93a06 | |||
| a0a28fef04 | |||
| 034feb4ff4 | |||
| 65c14b160e | |||
| c21d47f450 | |||
| 83ea9816b8 | |||
| e3f9b396ab | |||
| 2a6cf8c8e7 | |||
| be567af70d | |||
| 6494fbf916 | |||
| 2cc61ef8c1 | |||
| 5d7a7bb4b2 | |||
| 00f82f43a6 | |||
| d3ca636a70 | |||
| 01855d40df | |||
| 748602b04e | |||
| a97a9a0d1c | |||
| a78c754c0e | |||
| ef214f91e9 | |||
| 04a74df0b2 | |||
| c15bfe12eb | |||
| 5702f7bcd1 | |||
| 9a5bf53e11 | |||
| 69c6a7b89a | |||
| 2f0dbc5d15 | |||
| 93c79817cd | |||
| 3296287d70 | |||
| 774a7fa779 | |||
| 1ff4541a9f | |||
| 3448758c03 | |||
| ff4ccfa98f | |||
| d2c3c14ae0 | |||
| a470931fdd | |||
| 078db3460d | |||
| 0980a780d0 | |||
| 7f01bb509c | |||
| 4bb189cbf4 | |||
| b03e8ff0fb | |||
| 6179b7481e | |||
| 5f68e4a41a | |||
| e103422ca5 | |||
| 0cbfad975d | |||
| 2a20c69c69 | |||
| de2dfc1a7e | |||
| bad631df59 | |||
| e8f1aa253a | |||
| 889e57a5af | |||
| 5cfdeb928e | |||
| 7519b0225e | |||
| 04fdc54522 | |||
| f39155952f | |||
| 5acc181d64 | |||
| 2ae0b7dd3e | |||
| b0d4f095ef | |||
| 7c7a88650b | |||
| afaa8f4100 | |||
| 0d72295cc9 | |||
| 9d4f231619 | |||
| fcb0a47280 | |||
| 1e50f19f7e | |||
| 33bb5aa8e5 | |||
| 6a668f8aa5 | |||
| df499b22ab | |||
| 7bc00cb466 | |||
| 51f6108aab | |||
| c13f9f80d9 | |||
| 443abf9199 | |||
| 1556e05b2f | |||
| 1d645aa5f6 | |||
| 9f42da5bad | |||
| 4a8222f243 | |||
| db4c515853 | |||
| 462656a201 | |||
| ddd98be383 | |||
| 4ad3ebf36a | |||
| b5a2713a3a | |||
| 999fe10d86 | |||
| ce1472db1e | |||
| d6c6b78d8a | |||
| ee6c9a2ad7 | |||
| 3e4767269e | |||
| e0eb145081 | |||
| a6dd65435f | |||
| 26dc05c0dc | |||
| da20a6ab67 | |||
| 3949a31246 | |||
| e898be1ce9 | |||
| 2962575dda | |||
| 6a6045a21c | |||
| 717fe7dc8c | |||
| df69d12c0c | |||
| 99e49cb2ec | |||
| 5ee2856133 | |||
| 4a64048744 | |||
| 2ae795fd61 | |||
| 0829bc08b8 | |||
| 903a385229 | |||
| fafa33e190 | |||
| 90a01f7c53 | |||
| 19434197d4 | |||
| 18b62667f0 | |||
| 8ed7ca977f | |||
| 665e336946 | |||
| ccf8504dec | |||
| d107213fe1 | |||
| c115cbcd6a | |||
| 064ae7ba89 | |||
| 02302802b8 | |||
| 536e248424 | |||
| 5b56a23a8a | |||
| 97edb09fba | |||
| 85f7b10f90 | |||
| 0f49fbcfcd | |||
| e57979c3a8 | |||
| fc7c30977a | |||
| b3fd9dd88a | |||
| 4df9661903 | |||
| 8c363320d8 | |||
| d4afc78982 | |||
| 24de1d948a | |||
| ca0e85b4bc | |||
| 5b24d38d1e | |||
| 4a1d026215 | |||
| 5ef8f8c3a8 | |||
| 384de31989 | |||
| 5be3780a54 | |||
| 21e42714eb | |||
| 3474c00e7a | |||
| 3d6b0e5f74 | |||
| 9f619859d1 | |||
| 805a9c5f59 | |||
| 43329dc583 | |||
| 66fee56c47 | |||
| efb2ab57aa | |||
| 0a7d482299 | |||
| de047fb851 | |||
| 9836b5cf67 | |||
| c64591b8f7 | |||
| 3813162bac | |||
| 7099e17c7e | |||
| 2c75e8fcd4 | |||
| e8f01fb6ac | |||
| fd0764d4cb | |||
| 71b2bf6a64 | |||
| 2dcff247c8 | |||
| 93f19d3971 | |||
| bad44f35e2 | |||
| 4a339d49df | |||
| 57d0420399 | |||
| 90def9b882 | |||
| 84156829a7 | |||
| d210b1e5ff | |||
| 086538754e | |||
| 241f900dc4 | |||
| 604256a223 | |||
| 2dffc66c6f | |||
| 1bf24273d2 | |||
| c060280417 | |||
| bc6efd5f74 | |||
| efd6d2f9b1 | |||
| 9dd4cf71f1 | |||
| cfec31457c | |||
| 5ac5beb456 | |||
| 0e51131d67 | |||
| f9a87e26c9 | |||
| 9e16cd8ae8 | |||
| 9644f14746 | |||
| d9f545a5ec | |||
| 1cc32d92cf | |||
| 924e91cf64 | |||
| 9825c61a13 | |||
| 5a0a1b1ffd | |||
| a3bb7e7741 | |||
| a1251bdda8 | |||
| b90082d694 | |||
| a49fa42f35 | |||
| 7064a4156f | |||
| 106cb45b57 | |||
| 9a544650ee | |||
| 032d423add | |||
| 760b30ca0a | |||
| 6b08ca51cc | |||
| 268879b414 | |||
| 4c6dc960e4 | |||
| cc46b54f7f | |||
| 9e3b363d4a | |||
| b0d1dc5f04 | |||
| 158396937a | |||
| fb1467284c | |||
| 14addd4869 | |||
| 0a114fae9a | |||
| 2b224d42ad | |||
| 155ec9ac0d | |||
| 25b4b97c41 | |||
| 839f31b24d | |||
| 20728c31c4 | |||
| c6eb12ac16 | |||
| 34d21d4056 | |||
| d369b47ef4 | |||
| 404f7cada8 | |||
| 823e73336d | |||
| 0da6391be3 | |||
| 0348cb6b8e | |||
| b385a4385f | |||
| 6a9228ed6e | |||
| 8031bf0bcb | |||
| c1584da9cc | |||
| ee6f6f683c | |||
| 60707a14db | |||
| 54050924d8 | |||
| f727c9f75a | |||
| f410c89815 | |||
| 2e575652f6 | |||
| 8e831dce36 | |||
| 040c092795 | |||
| a25952910a | |||
| 66896a3121 | |||
| 4d2418af9d | |||
| 265b32f46f | |||
| 1cde55c535 | |||
| 369b5c2921 | |||
| bcc2e022dc | |||
| 0fef46a6c1 | |||
| b867d40774 | |||
| a489290eba | |||
| 549d731849 | |||
| 68a34565f9 | |||
| c05f951f81 | |||
| dc64561b3c | |||
| cb2aee2713 | |||
| 0730b6b588 | |||
| 826550acac | |||
| b71b3f5be0 | |||
| 1fe79f430c | |||
| e5dabe0afc | |||
| 5720ffbcb6 | |||
| 2b0c778ad1 | |||
| bf39a0540c | |||
| 08c8393988 | |||
| 8c12f7b431 | |||
| 037be84f38 | |||
| 4d355afe9d | |||
| 93eddf603b | |||
| 293f79268d | |||
| 7e35d5aa79 | |||
| f7e4fba584 | |||
| 01a0f906e1 | |||
| 0a11eaa092 | |||
| d0edb93d62 | |||
| 35c3778baf | |||
| abb41840f8 | |||
| cd63047e60 | |||
| 4fe5522212 | |||
| 0ccb18d017 | |||
| e010e41a83 | |||
| 886f80117c | |||
| 5c095ab87a | |||
| e8ca3f6942 | |||
| 706a06efb6 | |||
| 3335cacac1 | |||
| 1f0b2a8991 | |||
| a16f21d6fe | |||
| 900837f633 | |||
| d3e756287e | |||
| 7d0dd13d17 | |||
| ba5b901c16 | |||
| 3424ae2dde | |||
| 9aad8ae54c | |||
| 7cd6b4b8ab | |||
| 090019cf83 | |||
| d93ea9ed86 | |||
| a7b35594f8 | |||
| 29473aa7f5 | |||
| 03a27b02ff | |||
| f9ea7ddb62 | |||
| 40d1c33351 | |||
| ee2079ec35 | |||
| a90c760186 | |||
| fbb36a3e75 | |||
| bd29f1c5bb | |||
| a99e0a4b2c | |||
| be03628aa9 | |||
| f1a6006ee1 | |||
| dd40f2a0e6 | |||
| 7fa421d848 | |||
| 00658632de | |||
| eed45e5250 | |||
| 64c62c4f0a | |||
| ca0ae3cb98 | |||
| 9e3539295b | |||
| 7aa25f17f6 | |||
| e1c1d55ca5 | |||
| 403c54362e | |||
| a422484307 | |||
| c41f375129 | |||
| bd3e8b2afc | |||
| f5523b40d2 | |||
| 095f4fb56c | |||
| f8afadf0a9 | |||
| 9c23882d67 | |||
| 3510ba2493 | |||
| db7ab7a3ef | |||
| 6d13f46c40 | |||
| 2f90f26351 | |||
| 3341c0b7ab | |||
| 2587a7fed5 | |||
| 46fa2e589e | |||
| fc020b7580 | |||
| 933293098b | |||
| 4df9fa89bc | |||
| 09d1dc6a24 | |||
| 8fe02b5ed1 | |||
| 0d23ffe5e5 | |||
| 4c8b65ecc6 | |||
| 0c105a2b91 | |||
| 2253e43d2c | |||
| 5f244c2dd2 | |||
| 9e5a530f0f | |||
| ebf69e9b6e | |||
| c1ad086eaf | |||
| 143c4fe6aa | |||
| d9f437d90f | |||
| b15e73e1b2 | |||
| 6e1c4b768f | |||
| a80a6de59f | |||
| af4ee9f8d8 | |||
| c7dde7832d | |||
| 8c939ad8da | |||
| f322e85d4e | |||
| 7e13d07108 | |||
| 3e4231c662 | |||
| 039d4f09e3 | |||
| c544221838 | |||
| 16103b510d | |||
| 0b8b363c13 | |||
| 1531650b3a | |||
| 3a4ba6f422 | |||
| 501ea4b736 | |||
| aeda7127ec | |||
| 9c3c5b5230 | |||
| f962466573 | |||
| a6fa6084fa | |||
| 0c9c78fbab | |||
| 8fc665a3c1 | |||
| 7e7485be77 | |||
| a590ea1d52 | |||
| 2ed73199bf | |||
| d1430f6834 | |||
| 860b545fe3 | |||
| 8219cc9ea0 | |||
| d7ae3d5c6d | |||
| 6229852331 | |||
| 5bb27dd4c0 | |||
| 2f9a6daab5 | |||
| d5aecb228a | |||
| e811cb1e85 | |||
| c236c57a2c | |||
| db12c069ef | |||
| 4ea38bf896 | |||
| 0d1fa9e96e | |||
| 51c62d3b3e | |||
| 900e1aecf6 | |||
| ed6194ad19 | |||
| e6f58382de | |||
| 083d44d4fe | |||
| f12090d109 | |||
| f188c1394a | |||
| d9e5056657 | |||
| dce5f03e74 | |||
| 6ddd5db480 | |||
| 1338d21823 | |||
| 0fd4d82553 | |||
| bca04b969f | |||
| 89ba1270d9 | |||
| 337dc54eb9 | |||
| bc277ac296 | |||
| 7189bab848 | |||
| c3cb0b8cdf | |||
| ae4908b40c | |||
| 13a3afbfac | |||
| f5126222c2 | |||
| 70719852d6 | |||
| 46f993ef71 | |||
| 20efa83f73 | |||
| d3fac8a0cb | |||
| 8c707f9fe5 | |||
| c8218574cc | |||
| 3dfeda9cea | |||
| 1d06a4117a | |||
| b1c4e7c23f | |||
| 3872555332 | |||
| 86af0f0759 | |||
| 88e8b25fa1 | |||
| f7fb1c9fe1 | |||
| 91ea6462f2 | |||
| 3774dc50d9 | |||
| 0455868f66 | |||
| ef42e00df8 | |||
| a9c161011e | |||
| 423e6ae751 | |||
| 9a35cacf27 | |||
| e1d5274bd5 | |||
| ede3ed4df3 | |||
| 318e487515 | |||
| 7e0fe93039 | |||
| 7abc084cd1 | |||
| 5d5c2a4194 | |||
| 80fffb57b1 | |||
| 61b91d92c3 | |||
| 35d22913b9 | |||
| dbba22b153 | |||
| de7a632d67 | |||
| 85ae36ede5 | |||
| ecc34940b4 | |||
| a9cfacf54b | |||
| e7704f00f3 | |||
| 639f8e184a | |||
| 1d302f512e | |||
| 02c0a8fa7f | |||
| e928754df3 | |||
| 200c6cccaf | |||
| d6db35b84e | |||
| d0e7e8c4c4 | |||
| 29247a0f45 | |||
| 2d364e2fd1 | |||
| f6c5560e9c | |||
| fb4d4e1382 | |||
| 9a7770377d | |||
| 15b2baa663 | |||
| 253f4c07e0 | |||
| f7ae5850f0 | |||
| ea9a02bec4 | |||
| 31d57342e1 | |||
| 290ebf3b26 | |||
| 25f8ee2084 | |||
| 1002a5659b | |||
| dced08cf97 | |||
| b91d879662 | |||
| 1d1ffc66fe | |||
| 4423a9f160 | |||
| 217a6b6344 | |||
| 99052aec8b | |||
| 45c4fe55f0 | |||
| 52e1bc943a | |||
| dd3c76e9d2 | |||
| 5e6741cf17 | |||
| 8373dd1cb9 | |||
| 9f65159cb2 | |||
| f143d0a75f | |||
| 19e7f0a6b1 | |||
| 3c361be739 | |||
| 3424fe78f5 | |||
| 0dfa067974 | |||
| 0c56586f3b | |||
| 37af643b61 | |||
| f67767f28e | |||
| e2dfbeb116 | |||
| 5173a9179b | |||
| 0003f6f863 | |||
| 856aa51cb8 | |||
| 7ea77ee027 | |||
| ce4d96dc91 | |||
| bd95daa1f3 | |||
| 93d8471487 | |||
| 730cd3f28a | |||
| bb58a9cd20 | |||
| 8c994fef97 | |||
| 6ff52f94c4 | |||
| b5035d7e03 | |||
| 8f1b87c5e4 | |||
| e72ec4ae56 | |||
| fd2fc76706 | |||
| f668949c24 | |||
| 36887203d3 | |||
| e5ad9264d0 | |||
| df57138a61 | |||
| aa506110e1 | |||
| 2c656c4110 | |||
| 8d184fc6c0 | |||
| 9c967c24b8 | |||
| 31e5622dad | |||
| 8a449b0152 | |||
| 5f4a8d17f5 | |||
| c5c57b7541 | |||
| 3cb13969ff | |||
| fca99bb274 | |||
| 815593b9bc | |||
| 33b95c42c2 | |||
| e01ac39887 | |||
| 7e7358e9b6 | |||
| de63eaa4b2 | |||
| 3d7c43e92f | |||
| 69e90c1739 | |||
| 13b2af1a91 | |||
| 9c7dd70b5f | |||
| 070bf64d6a | |||
| f6dbdf5db8 | |||
| a3928ec504 | |||
| 8d1dd52db3 | |||
| 2218f46b5b | |||
| 53dcd14534 | |||
| dcbc9a358f | |||
| b512447448 | |||
| 444a4f6744 | |||
| 43ec9dc815 | |||
| 9e836a9780 | |||
| 3bc5d4b125 | |||
| 9f033df196 | |||
| 16ee25224d | |||
| 56510e6383 | |||
| bf43bda1e2 | |||
| 5708164511 | |||
| 7abb02655d | |||
| cb08c02537 | |||
| dea94ce63d | |||
| bd302b8394 | |||
| 221140c3c5 | |||
| 7092183103 | |||
| bbbebdd346 | |||
| 05723ad1e8 | |||
| 4c7a625d7c | |||
| 1b82e6b283 | |||
| 0240a9cc76 | |||
| eb02525d36 | |||
| d7097e84ff | |||
| 3de65d46b4 | |||
| 303b35a755 | |||
| a9e218acfa | |||
| 0f2da56b04 | |||
| f3f8a50d3c | |||
| bc72641eef | |||
| 18bfee5616 | |||
| 6c8930eacd | |||
| e18d4a81c5 | |||
| 77c3841a49 | |||
| 832bffa811 | |||
| 267472fc91 | |||
| 44f760d177 | |||
| 50fc4d68aa | |||
| ee167bbc64 | |||
| b20d0b84f6 | |||
| 267d73ca27 | |||
| c1626da40d | |||
| 554b41d424 | |||
| 714fb032e9 | |||
| 74dfc1ae3c | |||
| 6b1e3d94f8 | |||
| f357361474 | |||
| f8e7576ae7 | |||
| 19791195e5 | |||
| 9d766bf5dc | |||
| 7ac8fe17e5 | |||
| 959a17daea | |||
| 90406e0328 | |||
| e883703b2f |
@@ -1,21 +0,0 @@
|
||||
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.101.1/containers/ubuntu-18.04-git
|
||||
{
|
||||
"name": "Ubuntu 18.04 EQEMU",
|
||||
// Moved from dockerfile to image so it builds faster
|
||||
"image": "eqemu/devcontainer:0.0.2",
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
|
||||
"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": ["ms-vscode.cpptools", "ms-azuretools.vscode-docker"],
|
||||
"mounts": ["source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"],
|
||||
"remoteEnv": {
|
||||
"HOST_PROJECT_PATH": "${localWorkspaceFolder}"
|
||||
}
|
||||
}
|
||||
+81
-10
@@ -1,7 +1,8 @@
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: EQEmulator Server Linux CI
|
||||
name: Build Linux
|
||||
|
||||
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
|
||||
concurrency:
|
||||
@@ -10,18 +11,88 @@ concurrency:
|
||||
volumes:
|
||||
- name: cache
|
||||
host:
|
||||
path: /var/lib/cache
|
||||
path: /var/lib/cache-release
|
||||
|
||||
steps:
|
||||
- name: server-build
|
||||
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
|
||||
image: akkadius/eqemu-server:latest
|
||||
- name: Build Linux X64
|
||||
image: akkadius/eqemu-server:v11
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
commands:
|
||||
- sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
|
||||
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LUA=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O0 -g -DNDEBUG" -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
|
||||
- curl https://raw.githubusercontent.com/Akkadius/eqemu-install-v2/master/eqemu_config.json --output eqemu_config.json
|
||||
- ./bin/tests
|
||||
- ./utils/scripts/build/linux-build.sh
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /home/eqemu/.ccache/
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: exec
|
||||
name: Build Windows
|
||||
|
||||
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
platform:
|
||||
os: windows
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Build Windows X64
|
||||
environment:
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
commands:
|
||||
- .\utils\scripts\build\windows-build.ps1
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Publish Artifacts to Github
|
||||
|
||||
steps:
|
||||
- name: Upload Artifacts
|
||||
image: akkadius/eqemu-build-releaser:v3
|
||||
environment:
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
GH_RELEASE_GITHUB_API_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
commands:
|
||||
- ./utils/scripts/build/should-release/should-release
|
||||
- rclone config create remote ftp env_auth true > /dev/null
|
||||
- |
|
||||
rclone copy remote: --include "eqemu-server*.zip" .
|
||||
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
|
||||
- |
|
||||
rclone delete remote: --include "eqemu-server*.zip"
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- Build Windows
|
||||
- Build Linux
|
||||
|
||||
|
||||
|
||||
+15
@@ -56,3 +56,18 @@ bin/
|
||||
/client_files/**/CMakeFiles/
|
||||
|
||||
.idea
|
||||
|
||||
# Clangd Generated Files.
|
||||
compile_flags.txt
|
||||
.cache/
|
||||
|
||||
# vscode generated settings
|
||||
.vscode/
|
||||
|
||||
# Build pipeline
|
||||
!utils/scripts/build/
|
||||
!utils/scripts/build/should-release/should-release
|
||||
!utils/scripts/build/should-release/should-release.exe
|
||||
|
||||
# CMake Files
|
||||
cmake-build-relwithdebinfo/*
|
||||
|
||||
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/mysql"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-164
@@ -1,164 +0,0 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "make",
|
||||
"type": "shell",
|
||||
"command": "cd bin && make",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "make clean",
|
||||
"type": "shell",
|
||||
"command": "cd bin && make clean",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "cmake",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher":{
|
||||
"owner": "cpp",
|
||||
"fileLocation": "relative",
|
||||
"pattern":[
|
||||
{
|
||||
"regexp": "([\\w+|\\\\]*\\.\\w+)\\((\\d+)\\)\\: (warning|error) (.*)$",
|
||||
"file": 1,
|
||||
"location": 2,
|
||||
"severity": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "download maps",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "download quests",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "download eqemu_config",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "rebuild database (mariadb must be started)",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl linux_login_server_setup'",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "zone 7000",
|
||||
"type": "shell",
|
||||
"command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "zone 7001",
|
||||
"type": "shell",
|
||||
"command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "loginserver",
|
||||
"type": "shell",
|
||||
"command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "shared_memory, world",
|
||||
"type": "shell",
|
||||
"command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "queryserv",
|
||||
"type": "shell",
|
||||
"command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mariadb",
|
||||
"type": "shell",
|
||||
"command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "ucs",
|
||||
"type": "shell",
|
||||
"command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -40,14 +40,14 @@ Assuming it is starting in c:/projects/eqemu and the x64 dependencies were extra
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DEQEMU_ENABLE_BOTS=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
|
||||
|
||||
##### Linux
|
||||
Similarly to Windows running CMake on Linux is simple it just omits the toolchain file and uses a different generator.
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON ..
|
||||
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON ..
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
+1465
File diff suppressed because it is too large
Load Diff
+6
-12
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.7)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
|
||||
|
||||
@@ -12,7 +12,7 @@ IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 17)
|
||||
SET(CMAKE_CXX_STANDARD 20)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
@@ -21,8 +21,9 @@ IF(MSVC)
|
||||
ADD_DEFINITIONS(-DNOMINMAX)
|
||||
ADD_DEFINITIONS(-DCRASH_LOGGING)
|
||||
ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17
|
||||
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
|
||||
ELSE(MSVC)
|
||||
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
|
||||
ENDIF(MSVC)
|
||||
@@ -122,7 +123,6 @@ ENDIF()
|
||||
MESSAGE(STATUS "**************************************************")
|
||||
|
||||
#options
|
||||
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
|
||||
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
|
||||
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
|
||||
OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON)
|
||||
@@ -176,10 +176,6 @@ IF(EQEMU_COMMANDS_LOGGING)
|
||||
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
|
||||
ENDIF(EQEMU_COMMANDS_LOGGING)
|
||||
|
||||
IF(EQEMU_ENABLE_BOTS)
|
||||
ADD_DEFINITIONS(-DBOTS)
|
||||
ENDIF(EQEMU_ENABLE_BOTS)
|
||||
|
||||
#database
|
||||
IF(MySQL_FOUND AND MariaDB_FOUND)
|
||||
SET(DATABASE_LIBRARY_SELECTION MariaDB CACHE STRING "Database library to use:
|
||||
@@ -340,10 +336,8 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigat
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")
|
||||
|
||||
OPTION(EQEMU_BUILD_LOGGING "Build Logging (To speed up compilation)" ON)
|
||||
IF(EQEMU_BUILD_LOGGING)
|
||||
ADD_DEFINITIONS(-DBUILD_LOGGING)
|
||||
ENDIF()
|
||||
# silence obnoxious deprecation message
|
||||
ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
|
||||
|
||||
IF(TLS_LIBRARY_ENABLED)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${TLS_LIBRARY_LIBS})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# EQEmulator Core Server
|
||||
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|
||||
|:---:|:---:|:---:|
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server) |[](https://ci.appveyor.com/project/KimLS/server-87crp) |
|
||||
| Drone (Linux x64) | Drone (Windows x64) |
|
||||
|:---:|:---:|
|
||||
|[](http://drone.akkadius.com/EQEmu/Server) |[](http://drone.akkadius.com/EQEmu/Server) |
|
||||
|
||||
***
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
image: Visual Studio 2017
|
||||
configuration: RelWithDebInfo
|
||||
clone_folder: c:\projects\eqemu
|
||||
init:
|
||||
- ps: git config --global core.autocrlf input
|
||||
cache: c:\tools\vcpkg\installed\
|
||||
before_build:
|
||||
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
|
||||
build:
|
||||
project: C:\projects\eqemu\build\EQEmu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: >-
|
||||
7z a build_x64-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
|
||||
|
||||
appveyor PushArtifact build_x64-bots.zip
|
||||
@@ -1,21 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
image: Visual Studio 2017
|
||||
configuration: RelWithDebInfo
|
||||
clone_folder: c:\projects\eqemu
|
||||
init:
|
||||
- ps: git config --global core.autocrlf input
|
||||
cache: c:\tools\vcpkg\installed\
|
||||
before_build:
|
||||
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=OFF -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
|
||||
build:
|
||||
project: C:\projects\eqemu\build\EQEmu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: >-
|
||||
7z a build_x64-no-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
|
||||
|
||||
appveyor PushArtifact build_x64-no-bots.zip
|
||||
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
|
||||
SET(export_sources
|
||||
main.cpp
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
#include "../../common/strings.h"
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
|
||||
void ExportSpells(SharedDatabase *db);
|
||||
void ExportSkillCaps(SharedDatabase *db);
|
||||
@@ -44,6 +46,8 @@ int main(int argc, char **argv)
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
path.LoadPaths();
|
||||
|
||||
LogInfo("Client Files Export Utility");
|
||||
if (!EQEmuConfig::LoadConfig()) {
|
||||
LogError("Unable to load configuration file");
|
||||
@@ -82,10 +86,11 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
content_db.SetMysql(database.getMySQL());
|
||||
content_db.SetMySQL(database);
|
||||
}
|
||||
|
||||
LogSys.SetDatabase(&database)
|
||||
->SetLogPath(path.GetLogPath())
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
|
||||
@@ -126,7 +131,8 @@ void ExportSpells(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Spells");
|
||||
|
||||
FILE *f = fopen("export/spells_us.txt", "w");
|
||||
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
||||
return;
|
||||
@@ -177,7 +183,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
if (row[0] && atoi(row[0]) > 0) {
|
||||
if (row[0] && Strings::ToInt(row[0]) > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -201,14 +207,15 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToInt(row[0]);
|
||||
}
|
||||
|
||||
void ExportSkillCaps(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
FILE *f = fopen("export/SkillCaps.txt", "w");
|
||||
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
@@ -238,7 +245,8 @@ void ExportBaseData(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Base Data");
|
||||
|
||||
FILE *f = fopen("export/BaseData.txt", "w");
|
||||
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
||||
return;
|
||||
@@ -271,7 +279,8 @@ void ExportDBStrings(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting DB Strings");
|
||||
|
||||
FILE *f = fopen("export/dbstr_us.txt", "w");
|
||||
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
|
||||
SET(import_sources
|
||||
main.cpp
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include "../../common/strings.h"
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
|
||||
void ImportSpells(SharedDatabase *db);
|
||||
void ImportSkillCaps(SharedDatabase *db);
|
||||
@@ -41,6 +43,8 @@ int main(int argc, char **argv) {
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
path.LoadPaths();
|
||||
|
||||
LogInfo("Client Files Import Utility");
|
||||
if(!EQEmuConfig::LoadConfig()) {
|
||||
LogError("Unable to load configuration file.");
|
||||
@@ -79,10 +83,11 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
content_db.SetMysql(database.getMySQL());
|
||||
content_db.SetMySQL(database);
|
||||
}
|
||||
|
||||
LogSys.SetDatabase(&database)
|
||||
->SetLogPath(path.GetLogPath())
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
|
||||
@@ -127,9 +132,10 @@ bool IsStringField(int i) {
|
||||
|
||||
void ImportSpells(SharedDatabase *db) {
|
||||
LogInfo("Importing Spells");
|
||||
FILE *f = fopen("import/spells_us.txt", "r");
|
||||
std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open import/spells_us.txt to read, skipping.");
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,9 +222,10 @@ void ImportSpells(SharedDatabase *db) {
|
||||
void ImportSkillCaps(SharedDatabase *db) {
|
||||
LogInfo("Importing Skill Caps");
|
||||
|
||||
FILE *f = fopen("import/SkillCaps.txt", "r");
|
||||
std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open import/SkillCaps.txt to read, skipping.");
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,10 +241,10 @@ void ImportSkillCaps(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
int class_id, skill_id, level, cap;
|
||||
class_id = atoi(split[0].c_str());
|
||||
skill_id = atoi(split[1].c_str());
|
||||
level = atoi(split[2].c_str());
|
||||
cap = atoi(split[3].c_str());
|
||||
class_id = Strings::ToInt(split[0].c_str());
|
||||
skill_id = Strings::ToInt(split[1].c_str());
|
||||
level = Strings::ToInt(split[2].c_str());
|
||||
cap = Strings::ToInt(split[3].c_str());
|
||||
|
||||
std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
|
||||
class_id, skill_id, level, cap);
|
||||
@@ -251,9 +258,10 @@ void ImportSkillCaps(SharedDatabase *db) {
|
||||
void ImportBaseData(SharedDatabase *db) {
|
||||
LogInfo("Importing Base Data");
|
||||
|
||||
FILE *f = fopen("import/BaseData.txt", "r");
|
||||
std::string file = fmt::format("{}/import/BaseData.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open import/BaseData.txt to read, skipping.");
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -272,16 +280,16 @@ void ImportBaseData(SharedDatabase *db) {
|
||||
int level, class_id;
|
||||
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
|
||||
|
||||
level = atoi(split[0].c_str());
|
||||
class_id = atoi(split[1].c_str());
|
||||
hp = atof(split[2].c_str());
|
||||
mana = atof(split[3].c_str());
|
||||
end = atof(split[4].c_str());
|
||||
unk1 = atof(split[5].c_str());
|
||||
unk2 = atof(split[6].c_str());
|
||||
hp_fac = atof(split[7].c_str());
|
||||
mana_fac = atof(split[8].c_str());
|
||||
end_fac = atof(split[9].c_str());
|
||||
level = Strings::ToInt(split[0].c_str());
|
||||
class_id = Strings::ToInt(split[1].c_str());
|
||||
hp = Strings::ToFloat(split[2].c_str());
|
||||
mana = Strings::ToFloat(split[3].c_str());
|
||||
end = Strings::ToFloat(split[4].c_str());
|
||||
unk1 = Strings::ToFloat(split[5].c_str());
|
||||
unk2 = Strings::ToFloat(split[6].c_str());
|
||||
hp_fac = Strings::ToFloat(split[7].c_str());
|
||||
mana_fac = Strings::ToFloat(split[8].c_str());
|
||||
end_fac = Strings::ToFloat(split[9].c_str());
|
||||
|
||||
sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
|
||||
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
|
||||
@@ -296,9 +304,10 @@ void ImportBaseData(SharedDatabase *db) {
|
||||
void ImportDBStrings(SharedDatabase *db) {
|
||||
LogInfo("Importing DB Strings");
|
||||
|
||||
FILE *f = fopen("import/dbstr_us.txt", "r");
|
||||
std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open import/dbstr_us.txt to read, skipping.");
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -330,8 +339,8 @@ void ImportDBStrings(SharedDatabase *db) {
|
||||
int id, type;
|
||||
std::string value;
|
||||
|
||||
id = atoi(split[0].c_str());
|
||||
type = atoi(split[1].c_str());
|
||||
id = Strings::ToInt(split[0].c_str());
|
||||
type = Strings::ToInt(split[1].c_str());
|
||||
|
||||
if(split.size() >= 3) {
|
||||
value = ::Strings::Escape(split[2]);
|
||||
|
||||
+26
-14
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
|
||||
SET(common_sources
|
||||
base_packet.cpp
|
||||
@@ -33,11 +33,13 @@ SET(common_sources
|
||||
eq_stream_proxy.cpp
|
||||
eqtime.cpp
|
||||
event_sub.cpp
|
||||
events/player_event_logs.cpp
|
||||
events/player_event_discord_formatter.cpp
|
||||
expedition_lockout_timer.cpp
|
||||
extprofile.cpp
|
||||
discord_manager.cpp
|
||||
discord/discord_manager.cpp
|
||||
faction.cpp
|
||||
file_util.cpp
|
||||
file.cpp
|
||||
guild_base.cpp
|
||||
guilds.cpp
|
||||
inventory_profile.cpp
|
||||
@@ -61,8 +63,10 @@ SET(common_sources
|
||||
packet_dump.cpp
|
||||
packet_dump_file.cpp
|
||||
packet_functions.cpp
|
||||
path_manager.cpp
|
||||
perl_eqdb.cpp
|
||||
perl_eqdb_res.cpp
|
||||
process/process.cpp
|
||||
proc_launcher.cpp
|
||||
profanity_manager.cpp
|
||||
ptimer.cpp
|
||||
@@ -180,6 +184,8 @@ SET(repositories
|
||||
repositories/base/base_char_create_combinations_repository.h
|
||||
repositories/base/base_char_create_point_allocations_repository.h
|
||||
repositories/base/base_char_recipe_list_repository.h
|
||||
repositories/base/base_chatchannels_repository.h
|
||||
repositories/base/base_chatchannel_reserved_names_repository.h
|
||||
repositories/base/base_completed_shared_tasks_repository.h
|
||||
repositories/base/base_completed_shared_task_activity_state_repository.h
|
||||
repositories/base/base_completed_shared_task_members_repository.h
|
||||
@@ -194,7 +200,6 @@ SET(repositories
|
||||
repositories/base/base_dynamic_zones_repository.h
|
||||
repositories/base/base_dynamic_zone_members_repository.h
|
||||
repositories/base/base_dynamic_zone_templates_repository.h
|
||||
repositories/base/base_eventlog_repository.h
|
||||
repositories/base/base_expeditions_repository.h
|
||||
repositories/base/base_expedition_lockouts_repository.h
|
||||
repositories/base/base_faction_association_repository.h
|
||||
@@ -207,7 +212,6 @@ SET(repositories
|
||||
repositories/base/base_friends_repository.h
|
||||
repositories/base/base_global_loot_repository.h
|
||||
repositories/base/base_gm_ips_repository.h
|
||||
repositories/base/base_goallists_repository.h
|
||||
repositories/base/base_graveyard_repository.h
|
||||
repositories/base/base_ground_spawns_repository.h
|
||||
repositories/base/base_group_id_repository.h
|
||||
@@ -215,7 +219,6 @@ SET(repositories
|
||||
repositories/base/base_guilds_repository.h
|
||||
repositories/base/base_guild_ranks_repository.h
|
||||
repositories/base/base_guild_relations_repository.h
|
||||
repositories/base/base_hackers_repository.h
|
||||
repositories/base/base_horses_repository.h
|
||||
repositories/base/base_instance_list_repository.h
|
||||
repositories/base/base_instance_list_player_repository.h
|
||||
@@ -261,6 +264,8 @@ SET(repositories
|
||||
repositories/base/base_pets_equipmentset_repository.h
|
||||
repositories/base/base_pets_equipmentset_entries_repository.h
|
||||
repositories/base/base_player_titlesets_repository.h
|
||||
repositories/base/base_player_event_log_settings_repository.h
|
||||
repositories/base/base_player_event_logs_repository.h
|
||||
repositories/base/base_quest_globals_repository.h
|
||||
repositories/base/base_raid_details_repository.h
|
||||
repositories/base/base_raid_members_repository.h
|
||||
@@ -357,6 +362,8 @@ SET(repositories
|
||||
repositories/char_create_combinations_repository.h
|
||||
repositories/char_create_point_allocations_repository.h
|
||||
repositories/char_recipe_list_repository.h
|
||||
repositories/chatchannels_repository.h
|
||||
repositories/chatchannel_reserved_names_repository.h
|
||||
repositories/completed_shared_tasks_repository.h
|
||||
repositories/completed_shared_task_activity_state_repository.h
|
||||
repositories/completed_shared_task_members_repository.h
|
||||
@@ -371,7 +378,6 @@ SET(repositories
|
||||
repositories/dynamic_zones_repository.h
|
||||
repositories/dynamic_zone_members_repository.h
|
||||
repositories/dynamic_zone_templates_repository.h
|
||||
repositories/eventlog_repository.h
|
||||
repositories/expeditions_repository.h
|
||||
repositories/expedition_lockouts_repository.h
|
||||
repositories/faction_association_repository.h
|
||||
@@ -384,7 +390,6 @@ SET(repositories
|
||||
repositories/friends_repository.h
|
||||
repositories/global_loot_repository.h
|
||||
repositories/gm_ips_repository.h
|
||||
repositories/goallists_repository.h
|
||||
repositories/graveyard_repository.h
|
||||
repositories/ground_spawns_repository.h
|
||||
repositories/group_id_repository.h
|
||||
@@ -392,7 +397,6 @@ SET(repositories
|
||||
repositories/guilds_repository.h
|
||||
repositories/guild_ranks_repository.h
|
||||
repositories/guild_relations_repository.h
|
||||
repositories/hackers_repository.h
|
||||
repositories/horses_repository.h
|
||||
repositories/instance_list_repository.h
|
||||
repositories/instance_list_player_repository.h
|
||||
@@ -438,6 +442,8 @@ SET(repositories
|
||||
repositories/pets_equipmentset_repository.h
|
||||
repositories/pets_equipmentset_entries_repository.h
|
||||
repositories/player_titlesets_repository.h
|
||||
repositories/player_event_log_settings_repository.h
|
||||
repositories/player_event_logs_repository.h
|
||||
repositories/quest_globals_repository.h
|
||||
repositories/raid_details_repository.h
|
||||
repositories/raid_members_repository.h
|
||||
@@ -503,7 +509,7 @@ SET(common_headers
|
||||
dbcore.h
|
||||
deity.h
|
||||
discord/discord.h
|
||||
discord_manager.h
|
||||
discord/discord_manager.h
|
||||
dynamic_zone_base.h
|
||||
emu_constants.h
|
||||
emu_limits.h
|
||||
@@ -526,12 +532,15 @@ SET(common_headers
|
||||
eq_stream_locator.h
|
||||
eq_stream_proxy.h
|
||||
eqtime.h
|
||||
events/player_event_logs.h
|
||||
events/player_event_discord_formatter.h
|
||||
events/player_events.h
|
||||
errmsg.h
|
||||
event_sub.h
|
||||
expedition_lockout_timer.h
|
||||
extprofile.h
|
||||
faction.h
|
||||
file_util.h
|
||||
file.h
|
||||
features.h
|
||||
fixed_memory_hash_set.h
|
||||
fixed_memory_variable_hash_set.h
|
||||
@@ -567,7 +576,9 @@ SET(common_headers
|
||||
packet_dump.h
|
||||
packet_dump_file.h
|
||||
packet_functions.h
|
||||
path_manager.cpp
|
||||
platform.h
|
||||
process/process.h
|
||||
proc_launcher.h
|
||||
profanity_manager.h
|
||||
profiler.h
|
||||
@@ -597,11 +608,11 @@ SET(common_headers
|
||||
unix.h
|
||||
useperl.h
|
||||
version.h
|
||||
zone_numbers.h
|
||||
zone_store.h
|
||||
event/event_loop.h
|
||||
event/task.h
|
||||
event/timer.h
|
||||
json/json_archive_single_line.h
|
||||
json/json.h
|
||||
json/json-forwards.h
|
||||
net/console_server.h
|
||||
@@ -650,11 +661,12 @@ SET(common_headers
|
||||
patches/uf_limits.h
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
termcolor/rang.hpp
|
||||
stacktrace/backward.hpp
|
||||
StackWalker/StackWalker.h
|
||||
util/memory_stream.h
|
||||
util/directory.h
|
||||
util/uuid.h
|
||||
)
|
||||
util/uuid.h)
|
||||
|
||||
SOURCE_GROUP(Event FILES
|
||||
event/event_loop.h
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "../common/types.h"
|
||||
|
||||
#define NO_CLASS 0
|
||||
#define WARRIOR 1
|
||||
#define CLERIC 2
|
||||
#define PALADIN 3
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace EQEmuCommand {
|
||||
*/
|
||||
std::string command_section;
|
||||
for (auto &it: in_function_map) {
|
||||
description = "";
|
||||
description.clear();
|
||||
|
||||
(it.second)(argc, argv, cmd, description);
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
|
||||
/**
|
||||
* @param content_flags
|
||||
*/
|
||||
void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags)
|
||||
void WorldContentService::SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags)
|
||||
{
|
||||
WorldContentService::content_flags = content_flags;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
std::vector<std::string> GetContentFlagsDisabled();
|
||||
bool IsContentFlagEnabled(const std::string& content_flag);
|
||||
bool IsContentFlagDisabled(const std::string& content_flag);
|
||||
void SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags);
|
||||
void SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags);
|
||||
void ReloadContentFlags();
|
||||
WorldContentService * SetExpansionContext();
|
||||
|
||||
|
||||
+124
-47
@@ -1,47 +1,97 @@
|
||||
#include "global_define.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "crash.h"
|
||||
#include "strings.h"
|
||||
#include "process/process.h"
|
||||
#include "http/httplib.h"
|
||||
#include "http/uri.h"
|
||||
#include "json/json.h"
|
||||
#include "version.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "serverinfo.h"
|
||||
#include "rulesys.h"
|
||||
#include "platform.h"
|
||||
|
||||
inline std::string random_string(size_t length)
|
||||
{
|
||||
auto randchar = []() -> char {
|
||||
const char charset[] = "0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[static_cast<size_t>(std::rand()) % max_index];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
}
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
std::string execute(const std::string &cmd, bool return_result = true)
|
||||
{
|
||||
std::string random = "/tmp/" + random_string(25);
|
||||
const char *file_name = random.c_str();
|
||||
|
||||
if (return_result) {
|
||||
#ifdef _WINDOWS
|
||||
std::system((cmd + " > " + file_name + " 2>&1").c_str());
|
||||
#else
|
||||
std::system((cmd + " > " + file_name + " 2>&1").c_str());
|
||||
#if WINDOWS
|
||||
#define popen _popen
|
||||
#endif
|
||||
|
||||
void SendCrashReport(const std::string &crash_report)
|
||||
{
|
||||
// can configure multiple endpoints if need be
|
||||
std::vector<std::string> endpoints = {
|
||||
"http://spire.akkadius.com/api/v1/analytics/server-crash-report",
|
||||
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development
|
||||
};
|
||||
|
||||
auto config = EQEmuConfig::get();
|
||||
for (auto &e: endpoints) {
|
||||
uri u(e);
|
||||
|
||||
std::string base_url = fmt::format("{}://{}", u.get_scheme(), u.get_host());
|
||||
if (u.get_port()) {
|
||||
base_url += fmt::format(":{}", u.get_port());
|
||||
}
|
||||
|
||||
// client
|
||||
httplib::Client r(base_url);
|
||||
r.set_connection_timeout(1, 0);
|
||||
r.set_read_timeout(1, 0);
|
||||
r.set_write_timeout(1, 0);
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// os info
|
||||
auto os = EQ::GetOS();
|
||||
auto cpus = EQ::GetCPUs();
|
||||
auto process_id = EQ::GetPID();
|
||||
auto rss = EQ::GetRSS() / 1048576.0;
|
||||
auto uptime = static_cast<uint32>(EQ::GetUptime());
|
||||
|
||||
// payload
|
||||
Json::Value p;
|
||||
p["platform_name"] = GetPlatformName();
|
||||
p["crash_report"] = crash_report;
|
||||
p["server_version"] = CURRENT_VERSION;
|
||||
p["compile_date"] = COMPILE_DATE;
|
||||
p["compile_time"] = COMPILE_TIME;
|
||||
p["server_name"] = config->LongName;
|
||||
p["server_short_name"] = config->ShortName;
|
||||
p["uptime"] = uptime;
|
||||
p["os_machine"] = os.machine;
|
||||
p["os_release"] = os.release;
|
||||
p["os_version"] = os.version;
|
||||
p["os_sysname"] = os.sysname;
|
||||
p["process_id"] = process_id;
|
||||
p["rss_memory"] = rss;
|
||||
p["cpus"] = cpus.size();
|
||||
p["origination_info"] = "";
|
||||
|
||||
if (!LogSys.origination_info.zone_short_name.empty()) {
|
||||
p["origination_info"] = fmt::format(
|
||||
"{} ({}) instance_id [{}]",
|
||||
LogSys.origination_info.zone_short_name,
|
||||
LogSys.origination_info.zone_long_name,
|
||||
LogSys.origination_info.instance_id
|
||||
);
|
||||
}
|
||||
|
||||
std::stringstream payload;
|
||||
payload << p;
|
||||
|
||||
if (auto res = r.Post(e, payload.str(), "application/json")) {
|
||||
if (res->status == 200) {
|
||||
LogInfo("Sent crash report");
|
||||
}
|
||||
else {
|
||||
LogError("Failed to send crash report to [{}]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::system((cmd).c_str());
|
||||
}
|
||||
|
||||
std::string result;
|
||||
|
||||
if (return_result) {
|
||||
std::ifstream file(file_name);
|
||||
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
||||
std::remove(file_name);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS) && defined(CRASH_LOGGING)
|
||||
@@ -54,22 +104,30 @@ public:
|
||||
EQEmuStackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) { }
|
||||
virtual void OnOutput(LPCSTR szText) {
|
||||
char buffer[4096];
|
||||
for(int i = 0; i < 4096; ++i) {
|
||||
if(szText[i] == 0) {
|
||||
for (int i = 0; i < 4096; ++i) {
|
||||
if (szText[i] == 0) {
|
||||
buffer[i] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
if(szText[i] == '\n' || szText[i] == '\r') {
|
||||
if (szText[i] == '\n' || szText[i] == '\r') {
|
||||
buffer[i] = ' ';
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
buffer[i] = szText[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::string line = buffer;
|
||||
_lines.push_back(line);
|
||||
|
||||
Log(Logs::General, Logs::Crash, buffer);
|
||||
StackWalker::OnOutput(szText);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& GetLines() { return _lines; }
|
||||
private:
|
||||
std::vector<std::string> _lines;
|
||||
};
|
||||
|
||||
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
|
||||
@@ -143,7 +201,20 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
|
||||
|
||||
if(EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
|
||||
{
|
||||
EQEmuStackWalker sw; sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
|
||||
EQEmuStackWalker sw;
|
||||
sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
|
||||
|
||||
if (RuleB(Analytics, CrashReporting)) {
|
||||
std::string crash_report;
|
||||
auto& lines = sw.GetLines();
|
||||
|
||||
for (auto& line : lines) {
|
||||
crash_report += line;
|
||||
crash_report += "\n";
|
||||
}
|
||||
|
||||
SendCrashReport(crash_report);
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
@@ -167,7 +238,7 @@ void set_exception_handler() {
|
||||
|
||||
void print_trace()
|
||||
{
|
||||
bool does_gdb_exist = execute("gdb -v").find("GNU") != std::string::npos;
|
||||
bool does_gdb_exist = Strings::Contains(Process::execute("gdb -v"), "GNU");
|
||||
if (!does_gdb_exist) {
|
||||
LogCrash(
|
||||
"[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed"
|
||||
@@ -176,12 +247,12 @@ void print_trace()
|
||||
}
|
||||
|
||||
auto uid = geteuid();
|
||||
std::string temp_output_file = "/tmp/dump-output";
|
||||
std::string temp_output_file = fmt::format("/tmp/dump-output-{}", Strings::Random(10));
|
||||
|
||||
// check for passwordless sudo if not root
|
||||
if (uid != 0) {
|
||||
bool has_passwordless_sudo = execute("sudo -n true").find("a password is required") == std::string::npos;
|
||||
if (!has_passwordless_sudo) {
|
||||
bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required");
|
||||
if (sudo_password_required) {
|
||||
LogCrash(
|
||||
"[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root."
|
||||
);
|
||||
@@ -210,16 +281,22 @@ void print_trace()
|
||||
abort(); /* If gdb failed to start */
|
||||
}
|
||||
else {
|
||||
waitpid(child_pid, NULL, 0);
|
||||
waitpid(child_pid, nullptr, 0);
|
||||
}
|
||||
|
||||
std::ifstream input(temp_output_file);
|
||||
std::string crash_report;
|
||||
for (std::string line; getline(input, line);) {
|
||||
LogCrash("{}", line);
|
||||
crash_report += fmt::format("{}\n", line);
|
||||
}
|
||||
|
||||
std::remove(temp_output_file.c_str());
|
||||
|
||||
if (RuleB(Analytics, CrashReporting)) {
|
||||
SendCrashReport(crash_report);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace cron
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<cron_int>(std::stoul(text.data()));
|
||||
return static_cast<cron_int>(Strings::ToUnsignedInt(text.data()));
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
|
||||
+247
-248
@@ -71,11 +71,11 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
|
||||
uint32 errnum= 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(host, user, passwd, database, port, &errnum, errbuf)) {
|
||||
LogError("[MySQL] Connection [{}] Failed to connect to database: Error [{}]", connection_label, errbuf);
|
||||
LogError("Connection [{}] Failed to connect to database Error [{}]", connection_label, errbuf);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
LogInfo("[MySQL] Connection [{}] database [{}] at [{}]:[{}]", connection_label, database, host,port);
|
||||
LogInfo("Connected to database [{}] [{}] @ [{}:{}]", connection_label, database, host,port);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -121,10 +121,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, const char *
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
auto id = std::stoul(row[0]);
|
||||
auto id = Strings::ToUnsignedInt(row[0]);
|
||||
|
||||
if (oStatus) {
|
||||
*oStatus = std::stoi(row[1]);
|
||||
*oStatus = Strings::ToInt(row[1]);
|
||||
}
|
||||
|
||||
return id;
|
||||
@@ -202,11 +202,11 @@ int16 Database::CheckStatus(uint32 account_id)
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
int16 status = std::stoi(row[0]);
|
||||
int16 status = Strings::ToInt(row[0]);
|
||||
int32 date_diff = 0;
|
||||
|
||||
if (row[1]) {
|
||||
date_diff = std::stoi(row[1]);
|
||||
date_diff = Strings::ToInt(row[1]);
|
||||
}
|
||||
|
||||
if (date_diff > 0) {
|
||||
@@ -345,7 +345,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
std::string query = StringFormat("SELECT `account_id`, `name` FROM `character_data` WHERE `name` = '%s'", name);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (row[0] && atoi(row[0]) > 0){
|
||||
if (row[0] && Strings::ToInt(row[0]) > 0){
|
||||
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
|
||||
return false;
|
||||
}
|
||||
@@ -353,7 +353,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
|
||||
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success() || results.ErrorMessage() != ""){ return false; }
|
||||
if (!results.Success() || !results.ErrorMessage().empty()){ return false; }
|
||||
|
||||
// Put character into the default guild if rule is being used.
|
||||
int guild_id = RuleI(Character, DefaultGuild);
|
||||
@@ -363,7 +363,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
if (character_id > -1) {
|
||||
query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", character_id, guild_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success() || results.ErrorMessage() != ""){
|
||||
if (!results.Success() || !results.ErrorMessage().empty()){
|
||||
LogInfo("Could not put character [{}] into default Guild", name);
|
||||
}
|
||||
}
|
||||
@@ -376,9 +376,10 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
* @param character_name
|
||||
* @return
|
||||
*/
|
||||
bool Database::DeleteCharacter(char *character_name) {
|
||||
bool Database::DeleteCharacter(char *character_name)
|
||||
{
|
||||
uint32 character_id = 0;
|
||||
if(!character_name || !strlen(character_name)) {
|
||||
if (!character_name || !strlen(character_name)) {
|
||||
LogInfo("DeleteCharacter: request to delete without a name (empty char slot)");
|
||||
return false;
|
||||
}
|
||||
@@ -386,54 +387,70 @@ bool Database::DeleteCharacter(char *character_name) {
|
||||
std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", character_name);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
character_id = atoi(row[0]);
|
||||
character_id = Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
if (character_id <= 0) {
|
||||
LogError("DeleteCharacter | Invalid Character ID [{}]", character_name);
|
||||
LogError("Invalid Character ID [{}]", character_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string delete_type = "hard-deleted";
|
||||
if (RuleB(Character, SoftDeletes)) {
|
||||
delete_type = "soft-deleted";
|
||||
std::string query = fmt::format(
|
||||
delete_type = "soft-deleted";
|
||||
query = fmt::format(
|
||||
SQL(
|
||||
UPDATE
|
||||
character_data
|
||||
character_data
|
||||
SET
|
||||
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64),
|
||||
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64),
|
||||
deleted_at = NOW()
|
||||
WHERE
|
||||
id = '{}'
|
||||
WHERE
|
||||
id = '{}'
|
||||
),
|
||||
character_id
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
query = fmt::format(
|
||||
SQL(
|
||||
UPDATE
|
||||
bot_data
|
||||
SET
|
||||
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64)
|
||||
WHERE
|
||||
owner_id = '{}'
|
||||
),
|
||||
character_id
|
||||
);
|
||||
QueryDatabase(query);
|
||||
LogInfo(
|
||||
"[DeleteCharacter] character_name [{}] ({}) bots are being [{}]",
|
||||
character_name,
|
||||
character_id,
|
||||
delete_type
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type);
|
||||
|
||||
for (const auto& iter : DatabaseSchema::GetCharacterTables()) {
|
||||
for (const auto &iter: DatabaseSchema::GetCharacterTables()) {
|
||||
std::string table_name = iter.first;
|
||||
std::string character_id_column_name = iter.second;
|
||||
|
||||
QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById()
|
||||
QueryDatabase(query);
|
||||
#endif
|
||||
|
||||
LogInfo("character_name [{}] ({}) is being [{}]", character_name, character_id, delete_type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp){
|
||||
bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_data` ("
|
||||
"id,"
|
||||
@@ -618,101 +635,102 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
|
||||
"%u," // guild_auto_consent
|
||||
"%u" // RestTimer
|
||||
")",
|
||||
character_id, // " id, "
|
||||
account_id, // " account_id, "
|
||||
Strings::Escape(pp->name).c_str(), // " `name`, "
|
||||
character_id, // " id, "
|
||||
account_id, // " account_id, "
|
||||
Strings::Escape(pp->name).c_str(), // " `name`, "
|
||||
Strings::Escape(pp->last_name).c_str(), // " last_name, "
|
||||
pp->gender, // " gender, "
|
||||
pp->race, // " race, "
|
||||
pp->class_, // " class, "
|
||||
pp->level, // " `level`, "
|
||||
pp->deity, // " deity, "
|
||||
pp->birthday, // " birthday, "
|
||||
pp->lastlogin, // " last_login, "
|
||||
pp->timePlayedMin, // " time_played, "
|
||||
pp->pvp, // " pvp_status, "
|
||||
pp->level2, // " level2, "
|
||||
pp->anon, // " anon, "
|
||||
pp->gm, // " gm, "
|
||||
pp->intoxication, // " intoxication, "
|
||||
pp->haircolor, // " hair_color, "
|
||||
pp->beardcolor, // " beard_color, "
|
||||
pp->eyecolor1, // " eye_color_1, "
|
||||
pp->eyecolor2, // " eye_color_2, "
|
||||
pp->hairstyle, // " hair_style, "
|
||||
pp->beard, // " beard, "
|
||||
pp->ability_time_seconds, // " ability_time_seconds, "
|
||||
pp->ability_number, // " ability_number, "
|
||||
pp->ability_time_minutes, // " ability_time_minutes, "
|
||||
pp->ability_time_hours, // " ability_time_hours, "
|
||||
pp->gender, // " gender, "
|
||||
pp->race, // " race, "
|
||||
pp->class_, // " class, "
|
||||
pp->level, // " `level`, "
|
||||
pp->deity, // " deity, "
|
||||
pp->birthday, // " birthday, "
|
||||
pp->lastlogin, // " last_login, "
|
||||
pp->timePlayedMin, // " time_played, "
|
||||
pp->pvp, // " pvp_status, "
|
||||
pp->level2, // " level2, "
|
||||
pp->anon, // " anon, "
|
||||
pp->gm, // " gm, "
|
||||
pp->intoxication, // " intoxication, "
|
||||
pp->haircolor, // " hair_color, "
|
||||
pp->beardcolor, // " beard_color, "
|
||||
pp->eyecolor1, // " eye_color_1, "
|
||||
pp->eyecolor2, // " eye_color_2, "
|
||||
pp->hairstyle, // " hair_style, "
|
||||
pp->beard, // " beard, "
|
||||
pp->ability_time_seconds, // " ability_time_seconds, "
|
||||
pp->ability_number, // " ability_number, "
|
||||
pp->ability_time_minutes, // " ability_time_minutes, "
|
||||
pp->ability_time_hours, // " ability_time_hours, "
|
||||
Strings::Escape(pp->title).c_str(), // " title, "
|
||||
Strings::Escape(pp->suffix).c_str(), // " suffix, "
|
||||
pp->exp, // " exp, "
|
||||
pp->points, // " points, "
|
||||
pp->mana, // " mana, "
|
||||
pp->cur_hp, // " cur_hp, "
|
||||
pp->STR, // " str, "
|
||||
pp->STA, // " sta, "
|
||||
pp->CHA, // " cha, "
|
||||
pp->DEX, // " dex, "
|
||||
pp->INT, // " `int`, "
|
||||
pp->AGI, // " agi, "
|
||||
pp->WIS, // " wis, "
|
||||
pp->face, // " face, "
|
||||
pp->y, // " y, "
|
||||
pp->x, // " x, "
|
||||
pp->z, // " z, "
|
||||
pp->heading, // " heading, "
|
||||
pp->pvp2, // " pvp2, "
|
||||
pp->pvptype, // " pvp_type, "
|
||||
pp->autosplit, // " autosplit_enabled, "
|
||||
pp->zone_change_count, // " zone_change_count, "
|
||||
pp->drakkin_heritage, // " drakkin_heritage, "
|
||||
pp->drakkin_tattoo, // " drakkin_tattoo, "
|
||||
pp->drakkin_details, // " drakkin_details, "
|
||||
pp->toxicity, // " toxicity, "
|
||||
pp->hunger_level, // " hunger_level, "
|
||||
pp->thirst_level, // " thirst_level, "
|
||||
pp->ability_up, // " ability_up, "
|
||||
pp->zone_id, // " zone_id, "
|
||||
pp->zoneInstance, // " zone_instance, "
|
||||
pp->leadAAActive, // " leadership_exp_on, "
|
||||
pp->ldon_points_guk, // " ldon_points_guk, "
|
||||
pp->ldon_points_mir, // " ldon_points_mir, "
|
||||
pp->ldon_points_mmc, // " ldon_points_mmc, "
|
||||
pp->ldon_points_ruj, // " ldon_points_ruj, "
|
||||
pp->ldon_points_tak, // " ldon_points_tak, "
|
||||
pp->ldon_points_available, // " ldon_points_available, "
|
||||
pp->tribute_time_remaining, // " tribute_time_remaining, "
|
||||
pp->showhelm, // " show_helm, "
|
||||
pp->career_tribute_points, // " career_tribute_points, "
|
||||
pp->tribute_points, // " tribute_points, "
|
||||
pp->tribute_active, // " tribute_active, "
|
||||
pp->endurance, // " endurance, "
|
||||
pp->group_leadership_exp, // " group_leadership_exp, "
|
||||
pp->raid_leadership_exp, // " raid_leadership_exp, "
|
||||
pp->group_leadership_points, // " group_leadership_points, "
|
||||
pp->raid_leadership_points, // " raid_leadership_points, "
|
||||
pp->air_remaining, // " air_remaining, "
|
||||
pp->PVPKills, // " pvp_kills, "
|
||||
pp->PVPDeaths, // " pvp_deaths, "
|
||||
pp->PVPCurrentPoints, // " pvp_current_points, "
|
||||
pp->PVPCareerPoints, // " pvp_career_points, "
|
||||
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
|
||||
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
|
||||
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
|
||||
pp->aapoints_spent, // " aa_points_spent, "
|
||||
pp->expAA, // " aa_exp, "
|
||||
pp->aapoints, // " aa_points, "
|
||||
pp->groupAutoconsent, // " group_auto_consent, "
|
||||
pp->raidAutoconsent, // " raid_auto_consent, "
|
||||
pp->guildAutoconsent, // " guild_auto_consent, "
|
||||
pp->RestTimer // " RestTimer) "
|
||||
pp->exp, // " exp, "
|
||||
pp->points, // " points, "
|
||||
pp->mana, // " mana, "
|
||||
pp->cur_hp, // " cur_hp, "
|
||||
pp->STR, // " str, "
|
||||
pp->STA, // " sta, "
|
||||
pp->CHA, // " cha, "
|
||||
pp->DEX, // " dex, "
|
||||
pp->INT, // " `int`, "
|
||||
pp->AGI, // " agi, "
|
||||
pp->WIS, // " wis, "
|
||||
pp->face, // " face, "
|
||||
pp->y, // " y, "
|
||||
pp->x, // " x, "
|
||||
pp->z, // " z, "
|
||||
pp->heading, // " heading, "
|
||||
pp->pvp2, // " pvp2, "
|
||||
pp->pvptype, // " pvp_type, "
|
||||
pp->autosplit, // " autosplit_enabled, "
|
||||
pp->zone_change_count, // " zone_change_count, "
|
||||
pp->drakkin_heritage, // " drakkin_heritage, "
|
||||
pp->drakkin_tattoo, // " drakkin_tattoo, "
|
||||
pp->drakkin_details, // " drakkin_details, "
|
||||
pp->toxicity, // " toxicity, "
|
||||
pp->hunger_level, // " hunger_level, "
|
||||
pp->thirst_level, // " thirst_level, "
|
||||
pp->ability_up, // " ability_up, "
|
||||
pp->zone_id, // " zone_id, "
|
||||
pp->zoneInstance, // " zone_instance, "
|
||||
pp->leadAAActive, // " leadership_exp_on, "
|
||||
pp->ldon_points_guk, // " ldon_points_guk, "
|
||||
pp->ldon_points_mir, // " ldon_points_mir, "
|
||||
pp->ldon_points_mmc, // " ldon_points_mmc, "
|
||||
pp->ldon_points_ruj, // " ldon_points_ruj, "
|
||||
pp->ldon_points_tak, // " ldon_points_tak, "
|
||||
pp->ldon_points_available, // " ldon_points_available, "
|
||||
pp->tribute_time_remaining, // " tribute_time_remaining, "
|
||||
pp->showhelm, // " show_helm, "
|
||||
pp->career_tribute_points, // " career_tribute_points, "
|
||||
pp->tribute_points, // " tribute_points, "
|
||||
pp->tribute_active, // " tribute_active, "
|
||||
pp->endurance, // " endurance, "
|
||||
pp->group_leadership_exp, // " group_leadership_exp, "
|
||||
pp->raid_leadership_exp, // " raid_leadership_exp, "
|
||||
pp->group_leadership_points, // " group_leadership_points, "
|
||||
pp->raid_leadership_points, // " raid_leadership_points, "
|
||||
pp->air_remaining, // " air_remaining, "
|
||||
pp->PVPKills, // " pvp_kills, "
|
||||
pp->PVPDeaths, // " pvp_deaths, "
|
||||
pp->PVPCurrentPoints, // " pvp_current_points, "
|
||||
pp->PVPCareerPoints, // " pvp_career_points, "
|
||||
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
|
||||
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
|
||||
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
|
||||
pp->aapoints_spent, // " aa_points_spent, "
|
||||
pp->expAA, // " aa_exp, "
|
||||
pp->aapoints, // " aa_points, "
|
||||
pp->groupAutoconsent, // " group_auto_consent, "
|
||||
pp->raidAutoconsent, // " raid_auto_consent, "
|
||||
pp->guildAutoconsent, // " guild_auto_consent, "
|
||||
pp->RestTimer // " RestTimer) "
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
|
||||
/* Save Bind Points */
|
||||
query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
|
||||
query = StringFormat(
|
||||
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i), "
|
||||
"(%u, %u, %u, %f, %f, %f, %f, %i), "
|
||||
"(%u, %u, %u, %f, %f, %f, %f, %i), "
|
||||
@@ -723,57 +741,73 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
|
||||
character_id, pp->binds[2].zone_id, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2,
|
||||
character_id, pp->binds[3].zone_id, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3,
|
||||
character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4
|
||||
); results = QueryDatabase(query);
|
||||
);
|
||||
QueryDatabase(query);
|
||||
|
||||
/* HoTT Ability */
|
||||
if(RuleB(Character, GrantHoTTOnCreate))
|
||||
{
|
||||
query = StringFormat("INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)", character_id, 14, 1);
|
||||
results = QueryDatabase(query);
|
||||
}
|
||||
/* HoTT Ability */
|
||||
if (RuleB(Character, GrantHoTTOnCreate)) {
|
||||
query = StringFormat(
|
||||
"INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)",
|
||||
character_id,
|
||||
14,
|
||||
1
|
||||
);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/* Save Skills */
|
||||
int firstquery = 0;
|
||||
for (int i = 0; i < MAX_PP_SKILL; i++){
|
||||
if (pp->skills[i] > 0){
|
||||
if (firstquery != 1){
|
||||
int firstquery = 0;
|
||||
for (int i = 0; i < MAX_PP_SKILL; i++) {
|
||||
if (pp->skills[i] > 0) {
|
||||
if (firstquery != 1) {
|
||||
firstquery = 1;
|
||||
query = StringFormat("REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)", character_id, i, pp->skills[i]);
|
||||
}
|
||||
else{
|
||||
query = StringFormat(
|
||||
"REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)",
|
||||
character_id,
|
||||
i,
|
||||
pp->skills[i]
|
||||
);
|
||||
} else {
|
||||
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
results = QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
|
||||
/* Save Language */
|
||||
firstquery = 0;
|
||||
for (int i = 0; i < MAX_PP_LANGUAGE; i++){
|
||||
if (pp->languages[i] > 0){
|
||||
if (firstquery != 1){
|
||||
for (int i = 0; i < MAX_PP_LANGUAGE; i++) {
|
||||
if (pp->languages[i] > 0) {
|
||||
if (firstquery != 1) {
|
||||
firstquery = 1;
|
||||
query = StringFormat("REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)", character_id, i, pp->languages[i]);
|
||||
}
|
||||
else{
|
||||
query = StringFormat(
|
||||
"REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)",
|
||||
character_id,
|
||||
i,
|
||||
pp->languages[i]
|
||||
);
|
||||
} else {
|
||||
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
results = QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Database::GetCharacterID(const char *name) {
|
||||
std::string query = StringFormat("SELECT `id` FROM `character_data` WHERE `name` = '%s'", name);
|
||||
const auto query = fmt::format(
|
||||
"SELECT `id` FROM `character_data` WHERE `name` = '{}'",
|
||||
Strings::Escape(name)
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1)
|
||||
{
|
||||
return atoi(row[0]);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -796,10 +830,10 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
uint32 accountId = atoi(row[0]);
|
||||
uint32 accountId = Strings::ToUnsignedInt(row[0]);
|
||||
|
||||
if (oCharID)
|
||||
*oCharID = atoi(row[1]);
|
||||
*oCharID = Strings::ToUnsignedInt(row[1]);
|
||||
|
||||
return accountId;
|
||||
}
|
||||
@@ -816,7 +850,7 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetAccountIDByName(std::string account_name, std::string loginserver, int16* status, uint32* lsid) {
|
||||
@@ -836,14 +870,14 @@ uint32 Database::GetAccountIDByName(std::string account_name, std::string logins
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto account_id = std::stoul(row[0]);
|
||||
auto account_id = Strings::ToUnsignedInt(row[0]);
|
||||
|
||||
if (status) {
|
||||
*status = static_cast<int16>(std::stoi(row[1]));
|
||||
*status = static_cast<int16>(Strings::ToInt(row[1]));
|
||||
}
|
||||
|
||||
if (lsid) {
|
||||
*lsid = row[2] ? std::stoul(row[2]) : 0;
|
||||
*lsid = row[2] ? Strings::ToUnsignedInt(row[2]) : 0;
|
||||
}
|
||||
|
||||
return account_id;
|
||||
@@ -864,7 +898,7 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID
|
||||
|
||||
strcpy(name, row[0]);
|
||||
if (row[1] && oLSAccountID) {
|
||||
*oLSAccountID = atoi(row[1]);
|
||||
*oLSAccountID = Strings::ToUnsignedInt(row[1]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -952,13 +986,15 @@ bool Database::LoadVariables() {
|
||||
|
||||
std::string key, value;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
varcache.last_update = atoi(row[2]); // ahh should we be comparing if this is newer?
|
||||
varcache.last_update = Strings::ToUnsignedInt(row[2]); // ahh should we be comparing if this is newer?
|
||||
key = row[0];
|
||||
value = row[1];
|
||||
std::transform(std::begin(key), std::end(key), std::begin(key), ::tolower); // keys are lower case, DB doesn't have to be
|
||||
varcache.Add(key, value);
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] variable(s)", Strings::Commify(std::to_string(results.RowCount())));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -981,7 +1017,7 @@ bool Database::GetVariable(std::string varname, std::string &varvalue)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Database::SetVariable(const std::string varname, const std::string &varvalue)
|
||||
bool Database::SetVariable(const std::string& varname, const std::string &varvalue)
|
||||
{
|
||||
std::string escaped_name = Strings::Escape(varname);
|
||||
std::string escaped_value = Strings::Escape(varvalue);
|
||||
@@ -1034,15 +1070,15 @@ bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zon
|
||||
auto row = results.begin();
|
||||
|
||||
if(graveyard_zoneid != nullptr)
|
||||
*graveyard_zoneid = atoi(row[0]);
|
||||
*graveyard_zoneid = Strings::ToUnsignedInt(row[0]);
|
||||
if(graveyard_x != nullptr)
|
||||
*graveyard_x = atof(row[1]);
|
||||
*graveyard_x = Strings::ToFloat(row[1]);
|
||||
if(graveyard_y != nullptr)
|
||||
*graveyard_y = atof(row[2]);
|
||||
*graveyard_y = Strings::ToFloat(row[2]);
|
||||
if(graveyard_z != nullptr)
|
||||
*graveyard_z = atof(row[3]);
|
||||
*graveyard_z = Strings::ToFloat(row[3]);
|
||||
if(graveyard_heading != nullptr)
|
||||
*graveyard_heading = atof(row[4]);
|
||||
*graveyard_heading = Strings::ToFloat(row[4]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1150,13 +1186,13 @@ uint32 Database::GetAccountIDFromLSID(
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
account_id = std::stoi(row[0]);
|
||||
account_id = Strings::ToUnsignedInt(row[0]);
|
||||
|
||||
if (in_account_name) {
|
||||
strcpy(in_account_name, row[1]);
|
||||
}
|
||||
if (in_status) {
|
||||
*in_status = std::stoi(row[2]);
|
||||
*in_status = Strings::ToInt(row[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1180,7 +1216,7 @@ void Database::GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus) {
|
||||
if (oAccountName)
|
||||
strcpy(oAccountName, row[0]);
|
||||
if (oStatus)
|
||||
*oStatus = atoi(row[1]);
|
||||
*oStatus = Strings::ToInt(row[1]);
|
||||
}
|
||||
|
||||
void Database::ClearMerchantTemp(){
|
||||
@@ -1226,7 +1262,7 @@ uint8 Database::GetServerType() {
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
bool Database::MoveCharacterToZone(uint32 character_id, uint32 zone_id)
|
||||
@@ -1263,44 +1299,6 @@ bool Database::MoveCharacterToZone(const char *charname, uint32 zone_id)
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
|
||||
std::string query = StringFormat("INSERT INTO `hackers` (account, name, hacked) values('%s','%s','%s')", accountname, charactername, hacked);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
|
||||
//Utilize the "hacker" table, but also give zone information.
|
||||
std::string query = StringFormat("INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const std::string &hacked, const char* zone) {
|
||||
//Utilize the "hacker" table, but also give zone information.
|
||||
auto query = fmt::format("INSERT INTO hackers(account, name, hacked, zone) values('{}', '{}', '{}', '{}')",
|
||||
accountname, charactername, hacked, zone);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
|
||||
{
|
||||
uint16 race_cap = 0;
|
||||
@@ -1316,7 +1314,7 @@ uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level)
|
||||
@@ -1332,12 +1330,12 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
|
||||
if (results.Success() && results.RowsAffected() != 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
skill_level = atoi(row[0]);
|
||||
skill_formula = atoi(row[1]);
|
||||
skill_cap = atoi(row[2]);
|
||||
if (atoi(row[3]) > skill_cap)
|
||||
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
|
||||
skill_cap3 = atoi(row[4]);
|
||||
skill_level = Strings::ToUnsignedInt(row[0]);
|
||||
skill_formula = Strings::ToUnsignedInt(row[1]);
|
||||
skill_cap = Strings::ToUnsignedInt(row[2]);
|
||||
if (Strings::ToUnsignedInt(row[3]) > skill_cap)
|
||||
skill_cap2 = (Strings::ToUnsignedInt(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
|
||||
skill_cap3 = Strings::ToUnsignedInt(row[4]);
|
||||
}
|
||||
|
||||
int race_skill = GetRaceSkill(skillid,in_race);
|
||||
@@ -1382,10 +1380,10 @@ uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto character_id = std::stoul(row[0]);
|
||||
*account_id = std::stoul(row[1]);
|
||||
*zone_id = std::stoul(row[2]);
|
||||
*instance_id = std::stoul(row[3]);
|
||||
auto character_id = Strings::ToUnsignedInt(row[0]);
|
||||
*account_id = Strings::ToUnsignedInt(row[1]);
|
||||
*zone_id = Strings::ToUnsignedInt(row[2]);
|
||||
*instance_id = Strings::ToUnsignedInt(row[3]);
|
||||
|
||||
return character_id;
|
||||
}
|
||||
@@ -1508,7 +1506,7 @@ uint32 Database::GetGroupID(const char* name){
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
|
||||
@@ -1522,7 +1520,7 @@ std::string Database::GetGroupLeaderForLogin(std::string character_name) {
|
||||
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
group_id = std::stoul(row[0]);
|
||||
group_id = Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
if (!group_id) {
|
||||
@@ -1611,7 +1609,7 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
|
||||
strcpy(mentoree, row[5]);
|
||||
|
||||
if (mentor_percent)
|
||||
*mentor_percent = atoi(row[6]);
|
||||
*mentor_percent = Strings::ToInt(row[6]);
|
||||
|
||||
if(GLAA && results.LengthOfColumn(7) == sizeof(GroupLeadershipAA_Struct))
|
||||
memcpy(GLAA, row[7], sizeof(GroupLeadershipAA_Struct));
|
||||
@@ -1658,7 +1656,7 @@ uint8 Database::GetAgreementFlag(uint32 acctid) {
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
void Database::SetAgreementFlag(uint32 acctid) {
|
||||
@@ -1744,7 +1742,7 @@ uint32 Database::GetRaidID(const char* name)
|
||||
}
|
||||
|
||||
if (row[0]) // would it ever be possible to have a null here?
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1827,7 +1825,7 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank,
|
||||
strcpy(mentoree, row[4]);
|
||||
|
||||
if (mentor_percent)
|
||||
*mentor_percent = atoi(row[5]);
|
||||
*mentor_percent = Strings::ToInt(row[5]);
|
||||
|
||||
if (GLAA && results.LengthOfColumn(6) == sizeof(GroupLeadershipAA_Struct))
|
||||
memcpy(GLAA, row[6], sizeof(GroupLeadershipAA_Struct));
|
||||
@@ -2000,16 +1998,16 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
as->success.guk = atoi(row[0]);
|
||||
as->success.mir = atoi(row[1]);
|
||||
as->success.mmc = atoi(row[2]);
|
||||
as->success.ruj = atoi(row[3]);
|
||||
as->success.tak = atoi(row[4]);
|
||||
as->failure.guk = atoi(row[5]);
|
||||
as->failure.mir = atoi(row[6]);
|
||||
as->failure.mmc = atoi(row[7]);
|
||||
as->failure.ruj = atoi(row[8]);
|
||||
as->failure.tak = atoi(row[9]);
|
||||
as->success.guk = Strings::ToUnsignedInt(row[0]);
|
||||
as->success.mir = Strings::ToUnsignedInt(row[1]);
|
||||
as->success.mmc = Strings::ToUnsignedInt(row[2]);
|
||||
as->success.ruj = Strings::ToUnsignedInt(row[3]);
|
||||
as->success.tak = Strings::ToUnsignedInt(row[4]);
|
||||
as->failure.guk = Strings::ToUnsignedInt(row[5]);
|
||||
as->failure.mir = Strings::ToUnsignedInt(row[6]);
|
||||
as->failure.mmc = Strings::ToUnsignedInt(row[7]);
|
||||
as->failure.ruj = Strings::ToUnsignedInt(row[8]);
|
||||
as->failure.tak = Strings::ToUnsignedInt(row[9]);
|
||||
as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak;
|
||||
as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak;
|
||||
|
||||
@@ -2028,7 +2026,7 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
||||
@@ -2050,7 +2048,7 @@ uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
|
||||
@@ -2063,10 +2061,12 @@ uint32 Database::GetRaidIDByCharID(uint32 character_id) {
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
return atoi(row[0]);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
int Database::CountInvSnapshots() {
|
||||
@@ -2078,7 +2078,7 @@ int Database::CountInvSnapshots() {
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
int64 count = atoll(row[0]);
|
||||
int64 count = Strings::ToBigInt(row[0]);
|
||||
if (count > 2147483647)
|
||||
return -2;
|
||||
if (count < 0)
|
||||
@@ -2109,17 +2109,17 @@ struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
|
||||
eqTime.day = 1;
|
||||
eqTime.month = 1;
|
||||
eqTime.year = 3100;
|
||||
realtime = time(0);
|
||||
realtime = time(nullptr);
|
||||
}
|
||||
else{
|
||||
auto row = results.begin();
|
||||
|
||||
eqTime.minute = atoi(row[0]);
|
||||
eqTime.hour = atoi(row[1]);
|
||||
eqTime.day = atoi(row[2]);
|
||||
eqTime.month = atoi(row[3]);
|
||||
eqTime.year = atoi(row[4]);
|
||||
realtime = atoi(row[5]);
|
||||
eqTime.minute = Strings::ToUnsignedInt(row[0]);
|
||||
eqTime.hour = Strings::ToUnsignedInt(row[1]);
|
||||
eqTime.day = Strings::ToUnsignedInt(row[2]);
|
||||
eqTime.month = Strings::ToUnsignedInt(row[3]);
|
||||
eqTime.year = Strings::ToUnsignedInt(row[4]);
|
||||
realtime = Strings::ToBigInt(row[5]);
|
||||
}
|
||||
|
||||
return eqTime;
|
||||
@@ -2146,7 +2146,7 @@ int Database::GetIPExemption(std::string account_ip) {
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return std::stoi(row[0]);
|
||||
return Strings::ToInt(row[0]);
|
||||
}
|
||||
|
||||
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
@@ -2160,7 +2160,7 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
exemption_id = std::stoul(row[0]);
|
||||
exemption_id = Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
query = fmt::format(
|
||||
@@ -2186,7 +2186,7 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
|
||||
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);;
|
||||
return Strings::ToInt(row[0]);;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2292,7 +2292,6 @@ bool Database::CopyCharacter(
|
||||
new_rows.emplace_back(new_values);
|
||||
}
|
||||
|
||||
std::string insert_values;
|
||||
std::vector<std::string> insert_rows;
|
||||
|
||||
for (auto &r: new_rows) {
|
||||
@@ -2338,7 +2337,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
|
||||
uri request_uri(url);
|
||||
|
||||
LogHTTP(
|
||||
"[SourceDatabaseTableFromUrl] parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
|
||||
"parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
|
||||
url,
|
||||
request_uri.get_path(),
|
||||
request_uri.get_host(),
|
||||
@@ -2365,7 +2364,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
|
||||
|
||||
int sourced_queries = 0;
|
||||
|
||||
if (auto res = cli.Get(request_uri.get_path().c_str())) {
|
||||
if (auto res = cli.Get(request_uri.get_path())) {
|
||||
if (res->status == 200) {
|
||||
for (auto &s: Strings::Split(res->body, ';')) {
|
||||
if (!Strings::Trim(s).empty()) {
|
||||
@@ -2392,7 +2391,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
|
||||
|
||||
}
|
||||
catch (std::invalid_argument iae) {
|
||||
LogError("[SourceDatabaseTableFromUrl] URI parser error [{}]", iae.what());
|
||||
LogError("URI parser error [{}]", iae.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-17
@@ -34,8 +34,6 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
//atoi is not uint32 or uint32 safe!!!!
|
||||
#define atoul(str) strtoul(str, nullptr, 10)
|
||||
|
||||
class MySQLRequestResult;
|
||||
class Client;
|
||||
@@ -108,9 +106,6 @@ public:
|
||||
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
|
||||
bool ReserveName(uint32 account_id, char *name);
|
||||
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
|
||||
bool SetHackerFlag(const char *accountname, const char *charactername, const char *hacked);
|
||||
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const char *hacked, const char *zone);
|
||||
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
|
||||
bool UpdateName(const char *oldname, const char *newname);
|
||||
bool CopyCharacter(
|
||||
const std::string& source_character_name,
|
||||
@@ -145,31 +140,30 @@ public:
|
||||
|
||||
/* Instancing */
|
||||
|
||||
bool AddClientToInstance(uint16 instance_id, uint32 char_id);
|
||||
bool CharacterInInstanceGroup(uint16 instance_id, uint32 char_id);
|
||||
bool AddClientToInstance(uint16 instance_id, uint32 character_id);
|
||||
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id);
|
||||
bool CheckInstanceExists(uint16 instance_id);
|
||||
bool CheckInstanceExpired(uint16 instance_id);
|
||||
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
|
||||
bool GetUnusedInstanceID(uint16 &instance_id);
|
||||
bool GlobalInstance(uint16 instance_id);
|
||||
bool IsGlobalInstance(uint16 instance_id);
|
||||
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
|
||||
bool RemoveClientsFromInstance(uint16 instance_id);
|
||||
bool VerifyInstanceAlive(uint16 instance_id, uint32 char_id);
|
||||
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id);
|
||||
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
|
||||
|
||||
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
|
||||
uint16 GetInstanceVersion(uint16 instance_id);
|
||||
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id);
|
||||
uint8_t GetInstanceVersion(uint16 instance_id);
|
||||
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
|
||||
uint32 VersionFromInstanceID(uint16 instance_id);
|
||||
uint32 ZoneIDFromInstanceID(uint16 instance_id);
|
||||
uint32 GetInstanceZoneID(uint16 instance_id);
|
||||
|
||||
void AssignGroupToInstance(uint32 gid, uint32 instance_id);
|
||||
void AssignRaidToInstance(uint32 rid, uint32 instance_id);
|
||||
void BuryCorpsesInInstance(uint16 instance_id);
|
||||
void DeleteInstance(uint16 instance_id);
|
||||
void FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid);
|
||||
void FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list);
|
||||
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id);
|
||||
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids);
|
||||
void PurgeExpiredInstances();
|
||||
void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
|
||||
|
||||
@@ -241,7 +235,7 @@ public:
|
||||
/* Database Variables */
|
||||
|
||||
bool GetVariable(std::string varname, std::string &varvalue);
|
||||
bool SetVariable(const std::string varname, const std::string &varvalue);
|
||||
bool SetVariable(const std::string& varname, const std::string &varvalue);
|
||||
bool LoadVariables();
|
||||
|
||||
/* General Queries */
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
#include "../strings.h"
|
||||
#include "../eqemu_config.h"
|
||||
#include "../database_schema.h"
|
||||
#include "../file_util.h"
|
||||
#include "../file.h"
|
||||
#include "../process/process.h"
|
||||
#include "../termcolor/rang.hpp"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
@@ -35,43 +37,12 @@
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <thread>
|
||||
|
||||
#endif
|
||||
|
||||
#define DATABASE_DUMP_PATH "backups/"
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
* @param return_result
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
|
||||
{
|
||||
const char *file_name = "db-exec-result.txt";
|
||||
|
||||
if (return_result) {
|
||||
#ifdef _WINDOWS
|
||||
std::system((cmd + " > " + file_name + " 2>&1").c_str());
|
||||
#else
|
||||
std::system((cmd + " > " + file_name).c_str());
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
std::system((cmd).c_str());
|
||||
}
|
||||
|
||||
std::string result;
|
||||
|
||||
if (return_result) {
|
||||
std::ifstream file(file_name);
|
||||
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
||||
std::remove(file_name);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@@ -88,7 +59,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
|
||||
*/
|
||||
bool DatabaseDumpService::IsTarAvailable()
|
||||
{
|
||||
std::string version_output = execute("tar --version");
|
||||
std::string version_output = Process::execute("tar --version");
|
||||
|
||||
return version_output.find("GNU tar") != std::string::npos;
|
||||
}
|
||||
@@ -99,7 +70,7 @@ bool DatabaseDumpService::IsTarAvailable()
|
||||
*/
|
||||
bool DatabaseDumpService::Is7ZipAvailable()
|
||||
{
|
||||
std::string version_output = execute("7z --help");
|
||||
std::string version_output = Process::execute("7z --help");
|
||||
|
||||
return version_output.find("7-Zip") != std::string::npos;
|
||||
}
|
||||
@@ -117,7 +88,7 @@ bool DatabaseDumpService::HasCompressionBinary()
|
||||
*/
|
||||
std::string DatabaseDumpService::GetMySQLVersion()
|
||||
{
|
||||
std::string version_output = execute("mysql --version");
|
||||
std::string version_output = Process::execute("mysql --version");
|
||||
|
||||
return Strings::Trim(version_output);
|
||||
}
|
||||
@@ -149,109 +120,53 @@ std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetPlayerTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetPlayerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetPlayerTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetBotTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetBotTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetBotTables(), " ");
|
||||
}
|
||||
|
||||
std::string DatabaseDumpService::GetMercTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetMercTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetLoginTableList()
|
||||
{
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetLoginTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetQueryServTables()
|
||||
{
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetSystemTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
auto system_tables = DatabaseSchema::GetServerTables();
|
||||
auto version_tables = DatabaseSchema::GetVersionTables();
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
system_tables.insert(
|
||||
std::end(system_tables),
|
||||
std::begin(version_tables),
|
||||
std::end(version_tables)
|
||||
);
|
||||
|
||||
tables = DatabaseSchema::GetVersionTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(system_tables, " ");
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
|
||||
std::string DatabaseDumpService::GetStateTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetStateTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetContentTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Trim(tables_list);
|
||||
return Strings::Join(DatabaseSchema::GetContentTables(), " ");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +201,7 @@ std::string DatabaseDumpService::GetDumpFileNameWithPath()
|
||||
return GetSetDumpPath() + GetDumpFileName();
|
||||
}
|
||||
|
||||
void DatabaseDumpService::Dump()
|
||||
void DatabaseDumpService::DatabaseDump()
|
||||
{
|
||||
if (!IsMySQLInstalled()) {
|
||||
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
|
||||
@@ -337,6 +252,11 @@ void DatabaseDumpService::Dump()
|
||||
dump_descriptor += "-bots";
|
||||
}
|
||||
|
||||
if (IsDumpMercTables()) {
|
||||
tables_to_dump += GetMercTablesList() + " ";
|
||||
dump_descriptor += "-mercs";
|
||||
}
|
||||
|
||||
if (IsDumpSystemTables()) {
|
||||
tables_to_dump += GetSystemTablesList() + " ";
|
||||
dump_descriptor += "-system";
|
||||
@@ -375,22 +295,14 @@ void DatabaseDumpService::Dump()
|
||||
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
|
||||
}
|
||||
|
||||
std::string execute_command = fmt::format(
|
||||
"{} {} {} {}",
|
||||
GetBaseMySQLDumpCommand(),
|
||||
options,
|
||||
tables_to_dump,
|
||||
pipe_file
|
||||
);
|
||||
|
||||
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
|
||||
FileUtil::mkdir(GetSetDumpPath());
|
||||
if (!File::Exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
|
||||
File::Makedir(GetSetDumpPath());
|
||||
}
|
||||
|
||||
if (IsDumpDropTableSyntaxOnly()) {
|
||||
std::vector<std::string> tables = Strings::Split(tables_to_dump, ' ');
|
||||
|
||||
for (auto &table : tables) {
|
||||
for (auto &table: tables) {
|
||||
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
|
||||
}
|
||||
|
||||
@@ -399,14 +311,42 @@ void DatabaseDumpService::Dump()
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
|
||||
if (!execution_result.empty()) {
|
||||
const auto execute_command = fmt::format(
|
||||
"{} {} {} {}",
|
||||
GetBaseMySQLDumpCommand(),
|
||||
options,
|
||||
tables_to_dump,
|
||||
pipe_file
|
||||
);
|
||||
|
||||
std::string execution_result = Process::execute(execute_command);
|
||||
if (!execution_result.empty() && IsDumpOutputToConsole()) {
|
||||
std::cout << execution_result;
|
||||
}
|
||||
}
|
||||
|
||||
LogSys.EnableConsoleLogging();
|
||||
|
||||
if (!pipe_file.empty()) {
|
||||
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
|
||||
auto r = File::GetContents(file);
|
||||
if (!r.error.empty()) {
|
||||
LogError("{}", r.error);
|
||||
}
|
||||
|
||||
for (auto &line: Strings::Split(r.contents, "\n")) {
|
||||
if (Strings::Contains(line, "mysqldump:")) {
|
||||
LogError("{}", line);
|
||||
LogError("Database dump failed. Correct the error before continuing or trying again");
|
||||
LogError("This is to prevent data loss on behalf of the server operator");
|
||||
RemoveSqlBackup();
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tables_to_dump.empty()) {
|
||||
LogInfo("Dumping Tables [{}]", tables_to_dump);
|
||||
LogInfo("Dumping Tables [{}]", Strings::Trim(tables_to_dump));
|
||||
}
|
||||
|
||||
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
|
||||
@@ -416,7 +356,7 @@ void DatabaseDumpService::Dump()
|
||||
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
|
||||
|
||||
if (IsTarAvailable()) {
|
||||
execute(
|
||||
Process::execute(
|
||||
fmt::format(
|
||||
"tar -zcvf {}.tar.gz -C {} {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
@@ -425,9 +365,10 @@ void DatabaseDumpService::Dump()
|
||||
)
|
||||
);
|
||||
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
|
||||
RemoveSqlBackup();
|
||||
}
|
||||
else if (Is7ZipAvailable()) {
|
||||
execute(
|
||||
Process::execute(
|
||||
fmt::format(
|
||||
"7z a -t7z {}.zip {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
@@ -435,6 +376,7 @@ void DatabaseDumpService::Dump()
|
||||
)
|
||||
);
|
||||
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
|
||||
RemoveSqlBackup();
|
||||
}
|
||||
else {
|
||||
LogInfo("Compression requested, but no available compression binary was found");
|
||||
@@ -607,3 +549,21 @@ void DatabaseDumpService::SetDumpBotTables(bool dump_bot_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_bot_tables = dump_bot_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpMercTables() const
|
||||
{
|
||||
return dump_merc_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpMercTables(bool dump_merc_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_merc_tables = dump_merc_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::RemoveSqlBackup()
|
||||
{
|
||||
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
|
||||
if (File::Exists(file)) {
|
||||
std::filesystem::remove(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
class DatabaseDumpService {
|
||||
public:
|
||||
void Dump();
|
||||
void DatabaseDump();
|
||||
bool IsDumpAllTables() const;
|
||||
void SetDumpAllTables(bool dump_all_tables);
|
||||
bool IsDumpWithNoData() const;
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
void SetDumpStateTables(bool dump_state_tables);
|
||||
bool IsDumpBotTables() const;
|
||||
void SetDumpBotTables(bool dump_bot_tables);
|
||||
bool IsDumpMercTables() const;
|
||||
void SetDumpMercTables(bool dump_bot_tables);
|
||||
|
||||
private:
|
||||
bool dump_all_tables = false;
|
||||
@@ -70,15 +72,16 @@ private:
|
||||
bool dump_output_to_console = false;
|
||||
bool dump_drop_table_syntax_only = false;
|
||||
bool dump_bot_tables = false;
|
||||
bool dump_merc_tables = false;
|
||||
std::string dump_path;
|
||||
std::string dump_file_name;
|
||||
|
||||
std::string execute(const std::string &cmd, bool return_result);
|
||||
bool IsMySQLInstalled();
|
||||
std::string GetMySQLVersion();
|
||||
std::string GetBaseMySQLDumpCommand();
|
||||
std::string GetPlayerTablesList();
|
||||
std::string GetBotTablesList();
|
||||
std::string GetMercTablesList();
|
||||
std::string GetSystemTablesList();
|
||||
std::string GetStateTablesList();
|
||||
std::string GetContentTablesList();
|
||||
@@ -89,6 +92,7 @@ private:
|
||||
std::string GetDumpFileNameWithPath();
|
||||
std::string GetSetDumpPath();
|
||||
std::string GetQueryServTables();
|
||||
void RemoveSqlBackup();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "database.h"
|
||||
#include "extprofile.h"
|
||||
#include "path_manager.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@@ -475,8 +476,17 @@ bool Database::CheckDatabaseConversions() {
|
||||
CheckDatabaseConvertPPDeblob();
|
||||
CheckDatabaseConvertCorpseDeblob();
|
||||
|
||||
auto *r = RuleManager::Instance();
|
||||
r->LoadRules(this, "default", false);
|
||||
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
|
||||
LogInfo("Bot tables found but rule not enabled, enabling");
|
||||
r->SetRule("Bots:Enabled", "true", this, true, true);
|
||||
}
|
||||
|
||||
/* Run EQEmu Server script (Checks for database updates) */
|
||||
system("perl eqemu_server.pl ran_from_world");
|
||||
|
||||
const std::string file = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
|
||||
system(fmt::format("perl {} ran_from_world", file).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -489,7 +499,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
ExtendedProfile_Struct* e_pp;
|
||||
uint32 pplen = 0;
|
||||
uint32 i;
|
||||
int character_id = 0;
|
||||
uint32 character_id = 0;
|
||||
int account_id = 0;
|
||||
int number_of_characters = 0;
|
||||
int printppdebug = 0; /* Prints Player Profile */
|
||||
@@ -520,7 +530,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`");
|
||||
results = QueryDatabase(rquery);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
number_of_characters = atoi(row[0]);
|
||||
number_of_characters = Strings::ToInt(row[0]);
|
||||
printf("Number of Characters in Database: %i \n", number_of_characters);
|
||||
}
|
||||
|
||||
@@ -919,19 +929,19 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
char_iter_count++;
|
||||
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", atoi(row[0]));
|
||||
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", Strings::ToUnsignedInt(row[0]));
|
||||
auto results2 = QueryDatabase(squery);
|
||||
auto row2 = results2.begin();
|
||||
pp = (Convert::PlayerProfile_Struct*)row2[1];
|
||||
e_pp = (ExtendedProfile_Struct*)row2[11];
|
||||
character_id = atoi(row[0]);
|
||||
account_id = atoi(row2[4]);
|
||||
character_id = Strings::ToUnsignedInt(row[0]);
|
||||
account_id = Strings::ToInt(row2[4]);
|
||||
/* Convert some data from the character_ table that is still relevant */
|
||||
firstlogon = atoi(row2[5]);
|
||||
lfg = atoi(row2[6]);
|
||||
lfp = atoi(row2[7]);
|
||||
firstlogon = Strings::ToUnsignedInt(row2[5]);
|
||||
lfg = Strings::ToUnsignedInt(row2[6]);
|
||||
lfp = Strings::ToUnsignedInt(row2[7]);
|
||||
mailkey = row2[8];
|
||||
xtargets = atoi(row2[9]);
|
||||
xtargets = Strings::ToUnsignedInt(row2[9]);
|
||||
inspectmessage = row2[10];
|
||||
|
||||
/* Verify PP Integrity */
|
||||
@@ -957,7 +967,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
loadbar(char_iter_count, number_of_characters, 50);
|
||||
|
||||
/* Run inspect message convert */
|
||||
if (inspectmessage != ""){
|
||||
if (!inspectmessage.empty()){
|
||||
std::string rquery = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message)"
|
||||
"VALUES (%u, '%s')",
|
||||
character_id,
|
||||
@@ -1304,7 +1314,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
The speed difference is dramatic
|
||||
*/
|
||||
/* Run AA Convert */
|
||||
int first_entry = 0; rquery = "";
|
||||
int first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < MAX_PP_AA_ARRAY; i++){
|
||||
if (pp->aa_array[i].AA > 0 && pp->aa_array[i].value > 0){
|
||||
if (first_entry != 1){
|
||||
@@ -1317,14 +1327,14 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
|
||||
/* Run Bind Home Convert */
|
||||
if (pp->binds[4].zone_id < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) {
|
||||
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, 1)",
|
||||
character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading);
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
}
|
||||
|
||||
/* Run Bind Convert */
|
||||
@@ -1332,10 +1342,10 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, 0)",
|
||||
character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading);
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
}
|
||||
/* Run Language Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < MAX_PP_LANGUAGE; i++){
|
||||
if (pp->languages[i] > 0){
|
||||
if (first_entry != 1){
|
||||
@@ -1345,9 +1355,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Skill Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < MAX_PP_SKILL; i++){
|
||||
if (pp->skills[i] > 0){
|
||||
if (first_entry != 1){
|
||||
@@ -1357,9 +1367,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Spell Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < 480; i++){
|
||||
if (pp->spell_book[i] > 0 && pp->spell_book[i] != 4294967295 && pp->spell_book[i] < 40000 && pp->spell_book[i] != 1){
|
||||
if (first_entry != 1){
|
||||
@@ -1369,9 +1379,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->spell_book[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Max Memmed Spell Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < 9; i++){
|
||||
if (pp->mem_spells[i] > 0 && pp->mem_spells[i] != 65535 && pp->mem_spells[i] != 4294967295){
|
||||
if (first_entry != 1){
|
||||
@@ -1381,9 +1391,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->mem_spells[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Discipline Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < MAX_PP_DISCIPLINES; i++){
|
||||
if (pp->disciplines.values[i] > 0 && pp->disciplines.values[i] < 60000){
|
||||
if (first_entry != 1){
|
||||
@@ -1393,9 +1403,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->disciplines.values[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Material Color Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = EQ::textures::textureBegin; i < EQ::textures::materialCount; i++){
|
||||
if (pp->item_tint[i].color > 0){
|
||||
if (first_entry != 1){
|
||||
@@ -1405,9 +1415,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u)", character_id, i, pp->item_tint[i].rgb.blue, pp->item_tint[i].rgb.green, pp->item_tint[i].rgb.red, pp->item_tint[i].rgb.use_tint, pp->item_tint[i].color);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Tribute Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < 5; i++){
|
||||
if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != 4294967295){
|
||||
if (first_entry != 1){
|
||||
@@ -1417,9 +1427,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Bandolier Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < Convert::BANDOLIERS_SIZE; i++){
|
||||
if (strlen(pp->bandoliers[i].Name) < 32) {
|
||||
for (int si = 0; si < Convert::BANDOLIER_ITEM_COUNT; si++){
|
||||
@@ -1433,9 +1443,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Potion Belt Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < Convert::POTION_BELT_ITEM_COUNT; i++){
|
||||
if (pp->potionbelt.Items[i].ID > 0){
|
||||
if (first_entry != 1){
|
||||
@@ -1446,9 +1456,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
/* Run Leadership AA Convert */
|
||||
first_entry = 0; rquery = "";
|
||||
first_entry = 0; rquery.clear();
|
||||
for (i = 0; i < MAX_LEADERSHIP_AA_ARRAY; i++){
|
||||
if (pp->leader_abilities.ranks[i] > 0 && pp->leader_abilities.ranks[i] < 6){
|
||||
if (first_entry != 1){
|
||||
@@ -1458,7 +1468,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
rquery = rquery + StringFormat(", (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
|
||||
}
|
||||
}
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
if (!rquery.empty()){ results = QueryDatabase(rquery); }
|
||||
}
|
||||
}
|
||||
if (runconvert == 1){
|
||||
@@ -1557,7 +1567,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
rquery = StringFormat("SELECT DISTINCT charid FROM character_corpses");
|
||||
results = QueryDatabase(rquery);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", atoi(row[0]));
|
||||
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", Strings::ToUnsignedInt(row[0]));
|
||||
auto results2 = QueryDatabase(squery);
|
||||
for (auto row2 = results2.begin(); row2 != results2.end(); ++row2) {
|
||||
in_datasize = results2.LengthOfColumn(2);
|
||||
@@ -1589,7 +1599,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
c_type = "NULL";
|
||||
continue;
|
||||
}
|
||||
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << atoi(row2[0]) << std::endl;
|
||||
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << Strings::ToUnsignedInt(row2[0]) << std::endl;
|
||||
|
||||
if (is_sof){
|
||||
scquery = StringFormat("UPDATE `character_corpses` SET \n"
|
||||
@@ -1660,19 +1670,19 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
dbpc->item_tint[6].color,
|
||||
dbpc->item_tint[7].color,
|
||||
dbpc->item_tint[8].color,
|
||||
atoi(row2[0])
|
||||
Strings::ToUnsignedInt(row2[0])
|
||||
);
|
||||
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
|
||||
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); }
|
||||
|
||||
first_entry = 0;
|
||||
scquery = "";
|
||||
scquery.clear();
|
||||
/* Print Items */
|
||||
for (unsigned int i = 0; i < dbpc->itemcount; i++) {
|
||||
if (first_entry != 1){
|
||||
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
|
||||
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
|
||||
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
atoi(row2[0]),
|
||||
Strings::ToUnsignedInt(row2[0]),
|
||||
dbpc->items[i].equipSlot,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
@@ -1688,7 +1698,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
}
|
||||
else{
|
||||
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
atoi(row2[0]),
|
||||
Strings::ToUnsignedInt(row2[0]),
|
||||
dbpc->items[i].equipSlot,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
@@ -1702,7 +1712,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
);
|
||||
}
|
||||
}
|
||||
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
|
||||
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); }
|
||||
}
|
||||
else{
|
||||
/* Classic Converter */
|
||||
@@ -1768,12 +1778,12 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
dbpc_c->item_tint[6].color,
|
||||
dbpc_c->item_tint[7].color,
|
||||
dbpc_c->item_tint[8].color,
|
||||
atoi(row2[0])
|
||||
Strings::ToUnsignedInt(row2[0])
|
||||
);
|
||||
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
|
||||
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); }
|
||||
|
||||
first_entry = 0;
|
||||
scquery = "";
|
||||
scquery.clear();
|
||||
|
||||
/* Print Items */
|
||||
for (unsigned int i = 0; i < dbpc_c->itemcount; i++) {
|
||||
@@ -1781,7 +1791,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
|
||||
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
|
||||
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
atoi(row2[0]),
|
||||
Strings::ToUnsignedInt(row2[0]),
|
||||
dbpc_c->items[i].equipSlot,
|
||||
dbpc_c->items[i].item_id,
|
||||
dbpc_c->items[i].charges,
|
||||
@@ -1797,7 +1807,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
}
|
||||
else{
|
||||
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
atoi(row2[0]),
|
||||
Strings::ToUnsignedInt(row2[0]),
|
||||
dbpc_c->items[i].equipSlot,
|
||||
dbpc_c->items[i].item_id,
|
||||
dbpc_c->items[i].charges,
|
||||
@@ -1811,7 +1821,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
|
||||
);
|
||||
}
|
||||
}
|
||||
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
|
||||
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+230
-293
@@ -20,8 +20,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/dynamic_zone_members_repository.h"
|
||||
#include "../common/repositories/dynamic_zones_repository.h"
|
||||
#include "../common/repositories/group_id_repository.h"
|
||||
#include "../common/repositories/instance_list_repository.h"
|
||||
#include "../common/repositories/instance_list_player_repository.h"
|
||||
#include "../common/repositories/raid_members_repository.h"
|
||||
#include "../common/repositories/respawn_times_repository.h"
|
||||
#include "../common/repositories/spawn_condition_values_repository.h"
|
||||
|
||||
|
||||
#include "database.h"
|
||||
|
||||
@@ -41,115 +49,83 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param instance_id
|
||||
* @param char_id
|
||||
* @return
|
||||
*/
|
||||
bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
|
||||
bool Database::AddClientToInstance(uint16 instance_id, uint32 character_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `instance_list_player` (id, charid) "
|
||||
"VALUES "
|
||||
"(%lu, %lu)",
|
||||
(unsigned long) instance_id,
|
||||
(unsigned long) char_id
|
||||
);
|
||||
auto e = InstanceListPlayerRepository::NewEntity();
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
e.id = instance_id;
|
||||
e.charid = character_id;
|
||||
|
||||
return results.Success();
|
||||
return InstanceListPlayerRepository::ReplaceOne(*this, e);
|
||||
}
|
||||
|
||||
bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id)
|
||||
bool Database::CheckInstanceByCharID(uint16 instance_id, uint32 character_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("SELECT charid FROM instance_list_player where id=%u AND charid=%u", instance_id, char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
auto l = InstanceListPlayerRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND charid = {}",
|
||||
instance_id,
|
||||
character_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::CheckInstanceExists(uint16 instance_id) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"`id` "
|
||||
"FROM "
|
||||
"`instance_list` "
|
||||
"WHERE "
|
||||
"`id` = %u",
|
||||
instance_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
bool Database::CheckInstanceExists(uint16 instance_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::CheckInstanceExpired(uint16 instance_id)
|
||||
{
|
||||
|
||||
int32 start_time = 0;
|
||||
int32 duration = 0;
|
||||
uint32 never_expires = 0;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
|
||||
instance_id
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
if (!instance_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
if (never_expires == 1) {
|
||||
if (i.never_expires) {
|
||||
return false;
|
||||
}
|
||||
|
||||
timeval tv{};
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
return (start_time + duration) <= tv.tv_sec;
|
||||
|
||||
return (i.start_time + i.duration) <= tv.tv_sec;
|
||||
}
|
||||
|
||||
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
|
||||
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
|
||||
instance_id,
|
||||
zone_id,
|
||||
version,
|
||||
duration
|
||||
);
|
||||
auto e = InstanceListRepository::NewEntity();
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
e.id = instance_id;
|
||||
e.zone = zone_id;
|
||||
e.version = version;
|
||||
e.start_time = std::time(nullptr);
|
||||
e.duration = duration;
|
||||
|
||||
return results.Success();
|
||||
return InstanceListRepository::InsertOne(*this, e).id;
|
||||
}
|
||||
|
||||
bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
@@ -157,8 +133,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
|
||||
uint32 max = 32000;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
|
||||
auto query = fmt::format(
|
||||
"SELECT IFNULL(MAX(id), {}) + 1 FROM instance_list WHERE id > {}",
|
||||
max_reserved_instance_id,
|
||||
max_reserved_instance_id
|
||||
);
|
||||
@@ -191,8 +167,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (atoi(row[0]) <= max) {
|
||||
instance_id = atoi(row[0]);
|
||||
if (Strings::ToInt(row[0]) <= max) {
|
||||
instance_id = Strings::ToInt(row[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -202,7 +178,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
|
||||
query = fmt::format("SELECT id FROM instance_list where id > {} ORDER BY id", max_reserved_instance_id);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
@@ -216,8 +192,9 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
}
|
||||
|
||||
max_reserved_instance_id++;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (max_reserved_instance_id < atoi(row[0])) {
|
||||
|
||||
for (auto row : results) {
|
||||
if (max_reserved_instance_id < Strings::ToUnsignedInt(row[0])) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
@@ -235,57 +212,45 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::GlobalInstance(uint16 instance_id)
|
||||
bool Database::IsGlobalInstance(uint16 instance_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"is_global "
|
||||
"FROM "
|
||||
"instance_list "
|
||||
"WHERE "
|
||||
"id = %u "
|
||||
"LIMIT 1 ",
|
||||
instance_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return (atoi(row[0]) == 1) ? true : false;
|
||||
return i.is_global;
|
||||
}
|
||||
|
||||
bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
|
||||
{
|
||||
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu",
|
||||
(unsigned long)instance_id, (unsigned long)char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
return InstanceListPlayerRepository::DeleteWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND charid = {}",
|
||||
instance_id,
|
||||
char_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool Database::RemoveClientsFromInstance(uint16 instance_id)
|
||||
{
|
||||
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu", (unsigned long)instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
return InstanceListPlayerRepository::DeleteOne(*this, instance_id);
|
||||
}
|
||||
|
||||
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
|
||||
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id)
|
||||
{
|
||||
//we are not saved to this instance so set our instance to 0
|
||||
if (!GlobalInstance(instance_id) && !CharacterInInstanceGroup(instance_id, char_id))
|
||||
if (!IsGlobalInstance(instance_id) && !CheckInstanceByCharID(instance_id, character_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CheckInstanceExpired(instance_id))
|
||||
{
|
||||
if (CheckInstanceExpired(instance_id)) {
|
||||
DeleteInstance(instance_id);
|
||||
return false;
|
||||
}
|
||||
@@ -295,99 +260,102 @@ bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
|
||||
|
||||
bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("SELECT id FROM instance_list where id=%u AND zone=%u", instance_id, zone_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
auto l = InstanceListRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND zone = {}",
|
||||
instance_id,
|
||||
zone_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 Database::GetInstanceID(uint32 zone, uint32 character_id, int16 version)
|
||||
uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 version)
|
||||
{
|
||||
if (!zone)
|
||||
if (!zone_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"instance_list.id "
|
||||
"FROM "
|
||||
"instance_list, "
|
||||
"instance_list_player "
|
||||
"WHERE "
|
||||
"instance_list.zone = %u "
|
||||
"AND instance_list.version = %u "
|
||||
"AND instance_list.id = instance_list_player.id "
|
||||
"AND instance_list_player.charid = %u "
|
||||
"LIMIT 1; ",
|
||||
zone,
|
||||
const auto query = fmt::format(
|
||||
"SELECT instance_list.id FROM "
|
||||
"instance_list, instance_list_player WHERE "
|
||||
"instance_list.zone = {} AND "
|
||||
"instance_list.version = {} AND "
|
||||
"instance_list.id = instance_list_player.id AND "
|
||||
"instance_list_player.charid = {} "
|
||||
"LIMIT 1;",
|
||||
zone_id,
|
||||
version,
|
||||
character_id
|
||||
);
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
return static_cast<uint16>(Strings::ToUnsignedInt(row[0]));
|
||||
}
|
||||
|
||||
uint16 Database::GetInstanceVersion(uint16 instance_id) {
|
||||
if (instance_id == 0)
|
||||
return 0;
|
||||
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id)
|
||||
{
|
||||
std::vector<uint16> l;
|
||||
|
||||
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
|
||||
if (!zone_id) {
|
||||
return l;
|
||||
}
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT instance_list.id FROM "
|
||||
"instance_list, instance_list_player WHERE "
|
||||
"instance_list.zone = {} AND "
|
||||
"instance_list.id = instance_list_player.id AND "
|
||||
"instance_list_player.charid = {}",
|
||||
zone_id,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return l;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
for (auto row : results) {
|
||||
l.push_back(static_cast<uint16>(Strings::ToUnsignedInt(row[0])));
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
return l;
|
||||
}
|
||||
|
||||
uint8_t Database::GetInstanceVersion(uint16 instance_id) {
|
||||
if (!instance_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return i.version;
|
||||
}
|
||||
|
||||
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
|
||||
{
|
||||
uint32 start_time = 0;
|
||||
uint32 duration = 0;
|
||||
uint32 never_expires = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
is_perma = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
is_perma = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
if (never_expires == 1)
|
||||
{
|
||||
if (i.never_expires) {
|
||||
is_perma = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -396,204 +364,173 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return ((start_time + duration) - tv.tv_sec);
|
||||
return ((i.start_time + i.duration) - tv.tv_sec);
|
||||
}
|
||||
|
||||
uint32 Database::VersionFromInstanceID(uint16 instance_id)
|
||||
uint32 Database::GetInstanceZoneID(uint16 instance_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
if (!instance_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::ZoneIDFromInstanceID(uint16 instance_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("SELECT zone FROM instance_list where id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
return i.zone;
|
||||
}
|
||||
|
||||
void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
|
||||
{
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
|
||||
uint16 version = VersionFromInstanceID(instance_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `charid` FROM `group_id` WHERE `groupid` = %u", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
auto l = GroupIdRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"groupid = {}",
|
||||
group_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (GetInstanceID(zone_id, charid, version) == 0)
|
||||
AddClientToInstance(instance_id, charid);
|
||||
for (const auto& e : l) {
|
||||
if (!GetInstanceID(zone_id, e.charid, version)) {
|
||||
AddClientToInstance(instance_id, e.charid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
|
||||
{
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
|
||||
uint16 version = VersionFromInstanceID(instance_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `charid` FROM `raid_members` WHERE `raidid` = %u", raid_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (GetInstanceID(zone_id, charid, version) == 0)
|
||||
AddClientToInstance(instance_id, charid);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::BuryCorpsesInInstance(uint16 instance_id) {
|
||||
QueryDatabase(
|
||||
auto l = RaidMembersRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id = {}",
|
||||
instance_id
|
||||
"raidid = {}",
|
||||
raid_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (!GetInstanceID(zone_id, e.charid, version)) {
|
||||
AddClientToInstance(instance_id, e.charid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database::DeleteInstance(uint16 instance_id)
|
||||
{
|
||||
std::string query;
|
||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||
|
||||
query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
query = StringFormat("DELETE FROM respawn_times WHERE instance_id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
|
||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
BuryCorpsesInInstance(instance_id);
|
||||
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
|
||||
}
|
||||
|
||||
void Database::FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid)
|
||||
void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id)
|
||||
{
|
||||
uint16 id = GetInstanceID(zone, charid, version);
|
||||
if (id != 0)
|
||||
auto instance_id = GetInstanceID(zone_id, character_id, version);
|
||||
if (instance_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
char ln[128];
|
||||
memset(ln, 0, 128);
|
||||
GetGroupLeadershipInfo(gid, ln);
|
||||
uint32 l_charid = GetCharacterID((const char*)ln);
|
||||
uint16 l_id = GetInstanceID(zone, l_charid, version);
|
||||
GetGroupLeadershipInfo(group_id, ln);
|
||||
|
||||
if (l_id == 0)
|
||||
auto group_leader_id = GetCharacterID((const char*)ln);
|
||||
auto group_leader_instance_id = GetInstanceID(zone_id, group_leader_id, version);
|
||||
|
||||
if (!group_leader_instance_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddClientToInstance(l_id, charid);
|
||||
AddClientToInstance(group_leader_instance_id, character_id);
|
||||
}
|
||||
|
||||
void Database::FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid)
|
||||
void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id)
|
||||
{
|
||||
uint16 id = GetInstanceID(zone, charid, version);
|
||||
if (id != 0)
|
||||
uint16 instance_id = GetInstanceID(zone_id, character_id, version);
|
||||
if (instance_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
|
||||
uint16 l_id = GetInstanceID(zone, l_charid, version);
|
||||
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id));
|
||||
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version);
|
||||
|
||||
if (l_id == 0)
|
||||
if (!raid_leader_instance_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddClientToInstance(l_id, charid);
|
||||
AddClientToInstance(raid_leader_instance_id, character_id);
|
||||
}
|
||||
|
||||
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list) {
|
||||
|
||||
std::string query = StringFormat("SELECT `charid` FROM `instance_list_player` WHERE `id` = %u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids)
|
||||
{
|
||||
auto l = InstanceListPlayerRepository::GetWhere(*this, fmt::format("id = {}", instance_id));
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
charid_list.push_back(atoi(row[0]));
|
||||
for (const auto& e : l) {
|
||||
character_ids.push_back(e.charid);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::PurgeExpiredInstances()
|
||||
{
|
||||
|
||||
/**
|
||||
* Delay purging by a day so that we can continue using adjacent free instance id's
|
||||
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
|
||||
* has not been fully de-allocated
|
||||
*/
|
||||
std::string query =
|
||||
SQL(
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
instance_list
|
||||
where
|
||||
(start_time + duration) <= (UNIX_TIMESTAMP() - 86400)
|
||||
and never_expires = 0
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
auto l = InstanceListRepository::GetWhere(
|
||||
*this,
|
||||
"(start_time + duration) <= (UNIX_TIMESTAMP() - 86400) AND never_expires = 0"
|
||||
);
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> instance_ids;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
instance_ids.emplace_back(row[0]);
|
||||
for (const auto& e : l) {
|
||||
instance_ids.emplace_back(std::to_string(e.id));
|
||||
}
|
||||
|
||||
std::string imploded_instance_ids = Strings::Implode(",", instance_ids);
|
||||
const auto imploded_instance_ids = Strings::Implode(",", instance_ids);
|
||||
|
||||
QueryDatabase(fmt::format("DELETE FROM instance_list WHERE id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM instance_list_player WHERE id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
|
||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
|
||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids);
|
||||
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
|
||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
}
|
||||
|
||||
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
|
||||
"duration=%u WHERE id=%u", new_duration, instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
i.start_time = std::time(nullptr);
|
||||
i.duration = new_duration;
|
||||
|
||||
InstanceListRepository::UpdateOne(*this, i);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,6 @@ namespace DatabaseSchema {
|
||||
"fishing",
|
||||
"forage",
|
||||
"global_loot",
|
||||
"goallists",
|
||||
"graveyard",
|
||||
"grid",
|
||||
"grid_entries",
|
||||
@@ -322,18 +321,18 @@ namespace DatabaseSchema {
|
||||
"discord_webhooks",
|
||||
"dynamic_zone_members",
|
||||
"dynamic_zones",
|
||||
"eventlog",
|
||||
"expedition_lockouts",
|
||||
"expeditions",
|
||||
"gm_ips",
|
||||
"group_id",
|
||||
"group_leaders",
|
||||
"hackers",
|
||||
"instance_list",
|
||||
"ip_exemptions",
|
||||
"item_tick",
|
||||
"lfguild",
|
||||
"merc_buffs",
|
||||
"merchantlist_temp",
|
||||
"mercs",
|
||||
"object_contents",
|
||||
"raid_details",
|
||||
"raid_leaders",
|
||||
@@ -342,6 +341,8 @@ namespace DatabaseSchema {
|
||||
"respawn_times",
|
||||
"saylink",
|
||||
"server_scheduled_events",
|
||||
"player_event_log_settings",
|
||||
"player_event_logs",
|
||||
"shared_task_activity_state",
|
||||
"shared_task_dynamic_zones",
|
||||
"shared_task_members",
|
||||
@@ -391,9 +392,6 @@ namespace DatabaseSchema {
|
||||
"bot_command_settings",
|
||||
"bot_create_combinations",
|
||||
"bot_data",
|
||||
"bot_group_members",
|
||||
"bot_groups",
|
||||
"bot_guild_members",
|
||||
"bot_heal_rotation_members",
|
||||
"bot_heal_rotation_targets",
|
||||
"bot_heal_rotations",
|
||||
@@ -404,11 +402,31 @@ namespace DatabaseSchema {
|
||||
"bot_pet_inventories",
|
||||
"bot_pets",
|
||||
"bot_spell_casting_chances",
|
||||
"bot_spell_settings",
|
||||
"bot_spells_entries",
|
||||
"bot_stances",
|
||||
"bot_timers",
|
||||
"vw_bot_character_mobs",
|
||||
"vw_bot_groups"
|
||||
"bot_timers"
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> GetMercTables()
|
||||
{
|
||||
return {
|
||||
"merc_armorinfo",
|
||||
"merc_inventory",
|
||||
"merc_merchant_entries",
|
||||
"merc_merchant_template_entries",
|
||||
"merc_merchant_templates",
|
||||
"merc_name_types",
|
||||
"merc_npc_types",
|
||||
"merc_spell_list_entries",
|
||||
"merc_spell_lists",
|
||||
"merc_stance_entries",
|
||||
"merc_stats",
|
||||
"merc_subtypes",
|
||||
"merc_templates",
|
||||
"merc_types",
|
||||
"merc_weaponinfo"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+58
-52
@@ -34,14 +34,16 @@
|
||||
|
||||
DBcore::DBcore()
|
||||
{
|
||||
mysql_init(&mysql);
|
||||
pHost = nullptr;
|
||||
pUser = nullptr;
|
||||
pPassword = nullptr;
|
||||
pDatabase = nullptr;
|
||||
pCompress = false;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
mysql = mysql_init(nullptr);
|
||||
mysqlOwner = true;
|
||||
pHost = nullptr;
|
||||
pUser = nullptr;
|
||||
pPassword = nullptr;
|
||||
pDatabase = nullptr;
|
||||
pCompress = false;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
m_mutex = new Mutex;
|
||||
}
|
||||
|
||||
DBcore::~DBcore()
|
||||
@@ -51,16 +53,10 @@ DBcore::~DBcore()
|
||||
* are re-using the default database connection pointer when we dont have an
|
||||
* external configuration setup ex: (content_database)
|
||||
*/
|
||||
std::string mysql_connection_host;
|
||||
if (mysql.host) {
|
||||
mysql_connection_host = mysql.host;
|
||||
if (mysqlOwner) {
|
||||
mysql_close(mysql);
|
||||
}
|
||||
|
||||
if (GetOriginHost() != mysql_connection_host) {
|
||||
return;
|
||||
}
|
||||
|
||||
mysql_close(&mysql);
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
@@ -70,20 +66,21 @@ DBcore::~DBcore()
|
||||
// Sends the MySQL server a keepalive
|
||||
void DBcore::ping()
|
||||
{
|
||||
if (!MDatabase.trylock()) {
|
||||
if (!m_mutex->trylock()) {
|
||||
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
|
||||
return;
|
||||
}
|
||||
mysql_ping(&mysql);
|
||||
MDatabase.unlock();
|
||||
mysql_ping(mysql);
|
||||
m_mutex->unlock();
|
||||
}
|
||||
|
||||
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
|
||||
MySQLRequestResult DBcore::QueryDatabase(const std::string& query, bool retryOnFailureOnce)
|
||||
{
|
||||
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
|
||||
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBcore::DoesTableExist(std::string table_name)
|
||||
bool DBcore::DoesTableExist(const std::string& table_name)
|
||||
{
|
||||
auto results = QueryDatabase(fmt::format("SHOW TABLES LIKE '{}'", table_name));
|
||||
|
||||
@@ -95,18 +92,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
LockMutex lock(&MDatabase);
|
||||
LockMutex lock(m_mutex);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected) {
|
||||
Open();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// request query. != 0 indicates some kind of error.
|
||||
if (mysql_real_query(&mysql, query, querylen) != 0) {
|
||||
unsigned int errorNumber = mysql_errno(&mysql);
|
||||
if (mysql_real_query(mysql, query, querylen) != 0) {
|
||||
unsigned int errorNumber = mysql_errno(mysql);
|
||||
|
||||
if (errorNumber == CR_SERVER_GONE_ERROR) {
|
||||
pStatus = Error;
|
||||
@@ -130,26 +125,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
|
||||
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer);
|
||||
}
|
||||
|
||||
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
|
||||
|
||||
/**
|
||||
* Error logging
|
||||
*/
|
||||
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
|
||||
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
if (mysql_errno(mysql) > 0 && query[0] != '\0') {
|
||||
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
|
||||
}
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
|
||||
}
|
||||
|
||||
// successful query. get results.
|
||||
MYSQL_RES *res = mysql_store_result(&mysql);
|
||||
MYSQL_RES *res = mysql_store_result(mysql);
|
||||
uint32 rowCount = 0;
|
||||
|
||||
if (res != nullptr) {
|
||||
@@ -158,16 +153,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
|
||||
MySQLRequestResult requestResult(
|
||||
res,
|
||||
(uint32) mysql_affected_rows(&mysql),
|
||||
(uint32) mysql_affected_rows(mysql),
|
||||
rowCount,
|
||||
(uint32) mysql_field_count(&mysql),
|
||||
(uint32) mysql_insert_id(&mysql)
|
||||
(uint32) mysql_field_count(mysql),
|
||||
(uint32) mysql_insert_id(mysql)
|
||||
);
|
||||
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
||||
if ((strncasecmp(query, "select", 6) == 0)) {
|
||||
LogMySQLQuery(
|
||||
"{0}; -- ({1} row{2} returned) ({3}s)",
|
||||
"{0} -- ({1} row{2} returned) ({3}s)",
|
||||
query,
|
||||
requestResult.RowCount(),
|
||||
requestResult.RowCount() == 1 ? "" : "s",
|
||||
@@ -176,7 +171,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
}
|
||||
else {
|
||||
LogMySQLQuery(
|
||||
"{0}; -- ({1} row{2} affected) ({3}s)",
|
||||
"{0} -- ({1} row{2} affected) ({3}s)",
|
||||
query,
|
||||
requestResult.RowsAffected(),
|
||||
requestResult.RowsAffected() == 1 ? "" : "s",
|
||||
@@ -207,7 +202,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
|
||||
{
|
||||
// No good reason to lock the DB, we only need it in the first place to check char encoding.
|
||||
// LockMutex lock(&MDatabase);
|
||||
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
|
||||
return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen);
|
||||
}
|
||||
|
||||
bool DBcore::Open(
|
||||
@@ -222,7 +217,7 @@ bool DBcore::Open(
|
||||
bool iSSL
|
||||
)
|
||||
{
|
||||
LockMutex lock(&MDatabase);
|
||||
LockMutex lock(m_mutex);
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
@@ -242,13 +237,13 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
if (errbuf) {
|
||||
errbuf[0] = 0;
|
||||
}
|
||||
LockMutex lock(&MDatabase);
|
||||
LockMutex lock(m_mutex);
|
||||
if (GetStatus() == Connected) {
|
||||
return true;
|
||||
}
|
||||
if (GetStatus() == Error) {
|
||||
mysql_close(&mysql);
|
||||
mysql_init(&mysql); // Initialize structure again
|
||||
mysql_close(mysql);
|
||||
mysql_init(mysql); // Initialize structure again
|
||||
}
|
||||
if (!pHost) {
|
||||
return false;
|
||||
@@ -265,7 +260,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
if (pSSL) {
|
||||
flags |= CLIENT_SSL;
|
||||
}
|
||||
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
|
||||
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
|
||||
pStatus = Connected;
|
||||
|
||||
std::string connected_origin_host = pHost;
|
||||
@@ -275,21 +270,16 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
}
|
||||
else {
|
||||
if (errnum) {
|
||||
*errnum = mysql_errno(&mysql);
|
||||
*errnum = mysql_errno(mysql);
|
||||
}
|
||||
if (errbuf) {
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
|
||||
}
|
||||
pStatus = Error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DBcore::SetMysql(MYSQL *mysql)
|
||||
{
|
||||
DBcore::mysql = *mysql;
|
||||
}
|
||||
|
||||
const std::string &DBcore::GetOriginHost() const
|
||||
{
|
||||
return origin_host;
|
||||
@@ -299,3 +289,19 @@ void DBcore::SetOriginHost(const std::string &origin_host)
|
||||
{
|
||||
DBcore::origin_host = origin_host;
|
||||
}
|
||||
|
||||
std::string DBcore::Escape(const std::string& s)
|
||||
{
|
||||
const std::size_t s_len = s.length();
|
||||
std::vector<char> temp((s_len * 2) + 1, '\0');
|
||||
mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len);
|
||||
|
||||
return temp.data();
|
||||
}
|
||||
|
||||
void DBcore::SetMutex(Mutex *mutex)
|
||||
{
|
||||
safe_delete(m_mutex);
|
||||
|
||||
DBcore::m_mutex = mutex;
|
||||
}
|
||||
|
||||
+16
-6
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <mysql.h>
|
||||
#include <string.h>
|
||||
#include <mutex>
|
||||
|
||||
class DBcore {
|
||||
public:
|
||||
@@ -23,19 +24,25 @@ public:
|
||||
~DBcore();
|
||||
eStatus GetStatus() { return pStatus; }
|
||||
MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true);
|
||||
MySQLRequestResult QueryDatabase(std::string query, bool retryOnFailureOnce = true);
|
||||
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
|
||||
void TransactionBegin();
|
||||
void TransactionCommit();
|
||||
void TransactionRollback();
|
||||
std::string Escape(const std::string& s);
|
||||
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
|
||||
void ping();
|
||||
MYSQL *getMySQL() { return &mysql; }
|
||||
void SetMysql(MYSQL *mysql);
|
||||
|
||||
const std::string &GetOriginHost() const;
|
||||
void SetOriginHost(const std::string &origin_host);
|
||||
|
||||
bool DoesTableExist(std::string table_name);
|
||||
bool DoesTableExist(const std::string& table_name);
|
||||
|
||||
void SetMySQL(const DBcore &o)
|
||||
{
|
||||
mysql = o.mysql;
|
||||
mysqlOwner = false;
|
||||
}
|
||||
void SetMutex(Mutex *mutex);
|
||||
|
||||
protected:
|
||||
bool Open(
|
||||
@@ -53,10 +60,13 @@ protected:
|
||||
private:
|
||||
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
|
||||
|
||||
MYSQL mysql;
|
||||
Mutex MDatabase;
|
||||
MYSQL* mysql;
|
||||
bool mysqlOwner;
|
||||
Mutex *m_mutex;
|
||||
eStatus pStatus;
|
||||
|
||||
std::mutex m_query_lock{};
|
||||
|
||||
std::string origin_host;
|
||||
|
||||
char *pHost;
|
||||
|
||||
+89
-15
@@ -1,22 +1,17 @@
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
#include "discord.h"
|
||||
#include "../http/httplib.h"
|
||||
#include "../json/json.h"
|
||||
#include "../strings.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../events/player_event_logs.h"
|
||||
|
||||
constexpr int MAX_RETRIES = 10;
|
||||
|
||||
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
|
||||
{
|
||||
// validate
|
||||
if (webhook_url.empty()) {
|
||||
LogDiscord("[webhook_url] is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// validate
|
||||
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
|
||||
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
|
||||
if (!ValidateWebhookUrl(webhook_url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,13 +23,10 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
|
||||
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
|
||||
|
||||
// client
|
||||
httplib::Client cli(base_url.c_str());
|
||||
httplib::Client cli(base_url);
|
||||
cli.set_connection_timeout(0, 15000000); // 15 sec
|
||||
cli.set_read_timeout(15, 0); // 15 seconds
|
||||
cli.set_write_timeout(15, 0); // 15 seconds
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// payload
|
||||
Json::Value p;
|
||||
@@ -46,7 +38,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
|
||||
int retries = 0;
|
||||
int retry_timer = 1000;
|
||||
while (retry) {
|
||||
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
|
||||
if (auto res = cli.Post(endpoint, payload.str(), "application/json")) {
|
||||
if (res->status != 200 && res->status != 204) {
|
||||
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
|
||||
}
|
||||
@@ -62,7 +54,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
|
||||
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
|
||||
}
|
||||
|
||||
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
|
||||
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
|
||||
}
|
||||
|
||||
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
|
||||
@@ -81,6 +73,71 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
|
||||
}
|
||||
}
|
||||
|
||||
void Discord::SendPlayerEventMessage(
|
||||
const PlayerEvent::PlayerEventContainer &e,
|
||||
const std::string &webhook_url
|
||||
)
|
||||
{
|
||||
if (!ValidateWebhookUrl(webhook_url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto s = Strings::Split(webhook_url, '/');
|
||||
|
||||
// url
|
||||
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
|
||||
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
|
||||
|
||||
// client
|
||||
httplib::Client cli(base_url);
|
||||
cli.set_connection_timeout(0, 15000000); // 15 sec
|
||||
cli.set_read_timeout(15, 0); // 15 seconds
|
||||
cli.set_write_timeout(15, 0); // 15 seconds
|
||||
|
||||
std::string payload = PlayerEventLogs::GetDiscordPayloadFromEvent(e);
|
||||
if (payload.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool retry = true;
|
||||
int retries = 0;
|
||||
int retry_timer = 1000;
|
||||
while (retry) {
|
||||
if (auto res = cli.Post(endpoint, payload, "application/json")) {
|
||||
if (res->status != 200 && res->status != 204) {
|
||||
LogError("Code [{}] Error [{}]", res->status, res->body);
|
||||
}
|
||||
if (res->status == 429) {
|
||||
if (!res->body.empty()) {
|
||||
std::stringstream ss(res->body);
|
||||
Json::Value response;
|
||||
|
||||
try {
|
||||
ss >> response;
|
||||
}
|
||||
catch (std::exception const &ex) {
|
||||
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
|
||||
}
|
||||
|
||||
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
|
||||
}
|
||||
|
||||
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
|
||||
}
|
||||
if (res->status == 204) {
|
||||
retry = false;
|
||||
}
|
||||
if (retries > MAX_RETRIES) {
|
||||
LogDiscord("Retries exceeded for player event message");
|
||||
retry = false;
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
|
||||
{
|
||||
if (category_id == Logs::LogCategory::MySQLQuery) {
|
||||
@@ -89,3 +146,20 @@ std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string
|
||||
|
||||
return message + "\n";
|
||||
}
|
||||
|
||||
bool Discord::ValidateWebhookUrl(const std::string &webhook_url)
|
||||
{
|
||||
// validate
|
||||
if (webhook_url.empty()) {
|
||||
LogDiscord("[webhook_url] is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate
|
||||
if (!Strings::Contains(webhook_url, "http://") && !Strings::Contains(webhook_url, "https://")) {
|
||||
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
|
||||
#include <string>
|
||||
#include "../types.h"
|
||||
#include "../http/httplib.h"
|
||||
#include "../repositories/player_event_logs_repository.h"
|
||||
#include "../events/player_events.h"
|
||||
|
||||
class Discord {
|
||||
public:
|
||||
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
|
||||
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
|
||||
static void SendPlayerEventMessage(const PlayerEvent::PlayerEventContainer& e, const std::string &webhook_url);
|
||||
static bool ValidateWebhookUrl(const std::string &webhook_url);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "discord_manager.h"
|
||||
#include "../common/discord/discord.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../../common/discord/discord.h"
|
||||
#include "../events/player_event_logs.h"
|
||||
|
||||
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
|
||||
{
|
||||
@@ -38,7 +37,7 @@ void DiscordManager::ProcessMessageQueue()
|
||||
message,
|
||||
webhook.webhook_url
|
||||
);
|
||||
message = "";
|
||||
message.clear();
|
||||
}
|
||||
|
||||
message += m;
|
||||
@@ -52,10 +51,9 @@ void DiscordManager::ProcessMessageQueue()
|
||||
webhook.webhook_url
|
||||
);
|
||||
}
|
||||
message = "";
|
||||
message.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// final flush
|
||||
if (!message.empty()) {
|
||||
Discord::SendWebhookMessage(
|
||||
@@ -67,3 +65,11 @@ void DiscordManager::ProcessMessageQueue()
|
||||
webhook_message_queue.clear();
|
||||
webhook_queue_lock.unlock();
|
||||
}
|
||||
|
||||
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
|
||||
{
|
||||
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
|
||||
if (!w.empty()) {
|
||||
Discord::SendPlayerEventMessage(e, w);
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,15 @@
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/types.h"
|
||||
#include "../../common/types.h"
|
||||
#include "../repositories/player_event_logs_repository.h"
|
||||
#include "../events/player_events.h"
|
||||
|
||||
class DiscordManager {
|
||||
public:
|
||||
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
|
||||
void ProcessMessageQueue();
|
||||
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
|
||||
private:
|
||||
std::mutex webhook_queue_lock{};
|
||||
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
|
||||
+91
-24
@@ -197,11 +197,11 @@ const std::map<int, std::string>& EQ::constants::GetLanguageMap()
|
||||
|
||||
std::string EQ::constants::GetLanguageName(int language_id)
|
||||
{
|
||||
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
||||
if (!EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
|
||||
@@ -220,11 +220,11 @@ const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
|
||||
|
||||
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
|
||||
{
|
||||
if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
|
||||
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
|
||||
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
|
||||
}
|
||||
|
||||
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
@@ -243,11 +243,11 @@ const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
|
||||
std::string EQ::constants::GetFlyModeName(int8 flymode_id)
|
||||
{
|
||||
if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
|
||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||
if (!EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||
}
|
||||
|
||||
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
|
||||
@@ -365,11 +365,11 @@ const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
|
||||
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
|
||||
{
|
||||
if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) {
|
||||
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
|
||||
if (!EQ::ValueWithin(faction_consider_level, ConsiderLevel::Ally, ConsiderLevel::Scowls)) {
|
||||
return std::string();;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
|
||||
@@ -386,11 +386,11 @@ const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
|
||||
|
||||
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
|
||||
{
|
||||
if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
|
||||
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
|
||||
if (!EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
|
||||
@@ -407,11 +407,11 @@ const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
|
||||
|
||||
std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id)
|
||||
{
|
||||
if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
|
||||
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
|
||||
if (!EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
|
||||
@@ -429,11 +429,11 @@ const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
|
||||
|
||||
std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
|
||||
{
|
||||
if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
|
||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||
if (!EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||
}
|
||||
|
||||
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
|
||||
@@ -507,9 +507,76 @@ const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
|
||||
|
||||
std::string EQ::constants::GetObjectTypeName(int object_type)
|
||||
{
|
||||
if (EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
|
||||
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
|
||||
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
|
||||
return std::string();
|
||||
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> weather_type_map = {
|
||||
{WeatherTypes::None, "None"},
|
||||
{WeatherTypes::Raining, "Raining"},
|
||||
{WeatherTypes::Snowing, "Snowing"}
|
||||
};
|
||||
|
||||
return weather_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetWeatherTypeName(uint8 weather_type)
|
||||
{
|
||||
if (!EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> emote_event_type_map = {
|
||||
{ EmoteEventTypes::LeaveCombat, "Leave Combat" },
|
||||
{ EmoteEventTypes::EnterCombat, "Enter Combat" },
|
||||
{ EmoteEventTypes::OnDeath, "On Death" },
|
||||
{ EmoteEventTypes::AfterDeath, "After Death" },
|
||||
{ EmoteEventTypes::Hailed, "Hailed" },
|
||||
{ EmoteEventTypes::KilledPC, "Killed PC" },
|
||||
{ EmoteEventTypes::KilledNPC, "Killed NPC" },
|
||||
{ EmoteEventTypes::OnSpawn, "On Spawn" },
|
||||
{ EmoteEventTypes::OnDespawn, "On Despawn" }
|
||||
};
|
||||
|
||||
return emote_event_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
|
||||
{
|
||||
if (!EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> emote_type_map = {
|
||||
{ EmoteTypes::Emote, "Emote" },
|
||||
{ EmoteTypes::Shout, "Shout" },
|
||||
{ EmoteTypes::Proximity, "Proximity" }
|
||||
};
|
||||
|
||||
return emote_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
|
||||
{
|
||||
if (!EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
|
||||
}
|
||||
|
||||
+91
-1
@@ -217,6 +217,25 @@ namespace EQ
|
||||
stanceBurnAE
|
||||
};
|
||||
|
||||
enum BotSpellIDs : int {
|
||||
Warrior = 3001,
|
||||
Cleric,
|
||||
Paladin,
|
||||
Ranger,
|
||||
Shadowknight,
|
||||
Druid,
|
||||
Monk,
|
||||
Bard,
|
||||
Rogue,
|
||||
Shaman,
|
||||
Necromancer,
|
||||
Wizard,
|
||||
Magician,
|
||||
Enchanter,
|
||||
Beastlord,
|
||||
Berserker
|
||||
};
|
||||
|
||||
enum GravityBehavior : int8 {
|
||||
Ground,
|
||||
Flying,
|
||||
@@ -312,6 +331,30 @@ namespace EQ
|
||||
NoDeposit
|
||||
};
|
||||
|
||||
enum WeatherTypes : uint8 {
|
||||
None,
|
||||
Raining,
|
||||
Snowing
|
||||
};
|
||||
|
||||
enum EmoteEventTypes : uint8 {
|
||||
LeaveCombat,
|
||||
EnterCombat,
|
||||
OnDeath,
|
||||
AfterDeath,
|
||||
Hailed,
|
||||
KilledPC,
|
||||
KilledNPC,
|
||||
OnSpawn,
|
||||
OnDespawn
|
||||
};
|
||||
|
||||
enum EmoteTypes : uint8 {
|
||||
Emote,
|
||||
Shout,
|
||||
Proximity
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
@@ -345,6 +388,15 @@ namespace EQ
|
||||
extern const std::map<int, std::string>& GetObjectTypeMap();
|
||||
std::string GetObjectTypeName(int object_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
|
||||
std::string GetWeatherTypeName(uint8 weather_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEmoteEventTypeMap();
|
||||
std::string GetEmoteEventTypeName(uint8 emote_event_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEmoteTypeMap();
|
||||
std::string GetEmoteTypeName(uint8 emote_type);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
@@ -515,7 +567,7 @@ enum ReloadWorld : uint8 {
|
||||
ForceRepop
|
||||
};
|
||||
|
||||
enum MerchantBucketComparison : uint8 {
|
||||
enum BucketComparison : uint8 {
|
||||
BucketEqualTo = 0,
|
||||
BucketNotEqualTo,
|
||||
BucketGreaterThanOrEqualTo,
|
||||
@@ -528,4 +580,42 @@ enum MerchantBucketComparison : uint8 {
|
||||
BucketIsNotBetween
|
||||
};
|
||||
|
||||
enum class EntityFilterType {
|
||||
All,
|
||||
Bots,
|
||||
Clients,
|
||||
NPCs
|
||||
};
|
||||
|
||||
enum class ApplySpellType {
|
||||
Solo,
|
||||
Group,
|
||||
Raid
|
||||
};
|
||||
|
||||
|
||||
namespace HeroicBonusBucket
|
||||
{
|
||||
const std::string WisMaxMana = "HWIS-MaxMana";
|
||||
const std::string WisManaRegen = "HWIS-ManaRegen";
|
||||
const std::string WisHealAmt = "HWIS-HealAmt";
|
||||
const std::string IntMaxMana = "HINT-MaxMana";
|
||||
const std::string IntManaRegen = "HINT-ManaRegen";
|
||||
const std::string IntSpellDmg = "HINT-SpellDmg";
|
||||
const std::string StrMeleeDamage = "HSTR-MeleeDamage";
|
||||
const std::string StrShieldAC = "HSTR-ShieldAC";
|
||||
const std::string StrMaxEndurance = "HSTR-MaxEndurance";
|
||||
const std::string StrEnduranceRegen = "HSTR-EnduranceRegen";
|
||||
const std::string StaMaxHP = "HSTA-MaxHP";
|
||||
const std::string StaHPRegen = "HSTA-HPRegen";
|
||||
const std::string StaMaxEndurance = "HSTA-MaxEndurance";
|
||||
const std::string StaEnduranceRegen = "HSTA-EnduranceRegen";
|
||||
const std::string AgiAvoidance = "HAGI-Avoidance";
|
||||
const std::string AgiMaxEndurance = "HAGI-MaxEndurance";
|
||||
const std::string AgiEnduranceRegen = "HAGI-EnduranceRegen";
|
||||
const std::string DexRangedDamage = "HDEX-RangedDamage";
|
||||
const std::string DexMaxEndurance = "HDEX-MaxEndurance";
|
||||
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
|
||||
}
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
|
||||
N(OP_AltCurrencyPurchase),
|
||||
N(OP_AltCurrencyReclaim),
|
||||
N(OP_AltCurrencySell),
|
||||
N(OP_AltCurrencySellSelection),
|
||||
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
|
||||
N(OP_Animation),
|
||||
N(OP_AnnoyingZoneUnknown),
|
||||
N(OP_ApplyPoison),
|
||||
|
||||
+38
-9
@@ -79,6 +79,8 @@
|
||||
#define ANIM_DEATH 0x73
|
||||
#define ANIM_LOOT 0x69
|
||||
|
||||
constexpr int16 RECAST_TYPE_UNLINKED_ITEM = -1;
|
||||
|
||||
typedef enum {
|
||||
eaStanding = 0,
|
||||
eaSitting, //1
|
||||
@@ -684,14 +686,6 @@ namespace Zones {
|
||||
constexpr uint16 APPRENTICE = 999; // Designer Apprentice
|
||||
}
|
||||
|
||||
//ZoneChange_Struct->success values
|
||||
#define ZONE_ERROR_NOMSG 0
|
||||
#define ZONE_ERROR_NOTREADY -1
|
||||
#define ZONE_ERROR_VALIDPC -2
|
||||
#define ZONE_ERROR_STORYZONE -3
|
||||
#define ZONE_ERROR_NOEXPANSION -6
|
||||
#define ZONE_ERROR_NOEXPERIENCE -7
|
||||
|
||||
|
||||
typedef enum {
|
||||
FilterNone = 0,
|
||||
@@ -718,7 +712,7 @@ typedef enum {
|
||||
FilterPetMisses = 21, //0=show, 1=hide
|
||||
FilterFocusEffects = 22, //0=show, 1=hide
|
||||
FilterPetSpells = 23, //0=show, 1=hide
|
||||
FilterHealOverTime = 24, //0=show, 1=hide
|
||||
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
|
||||
FilterUnknown25 = 25,
|
||||
FilterUnknown26 = 26,
|
||||
FilterUnknown27 = 27,
|
||||
@@ -1016,4 +1010,39 @@ enum FVNoDropFlagRule
|
||||
AdminOnly = 2
|
||||
};
|
||||
|
||||
enum Anonymity : uint8
|
||||
{
|
||||
NotAnonymous,
|
||||
Anonymous,
|
||||
Roleplaying
|
||||
};
|
||||
|
||||
enum ZoningMessage : int8 {
|
||||
ZoneNoMessage = 0,
|
||||
ZoneSuccess = 1,
|
||||
ZoneNotReady = -1,
|
||||
ZoneValidPC = -2,
|
||||
ZoneStoryZone = -3,
|
||||
ZoneNoExpansion = -6,
|
||||
ZoneNoExperience = -7
|
||||
};
|
||||
|
||||
enum class RecipeCountType : uint8
|
||||
{
|
||||
Component,
|
||||
Container,
|
||||
Fail,
|
||||
Salvage,
|
||||
Success
|
||||
};
|
||||
|
||||
#define ALT_CURRENCY_ID_RADIANT 4
|
||||
#define ALT_CURRENCY_ID_EBON 5
|
||||
|
||||
enum ResurrectionActions
|
||||
{
|
||||
Decline,
|
||||
Accept
|
||||
};
|
||||
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ namespace EQ
|
||||
|
||||
LookupEntry(const LookupEntry *lookup_entry) { }
|
||||
LookupEntry(
|
||||
InventoryTypeSize_Struct InventoryTypeSize,
|
||||
const InventoryTypeSize_Struct& InventoryTypeSize,
|
||||
uint64 EquipmentBitmask,
|
||||
uint64 GeneralBitmask,
|
||||
uint64 CursorBitmask,
|
||||
|
||||
+1
-138
@@ -236,26 +236,6 @@ uint32 EQApplicationPacket::serialize(uint16 opcode, unsigned char *dest) const
|
||||
return size+OpCodeBytes;
|
||||
}
|
||||
|
||||
/*EQProtocolPacket::EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len)
|
||||
: BasePacket(buf, len),
|
||||
opcode(op)
|
||||
{
|
||||
|
||||
uint32 offset;
|
||||
opcode=ntohs(*(const uint16 *)buf);
|
||||
offset=2;
|
||||
|
||||
if (len-offset) {
|
||||
pBuffer= new unsigned char[len-offset];
|
||||
memcpy(pBuffer,buf+offset,len-offset);
|
||||
size=len-offset;
|
||||
} else {
|
||||
pBuffer=nullptr;
|
||||
size=0;
|
||||
}
|
||||
OpMgr=&RawOpcodeManager;
|
||||
}*/
|
||||
|
||||
bool EQProtocolPacket::combine(const EQProtocolPacket *rhs)
|
||||
{
|
||||
bool result=false;
|
||||
@@ -287,74 +267,6 @@ bool result=false;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
this is the code to do app-layer combining, instead of protocol layer.
|
||||
this was taken out due to complex interactions with the opcode manager,
|
||||
and will require a bit more thinking (likely moving into EQStream) to
|
||||
get running again... but might be a good thing some day.
|
||||
|
||||
bool EQApplicationPacket::combine(const EQApplicationPacket *rhs)
|
||||
{
|
||||
uint32 newsize=0, offset=0;
|
||||
unsigned char *tmpbuffer=nullptr;
|
||||
|
||||
if (opcode!=OP_AppCombined) {
|
||||
newsize=app_opcode_size+size+(size>254?3:1)+app_opcode_size+rhs->size+(rhs->size>254?3:1);
|
||||
tmpbuffer=new unsigned char [newsize];
|
||||
offset=0;
|
||||
if (size>254) {
|
||||
tmpbuffer[offset++]=0xff;
|
||||
*(uint16 *)(tmpbuffer+offset)=htons(size);
|
||||
offset+=1;
|
||||
} else {
|
||||
tmpbuffer[offset++]=size;
|
||||
}
|
||||
offset+=serialize(tmpbuffer+offset);
|
||||
} else {
|
||||
newsize=size+app_opcode_size+rhs->size+(rhs->size>254?3:1);
|
||||
tmpbuffer=new unsigned char [newsize];
|
||||
memcpy(tmpbuffer,pBuffer,size);
|
||||
offset=size;
|
||||
}
|
||||
|
||||
if (rhs->size>254) {
|
||||
tmpbuffer[offset++]=0xff;
|
||||
*(uint16 *)(tmpbuffer+offset)=htons(rhs->size);
|
||||
offset+=1;
|
||||
} else {
|
||||
tmpbuffer[offset++]=rhs->size;
|
||||
}
|
||||
offset+=rhs->serialize(tmpbuffer+offset);
|
||||
|
||||
size=offset;
|
||||
opcode=OP_AppCombined;
|
||||
|
||||
delete[] pBuffer;
|
||||
pBuffer=tmpbuffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key)
|
||||
{
|
||||
bool valid=false;
|
||||
// OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd
|
||||
if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) {
|
||||
valid=true;
|
||||
} else {
|
||||
uint16 comp_crc=CRC16(buffer,length-2,Key);
|
||||
uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2));
|
||||
#ifdef EQN_DEBUG
|
||||
if (packet_crc && comp_crc != packet_crc) {
|
||||
std::cout << "CRC mismatch: comp=" << std::hex << comp_crc << ", packet=" << packet_crc << std::dec << std::endl;
|
||||
}
|
||||
#endif
|
||||
valid = (!packet_crc || comp_crc == packet_crc);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize)
|
||||
{
|
||||
uint32 newlen=0;
|
||||
@@ -403,55 +315,6 @@ uint32 flag_offset=1,newlength;
|
||||
return newlength;
|
||||
}
|
||||
|
||||
void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey)
|
||||
{
|
||||
if ((size >= 2) && buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
|
||||
int Key=DecodeKey;
|
||||
unsigned char *test=(unsigned char *)malloc(size);
|
||||
buffer+=2;
|
||||
size-=2;
|
||||
|
||||
int i;
|
||||
for (i = 0 ; i+4 <= size ; i+=4)
|
||||
{
|
||||
int pt = (*(int*)&buffer[i])^(Key);
|
||||
Key = (*(int*)&buffer[i]);
|
||||
*(int*)&test[i]=pt;
|
||||
}
|
||||
unsigned char KC=Key&0xFF;
|
||||
for ( ; i < size ; i++)
|
||||
{
|
||||
test[i]=buffer[i]^KC;
|
||||
}
|
||||
memcpy(buffer,test,size);
|
||||
free(test);
|
||||
}
|
||||
}
|
||||
|
||||
void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey)
|
||||
{
|
||||
if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
|
||||
int Key=EncodeKey;
|
||||
char *test=(char*)malloc(size);
|
||||
int i;
|
||||
buffer+=2;
|
||||
size-=2;
|
||||
for ( i = 0 ; i+4 <= size ; i+=4)
|
||||
{
|
||||
int pt = (*(int*)&buffer[i])^(Key);
|
||||
Key = pt;
|
||||
*(int*)&test[i]=pt;
|
||||
}
|
||||
unsigned char KC=Key&0xFF;
|
||||
for ( ; i < size ; i++)
|
||||
{
|
||||
test[i]=buffer[i]^KC;
|
||||
}
|
||||
memcpy(buffer,test,size);
|
||||
free(test);
|
||||
}
|
||||
}
|
||||
|
||||
EQApplicationPacket *EQApplicationPacket::Copy() const {
|
||||
return(new EQApplicationPacket(*this));
|
||||
}
|
||||
@@ -515,4 +378,4 @@ std::string DumpPacketToString(const EQApplicationPacket* app){
|
||||
std::ostringstream out;
|
||||
out << DumpPacketHexToString(app->pBuffer, app->size);
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +80,8 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
static bool ValidateCRC(const unsigned char *buffer, int length, uint32 Key);
|
||||
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
|
||||
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
|
||||
static void ChatDecode(unsigned char *buffer, int size, int DecodeKey);
|
||||
static void ChatEncode(unsigned char *buffer, int size, int EncodeKey);
|
||||
|
||||
uint16 GetRawOpcode() const { return(opcode); }
|
||||
|
||||
|
||||
+22
-16
@@ -29,7 +29,7 @@
|
||||
#include "textures.h"
|
||||
|
||||
|
||||
static const uint32 BUFF_COUNT = 25;
|
||||
static const uint32 BUFF_COUNT = 42;
|
||||
static const uint32 PET_BUFF_COUNT = 30;
|
||||
static const uint32 MAX_MERC = 100;
|
||||
static const uint32 MAX_MERC_GRADES = 10;
|
||||
@@ -3632,17 +3632,19 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
|
||||
};
|
||||
|
||||
struct MerchantList {
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint8 min_status;
|
||||
uint8 max_status;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
std::string bucket_name;
|
||||
std::string bucket_value;
|
||||
uint8 bucket_comparison;
|
||||
uint8 bucket_comparison;
|
||||
};
|
||||
|
||||
struct TempMerchantList {
|
||||
@@ -4545,7 +4547,7 @@ struct ItemVerifyReply_Struct {
|
||||
struct ItemRecastDelay_Struct {
|
||||
/*000*/ uint32 recast_delay; // in seconds
|
||||
/*004*/ uint32 recast_type;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*008*/ bool ignore_casting_requirement; //Ignores recast times allows items to be reset?
|
||||
/*012*/
|
||||
};
|
||||
|
||||
@@ -5163,10 +5165,10 @@ struct AltCurrencySelectItemReply_Struct {
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint8 unknown004; //0xff
|
||||
/*005*/ uint8 unknown005; //0xff
|
||||
/*006*/ uint8 unknown006; //0xff
|
||||
/*007*/ uint8 unknown007; //0xff
|
||||
/*008*/ char item_name[64];
|
||||
/*072*/ uint32 unknown074;
|
||||
/*006*/ uint16 unknown006; //0xffff
|
||||
/*008*/ uint16 unknown008; //0xffff
|
||||
/*010*/ char item_name[64];
|
||||
/*074*/ uint16 unknown074;
|
||||
/*076*/ uint32 cost;
|
||||
/*080*/ uint32 unknown080;
|
||||
/*084*/ uint32 unknown084;
|
||||
@@ -5520,7 +5522,11 @@ struct ServerLootItem_Struct {
|
||||
uint32 aug_4; // uint32 aug_4;
|
||||
uint32 aug_5; // uint32 aug_5;
|
||||
uint32 aug_6; // uint32 aug_5;
|
||||
uint8 attuned;
|
||||
bool attuned;
|
||||
std::string custom_data;
|
||||
uint32 ornamenticon {};
|
||||
uint32 ornamentidfile {};
|
||||
uint32 ornament_hero_model {};
|
||||
uint16 trivial_min_level;
|
||||
uint16 trivial_max_level;
|
||||
uint16 npc_min_level;
|
||||
|
||||
+11
-6
@@ -218,13 +218,13 @@ class EQStream : public EQStreamInterface {
|
||||
|
||||
void init(bool resetSession=true);
|
||||
public:
|
||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
|
||||
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
|
||||
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
|
||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
|
||||
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
|
||||
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
|
||||
streamactive = false; }
|
||||
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
|
||||
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
|
||||
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
|
||||
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
|
||||
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
|
||||
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
|
||||
create_time = Timer::GetTimeSeconds(); }
|
||||
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
|
||||
void SetMaxLen(uint32 length) { MaxLen=length; }
|
||||
@@ -243,6 +243,11 @@ class EQStream : public EQStreamInterface {
|
||||
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
|
||||
|
||||
virtual OpcodeManager* GetOpcodeManager() const
|
||||
{
|
||||
return (*OpMgr);
|
||||
};
|
||||
|
||||
void CheckTimeout(uint32 now, uint32 timeout=30);
|
||||
bool HasOutgoingData();
|
||||
void Process(const unsigned char *data, const uint32 length);
|
||||
|
||||
@@ -26,7 +26,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
|
||||
}
|
||||
}
|
||||
|
||||
void EQStreamIdentifier::RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
|
||||
void EQStreamIdentifier::RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
|
||||
auto p = new Patch;
|
||||
p->signature = sig;
|
||||
p->name = name;
|
||||
@@ -145,7 +145,7 @@ void EQStreamIdentifier::Process() {
|
||||
}
|
||||
|
||||
void EQStreamIdentifier::AddStream(std::shared_ptr<EQStreamInterface> eqs) {
|
||||
m_streams.push_back(Record(eqs));
|
||||
m_streams.emplace_back(Record(eqs));
|
||||
eqs = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
~EQStreamIdentifier();
|
||||
|
||||
//registration interface.
|
||||
void RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
|
||||
void RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
|
||||
|
||||
//main processing interface
|
||||
void Process();
|
||||
|
||||
@@ -30,7 +30,7 @@ struct EQStreamManagerInterfaceOptions
|
||||
|
||||
//World seems to support both compression and xor zone supports one or the others.
|
||||
//Enforce one or the other in the convienence construct
|
||||
//Login I had trouble getting to recognize compression at all
|
||||
//Login I had trouble getting to recognize compression at all
|
||||
//but that might be because it was still a bit buggy when i was testing that.
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression;
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
|
||||
virtual EQStreamState GetState() = 0;
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
|
||||
virtual OpcodeManager* GetOpcodeManager() const = 0;
|
||||
virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; }
|
||||
virtual Stats GetStats() const = 0;
|
||||
virtual void ResetStats() = 0;
|
||||
|
||||
@@ -38,12 +38,8 @@ void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
|
||||
}
|
||||
|
||||
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
if(p == nullptr)
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
|
||||
if (p->GetOpcode() != OP_SpecialMesg) {
|
||||
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
|
||||
EQApplicationPacket *newp = p->Copy();
|
||||
@@ -112,3 +108,8 @@ bool EQStreamProxy::CheckState(EQStreamState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OpcodeManager *EQStreamProxy::GetOpcodeManager() const
|
||||
{
|
||||
return (*m_opcodes);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,15 @@ public:
|
||||
virtual Stats GetStats() const;
|
||||
virtual void ResetStats();
|
||||
virtual EQStreamManagerInterface* GetManager() const;
|
||||
virtual OpcodeManager* GetOpcodeManager() const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
|
||||
const StructStrategy *const m_structs; //we do not own this object.
|
||||
//this is a pointer to a pointer to make it less likely that a packet will
|
||||
//reference an invalid opcode manager when they are being reloaded.
|
||||
OpcodeManager **const m_opcodes; //we do not own this object.
|
||||
OpcodeManager **const m_opcodes;
|
||||
//we do not own this object.
|
||||
};
|
||||
|
||||
#endif /*EQSTREAMPROXY_H_*/
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
EQDB EQDB::s_EQDB;
|
||||
|
||||
EQDB::EQDB() {
|
||||
}
|
||||
|
||||
unsigned int EQDB::field_count() {
|
||||
return mysql_field_count(mysql_ref);
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
|
||||
//this is the main object exported to perl.
|
||||
class EQDB {
|
||||
EQDB();
|
||||
EQDB() = default;
|
||||
public:
|
||||
static EQDB *Singleton() { return(&s_EQDB); }
|
||||
|
||||
|
||||
+19
-18
@@ -19,6 +19,7 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "misc_functions.h"
|
||||
#include "strings.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -33,13 +34,13 @@ void EQEmuConfig::parse_config()
|
||||
LongName = _root["server"]["world"].get("longname", "").asString();
|
||||
WorldAddress = _root["server"]["world"].get("address", "").asString();
|
||||
LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
|
||||
MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
|
||||
MaxClients = Strings::ToInt(_root["server"]["world"].get("maxclients", "-1").asString());
|
||||
SharedKey = _root["server"]["world"].get("key", "").asString();
|
||||
LoginCount = 0;
|
||||
|
||||
if (_root["server"]["world"]["loginserver"].isObject()) {
|
||||
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
|
||||
LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
|
||||
LoginPort = Strings::ToUnsignedInt(_root["server"]["world"]["loginserver"].get("port", "5998").asString());
|
||||
LoginLegacy = false;
|
||||
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
|
||||
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
|
||||
@@ -62,7 +63,7 @@ void EQEmuConfig::parse_config()
|
||||
|
||||
auto loginconfig = new LoginConfig;
|
||||
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
|
||||
loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
|
||||
loginconfig->LoginPort = Strings::ToUnsignedInt(_root["server"]["world"][str].get("port", "5998").asString());
|
||||
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
|
||||
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
|
||||
|
||||
@@ -85,15 +86,15 @@ void EQEmuConfig::parse_config()
|
||||
Locked = false;
|
||||
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
|
||||
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
|
||||
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
|
||||
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
|
||||
|
||||
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
|
||||
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
|
||||
TelnetTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["telnet"].get("port", "9001").asString());
|
||||
TelnetEnabled = false;
|
||||
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; }
|
||||
|
||||
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
|
||||
WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
|
||||
WorldHTTPPort = Strings::ToUnsignedInt(_root["server"]["world"]["http"].get("port", "9080").asString());
|
||||
WorldHTTPEnabled = false;
|
||||
|
||||
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") {
|
||||
@@ -108,9 +109,9 @@ void EQEmuConfig::parse_config()
|
||||
* UCS
|
||||
*/
|
||||
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
|
||||
ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
|
||||
ChatPort = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "7778").asString());
|
||||
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
|
||||
MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
|
||||
MailPort = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "7778").asString());
|
||||
|
||||
/**
|
||||
* Database
|
||||
@@ -118,7 +119,7 @@ void EQEmuConfig::parse_config()
|
||||
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
|
||||
DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
|
||||
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
|
||||
DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
|
||||
DatabasePort = Strings::ToUnsignedInt(_root["server"]["database"].get("port", "3306").asString());
|
||||
DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
|
||||
|
||||
/**
|
||||
@@ -127,14 +128,14 @@ void EQEmuConfig::parse_config()
|
||||
ContentDbUsername = _root["server"]["content_database"].get("username", "").asString();
|
||||
ContentDbPassword = _root["server"]["content_database"].get("password", "").asString();
|
||||
ContentDbHost = _root["server"]["content_database"].get("host", "").asString();
|
||||
ContentDbPort = atoi(_root["server"]["content_database"].get("port", 0).asString().c_str());
|
||||
ContentDbPort = Strings::ToUnsignedInt(_root["server"]["content_database"].get("port", 0).asString());
|
||||
ContentDbName = _root["server"]["content_database"].get("db", "").asString();
|
||||
|
||||
/**
|
||||
* QS
|
||||
*/
|
||||
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
|
||||
QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
|
||||
QSDatabasePort = Strings::ToUnsignedInt(_root["server"]["qsdatabase"].get("port", "3306").asString());
|
||||
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
|
||||
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
|
||||
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
|
||||
@@ -142,9 +143,9 @@ void EQEmuConfig::parse_config()
|
||||
/**
|
||||
* Zones
|
||||
*/
|
||||
DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
|
||||
ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
|
||||
ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
|
||||
DefaultStatus = Strings::ToUnsignedInt(_root["server"]["zones"].get("defaultstatus", 0).asString());
|
||||
ZonePortLow = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("low", "7000").asString());
|
||||
ZonePortHigh = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("high", "7999").asString());
|
||||
|
||||
/**
|
||||
* Files
|
||||
@@ -174,10 +175,10 @@ void EQEmuConfig::parse_config()
|
||||
/**
|
||||
* Launcher
|
||||
*/
|
||||
RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
|
||||
TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
|
||||
InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
|
||||
ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
|
||||
RestartWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("restart", "10000").asString());
|
||||
TerminateWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString());
|
||||
InitialBootWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("initial", "20000").asString());
|
||||
ZoneBootInterval = Strings::ToInt(_root["server"]["launcher"]["timers"].get("interval", "2000").asString());
|
||||
#ifdef WIN32
|
||||
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
|
||||
#else
|
||||
|
||||
+15
-11
@@ -20,7 +20,9 @@
|
||||
|
||||
#include "json/json.h"
|
||||
#include "linked_list.h"
|
||||
#include "path_manager.h"
|
||||
#include <fstream>
|
||||
#include <fmt/format.h>
|
||||
|
||||
struct LoginConfig {
|
||||
std::string LoginHost;
|
||||
@@ -145,30 +147,32 @@ class EQEmuConfig
|
||||
return (_config);
|
||||
}
|
||||
|
||||
// Allow the use to set the conf file to be used.
|
||||
static void SetConfigFile(std::string file)
|
||||
{
|
||||
EQEmuConfig::ConfigFile = file;
|
||||
}
|
||||
|
||||
// Load the config
|
||||
static bool LoadConfig()
|
||||
static bool LoadConfig(const std::string& path = "")
|
||||
{
|
||||
if (_config != nullptr) {
|
||||
return true;
|
||||
}
|
||||
_config = new EQEmuConfig;
|
||||
|
||||
return parseFile();
|
||||
return parseFile(path);
|
||||
}
|
||||
|
||||
// Load config file and parse data
|
||||
static bool parseFile() {
|
||||
static bool parseFile(const std::string& file_path = ".")
|
||||
{
|
||||
if (_config == nullptr) {
|
||||
return LoadConfig();
|
||||
return LoadConfig(file_path);
|
||||
}
|
||||
|
||||
std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary);
|
||||
std::string file = fmt::format(
|
||||
"{}/{}",
|
||||
(file_path.empty() ? path.GetServerPath() : file_path),
|
||||
EQEmuConfig::ConfigFile
|
||||
);
|
||||
|
||||
std::ifstream fconfig(file, std::ifstream::binary);
|
||||
|
||||
try {
|
||||
fconfig >> _config->_root;
|
||||
_config->parse_config();
|
||||
|
||||
+265
-256
@@ -22,21 +22,19 @@
|
||||
#include "rulesys.h"
|
||||
#include "platform.h"
|
||||
#include "strings.h"
|
||||
#include "misc.h"
|
||||
#include "discord/discord.h"
|
||||
#include "repositories/discord_webhooks_repository.h"
|
||||
#include "repositories/logsys_categories_repository.h"
|
||||
#include "termcolor/rang.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
|
||||
std::ofstream process_log;
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
@@ -52,46 +50,12 @@ std::ofstream process_log;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Linux ANSI console color defines
|
||||
*/
|
||||
#define LC_RESET "\033[0m"
|
||||
#define LC_BLACK "\033[30m" /* Black */
|
||||
#define LC_RED "\033[31m" /* Red */
|
||||
#define LC_GREEN "\033[32m" /* Green */
|
||||
#define LC_YELLOW "\033[33m" /* Yellow */
|
||||
#define LC_BLUE "\033[34m" /* Blue */
|
||||
#define LC_MAGENTA "\033[35m" /* Magenta */
|
||||
#define LC_CYAN "\033[36m" /* Cyan */
|
||||
#define LC_WHITE "\033[37m" /* White */
|
||||
|
||||
namespace Console {
|
||||
enum Color {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Magenta = 5,
|
||||
Brown = 6,
|
||||
LightGray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
LightMagenta = 13,
|
||||
Yellow = 14,
|
||||
White = 15
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* EQEmuLogSys Constructor
|
||||
*/
|
||||
EQEmuLogSys::EQEmuLogSys()
|
||||
{
|
||||
m_on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||
m_on_log_gmsay_hook = [](uint16 log_type, const char *func, const std::string &) {};
|
||||
m_on_log_console_hook = [](uint16 log_type, const std::string &) {};
|
||||
}
|
||||
|
||||
@@ -120,14 +84,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
/**
|
||||
* Set Defaults
|
||||
*/
|
||||
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
|
||||
@@ -140,16 +98,14 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QuestErrors].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
*/
|
||||
log_settings[Logs::Emergency].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Alert].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Critical].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Notice].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
@@ -194,39 +150,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
|
||||
{
|
||||
return (
|
||||
log_category == Logs::Emergency ||
|
||||
log_category == Logs::Alert ||
|
||||
log_category == Logs::Critical ||
|
||||
log_category == Logs::Error ||
|
||||
log_category == Logs::Warning ||
|
||||
log_category == Logs::Notice ||
|
||||
log_category == Logs::Info ||
|
||||
log_category == Logs::Debug
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @param in_message
|
||||
* @return
|
||||
*/
|
||||
std::string EQEmuLogSys::FormatOutMessageString(
|
||||
uint16 log_category,
|
||||
const std::string &in_message
|
||||
)
|
||||
{
|
||||
std::string return_string = "[" + GetPlatformName() + "] ";
|
||||
|
||||
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
@@ -257,64 +180,6 @@ void EQEmuLogSys::ProcessLogWrite(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return Console::Color::Yellow;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Error:
|
||||
return Console::Color::LightRed;
|
||||
case Logs::MySQLQuery:
|
||||
case Logs::Debug:
|
||||
return Console::Color::LightGreen;
|
||||
case Logs::Quests:
|
||||
return Console::Color::LightCyan;
|
||||
case Logs::Commands:
|
||||
case Logs::Mercenaries:
|
||||
return Console::Color::LightMagenta;
|
||||
case Logs::Crash:
|
||||
return Console::Color::LightRed;
|
||||
default:
|
||||
return Console::Color::Yellow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return LC_YELLOW;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Warning:
|
||||
case Logs::Critical:
|
||||
case Logs::Error:
|
||||
return LC_RED;
|
||||
case Logs::MySQLQuery:
|
||||
case Logs::Debug:
|
||||
return LC_GREEN;
|
||||
case Logs::Quests:
|
||||
return LC_CYAN;
|
||||
case Logs::Commands:
|
||||
case Logs::Mercenaries:
|
||||
return LC_MAGENTA;
|
||||
case Logs::Crash:
|
||||
return LC_RED;
|
||||
default:
|
||||
return LC_YELLOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
@@ -322,11 +187,10 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
|
||||
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return Chat::Yellow;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Crash:
|
||||
case Logs::Error:
|
||||
case Logs::MySQLError:
|
||||
case Logs::QuestErrors:
|
||||
return Chat::Red;
|
||||
case Logs::MySQLQuery:
|
||||
case Logs::Debug:
|
||||
@@ -336,35 +200,149 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
||||
case Logs::Commands:
|
||||
case Logs::Mercenaries:
|
||||
return Chat::Magenta;
|
||||
case Logs::Crash:
|
||||
return Chat::Red;
|
||||
default:
|
||||
return Chat::Yellow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessConsoleMessage(uint16 log_category, const std::string &message)
|
||||
void EQEmuLogSys::ProcessConsoleMessage(
|
||||
uint16 log_category,
|
||||
const std::string &message,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line
|
||||
)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
HANDLE console_handle;
|
||||
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_FONT_INFOEX info = { 0 };
|
||||
info.cbSize = sizeof(info);
|
||||
info.dwFontSize.Y = 12; // leave X as zero
|
||||
info.FontWeight = FW_NORMAL;
|
||||
wcscpy(info.FaceName, L"Lucida Console");
|
||||
SetCurrentConsoleFontEx(console_handle, NULL, &info);
|
||||
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
|
||||
std::cout << message << "\n";
|
||||
SetConsoleTextAttribute(console_handle, Console::Color::White);
|
||||
#else
|
||||
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
||||
#endif
|
||||
bool is_error = (
|
||||
log_category == Logs::LogCategory::Error ||
|
||||
log_category == Logs::LogCategory::MySQLError ||
|
||||
log_category == Logs::LogCategory::Crash ||
|
||||
log_category == Logs::LogCategory::QuestErrors
|
||||
);
|
||||
bool is_warning = (
|
||||
log_category == Logs::LogCategory::Warning
|
||||
);
|
||||
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< ""
|
||||
<< rang::fgB::black
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:>6}", GetPlatformName().substr(0, 6))
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " | "
|
||||
<< ((is_error || is_warning) ? rang::fgB::red : rang::fgB::gray)
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:^10}", fmt::format("{}", Logs::LogCategoryName[log_category]).substr(0, 10))
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " | "
|
||||
<< rang::fgB::gray
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{}", func)
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " ";
|
||||
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< ""
|
||||
<< rang::fgB::green
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:}", fmt::format("{}:{}:{}", std::filesystem::path(file).filename().string(), func, line))
|
||||
<< rang::style::reset
|
||||
<< " | ";
|
||||
}
|
||||
|
||||
if (log_category == Logs::LogCategory::MySQLQuery) {
|
||||
auto s = Strings::Split(message, "--");
|
||||
if (s.size() > 1) {
|
||||
std::string query = Strings::Trim(s[0]);
|
||||
std::string meta = Strings::Trim(s[1]);
|
||||
|
||||
std::cout <<
|
||||
rang::fgB::green
|
||||
<<
|
||||
query
|
||||
<<
|
||||
rang::style::reset;
|
||||
|
||||
std::cout <<
|
||||
rang::fgB::black
|
||||
<<
|
||||
" -- "
|
||||
<<
|
||||
meta
|
||||
<<
|
||||
rang::style::reset;
|
||||
}
|
||||
}
|
||||
else if (Strings::Contains(message, "[")) {
|
||||
for (auto &e: Strings::Split(message, " ")) {
|
||||
if (Strings::Contains(e, "[") && Strings::Contains(e, "]")) {
|
||||
e = Strings::Replace(e, "[", "");
|
||||
e = Strings::Replace(e, "]", "");
|
||||
|
||||
bool is_upper = false;
|
||||
|
||||
for (int i = 0; i < strlen(e.c_str()); i++) {
|
||||
if (isupper(e[i])) {
|
||||
is_upper = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_upper) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< rang::fgB::gray
|
||||
<< "["
|
||||
<< rang::style::bold
|
||||
<< rang::fgB::yellow
|
||||
<< e
|
||||
<< rang::fgB::gray
|
||||
<< "] "
|
||||
;
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr) << rang::fgB::gray << "[" << e << "] ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< (is_error ? rang::fgB::red : rang::fgB::gray)
|
||||
<< e
|
||||
<< " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< (is_error ? rang::fgB::red : rang::fgB::gray)
|
||||
<< message
|
||||
<< " ";
|
||||
}
|
||||
|
||||
if (!origination_info.zone_short_name.empty()) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<<
|
||||
rang::fgB::black
|
||||
<<
|
||||
"-- "
|
||||
<<
|
||||
fmt::format(
|
||||
"[{}] ({}) inst_id [{}]",
|
||||
origination_info.zone_short_name,
|
||||
origination_info.zone_long_name,
|
||||
origination_info.instance_id
|
||||
);
|
||||
}
|
||||
|
||||
(!is_error ? std::cout : std::cerr) << rang::style::reset << std::endl;
|
||||
|
||||
m_on_log_console_hook(log_category, message);
|
||||
}
|
||||
@@ -378,33 +356,6 @@ constexpr const char *str_end(const char *str)
|
||||
return *str ? str_end(str + 1) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr bool str_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *r_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? (str + 1) : r_slant(str - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *base_file_name(const char *str)
|
||||
{
|
||||
return str_slant(str) ? r_slant(str_end(str)) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logging function
|
||||
*
|
||||
@@ -423,49 +374,54 @@ void EQEmuLogSys::Out(
|
||||
...
|
||||
)
|
||||
{
|
||||
bool log_to_console = log_settings[log_category].log_to_console > 0 &&
|
||||
log_settings[log_category].log_to_console >= debug_level;
|
||||
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
|
||||
log_settings[log_category].log_to_file >= debug_level;
|
||||
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
|
||||
log_settings[log_category].log_to_gmsay >= debug_level &&
|
||||
log_category != Logs::LogCategory::Netcode &&
|
||||
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
|
||||
bool log_to_discord = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
|
||||
log_settings[log_category].log_to_discord > 0 &&
|
||||
log_settings[log_category].log_to_discord >= debug_level &&
|
||||
log_settings[log_category].discord_webhook_id > 0 &&
|
||||
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
|
||||
auto l = GetLogsEnabled(debug_level, log_category);
|
||||
|
||||
// bail out if nothing to log
|
||||
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
|
||||
if (nothing_to_log) {
|
||||
if (!l.log_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prefix;
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", std::filesystem::path(file).filename().string(), func, line);
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
std::string output_message = vStringFormat(message, args);
|
||||
va_end(args);
|
||||
// remove this when we remove all legacy logs
|
||||
bool ignore_log_legacy_format = (
|
||||
log_category == Logs::Netcode ||
|
||||
log_category == Logs::PacketServerClient ||
|
||||
log_category == Logs::PacketClientServer ||
|
||||
log_category == Logs::PacketServerToServer
|
||||
);
|
||||
|
||||
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
|
||||
// remove this when we remove all legacy logs
|
||||
std::string output_message = message;
|
||||
if (!ignore_log_legacy_format) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
output_message = vStringFormat(message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (log_to_console) {
|
||||
EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
|
||||
if (l.log_to_console_enabled) {
|
||||
EQEmuLogSys::ProcessConsoleMessage(
|
||||
log_category,
|
||||
output_message,
|
||||
file,
|
||||
func,
|
||||
line
|
||||
);
|
||||
}
|
||||
if (log_to_gmsay) {
|
||||
m_on_log_gmsay_hook(log_category, output_message);
|
||||
if (l.log_to_gmsay_enabled) {
|
||||
m_on_log_gmsay_hook(log_category, func, output_message);
|
||||
}
|
||||
if (log_to_file) {
|
||||
EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
|
||||
if (l.log_to_file_enabled) {
|
||||
EQEmuLogSys::ProcessLogWrite(
|
||||
log_category,
|
||||
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
|
||||
);
|
||||
}
|
||||
if (log_to_discord && m_on_log_discord_hook) {
|
||||
if (l.log_to_discord_enabled && m_on_log_discord_hook) {
|
||||
m_on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
|
||||
}
|
||||
}
|
||||
@@ -479,7 +435,7 @@ void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
|
||||
struct tm *time_info;
|
||||
time(&raw_time);
|
||||
time_info = localtime(&raw_time);
|
||||
strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
|
||||
strftime(time_stamp, 80, "[%m-%d-%Y %H:%M:%S]", time_info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,37 +490,29 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", m_platform_file_name.c_str(), getpid());
|
||||
LogInfo("Starting File Log [{}/zone/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
|
||||
|
||||
/**
|
||||
* Make directory if not exists
|
||||
*/
|
||||
EQEmuLogSys::MakeDirectory("logs/zone");
|
||||
// Make directory if not exists
|
||||
EQEmuLogSys::MakeDirectory(fmt::format("{}/zone", GetLogPath()));
|
||||
|
||||
/**
|
||||
* Open file pointer
|
||||
*/
|
||||
// Open file pointer
|
||||
process_log.open(
|
||||
StringFormat("logs/zone/%s_%i.log", m_platform_file_name.c_str(), getpid()),
|
||||
fmt::format("{}/zone/{}_{}.log", GetLogPath(), m_platform_file_name, getpid()),
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
/**
|
||||
* All other processes
|
||||
*/
|
||||
// All other processes
|
||||
if (m_platform_file_name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", m_platform_file_name.c_str(), getpid());
|
||||
LogInfo("Starting File Log [{}/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
|
||||
|
||||
/**
|
||||
* Open file pointer
|
||||
*/
|
||||
// Open file pointer
|
||||
process_log.open(
|
||||
StringFormat("logs/%s_%i.log", m_platform_file_name.c_str(), getpid()),
|
||||
fmt::format("{}/{}_{}.log", GetLogPath(), m_platform_file_name.c_str(), getpid()),
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
}
|
||||
@@ -579,6 +527,8 @@ void EQEmuLogSys::SilenceConsoleLogging()
|
||||
log_settings[log_index].log_to_console = 0;
|
||||
log_settings[log_index].is_category_enabled = 0;
|
||||
}
|
||||
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,10 +592,23 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
|
||||
// Auto inject categories that don't exist in the database...
|
||||
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
|
||||
if (std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end()) {
|
||||
|
||||
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
|
||||
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
|
||||
if (!is_missing_in_database && is_deprecated_category) {
|
||||
LogInfo(
|
||||
"Automatically adding new log category [{0}]",
|
||||
Logs::LogCategoryName[i]
|
||||
"Logging category [{}] ({}) is now deprecated, deleting from database",
|
||||
Logs::LogCategoryName[i],
|
||||
i
|
||||
);
|
||||
LogsysCategoriesRepository::DeleteOne(*m_database, i);
|
||||
}
|
||||
|
||||
if (is_missing_in_database && !is_deprecated_category) {
|
||||
LogInfo(
|
||||
"Automatically adding new log category [{}] ({})",
|
||||
Logs::LogCategoryName[i],
|
||||
i
|
||||
);
|
||||
|
||||
auto new_category = LogsysCategoriesRepository::NewEntity();
|
||||
@@ -670,6 +633,11 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
|
||||
}
|
||||
|
||||
// force override this setting
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -696,13 +664,13 @@ void EQEmuLogSys::InjectTablesIfNotExist()
|
||||
CREATE TABLE discord_webhooks
|
||||
(
|
||||
id INT auto_increment primary key NULL,
|
||||
webhook_name varchar(100) NULL,
|
||||
webhook_url varchar(255) NULL,
|
||||
created_at DATETIME NULL,
|
||||
deleted_at DATETIME NULL
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_general_ci;
|
||||
webhook_name varchar(100) NULL,
|
||||
webhook_url varchar(255) NULL,
|
||||
created_at DATETIME NULL,
|
||||
deleted_at DATETIME NULL
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_general_ci;
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -713,15 +681,15 @@ void EQEmuLogSys::InjectTablesIfNotExist()
|
||||
m_database->QueryDatabase(
|
||||
SQL(
|
||||
CREATE TABLE `logsys_categories` (
|
||||
`log_category_id` int(11) NOT NULL,
|
||||
`log_category_description` varchar(150) DEFAULT NULL,
|
||||
`log_to_console` smallint(11) DEFAULT 0,
|
||||
`log_to_file` smallint(11) DEFAULT 0,
|
||||
`log_to_gmsay` smallint(11) DEFAULT 0,
|
||||
`log_to_discord` smallint(11) DEFAULT 0,
|
||||
`discord_webhook_id` int(11) DEFAULT 0,
|
||||
PRIMARY KEY (`log_category_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
`log_category_id` int(11) NOT NULL,
|
||||
`log_category_description` varchar(150) DEFAULT NULL,
|
||||
`log_to_console` smallint(11) DEFAULT 0,
|
||||
`log_to_file` smallint(11) DEFAULT 0,
|
||||
`log_to_gmsay` smallint(11) DEFAULT 0,
|
||||
`log_to_discord` smallint(11) DEFAULT 0,
|
||||
`discord_webhook_id` int(11) DEFAULT 0,
|
||||
PRIMARY KEY (`log_category_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -732,3 +700,44 @@ const EQEmuLogSys::DiscordWebhooks *EQEmuLogSys::GetDiscordWebhooks() const
|
||||
return m_discord_webhooks;
|
||||
}
|
||||
|
||||
EQEmuLogSys::LogEnabled EQEmuLogSys::GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
|
||||
{
|
||||
auto e = LogEnabled{};
|
||||
|
||||
e.log_to_console_enabled = log_settings[log_category].log_to_console > 0 &&
|
||||
log_settings[log_category].log_to_console >= debug_level;
|
||||
e.log_to_file_enabled = log_settings[log_category].log_to_file > 0 &&
|
||||
log_settings[log_category].log_to_file >= debug_level;
|
||||
e.log_to_gmsay_enabled = log_settings[log_category].log_to_gmsay > 0 &&
|
||||
log_settings[log_category].log_to_gmsay >= debug_level &&
|
||||
log_category != Logs::LogCategory::Netcode &&
|
||||
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
|
||||
e.log_to_discord_enabled = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
|
||||
log_settings[log_category].log_to_discord > 0 &&
|
||||
log_settings[log_category].log_to_discord >= debug_level &&
|
||||
log_settings[log_category].discord_webhook_id > 0 &&
|
||||
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
|
||||
e.log_enabled =
|
||||
e.log_to_console_enabled || e.log_to_file_enabled || e.log_to_gmsay_enabled || e.log_to_discord_enabled;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool EQEmuLogSys::IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
|
||||
{
|
||||
return GetLogsEnabled(debug_level, log_category).log_enabled;
|
||||
}
|
||||
|
||||
const std::string &EQEmuLogSys::GetLogPath() const
|
||||
{
|
||||
return m_log_path;
|
||||
}
|
||||
|
||||
EQEmuLogSys *EQEmuLogSys::SetLogPath(const std::string &log_path)
|
||||
{
|
||||
EQEmuLogSys::m_log_path = log_path;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+87
-60
@@ -39,8 +39,7 @@
|
||||
namespace Logs {
|
||||
enum DebugLevel {
|
||||
General = 1, // 1 - Low-Level general debugging, useful info on single line
|
||||
Moderate, // 2 - Informational based, used in functions, when particular things load
|
||||
Detail // 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication
|
||||
Detail // 2 - Use this for very chatty logging you want to leave in but don't want on by default
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -54,7 +53,7 @@ namespace Logs {
|
||||
AI,
|
||||
Aggro,
|
||||
Attack,
|
||||
PacketClientServer,
|
||||
DeprecatedCS, // deprecated
|
||||
Combat,
|
||||
Commands,
|
||||
Crash,
|
||||
@@ -65,36 +64,36 @@ namespace Logs {
|
||||
Inventory,
|
||||
Launcher,
|
||||
Netcode,
|
||||
Normal,
|
||||
Normal, // deprecated
|
||||
Object,
|
||||
Pathing,
|
||||
QSServer,
|
||||
QSServer, // deprecated
|
||||
Quests,
|
||||
Rules,
|
||||
Skills,
|
||||
Spawns,
|
||||
Spells,
|
||||
Status,
|
||||
Status, // deprecated
|
||||
TCPConnection,
|
||||
Tasks,
|
||||
Tradeskills,
|
||||
Trading,
|
||||
Tribute,
|
||||
UCSServer,
|
||||
WebInterfaceServer,
|
||||
WorldServer,
|
||||
ZoneServer,
|
||||
UCSServer, // deprecated
|
||||
WebInterfaceServer, // deprecated
|
||||
WorldServer, // deprecated
|
||||
ZoneServer, // deprecated
|
||||
MySQLError,
|
||||
MySQLQuery,
|
||||
Mercenaries,
|
||||
QuestDebug,
|
||||
PacketServerClient,
|
||||
PacketClientServerUnhandled,
|
||||
PacketServerClientWithDump,
|
||||
PacketClientServerWithDump,
|
||||
Loginserver,
|
||||
DeprecatedSC, // deprecated
|
||||
DeprecatedCSU, // deprecated
|
||||
DeprecatedSCD, // deprecated
|
||||
DeprecatedCSD, // deprecated
|
||||
Loginserver, // deprecated
|
||||
ClientLogin,
|
||||
HeadlessClient,
|
||||
HeadlessClient, // deprecated
|
||||
HPUpdate,
|
||||
FixZ,
|
||||
Food,
|
||||
@@ -104,10 +103,10 @@ namespace Logs {
|
||||
MobAppearance,
|
||||
Info,
|
||||
Warning,
|
||||
Critical,
|
||||
Emergency,
|
||||
Alert,
|
||||
Notice,
|
||||
Critical, // deprecated
|
||||
Emergency, // deprecated
|
||||
Alert, // deprecated
|
||||
Notice, // deprecated
|
||||
AIScanClose,
|
||||
AIYellForHelp,
|
||||
AICastBeneficialClose,
|
||||
@@ -132,6 +131,12 @@ namespace Logs {
|
||||
Hate,
|
||||
Discord,
|
||||
Faction,
|
||||
PacketServerClient,
|
||||
PacketClientServer,
|
||||
PacketServerToServer,
|
||||
Bugs,
|
||||
QuestErrors,
|
||||
PlayerEvents,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@@ -144,7 +149,7 @@ namespace Logs {
|
||||
"AI",
|
||||
"Aggro",
|
||||
"Attack",
|
||||
"Packet :: Client -> Server",
|
||||
"Deprecated",
|
||||
"Combat",
|
||||
"Commands",
|
||||
"Crash",
|
||||
@@ -155,52 +160,52 @@ namespace Logs {
|
||||
"Inventory",
|
||||
"Launcher",
|
||||
"Netcode",
|
||||
"Normal",
|
||||
"Normal (Deprecated)",
|
||||
"Object",
|
||||
"Pathing",
|
||||
"QS Server",
|
||||
"QS Server (Deprecated)",
|
||||
"Quests",
|
||||
"Rules",
|
||||
"Skills",
|
||||
"Spawns",
|
||||
"Spells",
|
||||
"Status",
|
||||
"Status (Deprecated)",
|
||||
"TCP Connection",
|
||||
"Tasks",
|
||||
"Tradeskills",
|
||||
"Trading",
|
||||
"Tribute",
|
||||
"UCS Server",
|
||||
"WebInterface Server",
|
||||
"World Server",
|
||||
"Zone Server",
|
||||
"MySQL Error",
|
||||
"MySQL Query",
|
||||
"UCS Server (Deprecated)",
|
||||
"Web Interface (Deprecated)",
|
||||
"World Server (Deprecated)",
|
||||
"Zone Server (Deprecated)",
|
||||
"QueryErr",
|
||||
"Query",
|
||||
"Mercenaries",
|
||||
"Quest Debug",
|
||||
"Packet :: Server -> Client",
|
||||
"Packet :: Client -> Server Unhandled",
|
||||
"Packet :: Server -> Client (Dump)",
|
||||
"Packet :: Client -> Server (Dump)",
|
||||
"Login Server",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Login Server (Deprecated)",
|
||||
"Client Login",
|
||||
"Headless Client",
|
||||
"Headless Client (Deprecated)",
|
||||
"HP Update",
|
||||
"FixZ",
|
||||
"Food",
|
||||
"Traps",
|
||||
"NPC Roam Box",
|
||||
"NPC Scaling",
|
||||
"Mob Appearance",
|
||||
"MobAppearance",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Critical",
|
||||
"Emergency",
|
||||
"Alert",
|
||||
"Notice",
|
||||
"AI Scan Close",
|
||||
"AI Yell For Help",
|
||||
"AI Cast Beneficial Close",
|
||||
"Critical (Deprecated)",
|
||||
"Emergency (Deprecated)",
|
||||
"Alert (Deprecated)",
|
||||
"Notice (Deprecated)",
|
||||
"AI Scan",
|
||||
"AI Yell",
|
||||
"AI CastBeneficial",
|
||||
"AOE Cast",
|
||||
"Entity Management",
|
||||
"Flee",
|
||||
@@ -217,11 +222,17 @@ namespace Logs {
|
||||
"DialogueWindow",
|
||||
"HTTP",
|
||||
"Saylink",
|
||||
"ChecksumVerification",
|
||||
"ChecksumVer",
|
||||
"CombatRecord",
|
||||
"Hate",
|
||||
"Discord",
|
||||
"Faction",
|
||||
"Packet S->C",
|
||||
"Packet C->S",
|
||||
"Packet S->S",
|
||||
"Bugs",
|
||||
"QuestErrors",
|
||||
"PlayerEvents",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -313,6 +324,17 @@ public:
|
||||
*/
|
||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
||||
|
||||
struct LogEnabled {
|
||||
bool log_to_file_enabled;
|
||||
bool log_to_console_enabled;
|
||||
bool log_to_gmsay_enabled;
|
||||
bool log_to_discord_enabled;
|
||||
bool log_enabled;
|
||||
};
|
||||
|
||||
LogEnabled GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
|
||||
bool IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
|
||||
|
||||
struct DiscordWebhooks {
|
||||
int id;
|
||||
std::string webhook_name;
|
||||
@@ -324,7 +346,7 @@ public:
|
||||
// gmsay
|
||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||
|
||||
EQEmuLogSys *SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f)
|
||||
EQEmuLogSys *SetGMSayHandler(const std::function<void(uint16 log_type, const char *func, const std::string &)>& f)
|
||||
{
|
||||
m_on_log_gmsay_hook = f;
|
||||
return this;
|
||||
@@ -349,25 +371,30 @@ public:
|
||||
// database
|
||||
EQEmuLogSys *SetDatabase(Database *db);
|
||||
|
||||
[[nodiscard]] const std::string &GetLogPath() const;
|
||||
EQEmuLogSys * SetLogPath(const std::string &log_path);
|
||||
|
||||
private:
|
||||
|
||||
// reference to database
|
||||
Database *m_database;
|
||||
std::function<void(uint16 log_category, const std::string &)> m_on_log_gmsay_hook;
|
||||
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook;
|
||||
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook;
|
||||
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
|
||||
bool m_file_logs_enabled = false;
|
||||
int m_log_platform = 0;
|
||||
std::string m_platform_file_name;
|
||||
Database *m_database;
|
||||
std::function<void(uint16 log_category, const char *func, const std::string &)> m_on_log_gmsay_hook;
|
||||
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook;
|
||||
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook;
|
||||
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
|
||||
bool m_file_logs_enabled = false;
|
||||
int m_log_platform = 0;
|
||||
std::string m_platform_file_name;
|
||||
std::string m_log_path;
|
||||
|
||||
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
|
||||
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
|
||||
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
||||
|
||||
void ProcessConsoleMessage(uint16 log_category, const std::string &message);
|
||||
void ProcessConsoleMessage(
|
||||
uint16 log_category,
|
||||
const std::string &message,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line
|
||||
);
|
||||
void ProcessLogWrite(uint16 log_category, const std::string &message);
|
||||
bool IsRfc5424LogCategory(uint16 log_category);
|
||||
void InjectTablesIfNotExist();
|
||||
};
|
||||
|
||||
|
||||
+405
-803
File diff suppressed because it is too large
Load Diff
+1
-5
@@ -58,10 +58,6 @@ EQTime::EQTime()
|
||||
SetCurrentEQTimeOfDay(start, time(0));
|
||||
}
|
||||
|
||||
EQTime::~EQTime()
|
||||
{
|
||||
}
|
||||
|
||||
//getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay
|
||||
//This function was written by the ShowEQ Project.
|
||||
//Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to.
|
||||
@@ -203,4 +199,4 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) {
|
||||
t->month, t->day, t->year, t->hour, t->minute);
|
||||
buf[127] = '\0';
|
||||
str = buf;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ public:
|
||||
//Constructor/destructor
|
||||
EQTime(TimeOfDay_Struct start_eq, time_t start_real);
|
||||
EQTime();
|
||||
~EQTime();
|
||||
~EQTime() = default;
|
||||
|
||||
//Get functions
|
||||
int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace EQ
|
||||
_running = true;
|
||||
|
||||
for (size_t i = 0; i < threads; ++i) {
|
||||
_threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
|
||||
_threads.emplace_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,214 @@
|
||||
#ifndef EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
|
||||
#define EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
|
||||
|
||||
#include <string>
|
||||
#include "player_events.h"
|
||||
#include "../repositories/base/base_player_event_logs_repository.h"
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
|
||||
struct DiscordField {
|
||||
std::string name;
|
||||
std::string value;
|
||||
bool is_inline;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(name),
|
||||
CEREAL_NVP(value),
|
||||
cereal::make_nvp("inline", is_inline)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DiscordAuthor {
|
||||
std::string name;
|
||||
std::string icon_url;
|
||||
std::string url;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(name),
|
||||
CEREAL_NVP(icon_url),
|
||||
CEREAL_NVP(url)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DiscordEmbed {
|
||||
std::vector<DiscordField> fields;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string timestamp;
|
||||
DiscordAuthor author;
|
||||
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(fields),
|
||||
CEREAL_NVP(title),
|
||||
CEREAL_NVP(description),
|
||||
CEREAL_NVP(timestamp),
|
||||
CEREAL_NVP(author)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DiscordWebhook {
|
||||
std::vector<DiscordEmbed> embeds;
|
||||
std::string content;
|
||||
std::string avatar_url;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(embeds),
|
||||
CEREAL_NVP(avatar_url),
|
||||
CEREAL_NVP(content)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PlayerEventDiscordFormatter {
|
||||
public:
|
||||
static std::string GetCurrentTimestamp();
|
||||
static std::string FormatEventSay(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::SayEvent &e);
|
||||
static std::string
|
||||
FormatGMCommand(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::GMCommandEvent &e);
|
||||
static void BuildDiscordField(
|
||||
std::vector<DiscordField> *f,
|
||||
const std::string &name,
|
||||
const std::string &value,
|
||||
bool is_inline = true
|
||||
);
|
||||
static void BuildBaseEmbed(
|
||||
std::vector<DiscordEmbed> *e,
|
||||
const std::vector<DiscordField> &f,
|
||||
PlayerEvent::PlayerEventContainer c
|
||||
);
|
||||
static std::string FormatWithNodata(const PlayerEvent::PlayerEventContainer &c);
|
||||
|
||||
static std::string FormatAAGainedEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::AAGainedEvent &e
|
||||
);
|
||||
static std::string FormatAAPurchasedEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::AAPurchasedEvent &e
|
||||
);
|
||||
static std::string FormatDeathEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::DeathEvent &e
|
||||
);
|
||||
static std::string FormatFishSuccessEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::FishSuccessEvent &e
|
||||
);
|
||||
static std::string FormatForageSuccessEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::ForageSuccessEvent &e
|
||||
);
|
||||
static std::string FormatDestroyItemEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::DestroyItemEvent &e
|
||||
);
|
||||
static std::string FormatDiscoverItemEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::DiscoverItemEvent &e
|
||||
);
|
||||
static std::string FormatDroppedItemEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::DroppedItemEvent &e
|
||||
);
|
||||
static std::string FormatLevelGainedEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::LevelGainedEvent &e
|
||||
);
|
||||
static std::string FormatLevelLostEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::LevelLostEvent &e
|
||||
);
|
||||
static std::string FormatLootItemEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::LootItemEvent &e
|
||||
);
|
||||
static std::string FormatGroundSpawnPickupEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::GroundSpawnPickupEvent &e
|
||||
);
|
||||
static std::string FormatMerchantPurchaseEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::MerchantPurchaseEvent &e
|
||||
);
|
||||
static std::string FormatMerchantSellEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::MerchantSellEvent &e
|
||||
);
|
||||
static std::string FormatNPCHandinEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::HandinEvent &e
|
||||
);
|
||||
static std::string FormatSkillUpEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::SkillUpEvent &e
|
||||
);
|
||||
static std::string FormatTaskAcceptEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TaskAcceptEvent &e
|
||||
);
|
||||
static std::string FormatTaskCompleteEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TaskCompleteEvent &e
|
||||
);
|
||||
static std::string FormatTaskUpdateEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TaskUpdateEvent &e
|
||||
);
|
||||
static std::string FormatTradeEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TradeEvent &e
|
||||
);
|
||||
static std::string FormatTraderPurchaseEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TraderPurchaseEvent &e
|
||||
);
|
||||
static std::string FormatTraderSellEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::TraderSellEvent &e
|
||||
);
|
||||
static std::string FormatResurrectAcceptEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::ResurrectAcceptEvent &e
|
||||
);
|
||||
static std::string FormatSplitMoneyEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::SplitMoneyEvent &e
|
||||
);
|
||||
static std::string FormatCombineEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::CombineEvent &e
|
||||
);
|
||||
static std::string FormatZoningEvent(
|
||||
const PlayerEvent::PlayerEventContainer &c,
|
||||
const PlayerEvent::ZoningEvent &e
|
||||
);
|
||||
static DiscordWebhook BuildDiscordWebhook(
|
||||
const PlayerEvent::PlayerEventContainer &p,
|
||||
std::vector<DiscordEmbed> &embeds
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
|
||||
@@ -0,0 +1,702 @@
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include "player_event_logs.h"
|
||||
#include "player_event_discord_formatter.h"
|
||||
#include "../platform.h"
|
||||
#include "../rulesys.h"
|
||||
|
||||
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
|
||||
|
||||
// general initialization routine
|
||||
void PlayerEventLogs::Init()
|
||||
{
|
||||
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
|
||||
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
|
||||
|
||||
ValidateDatabaseConnection();
|
||||
|
||||
// initialize settings array
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
m_settings[i].id = i;
|
||||
m_settings[i].event_name = PlayerEvent::EventName[i];
|
||||
m_settings[i].event_enabled = 1;
|
||||
m_settings[i].retention_days = 0;
|
||||
m_settings[i].discord_webhook_id = 0;
|
||||
}
|
||||
|
||||
SetSettingsDefaults();
|
||||
|
||||
// initialize settings from database
|
||||
auto s = PlayerEventLogSettingsRepository::All(*m_database);
|
||||
std::vector<int> db{};
|
||||
db.reserve(s.size());
|
||||
for (auto &e: s) {
|
||||
if (e.id >= PlayerEvent::MAX) {
|
||||
continue;
|
||||
}
|
||||
m_settings[e.id] = e;
|
||||
db.emplace_back(e.id);
|
||||
}
|
||||
|
||||
// insert entries that don't exist in database
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
|
||||
bool is_deprecated = Strings::Contains(PlayerEvent::EventName[i], "Deprecated");
|
||||
bool is_implemented = !Strings::Contains(PlayerEvent::EventName[i], "Unimplemented");
|
||||
|
||||
// remove when deprecated
|
||||
if (is_deprecated && is_in_database) {
|
||||
LogInfo("[Deprecated] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
|
||||
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
|
||||
}
|
||||
// remove when unimplemented if present
|
||||
if (!is_implemented && is_in_database) {
|
||||
LogInfo("[Unimplemented] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
|
||||
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
|
||||
}
|
||||
|
||||
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
|
||||
if (is_missing_in_database && is_implemented && !is_deprecated) {
|
||||
LogInfo(
|
||||
"[New] PlayerEvent [{}] ({})",
|
||||
PlayerEvent::EventName[i],
|
||||
i
|
||||
);
|
||||
|
||||
auto c = PlayerEventLogSettingsRepository::NewEntity();
|
||||
c.id = i;
|
||||
c.event_name = PlayerEvent::EventName[i];
|
||||
c.event_enabled = m_settings[i].event_enabled;
|
||||
c.retention_days = m_settings[i].retention_days;
|
||||
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
|
||||
}
|
||||
}
|
||||
|
||||
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
|
||||
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
|
||||
|
||||
// on initial boot process truncation
|
||||
if (processing_in_world || processing_in_qs) {
|
||||
ProcessRetentionTruncation();
|
||||
}
|
||||
}
|
||||
|
||||
// set the database object, during initialization
|
||||
PlayerEventLogs *PlayerEventLogs::SetDatabase(Database *db)
|
||||
{
|
||||
m_database = db;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// validates whether the connection is valid or not, used in initialization
|
||||
bool PlayerEventLogs::ValidateDatabaseConnection()
|
||||
{
|
||||
if (!m_database) {
|
||||
LogError("No database connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// determines if the passed in event is enabled or not
|
||||
// this is used to gate logic or events from firing off
|
||||
// this is used prior to building the events, we don't want to
|
||||
// build the events, send them through the stack in a function call
|
||||
// only to discard them immediately afterwards, very wasteful on resources
|
||||
// the quest api currently does this
|
||||
bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
|
||||
{
|
||||
return m_settings[event].event_enabled ? m_settings[event].event_enabled : false;
|
||||
}
|
||||
|
||||
// this processes any current player events on the queue
|
||||
void PlayerEventLogs::ProcessBatchQueue()
|
||||
{
|
||||
m_batch_queue_lock.lock();
|
||||
if (m_record_batch_queue.empty()) {
|
||||
m_batch_queue_lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
BenchTimer benchmark;
|
||||
|
||||
// flush many
|
||||
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
|
||||
LogPlayerEventsDetail(
|
||||
"Processing batch player event log queue of [{}] took [{}]",
|
||||
m_record_batch_queue.size(),
|
||||
benchmark.elapsed()
|
||||
);
|
||||
|
||||
// empty
|
||||
m_record_batch_queue = {};
|
||||
m_batch_queue_lock.unlock();
|
||||
}
|
||||
|
||||
// adds a player event to the queue
|
||||
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
|
||||
{
|
||||
m_batch_queue_lock.lock();
|
||||
m_record_batch_queue.emplace_back(log);
|
||||
m_batch_queue_lock.unlock();
|
||||
}
|
||||
|
||||
// fills common event data in the SendEvent function
|
||||
void PlayerEventLogs::FillPlayerEvent(
|
||||
const PlayerEvent::PlayerEvent &p,
|
||||
PlayerEventLogsRepository::PlayerEventLogs &n
|
||||
)
|
||||
{
|
||||
n.account_id = p.account_id;
|
||||
n.character_id = p.character_id;
|
||||
n.zone_id = p.zone_id;
|
||||
n.instance_id = p.instance_id;
|
||||
n.x = p.x;
|
||||
n.y = p.y;
|
||||
n.z = p.z;
|
||||
n.heading = p.heading;
|
||||
}
|
||||
|
||||
// builds the dynamic packet used to ship the player event over the wire
|
||||
// supports serializing the struct so it can be rebuilt on the other end
|
||||
std::unique_ptr<ServerPacket>
|
||||
PlayerEventLogs::BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e)
|
||||
{
|
||||
EQ::Net::DynamicPacket dyn_pack;
|
||||
dyn_pack.PutSerialize(0, e);
|
||||
auto pack_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length();
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_PlayerEvent, static_cast<uint32_t>(pack_size));
|
||||
auto buf = reinterpret_cast<ServerSendPlayerEvent_Struct *>(pack->pBuffer);
|
||||
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
|
||||
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
const PlayerEventLogSettingsRepository::PlayerEventLogSettings *PlayerEventLogs::GetSettings() const
|
||||
{
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
|
||||
{
|
||||
// out of bounds check
|
||||
if (event_type_id >= PlayerEvent::EventType::MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure webhook id is set
|
||||
if (m_settings[event_type_id].discord_webhook_id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure there is a matching webhook to begin with
|
||||
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_type_id)
|
||||
{
|
||||
// out of bounds check
|
||||
if (event_type_id >= PlayerEvent::EventType::MAX) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// make sure webhook id is set
|
||||
if (m_settings[event_type_id].discord_webhook_id == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// ensure there is a matching webhook to begin with
|
||||
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
|
||||
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// GM_COMMAND | [x] Implemented Formatter
|
||||
// ZONING | [x] Implemented Formatter
|
||||
// AA_GAIN | [x] Implemented Formatter
|
||||
// AA_PURCHASE | [x] Implemented Formatter
|
||||
// FORAGE_SUCCESS | [x] Implemented Formatter
|
||||
// FORAGE_FAILURE | [x] Implemented Formatter
|
||||
// FISH_SUCCESS | [x] Implemented Formatter
|
||||
// FISH_FAILURE | [x] Implemented Formatter
|
||||
// ITEM_DESTROY | [x] Implemented Formatter
|
||||
// WENT_ONLINE | [x] Implemented Formatter
|
||||
// WENT_OFFLINE | [x] Implemented Formatter
|
||||
// LEVEL_GAIN | [x] Implemented Formatter
|
||||
// LEVEL_LOSS | [x] Implemented Formatter
|
||||
// LOOT_ITEM | [x] Implemented Formatter
|
||||
// MERCHANT_PURCHASE | [x] Implemented Formatter
|
||||
// MERCHANT_SELL | [x] Implemented Formatter
|
||||
// GROUP_JOIN | [] Implemented Formatter
|
||||
// GROUP_LEAVE | [] Implemented Formatter
|
||||
// RAID_JOIN | [] Implemented Formatter
|
||||
// RAID_LEAVE | [] Implemented Formatter
|
||||
// GROUNDSPAWN_PICKUP | [x] Implemented Formatter
|
||||
// NPC_HANDIN | [x] Implemented Formatter
|
||||
// SKILL_UP | [x] Implemented Formatter
|
||||
// TASK_ACCEPT | [x] Implemented Formatter
|
||||
// TASK_UPDATE | [x] Implemented Formatter
|
||||
// TASK_COMPLETE | [x] Implemented Formatter
|
||||
// TRADE | [] Implemented Formatter
|
||||
// GIVE_ITEM | [] Implemented Formatter
|
||||
// SAY | [x] Implemented Formatter
|
||||
// REZ_ACCEPTED | [x] Implemented Formatter
|
||||
// DEATH | [x] Implemented Formatter
|
||||
// COMBINE_FAILURE | [x] Implemented Formatter
|
||||
// COMBINE_SUCCESS | [x] Implemented Formatter
|
||||
// DROPPED_ITEM | [x] Implemented Formatter
|
||||
// SPLIT_MONEY | [x] Implemented Formatter
|
||||
// DZ_JOIN | [] Implemented Formatter
|
||||
// DZ_LEAVE | [] Implemented Formatter
|
||||
// TRADER_PURCHASE | [x] Implemented Formatter
|
||||
// TRADER_SELL | [x] Implemented Formatter
|
||||
// BANDOLIER_CREATE | [] Implemented Formatter
|
||||
// BANDOLIER_SWAP | [] Implemented Formatter
|
||||
// DISCOVER_ITEM | [X] Implemented Formatter
|
||||
|
||||
std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e)
|
||||
{
|
||||
std::string payload;
|
||||
switch (e.player_event_log.event_type_id) {
|
||||
case PlayerEvent::AA_GAIN: {
|
||||
PlayerEvent::AAGainedEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatAAGainedEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::AA_PURCHASE: {
|
||||
PlayerEvent::AAPurchasedEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatAAPurchasedEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::COMBINE_FAILURE:
|
||||
case PlayerEvent::COMBINE_SUCCESS: {
|
||||
PlayerEvent::CombineEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatCombineEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::DEATH: {
|
||||
PlayerEvent::DeathEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatDeathEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::DISCOVER_ITEM: {
|
||||
PlayerEvent::DiscoverItemEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatDiscoverItemEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::DROPPED_ITEM: {
|
||||
PlayerEvent::DroppedItemEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatDroppedItemEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::FISH_FAILURE:
|
||||
case PlayerEvent::FORAGE_FAILURE:
|
||||
case PlayerEvent::WENT_ONLINE:
|
||||
case PlayerEvent::WENT_OFFLINE: {
|
||||
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::FISH_SUCCESS: {
|
||||
PlayerEvent::FishSuccessEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatFishSuccessEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::FORAGE_SUCCESS: {
|
||||
PlayerEvent::ForageSuccessEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatForageSuccessEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::ITEM_DESTROY: {
|
||||
PlayerEvent::DestroyItemEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatDestroyItemEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::LEVEL_GAIN: {
|
||||
PlayerEvent::LevelGainedEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatLevelGainedEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::LEVEL_LOSS: {
|
||||
PlayerEvent::LevelLostEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatLevelLostEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::LOOT_ITEM: {
|
||||
PlayerEvent::LootItemEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatLootItemEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::GROUNDSPAWN_PICKUP: {
|
||||
PlayerEvent::GroundSpawnPickupEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatGroundSpawnPickupEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::NPC_HANDIN: {
|
||||
PlayerEvent::HandinEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatNPCHandinEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::SAY: {
|
||||
PlayerEvent::SayEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatEventSay(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::GM_COMMAND: {
|
||||
PlayerEvent::GMCommandEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatGMCommand(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::SKILL_UP: {
|
||||
PlayerEvent::SkillUpEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatSkillUpEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::SPLIT_MONEY: {
|
||||
PlayerEvent::SplitMoneyEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatSplitMoneyEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TASK_ACCEPT: {
|
||||
PlayerEvent::TaskAcceptEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTaskAcceptEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TASK_COMPLETE: {
|
||||
PlayerEvent::TaskCompleteEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTaskCompleteEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TASK_UPDATE: {
|
||||
PlayerEvent::TaskUpdateEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTaskUpdateEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TRADE: {
|
||||
PlayerEvent::TradeEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTradeEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TRADER_PURCHASE: {
|
||||
PlayerEvent::TraderPurchaseEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTraderPurchaseEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::TRADER_SELL: {
|
||||
PlayerEvent::TraderSellEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatTraderSellEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::REZ_ACCEPTED: {
|
||||
PlayerEvent::ResurrectAcceptEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
payload = PlayerEventDiscordFormatter::FormatResurrectAcceptEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::MERCHANT_PURCHASE: {
|
||||
PlayerEvent::MerchantPurchaseEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
|
||||
payload = PlayerEventDiscordFormatter::FormatMerchantPurchaseEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::MERCHANT_SELL: {
|
||||
PlayerEvent::MerchantSellEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
|
||||
payload = PlayerEventDiscordFormatter::FormatMerchantSellEvent(e, n);
|
||||
break;
|
||||
}
|
||||
case PlayerEvent::ZONING: {
|
||||
PlayerEvent::ZoningEvent n{};
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << e.player_event_log.event_data;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
n.serialize(ar);
|
||||
}
|
||||
|
||||
payload = PlayerEventDiscordFormatter::FormatZoningEvent(e, n);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogInfo(
|
||||
"Player event [{}] ({}) Discord formatter not implemented",
|
||||
e.player_event_log.event_type_name,
|
||||
e.player_event_log.event_type_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
|
||||
void PlayerEventLogs::Process()
|
||||
{
|
||||
if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
|
||||
ProcessBatchQueue();
|
||||
}
|
||||
|
||||
if (m_process_retention_truncation_timer.Check()) {
|
||||
ProcessRetentionTruncation();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerEventLogs::ProcessRetentionTruncation()
|
||||
{
|
||||
LogInfo("Running truncation");
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
if (m_settings[i].retention_days > 0) {
|
||||
int deleted_count = PlayerEventLogsRepository::DeleteWhere(
|
||||
*m_database,
|
||||
fmt::format(
|
||||
"event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
|
||||
i,
|
||||
m_settings[i].retention_days
|
||||
)
|
||||
);
|
||||
|
||||
if (deleted_count > 0) {
|
||||
LogInfo(
|
||||
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
|
||||
deleted_count,
|
||||
PlayerEvent::EventName[i],
|
||||
i,
|
||||
m_settings[i].retention_days
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerEventLogs::ReloadSettings()
|
||||
{
|
||||
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
|
||||
m_settings[e.id] = e;
|
||||
}
|
||||
}
|
||||
|
||||
const int32_t RETENTION_DAYS_DEFAULT = 7;
|
||||
|
||||
void PlayerEventLogs::SetSettingsDefaults()
|
||||
{
|
||||
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ZONING].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
|
||||
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SAY].event_enabled = 0;
|
||||
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DEATH].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef EQEMU_PLAYER_EVENT_LOGS_H
|
||||
#define EQEMU_PLAYER_EVENT_LOGS_H
|
||||
|
||||
#include "../repositories/player_event_log_settings_repository.h"
|
||||
#include "player_events.h"
|
||||
#include "../servertalk.h"
|
||||
#include "../repositories/player_event_logs_repository.h"
|
||||
#include "../timer.h"
|
||||
#include "../json/json_archive_single_line.h"
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <mutex>
|
||||
|
||||
class PlayerEventLogs {
|
||||
public:
|
||||
void Init();
|
||||
void ReloadSettings();
|
||||
PlayerEventLogs *SetDatabase(Database *db);
|
||||
bool ValidateDatabaseConnection();
|
||||
bool IsEventEnabled(PlayerEvent::EventType event);
|
||||
|
||||
void Process();
|
||||
|
||||
// batch queue
|
||||
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
|
||||
|
||||
// main event record generic function
|
||||
// can ingest any struct event types
|
||||
template<typename T>
|
||||
std::unique_ptr<ServerPacket> RecordEvent(
|
||||
PlayerEvent::EventType t,
|
||||
const PlayerEvent::PlayerEvent &p,
|
||||
T e
|
||||
)
|
||||
{
|
||||
auto n = PlayerEventLogsRepository::NewEntity();
|
||||
FillPlayerEvent(p, n);
|
||||
n.event_type_id = t;
|
||||
|
||||
std::stringstream ss;
|
||||
{
|
||||
cereal::JSONOutputArchiveSingleLine ar(ss);
|
||||
e.serialize(ar);
|
||||
}
|
||||
|
||||
n.event_type_name = PlayerEvent::EventName[t];
|
||||
n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str();
|
||||
n.created_at = std::time(nullptr);
|
||||
|
||||
auto c = PlayerEvent::PlayerEventContainer{
|
||||
.player_event = p,
|
||||
.player_event_log = n
|
||||
};
|
||||
|
||||
return BuildPlayerEventPacket(c);
|
||||
}
|
||||
|
||||
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
|
||||
bool IsEventDiscordEnabled(int32_t event_type_id);
|
||||
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
|
||||
|
||||
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
|
||||
private:
|
||||
Database *m_database; // reference to database
|
||||
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
|
||||
|
||||
// batch queue is used to record events in batch
|
||||
std::vector<PlayerEventLogsRepository::PlayerEventLogs> m_record_batch_queue{};
|
||||
static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n);
|
||||
static std::unique_ptr<ServerPacket>
|
||||
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
|
||||
|
||||
// timers
|
||||
Timer m_process_batch_events_timer; // events processing timer
|
||||
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
|
||||
|
||||
// processing
|
||||
std::mutex m_batch_queue_lock{};
|
||||
void ProcessBatchQueue();
|
||||
void ProcessRetentionTruncation();
|
||||
void SetSettingsDefaults();
|
||||
};
|
||||
|
||||
extern PlayerEventLogs player_event_logs;
|
||||
|
||||
#endif //EQEMU_PLAYER_EVENT_LOGS_H
|
||||
@@ -0,0 +1,971 @@
|
||||
#ifndef EQEMU_PLAYER_EVENTS_H
|
||||
#define EQEMU_PLAYER_EVENTS_H
|
||||
|
||||
#include <string>
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "../types.h"
|
||||
#include "../repositories/player_event_logs_repository.h"
|
||||
|
||||
namespace PlayerEvent {
|
||||
|
||||
enum EventType {
|
||||
GM_COMMAND = 1,
|
||||
ZONING,
|
||||
AA_GAIN,
|
||||
AA_PURCHASE,
|
||||
FORAGE_SUCCESS,
|
||||
FORAGE_FAILURE,
|
||||
FISH_SUCCESS,
|
||||
FISH_FAILURE,
|
||||
ITEM_DESTROY,
|
||||
WENT_ONLINE,
|
||||
WENT_OFFLINE,
|
||||
LEVEL_GAIN,
|
||||
LEVEL_LOSS,
|
||||
LOOT_ITEM,
|
||||
MERCHANT_PURCHASE,
|
||||
MERCHANT_SELL,
|
||||
GROUP_JOIN, // unimplemented
|
||||
GROUP_LEAVE, // unimplemented
|
||||
RAID_JOIN, // unimplemented
|
||||
RAID_LEAVE, // unimplemented
|
||||
GROUNDSPAWN_PICKUP,
|
||||
NPC_HANDIN,
|
||||
SKILL_UP,
|
||||
TASK_ACCEPT,
|
||||
TASK_UPDATE,
|
||||
TASK_COMPLETE,
|
||||
TRADE,
|
||||
GIVE_ITEM, // unimplemented
|
||||
SAY,
|
||||
REZ_ACCEPTED,
|
||||
DEATH,
|
||||
COMBINE_FAILURE,
|
||||
COMBINE_SUCCESS,
|
||||
DROPPED_ITEM,
|
||||
SPLIT_MONEY,
|
||||
DZ_JOIN, // unimplemented
|
||||
DZ_LEAVE, // unimplemented
|
||||
TRADER_PURCHASE,
|
||||
TRADER_SELL,
|
||||
BANDOLIER_CREATE, // unimplemented
|
||||
BANDOLIER_SWAP, // unimplemented
|
||||
DISCOVER_ITEM,
|
||||
POSSIBLE_HACK,
|
||||
KILLED_NPC,
|
||||
KILLED_NAMED_NPC,
|
||||
KILLED_RAID_NPC,
|
||||
ITEM_CREATION,
|
||||
MAX // dont remove
|
||||
};
|
||||
|
||||
// Don't ever remove items, even if they are deprecated
|
||||
// If event is deprecated just tag (Deprecated) in the name
|
||||
// If event is unimplemented just tag (Unimplemented) in the name
|
||||
// Events don't get saved to the database if unimplemented or deprecated
|
||||
// Events tagged as deprecated will get automatically removed
|
||||
static const char *EventName[PlayerEvent::MAX] = {
|
||||
"None",
|
||||
"GM Command",
|
||||
"Zoning",
|
||||
"AA Gain",
|
||||
"AA Purchase",
|
||||
"Forage Success",
|
||||
"Forage Failure",
|
||||
"Fish Success",
|
||||
"Fish Failure",
|
||||
"Item Destroy",
|
||||
"Went Online",
|
||||
"Went Offline",
|
||||
"Level Gain",
|
||||
"Level Loss",
|
||||
"Loot Item",
|
||||
"Merchant Purchase",
|
||||
"Merchant Sell",
|
||||
"Group Join (Unimplemented)",
|
||||
"Group Leave (Unimplemented)",
|
||||
"Raid Join (Unimplemented)",
|
||||
"Raid Leave (Unimplemented)",
|
||||
"Groundspawn Pickup",
|
||||
"NPC Handin",
|
||||
"Skill Up",
|
||||
"Task Accept",
|
||||
"Task Update",
|
||||
"Task Complete",
|
||||
"Trade",
|
||||
"Given Item (Unimplemented)",
|
||||
"Say",
|
||||
"Rez Accepted",
|
||||
"Death",
|
||||
"Combine Failure",
|
||||
"Combine Success",
|
||||
"Dropped Item",
|
||||
"Split Money",
|
||||
"DZ Join (Unimplemented)",
|
||||
"DZ Leave (Unimplemented)",
|
||||
"Trader Purchase",
|
||||
"Trader Sell",
|
||||
"Bandolier Create (Unimplemented)",
|
||||
"Bandolier Swap (Unimplemented)",
|
||||
"Discover Item",
|
||||
"Possible Hack",
|
||||
"Killed NPC",
|
||||
"Killed Named NPC",
|
||||
"Killed Raid NPC",
|
||||
"Item Creation"
|
||||
};
|
||||
|
||||
// Generic struct used by all events
|
||||
struct PlayerEvent {
|
||||
int64 account_id;
|
||||
std::string account_name;
|
||||
int64 character_id;
|
||||
std::string character_name;
|
||||
int64 guild_id;
|
||||
std::string guild_name;
|
||||
int zone_id;
|
||||
std::string zone_short_name;
|
||||
std::string zone_long_name;
|
||||
int instance_id;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float heading;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(account_id),
|
||||
CEREAL_NVP(account_name),
|
||||
CEREAL_NVP(character_id),
|
||||
CEREAL_NVP(character_name),
|
||||
CEREAL_NVP(guild_id),
|
||||
CEREAL_NVP(guild_name),
|
||||
CEREAL_NVP(zone_id),
|
||||
CEREAL_NVP(zone_short_name),
|
||||
CEREAL_NVP(zone_long_name),
|
||||
CEREAL_NVP(instance_id),
|
||||
CEREAL_NVP(x),
|
||||
CEREAL_NVP(y),
|
||||
CEREAL_NVP(z),
|
||||
CEREAL_NVP(heading)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// contains metadata in use for things like log/discord formatters
|
||||
// along with the actual event to be persisted
|
||||
struct PlayerEventContainer {
|
||||
PlayerEvent player_event;
|
||||
PlayerEventLogsRepository::PlayerEventLogs player_event_log;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(player_event),
|
||||
CEREAL_NVP(player_event_log)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// used in events with no extra data
|
||||
struct EmptyEvent {
|
||||
std::string noop; // noop, gets discard upstream
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(noop)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// used in Trade event
|
||||
struct ItemCreationEvent {
|
||||
int64 item_id;
|
||||
std::string item_name;
|
||||
uint16 to_slot;
|
||||
int16 charges;
|
||||
uint32 aug1;
|
||||
uint32 aug2;
|
||||
uint32 aug3;
|
||||
uint32 aug4;
|
||||
uint32 aug5;
|
||||
uint32 aug6;
|
||||
bool attuned;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(to_slot),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(aug1),
|
||||
CEREAL_NVP(aug2),
|
||||
CEREAL_NVP(aug3),
|
||||
CEREAL_NVP(aug4),
|
||||
CEREAL_NVP(aug5),
|
||||
CEREAL_NVP(aug6),
|
||||
CEREAL_NVP(attuned)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// used in Trade event
|
||||
struct TradeItem {
|
||||
int64 item_id;
|
||||
std::string item_name;
|
||||
int32 slot;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(slot)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// used in Trade event
|
||||
class TradeItemEntry {
|
||||
public:
|
||||
uint16 slot;
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint16 charges;
|
||||
uint32 aug_1_item_id;
|
||||
std::string aug_1_item_name;
|
||||
uint32 aug_2_item_id;
|
||||
std::string aug_2_item_name;
|
||||
uint32 aug_3_item_id;
|
||||
std::string aug_3_item_name;
|
||||
uint32 aug_4_item_id;
|
||||
std::string aug_4_item_name;
|
||||
uint32 aug_5_item_id;
|
||||
std::string aug_5_item_name;
|
||||
uint32 aug_6_item_id;
|
||||
std::string aug_6_item_name;
|
||||
bool in_bag;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(slot),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(aug_1_item_id),
|
||||
CEREAL_NVP(aug_2_item_id),
|
||||
CEREAL_NVP(aug_3_item_id),
|
||||
CEREAL_NVP(aug_4_item_id),
|
||||
CEREAL_NVP(aug_5_item_id),
|
||||
CEREAL_NVP(in_bag)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Events
|
||||
*/
|
||||
struct Money {
|
||||
int32 platinum;
|
||||
int32 gold;
|
||||
int32 silver;
|
||||
int32 copper;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(platinum),
|
||||
CEREAL_NVP(gold),
|
||||
CEREAL_NVP(silver),
|
||||
CEREAL_NVP(copper)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TradeEvent {
|
||||
uint32 character_1_id;
|
||||
std::string character_1_name;
|
||||
uint32 character_2_id;
|
||||
std::string character_2_name;
|
||||
Money character_1_give_money;
|
||||
Money character_2_give_money;
|
||||
std::vector<TradeItemEntry> character_1_give_items;
|
||||
std::vector<TradeItemEntry> character_2_give_items;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(character_1_id),
|
||||
CEREAL_NVP(character_1_name),
|
||||
CEREAL_NVP(character_2_id),
|
||||
CEREAL_NVP(character_2_name),
|
||||
CEREAL_NVP(character_1_give_money),
|
||||
CEREAL_NVP(character_2_give_money),
|
||||
CEREAL_NVP(character_1_give_items),
|
||||
CEREAL_NVP(character_2_give_items)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct GMCommandEvent {
|
||||
std::string message;
|
||||
std::string target;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(message),
|
||||
CEREAL_NVP(target)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct ZoningEvent {
|
||||
std::string from_zone_long_name;
|
||||
std::string from_zone_short_name;
|
||||
int32 from_zone_id;
|
||||
int32 from_instance_id;
|
||||
int32 from_instance_version;
|
||||
std::string to_zone_long_name;
|
||||
std::string to_zone_short_name;
|
||||
int32 to_zone_id;
|
||||
int32 to_instance_id;
|
||||
int32 to_instance_version;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(from_zone_long_name),
|
||||
CEREAL_NVP(from_zone_short_name),
|
||||
CEREAL_NVP(from_zone_id),
|
||||
CEREAL_NVP(from_instance_id),
|
||||
CEREAL_NVP(from_instance_version),
|
||||
CEREAL_NVP(to_zone_long_name),
|
||||
CEREAL_NVP(to_zone_short_name),
|
||||
CEREAL_NVP(to_zone_id),
|
||||
CEREAL_NVP(to_instance_id),
|
||||
CEREAL_NVP(to_instance_version)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct AAGainedEvent {
|
||||
uint32 aa_gained;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(CEREAL_NVP(aa_gained));
|
||||
}
|
||||
};
|
||||
|
||||
struct AAPurchasedEvent {
|
||||
uint32 aa_id;
|
||||
int32 aa_cost;
|
||||
int32 aa_previous_id;
|
||||
int32 aa_next_id;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(aa_id),
|
||||
CEREAL_NVP(aa_cost),
|
||||
CEREAL_NVP(aa_previous_id),
|
||||
CEREAL_NVP(aa_next_id)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct ForageSuccessEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct FishSuccessEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DestroyItemEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
int16 charges;
|
||||
std::string reason;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(reason),
|
||||
CEREAL_NVP(charges)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct LevelGainedEvent {
|
||||
uint32 from_level;
|
||||
uint8 to_level;
|
||||
int levels_gained;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(from_level),
|
||||
CEREAL_NVP(to_level),
|
||||
CEREAL_NVP(levels_gained)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct LevelLostEvent {
|
||||
uint32 from_level;
|
||||
uint8 to_level;
|
||||
int levels_lost;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(from_level),
|
||||
CEREAL_NVP(to_level),
|
||||
CEREAL_NVP(levels_lost)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct LootItemEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
int16 charges;
|
||||
uint32 npc_id;
|
||||
std::string corpse_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(corpse_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct MerchantPurchaseEvent {
|
||||
uint32 npc_id;
|
||||
std::string merchant_name;
|
||||
uint32 merchant_type;
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
int16 charges;
|
||||
uint32 cost;
|
||||
uint32 alternate_currency_id;
|
||||
uint64 player_money_balance;
|
||||
uint64 player_currency_balance;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(merchant_name),
|
||||
CEREAL_NVP(merchant_type),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(cost),
|
||||
CEREAL_NVP(alternate_currency_id),
|
||||
CEREAL_NVP(player_money_balance),
|
||||
CEREAL_NVP(player_currency_balance)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct MerchantSellEvent {
|
||||
uint32 npc_id;
|
||||
std::string merchant_name;
|
||||
uint32 merchant_type;
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
int16 charges;
|
||||
uint32 cost;
|
||||
uint32 alternate_currency_id;
|
||||
uint64 player_money_balance;
|
||||
uint64 player_currency_balance;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(merchant_name),
|
||||
CEREAL_NVP(merchant_type),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(cost),
|
||||
CEREAL_NVP(alternate_currency_id),
|
||||
CEREAL_NVP(player_money_balance),
|
||||
CEREAL_NVP(player_currency_balance)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct SkillUpEvent {
|
||||
uint32 skill_id;
|
||||
int value;
|
||||
int16 max_skill;
|
||||
std::string against_who;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(skill_id),
|
||||
CEREAL_NVP(value),
|
||||
CEREAL_NVP(max_skill),
|
||||
CEREAL_NVP(against_who)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TaskAcceptEvent {
|
||||
uint32 npc_id;
|
||||
std::string npc_name;
|
||||
uint32 task_id;
|
||||
std::string task_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(npc_name),
|
||||
CEREAL_NVP(task_id),
|
||||
CEREAL_NVP(task_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TaskUpdateEvent {
|
||||
uint32 task_id;
|
||||
std::string task_name;
|
||||
uint32 activity_id;
|
||||
uint32 done_count;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(task_id),
|
||||
CEREAL_NVP(task_name),
|
||||
CEREAL_NVP(activity_id),
|
||||
CEREAL_NVP(done_count)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TaskCompleteEvent {
|
||||
uint32 task_id;
|
||||
std::string task_name;
|
||||
uint32 activity_id;
|
||||
uint32 done_count;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(task_id),
|
||||
CEREAL_NVP(task_name),
|
||||
CEREAL_NVP(activity_id),
|
||||
CEREAL_NVP(done_count)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct GroundSpawnPickupEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct SayEvent {
|
||||
std::string message;
|
||||
std::string target;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(message),
|
||||
CEREAL_NVP(target)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct ResurrectAcceptEvent {
|
||||
std::string resurrecter_name;
|
||||
std::string spell_name;
|
||||
uint32 spell_id;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(resurrecter_name),
|
||||
CEREAL_NVP(spell_name),
|
||||
CEREAL_NVP(spell_id)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct CombineEvent {
|
||||
uint32 recipe_id;
|
||||
std::string recipe_name;
|
||||
uint32 made_count;
|
||||
uint32 tradeskill_id;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(recipe_id),
|
||||
CEREAL_NVP(recipe_name),
|
||||
CEREAL_NVP(made_count),
|
||||
CEREAL_NVP(tradeskill_id)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DroppedItemEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
int16 slot_id;
|
||||
uint32 charges;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(slot_id),
|
||||
CEREAL_NVP(charges)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DeathEvent {
|
||||
uint32 killer_id;
|
||||
std::string killer_name;
|
||||
int64 damage;
|
||||
uint32 spell_id;
|
||||
std::string spell_name;
|
||||
int skill_id;
|
||||
std::string skill_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(killer_id),
|
||||
CEREAL_NVP(killer_name),
|
||||
CEREAL_NVP(damage),
|
||||
CEREAL_NVP(spell_id),
|
||||
CEREAL_NVP(spell_name),
|
||||
CEREAL_NVP(skill_id),
|
||||
CEREAL_NVP(skill_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct SplitMoneyEvent {
|
||||
uint32 copper;
|
||||
uint32 silver;
|
||||
uint32 gold;
|
||||
uint32 platinum;
|
||||
uint64 player_money_balance;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(copper),
|
||||
CEREAL_NVP(silver),
|
||||
CEREAL_NVP(gold),
|
||||
CEREAL_NVP(platinum),
|
||||
CEREAL_NVP(player_money_balance)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TraderPurchaseEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint32 trader_id;
|
||||
std::string trader_name;
|
||||
uint32 price;
|
||||
uint32 charges;
|
||||
uint32 total_cost;
|
||||
uint64 player_money_balance;
|
||||
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(trader_id),
|
||||
CEREAL_NVP(trader_name),
|
||||
CEREAL_NVP(price),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(total_cost),
|
||||
CEREAL_NVP(player_money_balance)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct TraderSellEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint32 buyer_id;
|
||||
std::string buyer_name;
|
||||
uint32 price;
|
||||
uint32 charges;
|
||||
uint32 total_cost;
|
||||
uint64 player_money_balance;
|
||||
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(buyer_id),
|
||||
CEREAL_NVP(buyer_name),
|
||||
CEREAL_NVP(price),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(total_cost),
|
||||
CEREAL_NVP(player_money_balance)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct DiscoverItemEvent {
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class HandinEntry {
|
||||
public:
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint16 charges;
|
||||
bool attuned;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(attuned)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class HandinMoney {
|
||||
public:
|
||||
uint32 copper;
|
||||
uint32 silver;
|
||||
uint32 gold;
|
||||
uint32 platinum;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(copper),
|
||||
CEREAL_NVP(silver),
|
||||
CEREAL_NVP(gold),
|
||||
CEREAL_NVP(platinum)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct HandinEvent {
|
||||
uint32 npc_id;
|
||||
std::string npc_name;
|
||||
std::vector<HandinEntry> handin_items;
|
||||
HandinMoney handin_money;
|
||||
std::vector<HandinEntry> return_items;
|
||||
HandinMoney return_money;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(npc_name),
|
||||
CEREAL_NVP(handin_items),
|
||||
CEREAL_NVP(handin_money),
|
||||
CEREAL_NVP(return_items),
|
||||
CEREAL_NVP(return_money)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct PossibleHackEvent {
|
||||
std::string message;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(message)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct KilledNPCEvent {
|
||||
uint32 npc_id;
|
||||
std::string npc_name;
|
||||
uint32 combat_time_seconds;
|
||||
uint64 total_damage_per_second_taken;
|
||||
uint64 total_heal_per_second_taken;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(npc_name),
|
||||
CEREAL_NVP(combat_time_seconds),
|
||||
CEREAL_NVP(total_damage_per_second_taken),
|
||||
CEREAL_NVP(total_heal_per_second_taken)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //EQEMU_PLAYER_EVENTS_H
|
||||
|
||||
#define RecordPlayerEventLog(event_type, event_data) do {\
|
||||
if (player_event_logs.IsEventEnabled(event_type)) {\
|
||||
worldserver.SendPacket(\
|
||||
player_event_logs.RecordEvent(\
|
||||
event_type,\
|
||||
GetPlayerEvent(),\
|
||||
event_data\
|
||||
).get()\
|
||||
);\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
|
||||
if (player_event_logs.IsEventEnabled(event_type)) {\
|
||||
worldserver.SendPacket(\
|
||||
player_event_logs.RecordEvent(\
|
||||
event_type,\
|
||||
(c)->GetPlayerEvent(),\
|
||||
event_data\
|
||||
).get()\
|
||||
);\
|
||||
}\
|
||||
} while (0)
|
||||
+2
-2
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
|
||||
// TODO: add more values
|
||||
switch (r1) {
|
||||
case DARK_ELF:
|
||||
if (r2 == 77) {
|
||||
if (r2 == RACE_NERIAK_CITIZEN_77) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case BARBARIAN:
|
||||
if (r2 == 90) {
|
||||
if (r2 == RACE_HALAS_CITIZEN_90) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -132,7 +132,7 @@ enum { //reuse times
|
||||
InstillDoubtReuseTime = 9,
|
||||
FishingReuseTime = 11,
|
||||
ForagingReuseTime = 50,
|
||||
MendReuseTime = 290,
|
||||
MendReuseTime = 360,
|
||||
BashReuseTime = 5,
|
||||
BackstabReuseTime = 9,
|
||||
KickReuseTime = 5,
|
||||
@@ -218,14 +218,14 @@ enum { //some random constants
|
||||
#define HARD_LEVEL_CAP 127
|
||||
|
||||
//the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc)
|
||||
#define USE_NPC_RANGE2 200*200 //arbitrary right now
|
||||
#define USE_NPC_RANGE2 40000 //arbitrary right now
|
||||
|
||||
// Squared range for rampage 75.0 * 75.0 for now
|
||||
#define NPC_RAMPAGE_RANGE2 5625.0f
|
||||
|
||||
//the formula for experience for killing a mob.
|
||||
//level is the only valid variable to use
|
||||
#define EXP_FORMULA level*level*75*35/10
|
||||
#define EXP_FORMULA (level * level * 75 * 35 / 10)
|
||||
|
||||
#define HIGHEST_AA_VALUE 35
|
||||
|
||||
@@ -295,7 +295,7 @@ Developer configuration
|
||||
|
||||
#define COMMON_PROFILE
|
||||
|
||||
#define PROFILE_DUMP_TIME 3*60
|
||||
#define PROFILE_DUMP_TIME 180
|
||||
#endif //EQPROFILE
|
||||
|
||||
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include "file.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
#include <iostream>
|
||||
#include <dos.h>
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
bool File::Exists(const std::string &name)
|
||||
{
|
||||
return fs::exists(fs::path{name});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param directory_name
|
||||
*/
|
||||
void File::Makedir(const std::string &directory_name)
|
||||
{
|
||||
fs::create_directory(directory_name);
|
||||
fs::permissions(directory_name, fs::perms::owner_all);
|
||||
}
|
||||
|
||||
std::string File::FindEqemuConfigPath()
|
||||
{
|
||||
if (File::Exists(fs::path{File::GetCwd() + "/eqemu_config.json"}.string())) {
|
||||
return File::GetCwd();
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/../eqemu_config.json"}.string())) {
|
||||
return canonical(fs::path{File::GetCwd() + "/../"}).string();
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/login.json"}.string())) {
|
||||
return File::GetCwd();
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/../login.json"}.string())) {
|
||||
return canonical(fs::path{File::GetCwd() + "/../"}).string();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string File::GetCwd()
|
||||
{
|
||||
return fs::current_path().string();
|
||||
}
|
||||
|
||||
FileContentsResult File::GetContents(const std::string &file_name)
|
||||
{
|
||||
std::string error;
|
||||
std::ifstream f;
|
||||
f.open(file_name);
|
||||
std::string line;
|
||||
std::string lines;
|
||||
if (f.is_open()) {
|
||||
while (f) {
|
||||
std::getline(f, line);
|
||||
lines += line + "\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
error = fmt::format("Couldn't open file [{}]", file_name);
|
||||
}
|
||||
|
||||
return FileContentsResult{
|
||||
.contents = lines,
|
||||
.error = error,
|
||||
};
|
||||
}
|
||||
@@ -18,16 +18,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_FILE_UTIL_H
|
||||
#define EQEMU_FILE_UTIL_H
|
||||
#ifndef EQEMU_FILE_H
|
||||
#define EQEMU_FILE_H
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class FileUtil {
|
||||
public:
|
||||
static bool exists(const std::string &name);
|
||||
static void mkdir(const std::string& directory_name);
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct FileContentsResult {
|
||||
std::string contents;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
bool file_exists(const std::string& name);
|
||||
class File {
|
||||
public:
|
||||
static bool Exists(const std::string &name);
|
||||
static void Makedir(const std::string& directory_name);
|
||||
static FileContentsResult GetContents(const std::string &file_name);
|
||||
static std::string FindEqemuConfigPath();
|
||||
static std::string GetCwd();
|
||||
};
|
||||
|
||||
#endif //EQEMU_FILE_UTIL_H
|
||||
bool Exists(const std::string& name);
|
||||
|
||||
#endif //EQEMU_FILE_H
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include "file_util.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
#include <iostream>
|
||||
#include <dos.h>
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
bool FileUtil::exists(const std::string &name)
|
||||
{
|
||||
std::ifstream f(name.c_str());
|
||||
|
||||
return f.good();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param directory_name
|
||||
*/
|
||||
void FileUtil::mkdir(const std::string& directory_name)
|
||||
{
|
||||
|
||||
#ifdef _WINDOWS
|
||||
struct _stat st;
|
||||
if (_stat(directory_name.c_str(), &st) == 0) // exists
|
||||
return;
|
||||
_mkdir(directory_name.c_str());
|
||||
#else
|
||||
struct stat st{};
|
||||
if (stat(directory_name.c_str(), &st) == 0) { // exists
|
||||
return;
|
||||
}
|
||||
::mkdir(directory_name.c_str(), 0755);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool file_exists(const std::string& name) {
|
||||
std::ifstream f(name.c_str());
|
||||
return f.good();
|
||||
}
|
||||
+22
-38
@@ -61,9 +61,11 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
}
|
||||
|
||||
for (auto row=results.begin();row!=results.end();++row)
|
||||
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
|
||||
_CreateGuild(Strings::ToUnsignedInt(row[0]), row[1], Strings::ToUnsignedInt(row[2]), Strings::ToUnsignedInt(row[3]), row[4], row[5], row[6], row[7]);
|
||||
|
||||
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
|
||||
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount())));
|
||||
|
||||
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
|
||||
results = m_db->QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
@@ -73,8 +75,8 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
|
||||
for (auto row=results.begin();row!=results.end();++row)
|
||||
{
|
||||
uint32 guild_id = atoi(row[0]);
|
||||
uint8 rankn = atoi(row[1]);
|
||||
uint32 guild_id = Strings::ToUnsignedInt(row[0]);
|
||||
uint8 rankn = Strings::ToUnsignedInt(row[1]);
|
||||
|
||||
if(rankn > GUILD_MAX_RANK) {
|
||||
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
|
||||
@@ -129,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
|
||||
info = _CreateGuild(guild_id, row[0], Strings::ToUnsignedInt(row[1]), Strings::ToUnsignedInt(row[2]), row[3], row[4], row[5], row[6]);
|
||||
|
||||
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
|
||||
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
|
||||
@@ -142,7 +144,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
|
||||
for (auto row=results.begin();row!=results.end();++row)
|
||||
{
|
||||
uint8 rankn = atoi(row[1]);
|
||||
uint8 rankn = Strings::ToUnsignedInt(row[1]);
|
||||
|
||||
if(rankn > GUILD_MAX_RANK) {
|
||||
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
|
||||
@@ -785,9 +787,7 @@ bool BaseGuildManager::GetBankerFlag(uint32 CharID)
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
bool IsBanker = atoi(row[0]);
|
||||
|
||||
return IsBanker;
|
||||
return Strings::ToBool(row[0]);
|
||||
}
|
||||
|
||||
bool BaseGuildManager::DBSetAltFlag(uint32 charid, bool is_alt)
|
||||
@@ -815,9 +815,7 @@ bool BaseGuildManager::GetAltFlag(uint32 CharID)
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
bool IsAlt = atoi(row[0]);
|
||||
|
||||
return IsAlt;
|
||||
return Strings::ToBool(row[0]);
|
||||
}
|
||||
|
||||
bool BaseGuildManager::DBSetTributeFlag(uint32 charid, bool enabled) {
|
||||
@@ -864,35 +862,26 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
//factored out so I dont have to copy this crap.
|
||||
#ifdef BOTS
|
||||
#define GuildMemberBaseQuery \
|
||||
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
|
||||
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
|
||||
" g.`banker`, g.`public_note`, g.`alt`" \
|
||||
" FROM `vw_bot_character_mobs` AS c LEFT JOIN `vw_guild_members` AS g ON c.`id` = g.`char_id` AND c.`mob_type` = g.`mob_type` "
|
||||
#else
|
||||
#define GuildMemberBaseQuery \
|
||||
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
|
||||
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
|
||||
" g.`banker`, g.`public_note`, g.`alt` " \
|
||||
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
|
||||
#endif
|
||||
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
|
||||
//fields from `characer_`
|
||||
into.char_id = atoi(row[0]);
|
||||
into.char_id = Strings::ToUnsignedInt(row[0]);
|
||||
into.char_name = row[1];
|
||||
into.class_ = atoi(row[2]);
|
||||
into.level = atoi(row[3]);
|
||||
into.time_last_on = atoul(row[4]);
|
||||
into.zone_id = atoi(row[5]);
|
||||
into.class_ = Strings::ToUnsignedInt(row[2]);
|
||||
into.level = Strings::ToUnsignedInt(row[3]);
|
||||
into.time_last_on = Strings::ToUnsignedInt(row[4]);
|
||||
into.zone_id = Strings::ToUnsignedInt(row[5]);
|
||||
|
||||
//fields from `guild_members`, leave at defaults if missing
|
||||
into.guild_id = row[6] ? atoi(row[6]) : GUILD_NONE;
|
||||
into.rank = row[7] ? atoi(row[7]) : (GUILD_MAX_RANK+1);
|
||||
into.guild_id = row[6] ? Strings::ToUnsignedInt(row[6]) : GUILD_NONE;
|
||||
into.rank = row[7] ? Strings::ToUnsignedInt(row[7]) : (GUILD_MAX_RANK+1);
|
||||
into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false;
|
||||
into.total_tribute = row[9] ? atoi(row[9]) : 0;
|
||||
into.last_tribute = row[10]? atoul(row[10]) : 0; //timestamp
|
||||
into.total_tribute = row[9] ? Strings::ToUnsignedInt(row[9]) : 0;
|
||||
into.last_tribute = row[10]? Strings::ToUnsignedInt(row[10]) : 0; //timestamp
|
||||
into.banker = row[11]? (row[11][0] == '0'?false:true) : false;
|
||||
into.public_note = row[12]? row[12] : "";
|
||||
into.alt = row[13]? (row[13][0] == '0'?false:true) : false;
|
||||
@@ -967,13 +956,8 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
}
|
||||
|
||||
//load up the rank info for each guild.
|
||||
std::string query;
|
||||
#ifdef BOTS
|
||||
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id);
|
||||
#else
|
||||
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
|
||||
#endif
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1270,7 +1254,7 @@ uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto guild_id = std::stoul(row[0]);
|
||||
auto guild_id = Strings::ToUnsignedInt(row[0]);
|
||||
return guild_id;
|
||||
}
|
||||
|
||||
|
||||
+2838
-2113
File diff suppressed because it is too large
Load Diff
@@ -412,11 +412,12 @@ bool EQ::InventoryProfile::DeleteItem(int16 slot_id, int16 quantity) {
|
||||
// If there are no charges left on the item,
|
||||
if (item_to_delete->GetCharges() <= 0) {
|
||||
// If the item is stackable (e.g arrows), or
|
||||
// the item is not stackable, and is not a charged item, or is expendable, delete it
|
||||
if (item_to_delete->IsStackable() ||
|
||||
(!item_to_delete->IsStackable() &&
|
||||
((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))
|
||||
) {
|
||||
// the item is not a charged item, or is expendable, delete it
|
||||
if (
|
||||
item_to_delete->IsStackable() ||
|
||||
item_to_delete->GetItem()->MaxCharges == 0 ||
|
||||
item_to_delete->IsExpendable()
|
||||
) {
|
||||
// Item can now be destroyed
|
||||
InventoryProfile::MarkDirty(item_to_delete);
|
||||
return true;
|
||||
@@ -1718,3 +1719,17 @@ int16 EQ::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 lo
|
||||
|
||||
return EQ::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
|
||||
{
|
||||
std::vector<uint32> augments;
|
||||
const auto* item = GetItem(slot_id);
|
||||
|
||||
if (item) {
|
||||
for (uint8 i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
|
||||
augments.push_back(item->GetAugment(i) ? item->GetAugmentItemID(i) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return augments;
|
||||
}
|
||||
|
||||
@@ -26,8 +26,11 @@
|
||||
|
||||
|
||||
#include "item_instance.h"
|
||||
#include "classes.h"
|
||||
#include "races.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//FatherNitwit: location bits for searching specific
|
||||
@@ -129,7 +132,7 @@ namespace EQ
|
||||
|
||||
// Swap items in inventory
|
||||
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = NO_CLASS, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
|
||||
|
||||
// Remove item from inventory
|
||||
bool DeleteItem(int16 slot_id, int16 quantity = 0);
|
||||
@@ -152,6 +155,9 @@ namespace EQ
|
||||
// Check how many of a specific augment the player has equipped by Item ID
|
||||
int CountAugmentEquippedByID(uint32 item_id);
|
||||
|
||||
// Get a list of augments from a specific slot ID
|
||||
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
|
||||
|
||||
// Check whether there is space for the specified number of the specified item.
|
||||
bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity);
|
||||
|
||||
@@ -197,12 +203,12 @@ namespace EQ
|
||||
void dumpBankItems();
|
||||
void dumpSharedBankItems();
|
||||
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
|
||||
std::string GetCustomItemData(int16 slot_id, std::string identifier);
|
||||
static int GetItemStatValue(uint32 item_id, const char* identifier);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
|
||||
std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
|
||||
static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
|
||||
protected:
|
||||
///////////////////////////////
|
||||
// Protected Methods
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ std::string IpUtil::DNSLookupSync(const std::string &addr, int port)
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
|
||||
LogInfo(
|
||||
"[DNSLookupSync] Deadline exceeded [{}]",
|
||||
"Deadline exceeded [{}]",
|
||||
1500
|
||||
);
|
||||
running = false;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "types.h"
|
||||
#include "eqemu_exception.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "path_manager.h"
|
||||
|
||||
namespace EQ {
|
||||
struct IPCMutex::Implementation {
|
||||
@@ -40,12 +41,11 @@ namespace EQ {
|
||||
#endif
|
||||
};
|
||||
|
||||
IPCMutex::IPCMutex(std::string name) : locked_(false) {
|
||||
IPCMutex::IPCMutex(const std::string& name) : locked_(false) {
|
||||
imp_ = new Implementation;
|
||||
#ifdef _WINDOWS
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string final_name = Config->SharedMemDir + "EQEmuMutex_";
|
||||
final_name += name;
|
||||
std::string final_name = fmt::format("{}/EQEmuMutex_{}", Config->SharedMemDir, name);
|
||||
|
||||
imp_->mut_ = CreateMutex(nullptr,
|
||||
FALSE,
|
||||
@@ -55,9 +55,7 @@ namespace EQ {
|
||||
EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
|
||||
}
|
||||
#else
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string final_name = Config->SharedMemDir + name;
|
||||
final_name += ".lock";
|
||||
std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name);
|
||||
|
||||
#ifdef __DARWIN
|
||||
#if __DARWIN_C_LEVEL < 200809L
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ namespace EQ {
|
||||
Creates a named binary semaphore, basically a semaphore that is init S <- 1
|
||||
\param name The name of this mutex.
|
||||
*/
|
||||
IPCMutex(std::string name);
|
||||
IPCMutex(const std::string& name);
|
||||
|
||||
//! Destructor
|
||||
~IPCMutex();
|
||||
|
||||
+24
-2
@@ -169,11 +169,33 @@ uint8 EQ::item::ConvertAugTypeBitToAugType(uint32 aug_type_bit)
|
||||
|
||||
bool EQ::ItemData::IsEquipable(uint16 race_id, uint16 class_id) const
|
||||
{
|
||||
if (!(Races & GetPlayerRaceBit(race_id)))
|
||||
if (!(Races & GetPlayerRaceBit(race_id))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id))))
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ItemData::IsClassEquipable(uint16 class_id) const
|
||||
{
|
||||
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ItemData::IsRaceEquipable(uint16 race_id) const
|
||||
{
|
||||
|
||||
if (!(Races & GetPlayerRaceBit(race_id))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+167
-160
@@ -131,7 +131,7 @@ namespace EQ
|
||||
Mounts?
|
||||
Ornamentations?
|
||||
GuildBanners?
|
||||
Collectible?
|
||||
Collectible?
|
||||
Placeable?
|
||||
(others?)
|
||||
*/
|
||||
@@ -355,184 +355,191 @@ namespace EQ
|
||||
|
||||
struct ItemData {
|
||||
// Non packet based fields
|
||||
uint8 MinStatus;
|
||||
uint8 MinStatus {};
|
||||
|
||||
// Packet based fields
|
||||
uint8 ItemClass; // Item Type: 0=common, 1=container, 2=book
|
||||
char Name[64]; // Name
|
||||
char Lore[80]; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore
|
||||
char IDFile[30]; // Visible model
|
||||
uint32 ID; // Unique ID (also PK for DB)
|
||||
int32 Weight; // Item weight * 10
|
||||
uint8 NoRent; // No Rent: 0=norent, 255=not norent
|
||||
uint8 NoDrop; // No Drop: 0=nodrop, 255=not nodrop
|
||||
uint8 Size; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant
|
||||
uint32 Slots; // Bitfield for which slots this item can be used in
|
||||
uint32 Price; // Item cost (?)
|
||||
uint32 Icon; // Icon Number
|
||||
int32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
bool LoreFlag; // This will be true if LoreGroup is non-zero
|
||||
bool PendingLoreFlag;
|
||||
bool ArtifactFlag;
|
||||
bool SummonedFlag;
|
||||
uint8 FVNoDrop; // Firiona Vie nodrop flag
|
||||
uint32 Favor; // Individual favor
|
||||
uint32 GuildFavor; // Guild favor
|
||||
uint32 PointType;
|
||||
uint8 ItemClass {}; // Item Type: 0=common, 1=container, 2=book
|
||||
char Name[64] {}; // Name
|
||||
char Lore[80] {}; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore
|
||||
char IDFile[30] {}; // Visible model
|
||||
uint32 ID {}; // Unique ID (also PK for DB)
|
||||
int32 Weight {}; // Item weight * 10
|
||||
uint8 NoRent{} ; // No Rent: 0=norent, 255=not norent
|
||||
uint8 NoDrop {}; // No Drop: 0=nodrop, 255=not nodrop
|
||||
uint8 Size {}; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant
|
||||
uint32 Slots {}; // Bitfield for which slots this item can be used in
|
||||
uint32 Price {}; // Item cost (?)
|
||||
uint32 Icon {}; // Icon Number
|
||||
int32 LoreGroup {}; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
bool LoreFlag {}; // This will be true if LoreGroup is non-zero
|
||||
bool PendingLoreFlag {};
|
||||
bool ArtifactFlag {};
|
||||
bool SummonedFlag {};
|
||||
uint8 FVNoDrop {}; // Firiona Vie nodrop flag
|
||||
uint32 Favor {}; // Individual favor
|
||||
uint32 GuildFavor {}; // Guild favor
|
||||
uint32 PointType {};
|
||||
|
||||
//uint32 Unk117;
|
||||
//uint32 Unk118;
|
||||
//uint32 Unk121;
|
||||
//uint32 Unk124;
|
||||
|
||||
uint8 BagType; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types
|
||||
uint8 BagSlots; // Number of slots: can only be 2, 4, 6, 8, or 10
|
||||
uint8 BagSize; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT
|
||||
uint8 BagWR; // 0->100
|
||||
uint8 BagType {}; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types
|
||||
uint8 BagSlots {}; // Number of slots: can only be 2, 4, 6, 8, or 10
|
||||
uint8 BagSize {}; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT
|
||||
uint8 BagWR {}; // 0->100
|
||||
|
||||
bool BenefitFlag;
|
||||
bool Tradeskills; // Is this a tradeskill item?
|
||||
int8 CR; // Save vs Cold
|
||||
int8 DR; // Save vs Disease
|
||||
int8 PR; // Save vs Poison
|
||||
int8 MR; // Save vs Magic
|
||||
int8 FR; // Save vs Fire
|
||||
int8 AStr; // Strength
|
||||
int8 ASta; // Stamina
|
||||
int8 AAgi; // Agility
|
||||
int8 ADex; // Dexterity
|
||||
int8 ACha; // Charisma
|
||||
int8 AInt; // Intelligence
|
||||
int8 AWis; // Wisdom
|
||||
int32 HP; // HP
|
||||
int32 Mana; // Mana
|
||||
int32 AC; // AC
|
||||
uint32 Deity; // Bitmask of Deities that can equip this item
|
||||
bool BenefitFlag {};
|
||||
bool Tradeskills {}; // Is this a tradeskill item?
|
||||
int8 CR {}; // Save vs Cold
|
||||
int8 DR {}; // Save vs Disease
|
||||
int8 PR {}; // Save vs Poison
|
||||
int8 MR {}; // Save vs Magic
|
||||
int8 FR {}; // Save vs Fire
|
||||
int8 AStr {}; // Strength
|
||||
int8 ASta {}; // Stamina
|
||||
int8 AAgi {}; // Agility
|
||||
int8 ADex {}; // Dexterity
|
||||
int8 ACha {}; // Charisma
|
||||
int8 AInt {}; // Intelligence
|
||||
int8 AWis {}; // Wisdom
|
||||
int32 HP {}; // HP
|
||||
int32 Mana {}; // Mana
|
||||
int32 AC {}; // AC
|
||||
uint32 Deity {}; // Bitmask of Deities that can equip this item
|
||||
//uint32 Unk033
|
||||
int32 SkillModValue; // % Mod to skill specified in SkillModType
|
||||
int32 SkillModMax; // Max skill point modification
|
||||
uint32 SkillModType; // Type of skill for SkillModValue to apply to
|
||||
uint32 BaneDmgRace; // Bane Damage Race
|
||||
int32 BaneDmgAmt; // Bane Damage Body Amount
|
||||
uint32 BaneDmgBody; // Bane Damage Body
|
||||
bool Magic; // True=Magic Item, False=not
|
||||
int32 CastTime_;
|
||||
uint8 ReqLevel; // Required Level to use item
|
||||
uint32 BardType; // Bard Skill Type
|
||||
int32 BardValue; // Bard Skill Amount
|
||||
int8 Light; // Light
|
||||
uint8 Delay; // Delay * 10
|
||||
uint8 RecLevel; // Recommended level to use item
|
||||
uint8 RecSkill; // Recommended skill to use item (refers to primary skill of item)
|
||||
uint8 ElemDmgType; // Elemental Damage Type (1=magic, 2=fire)
|
||||
uint8 ElemDmgAmt; // Elemental Damage
|
||||
uint8 Range; // Range of item
|
||||
uint32 Damage; // Delay between item usage (in 0.1 sec increments)
|
||||
uint32 Color; // RR GG BB 00 <-- as it appears in pc
|
||||
uint32 Classes; // Bitfield of classes that can equip item (1 << class#)
|
||||
uint32 Races; // Bitfield of races that can equip item (1 << race#)
|
||||
//uint32 Unk054;
|
||||
int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item
|
||||
uint8 ItemType; // Item Type/Skill (itemClass* from above)
|
||||
int32 SubType; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass)
|
||||
uint8 Material; // Item material type
|
||||
uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?)
|
||||
float SellRate; // Sell rate
|
||||
//uint32 Unk059;
|
||||
int32 SkillModValue {}; // % Mod to skill specified in SkillModType
|
||||
int32 SkillModMax {}; // Max skill point modification
|
||||
uint32 SkillModType {}; // Type of skill for SkillModValue to apply to
|
||||
uint32 BaneDmgRace {}; // Bane Damage Race
|
||||
int32 BaneDmgAmt {}; // Bane Damage Body Amount
|
||||
uint32 BaneDmgBody {}; // Bane Damage Body
|
||||
bool Magic {}; // True=Magic Item, False=not
|
||||
int32 CastTime_ {};
|
||||
uint8 ReqLevel {}; // Required Level to use item
|
||||
uint32 BardType {}; // Bard Skill Type
|
||||
int32 BardValue {}; // Bard Skill Amount
|
||||
int8 Light {}; // Light
|
||||
uint8 Delay {}; // Delay * 10
|
||||
uint8 RecLevel {}; // Recommended level to use item
|
||||
uint8 RecSkill {}; // Recommended skill to use item (refers to primary skill of item)
|
||||
uint8 ElemDmgType {}; // Elemental Damage Type (1=magic, 2=fire)
|
||||
uint8 ElemDmgAmt {}; // Elemental Damage
|
||||
uint8 Range {}; // Range of item
|
||||
uint32 Damage {}; // Delay between item usage (in 0.1 sec increments)
|
||||
uint32 Color {}; // RR GG BB 00 <-- as it appears in pc
|
||||
uint32 Classes {}; // Bitfield of classes that can equip item (1 << class#)
|
||||
uint32 Races {}; // Bitfield of races that can equip item (1 << race#)
|
||||
//uint32 Unk054 {};
|
||||
int16 MaxCharges {}; // Maximum charges items can hold: -1 if not a chargeable item
|
||||
uint8 ItemType {}; // Item Type/Skill (itemClass* from above)
|
||||
int32 SubType {}; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass)
|
||||
uint8 Material {}; // Item material type
|
||||
uint32 HerosForgeModel {};// Hero's Forge Armor Model Type (2-13?)
|
||||
float SellRate {}; // Sell rate
|
||||
//uint32 Unk059 {};
|
||||
union {
|
||||
uint32 Fulfilment; // Food fulfilment (How long it lasts)
|
||||
uint32 CastTime; // Cast Time for clicky effects, in milliseconds
|
||||
};
|
||||
uint32 EliteMaterial;
|
||||
int32 ProcRate;
|
||||
int8 CombatEffects; // PoP: Combat Effects +
|
||||
int8 Shielding; // PoP: Shielding %
|
||||
int8 StunResist; // PoP: Stun Resist %
|
||||
int8 StrikeThrough; // PoP: Strike Through %
|
||||
uint32 ExtraDmgSkill;
|
||||
uint32 ExtraDmgAmt;
|
||||
int8 SpellShield; // PoP: Spell Shield %
|
||||
int8 Avoidance; // PoP: Avoidance +
|
||||
int8 Accuracy; // PoP: Accuracy +
|
||||
uint32 CharmFileID;
|
||||
int32 FactionMod1; // Faction Mod 1
|
||||
int32 FactionMod2; // Faction Mod 2
|
||||
int32 FactionMod3; // Faction Mod 3
|
||||
int32 FactionMod4; // Faction Mod 4
|
||||
int32 FactionAmt1; // Faction Amt 1
|
||||
int32 FactionAmt2; // Faction Amt 2
|
||||
int32 FactionAmt3; // Faction Amt 3
|
||||
int32 FactionAmt4; // Faction Amt 4
|
||||
char CharmFile[32]; // ?
|
||||
uint32 AugType;
|
||||
uint8 AugSlotType[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Type
|
||||
uint8 AugSlotVisible[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Visible
|
||||
uint8 AugSlotUnk2[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
|
||||
uint32 LDoNTheme;
|
||||
uint32 LDoNPrice;
|
||||
uint32 LDoNSold;
|
||||
uint32 BaneDmgRaceAmt;
|
||||
uint32 AugRestrict;
|
||||
int32 Endur;
|
||||
int32 DotShielding;
|
||||
int32 Attack;
|
||||
int32 Regen;
|
||||
int32 ManaRegen;
|
||||
int32 EnduranceRegen;
|
||||
int32 Haste;
|
||||
int32 DamageShield;
|
||||
uint32 RecastDelay;
|
||||
int RecastType;
|
||||
uint32 AugDistiller;
|
||||
bool Attuneable;
|
||||
bool NoPet;
|
||||
bool PotionBelt;
|
||||
bool Stackable;
|
||||
bool NoTransfer;
|
||||
bool QuestItemFlag;
|
||||
int16 StackSize;
|
||||
uint8 PotionBeltSlots;
|
||||
item::ItemEffect_Struct Click, Proc, Worn, Focus, Scroll, Bard;
|
||||
uint32 EliteMaterial {};
|
||||
int32 ProcRate {};
|
||||
int8 CombatEffects {}; // PoP: Combat Effects +
|
||||
int8 Shielding {}; // PoP: Shielding %
|
||||
int8 StunResist {}; // PoP: Stun Resist %
|
||||
int8 StrikeThrough {}; // PoP: Strike Through %
|
||||
int32 ExtraDmgSkill {};
|
||||
int32 ExtraDmgAmt {};
|
||||
int8 SpellShield {}; // PoP: Spell Shield %
|
||||
int8 Avoidance {}; // PoP: Avoidance +
|
||||
int8 Accuracy {}; // PoP: Accuracy +
|
||||
uint32 CharmFileID {};
|
||||
int32 FactionMod1 {}; // Faction Mod 1
|
||||
int32 FactionMod2 {}; // Faction Mod 2
|
||||
int32 FactionMod3 {}; // Faction Mod 3
|
||||
int32 FactionMod4 {}; // Faction Mod 4
|
||||
int32 FactionAmt1 {}; // Faction Amt 1
|
||||
int32 FactionAmt2 {}; // Faction Amt 2
|
||||
int32 FactionAmt3 {}; // Faction Amt 3
|
||||
int32 FactionAmt4 {}; // Faction Amt 4
|
||||
char CharmFile[32] {}; // ?
|
||||
uint32 AugType {};
|
||||
uint8 AugSlotType[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Type
|
||||
uint8 AugSlotVisible[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Visible
|
||||
uint8 AugSlotUnk2[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
|
||||
uint32 LDoNTheme {};
|
||||
uint32 LDoNPrice {};
|
||||
uint32 LDoNSold {};
|
||||
uint32 BaneDmgRaceAmt {};
|
||||
uint32 AugRestrict {};
|
||||
int32 Endur {};
|
||||
int32 DotShielding {};
|
||||
int32 Attack {};
|
||||
int32 Regen {};
|
||||
int32 ManaRegen {};
|
||||
int32 EnduranceRegen {};
|
||||
int32 Haste {};
|
||||
int32 DamageShield {};
|
||||
uint32 RecastDelay {};
|
||||
int RecastType {};
|
||||
uint32 AugDistiller {};
|
||||
bool Attuneable {};
|
||||
bool NoPet {};
|
||||
bool PotionBelt {};
|
||||
bool Stackable {};
|
||||
bool NoTransfer {};
|
||||
bool QuestItemFlag {};
|
||||
int16 StackSize {};
|
||||
uint8 PotionBeltSlots {};
|
||||
item::ItemEffect_Struct Click {};
|
||||
item::ItemEffect_Struct Proc {};
|
||||
item::ItemEffect_Struct Worn {};
|
||||
item::ItemEffect_Struct Focus {};
|
||||
item::ItemEffect_Struct Scroll {};
|
||||
item::ItemEffect_Struct Bard {};
|
||||
|
||||
uint8 Book; // 0=Not book, 1=Book
|
||||
uint32 BookType;
|
||||
char Filename[33]; // Filename for book data
|
||||
uint8 Book {}; // 0=Not book, 1=Book
|
||||
uint32 BookType {};
|
||||
char Filename[33] {}; // Filename for book data
|
||||
// Begin SoF Fields
|
||||
int32 SVCorruption;
|
||||
uint32 Purity;
|
||||
uint8 EvolvingItem;
|
||||
uint32 EvolvingID;
|
||||
uint8 EvolvingLevel;
|
||||
uint8 EvolvingMax;
|
||||
uint32 BackstabDmg;
|
||||
uint32 DSMitigation;
|
||||
int32 HeroicStr;
|
||||
int32 HeroicInt;
|
||||
int32 HeroicWis;
|
||||
int32 HeroicAgi;
|
||||
int32 HeroicDex;
|
||||
int32 HeroicSta;
|
||||
int32 HeroicCha;
|
||||
int32 HeroicMR;
|
||||
int32 HeroicFR;
|
||||
int32 HeroicCR;
|
||||
int32 HeroicDR;
|
||||
int32 HeroicPR;
|
||||
int32 HeroicSVCorrup;
|
||||
int32 HealAmt;
|
||||
int32 SpellDmg;
|
||||
uint32 LDoNSellBackRate;
|
||||
uint32 ScriptFileID;
|
||||
uint16 ExpendableArrow;
|
||||
uint32 Clairvoyance;
|
||||
char ClickName[65];
|
||||
char ProcName[65];
|
||||
char WornName[65];
|
||||
char FocusName[65];
|
||||
char ScrollName[65];
|
||||
int32 SVCorruption {};
|
||||
uint32 Purity {};
|
||||
uint8 EvolvingItem {};
|
||||
uint32 EvolvingID {};
|
||||
uint8 EvolvingLevel {};
|
||||
uint8 EvolvingMax {};
|
||||
uint32 BackstabDmg {};
|
||||
uint32 DSMitigation {};
|
||||
int32 HeroicStr {};
|
||||
int32 HeroicInt {};
|
||||
int32 HeroicWis {};
|
||||
int32 HeroicAgi {};
|
||||
int32 HeroicDex {};
|
||||
int32 HeroicSta {};
|
||||
int32 HeroicCha {};
|
||||
int32 HeroicMR {};
|
||||
int32 HeroicFR {};
|
||||
int32 HeroicCR {};
|
||||
int32 HeroicDR {};
|
||||
int32 HeroicPR {};
|
||||
int32 HeroicSVCorrup {};
|
||||
int32 HealAmt {};
|
||||
int32 SpellDmg {};
|
||||
uint32 LDoNSellBackRate {};
|
||||
uint32 ScriptFileID {};
|
||||
uint16 ExpendableArrow {};
|
||||
uint32 Clairvoyance {};
|
||||
char ClickName[65] {};
|
||||
char ProcName[65] {};
|
||||
char WornName[65] {};
|
||||
char FocusName[65] {};
|
||||
char ScrollName[65] {};
|
||||
//BardName
|
||||
|
||||
bool IsEquipable(uint16 Race, uint16 Class) const;
|
||||
bool IsClassEquipable(uint16 Class) const;
|
||||
bool IsRaceEquipable(uint16 Race) const;
|
||||
bool IsClassCommon() const;
|
||||
bool IsClassBag() const;
|
||||
bool IsClassBook() const;
|
||||
|
||||
+262
-194
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "inventory_profile.h"
|
||||
#include "../common/data_verification.h"
|
||||
//#include "classes.h"
|
||||
//#include "global_define.h"
|
||||
//#include "item_instance.h"
|
||||
@@ -57,108 +58,62 @@ static inline int32 GetNextItemInstSerialNumber() {
|
||||
// class EQ::ItemInstance
|
||||
//
|
||||
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
||||
m_use_type = ItemInstNormal;
|
||||
if(item) {
|
||||
m_item = new ItemData(*item);
|
||||
} else {
|
||||
m_item = nullptr;
|
||||
}
|
||||
m_charges = charges;
|
||||
m_price = 0;
|
||||
m_attuned = false;
|
||||
m_merchantslot = 0;
|
||||
if (m_item && m_item->IsClassCommon())
|
||||
m_color = m_item->Color;
|
||||
else
|
||||
m_color = 0;
|
||||
m_merchantcount = 1;
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
|
||||
m_exp = 0;
|
||||
m_evolveLvl = 0;
|
||||
m_activated = false;
|
||||
m_scaledItem = nullptr;
|
||||
m_evolveInfo = nullptr;
|
||||
m_scaling = false;
|
||||
m_ornamenticon = 0;
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
if (item) {
|
||||
m_item = new ItemData(*item);
|
||||
}
|
||||
|
||||
m_charges = charges;
|
||||
|
||||
if (m_item && m_item->IsClassCommon()) {
|
||||
m_color = m_item->Color;
|
||||
}
|
||||
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
}
|
||||
|
||||
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
|
||||
m_use_type = ItemInstNormal;
|
||||
m_item = db->GetItem(item_id);
|
||||
if(m_item) {
|
||||
|
||||
m_item = db->GetItem(item_id);
|
||||
|
||||
if (m_item) {
|
||||
m_item = new ItemData(*m_item);
|
||||
}
|
||||
else {
|
||||
m_item = nullptr;
|
||||
}
|
||||
|
||||
m_charges = charges;
|
||||
m_price = 0;
|
||||
m_merchantslot = 0;
|
||||
m_attuned=false;
|
||||
if (m_item && m_item->IsClassCommon())
|
||||
m_color = m_item->Color;
|
||||
else
|
||||
m_color = 0;
|
||||
m_merchantcount = 1;
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
|
||||
m_exp = 0;
|
||||
m_evolveLvl = 0;
|
||||
m_activated = false;
|
||||
m_scaledItem = nullptr;
|
||||
m_evolveInfo = nullptr;
|
||||
m_scaling = false;
|
||||
m_ornamenticon = 0;
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
if (m_item && m_item->IsClassCommon()) {
|
||||
m_color = m_item->Color;
|
||||
} else {
|
||||
m_color = 0;
|
||||
}
|
||||
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
}
|
||||
|
||||
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
|
||||
m_use_type = use_type;
|
||||
m_item = nullptr;
|
||||
m_charges = 0;
|
||||
m_price = 0;
|
||||
m_attuned = false;
|
||||
m_merchantslot = 0;
|
||||
m_color = 0;
|
||||
|
||||
m_exp = 0;
|
||||
m_evolveLvl = 0;
|
||||
m_activated = false;
|
||||
m_scaledItem = nullptr;
|
||||
m_evolveInfo = nullptr;
|
||||
m_scaling = false;
|
||||
m_ornamenticon = 0;
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
m_use_type = use_type;
|
||||
}
|
||||
|
||||
// Make a copy of an EQ::ItemInstance object
|
||||
EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
||||
{
|
||||
m_use_type=copy.m_use_type;
|
||||
if(copy.m_item)
|
||||
m_item = new ItemData(*copy.m_item);
|
||||
else
|
||||
m_item = nullptr;
|
||||
m_use_type = copy.m_use_type;
|
||||
|
||||
if (copy.m_item) {
|
||||
m_item = new ItemData(*copy.m_item);
|
||||
} else {
|
||||
m_item = nullptr;
|
||||
}
|
||||
|
||||
m_charges = copy.m_charges;
|
||||
m_price = copy.m_price;
|
||||
m_color = copy.m_color;
|
||||
m_merchantslot = copy.m_merchantslot;
|
||||
m_currentslot = copy.m_currentslot;
|
||||
m_attuned = copy.m_attuned;
|
||||
m_merchantcount = copy.m_merchantcount;
|
||||
|
||||
m_charges=copy.m_charges;
|
||||
m_price=copy.m_price;
|
||||
m_color=copy.m_color;
|
||||
m_merchantslot=copy.m_merchantslot;
|
||||
m_currentslot=copy.m_currentslot;
|
||||
m_attuned=copy.m_attuned;
|
||||
m_merchantcount=copy.m_merchantcount;
|
||||
// Copy container contents
|
||||
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
|
||||
ItemInstance* inst_old = it->second;
|
||||
@@ -168,37 +123,42 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
||||
inst_new = inst_old->Clone();
|
||||
}
|
||||
|
||||
if (inst_new != nullptr) {
|
||||
if (inst_new) {
|
||||
m_contents[it->first] = inst_new;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>::const_iterator iter;
|
||||
for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) {
|
||||
m_custom_data[iter->first] = iter->second;
|
||||
}
|
||||
m_SerialNumber = copy.m_SerialNumber;
|
||||
m_custom_data = copy.m_custom_data;
|
||||
m_timers = copy.m_timers;
|
||||
|
||||
m_exp = copy.m_exp;
|
||||
m_SerialNumber = copy.m_SerialNumber;
|
||||
m_custom_data = copy.m_custom_data;
|
||||
m_timers = copy.m_timers;
|
||||
|
||||
m_exp = copy.m_exp;
|
||||
m_evolveLvl = copy.m_evolveLvl;
|
||||
m_activated = copy.m_activated;
|
||||
if (copy.m_scaledItem)
|
||||
|
||||
if (copy.m_scaledItem) {
|
||||
m_scaledItem = new ItemData(*copy.m_scaledItem);
|
||||
else
|
||||
} else {
|
||||
m_scaledItem = nullptr;
|
||||
}
|
||||
|
||||
if(copy.m_evolveInfo)
|
||||
if (copy.m_evolveInfo) {
|
||||
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
|
||||
else
|
||||
} else {
|
||||
m_evolveInfo = nullptr;
|
||||
}
|
||||
|
||||
m_scaling = copy.m_scaling;
|
||||
m_ornamenticon = copy.m_ornamenticon;
|
||||
m_ornamentidfile = copy.m_ornamentidfile;
|
||||
m_scaling = copy.m_scaling;
|
||||
m_ornamenticon = copy.m_ornamenticon;
|
||||
m_ornamentidfile = copy.m_ornamentidfile;
|
||||
m_ornament_hero_model = copy.m_ornament_hero_model;
|
||||
m_recast_timestamp = copy.m_recast_timestamp;
|
||||
m_new_id_file = copy.m_new_id_file;
|
||||
m_recast_timestamp = copy.m_recast_timestamp;
|
||||
m_new_id_file = copy.m_new_id_file;
|
||||
}
|
||||
|
||||
// Clean up container contents
|
||||
@@ -216,11 +176,13 @@ bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
|
||||
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
|
||||
|
||||
// Check usage type
|
||||
if ((m_use_type == ItemInstWorldContainer) && (item_class == item::ItemClassBag))
|
||||
if (m_use_type == ItemInstWorldContainer && item_class == item::ItemClassBag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_item)
|
||||
if (!m_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (m_item->ItemClass == item_class);
|
||||
}
|
||||
@@ -243,96 +205,145 @@ bool EQ::ItemInstance::IsClassBook() const
|
||||
// Is item stackable?
|
||||
bool EQ::ItemInstance::IsStackable() const
|
||||
{
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
return m_item->Stackable;
|
||||
return (m_item && m_item->Stackable);
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::IsCharged() const
|
||||
{
|
||||
if (!m_item)
|
||||
if (!m_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_item->MaxCharges > 1)
|
||||
if (m_item->MaxCharges > 1) {
|
||||
return true;
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Can item be equipped?
|
||||
bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const
|
||||
{
|
||||
if (!m_item || (m_item->Slots == 0))
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsEquipable(race, class_);
|
||||
}
|
||||
|
||||
// Can item be equipped by Class?
|
||||
bool EQ::ItemInstance::IsClassEquipable(uint16 class_) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsClassEquipable(class_);
|
||||
}
|
||||
|
||||
// Can item be equipped by Race?
|
||||
bool EQ::ItemInstance::IsRaceEquipable(uint16 race) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsRaceEquipable(race);
|
||||
}
|
||||
|
||||
// Can equip at this slot?
|
||||
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
|
||||
{
|
||||
if (!m_item)
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END)
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((m_item->Slots & (1 << slot_id)) != 0);
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::IsAugmentable() const
|
||||
{
|
||||
if (!m_item)
|
||||
if (!m_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (m_item->AugSlotType[index] != 0)
|
||||
if (m_item->AugSlotType[index] != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = invslot::EQUIPMENT_BEGIN;
|
||||
for (; index <= invslot::EQUIPMENT_END; ++index) {
|
||||
if (m_item->Slots & (1 << index)) {
|
||||
if (aug_wear_slots & (1 << index))
|
||||
if (aug_wear_slots & (1 << index)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (index <= EQ::invslot::EQUIPMENT_END);
|
||||
}
|
||||
|
||||
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augtype) const
|
||||
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return INVALID_INDEX;
|
||||
|
||||
int index = invaug::SOCKET_BEGIN;
|
||||
for (; index <= invaug::SOCKET_END; ++index) {
|
||||
if (GetItem(index)) { continue; }
|
||||
if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype)))
|
||||
break;
|
||||
}
|
||||
|
||||
return (index <= invaug::SOCKET_END) ? index : INVALID_INDEX;
|
||||
auto i = invaug::SOCKET_BEGIN;
|
||||
for (; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetItem(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[i] &&
|
||||
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
|
||||
)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
|
||||
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
|
||||
if (
|
||||
(
|
||||
!GetItem(slot) &&
|
||||
m_item->AugSlotVisible[slot]
|
||||
) &&
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[slot] &&
|
||||
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve item inside container
|
||||
@@ -348,9 +359,10 @@ EQ::ItemInstance* EQ::ItemInstance::GetItem(uint8 index) const
|
||||
|
||||
uint32 EQ::ItemInstance::GetItemID(uint8 slot) const
|
||||
{
|
||||
ItemInstance *item = GetItem(slot);
|
||||
if (item)
|
||||
const auto item = GetItem(slot);
|
||||
if (item) {
|
||||
return item->GetID();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -474,14 +486,21 @@ uint8 EQ::ItemInstance::FirstOpenSlot() const
|
||||
|
||||
uint8 EQ::ItemInstance::GetTotalItemCount() const
|
||||
{
|
||||
if (!m_item)
|
||||
if (!m_item) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 item_count = 1;
|
||||
|
||||
if (m_item && !m_item->IsClassBag()) { return item_count; }
|
||||
if (!m_item->IsClassBag()) {
|
||||
return item_count;
|
||||
}
|
||||
|
||||
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } }
|
||||
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) {
|
||||
if (GetItem(index)) {
|
||||
++item_count;
|
||||
}
|
||||
}
|
||||
|
||||
return item_count;
|
||||
}
|
||||
@@ -500,86 +519,108 @@ bool EQ::ItemInstance::IsNoneEmptyContainer()
|
||||
}
|
||||
|
||||
// Retrieve augment inside item
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 slot) const
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 augment_index) const
|
||||
{
|
||||
if (m_item && m_item->IsClassCommon())
|
||||
return GetItem(slot);
|
||||
if (m_item && m_item->IsClassCommon()) {
|
||||
return GetItem(augment_index);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugtype) const
|
||||
bool EQ::ItemInstance::IsOrnamentationAugment(EQ::ItemInstance* augment) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) { return nullptr; }
|
||||
if (ornamentationAugtype == 0) { return nullptr; }
|
||||
if (!m_item || !m_item->IsClassCommon() || !augment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++)
|
||||
{
|
||||
if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype)
|
||||
{
|
||||
const char *item_IDFile = GetAugment(i)->GetItem()->IDFile;
|
||||
if (
|
||||
(strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0
|
||||
|| strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0)
|
||||
&& GetAugment(i)->GetItem()->HerosForgeModel == 0
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return GetAugment(i);
|
||||
const auto augment_item = augment->GetItem();
|
||||
if (!augment_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& idfile = augment_item->IDFile;
|
||||
|
||||
if (
|
||||
EQ::ValueWithin(
|
||||
augment->GetAugmentType(),
|
||||
OrnamentationAugmentTypes::StandardOrnamentation,
|
||||
OrnamentationAugmentTypes::SpecialOrnamentation
|
||||
) ||
|
||||
(
|
||||
idfile != "IT63" &&
|
||||
idfile != "IT64"
|
||||
) ||
|
||||
augment_item->HerosForgeModel
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
|
||||
const auto augment = GetAugment(i);
|
||||
if (augment && IsOrnamentationAugment(augment)) {
|
||||
return augment;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
|
||||
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
|
||||
{
|
||||
// Not a Hero Forge item.
|
||||
if (m_ornament_hero_model == 0 || material_slot < 0)
|
||||
if (m_ornament_hero_model == 0 || material_slot < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Item is using an explicit Hero Forge ID
|
||||
if (m_ornament_hero_model >= 1000)
|
||||
if (m_ornament_hero_model >= 1000) {
|
||||
return m_ornament_hero_model;
|
||||
}
|
||||
|
||||
// Item is using a shorthand ID
|
||||
return (m_ornament_hero_model * 100) + material_slot;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::UpdateOrnamentationInfo() {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
bool EQ::ItemInstance::UpdateOrnamentationInfo()
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ornamentSet = false;
|
||||
const auto augment = GetOrnamentationAugment();
|
||||
|
||||
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
if (GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
const ItemData* ornamentItem;
|
||||
ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
if (ornamentItem != nullptr)
|
||||
{
|
||||
SetOrnamentIcon(ornamentItem->Icon);
|
||||
SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
|
||||
if (strlen(ornamentItem->IDFile) > 2)
|
||||
{
|
||||
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (augment) {
|
||||
const auto augment_item = GetOrnamentationAugment()->GetItem();
|
||||
|
||||
if (augment_item) {
|
||||
SetOrnamentIcon(augment_item->Icon);
|
||||
SetOrnamentHeroModel(augment_item->HerosForgeModel);
|
||||
|
||||
if (strlen(augment_item->IDFile) > 2) {
|
||||
SetOrnamentationIDFile(Strings::ToUnsignedInt(&augment_item->IDFile[2]));
|
||||
} else {
|
||||
SetOrnamentationIDFile(0);
|
||||
}
|
||||
ornamentSet = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetOrnamentIcon(0);
|
||||
SetOrnamentHeroModel(0);
|
||||
SetOrnamentationIDFile(0);
|
||||
}
|
||||
|
||||
return ornamentSet;
|
||||
SetOrnamentIcon(0);
|
||||
SetOrnamentHeroModel(0);
|
||||
SetOrnamentationIDFile(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll) {
|
||||
@@ -629,12 +670,13 @@ bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *C
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 slot) const
|
||||
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 augment_index) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetItemID(slot);
|
||||
return GetItemID(augment_index);
|
||||
}
|
||||
|
||||
// Add an augment to the item
|
||||
@@ -792,7 +834,20 @@ std::string EQ::ItemInstance::GetCustomDataString() const {
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
|
||||
void EQ::ItemInstance::SetCustomDataString(const std::string& str)
|
||||
{
|
||||
auto components = Strings::Split(str, "^");
|
||||
auto value_count = components.size() / 2;
|
||||
|
||||
for (auto i = 0; i < value_count; i++) {
|
||||
auto identifier = components[i * 2];
|
||||
auto value = components[(i * 2) + 1];
|
||||
|
||||
SetCustomData(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
|
||||
std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier);
|
||||
if (iter != m_custom_data.end()) {
|
||||
return iter->second;
|
||||
@@ -801,33 +856,33 @@ std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetCustomData(std::string identifier, std::string value) {
|
||||
void EQ::ItemInstance::SetCustomData(const std::string& identifier, const std::string& value) {
|
||||
DeleteCustomData(identifier);
|
||||
m_custom_data[identifier] = value;
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetCustomData(std::string identifier, int value) {
|
||||
void EQ::ItemInstance::SetCustomData(const std::string& identifier, int value) {
|
||||
DeleteCustomData(identifier);
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
m_custom_data[identifier] = ss.str();
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetCustomData(std::string identifier, float value) {
|
||||
void EQ::ItemInstance::SetCustomData(const std::string& identifier, float value) {
|
||||
DeleteCustomData(identifier);
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
m_custom_data[identifier] = ss.str();
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetCustomData(std::string identifier, bool value) {
|
||||
void EQ::ItemInstance::SetCustomData(const std::string& identifier, bool value) {
|
||||
DeleteCustomData(identifier);
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
m_custom_data[identifier] = ss.str();
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::DeleteCustomData(std::string identifier) {
|
||||
void EQ::ItemInstance::DeleteCustomData(const std::string& identifier) {
|
||||
auto iter = m_custom_data.find(identifier);
|
||||
if (iter != m_custom_data.end()) {
|
||||
m_custom_data.erase(iter);
|
||||
@@ -879,8 +934,9 @@ bool EQ::ItemInstance::IsDroppable(bool recurse) const
|
||||
|
||||
void EQ::ItemInstance::Initialize(SharedDatabase *db) {
|
||||
// if there's no actual item, don't do anything
|
||||
if (!m_item)
|
||||
if (!m_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize scaling items
|
||||
if (m_item->CharmFileID != 0) {
|
||||
@@ -889,7 +945,7 @@ void EQ::ItemInstance::Initialize(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
// initialize evolving items
|
||||
else if ((db) && m_item->LoreGroup >= 1000 && m_item->LoreGroup != -1) {
|
||||
else if (db && m_item->LoreGroup >= 1000) {
|
||||
// not complete yet
|
||||
}
|
||||
}
|
||||
@@ -1215,7 +1271,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
{
|
||||
int race = 0;
|
||||
int race = RACE_DOUG_0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
race = item->BaneDmgRace;
|
||||
@@ -1721,6 +1777,18 @@ int EQ::ItemInstance::GetItemHaste(bool augments) const
|
||||
return total;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::RemoveTaskDeliveredItems()
|
||||
{
|
||||
int count = IsStackable() ? GetCharges() : 1;
|
||||
count -= GetTaskDeliveredCount();
|
||||
if (IsStackable())
|
||||
{
|
||||
SetCharges(count);
|
||||
}
|
||||
SetTaskDeliveredCount(0);
|
||||
return count;
|
||||
}
|
||||
|
||||
//
|
||||
// class EvolveInfo
|
||||
//
|
||||
|
||||
+55
-37
@@ -51,6 +51,11 @@ typedef enum {
|
||||
byFlagNotSet //apply action if the flag is NOT set
|
||||
} byFlagSetting;
|
||||
|
||||
enum OrnamentationAugmentTypes {
|
||||
StandardOrnamentation = 20,
|
||||
SpecialOrnamentation = 21
|
||||
};
|
||||
|
||||
class SharedDatabase;
|
||||
|
||||
// ########################################
|
||||
@@ -92,6 +97,8 @@ namespace EQ
|
||||
|
||||
// Can item be equipped by/at?
|
||||
bool IsEquipable(uint16 race, uint16 class_) const;
|
||||
bool IsClassEquipable(uint16 class_) const;
|
||||
bool IsRaceEquipable(uint16 race) const;
|
||||
bool IsEquipable(int16 slot_id) const;
|
||||
|
||||
//
|
||||
@@ -99,8 +106,8 @@ namespace EQ
|
||||
//
|
||||
bool IsAugmentable() const;
|
||||
bool AvailableWearSlot(uint32 aug_wear_slots) const;
|
||||
int8 AvailableAugmentSlot(int32 augtype) const;
|
||||
bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const;
|
||||
int8 AvailableAugmentSlot(int32 augment_type) const;
|
||||
bool IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const;
|
||||
inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); }
|
||||
|
||||
inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); }
|
||||
@@ -125,8 +132,8 @@ namespace EQ
|
||||
//
|
||||
// Augments
|
||||
//
|
||||
ItemInstance* GetAugment(uint8 slot) const;
|
||||
uint32 GetAugmentItemID(uint8 slot) const;
|
||||
ItemInstance* GetAugment(uint8 augment_index) const;
|
||||
uint32 GetAugmentItemID(uint8 augment_index) const;
|
||||
void PutAugment(uint8 slot, const ItemInstance& inst);
|
||||
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
|
||||
void DeleteAugment(uint8 slot);
|
||||
@@ -134,7 +141,8 @@ namespace EQ
|
||||
bool IsAugmented();
|
||||
bool ContainsAugmentByID(uint32 item_id);
|
||||
int CountAugmentByID(uint32 item_id);
|
||||
ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const;
|
||||
bool IsOrnamentationAugment(EQ::ItemInstance* augment) const;
|
||||
ItemInstance* GetOrnamentationAugment() const;
|
||||
bool UpdateOrnamentationInfo();
|
||||
static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false);
|
||||
|
||||
@@ -148,6 +156,8 @@ namespace EQ
|
||||
const ItemData* GetItem() const;
|
||||
const ItemData* GetUnscaledItem() const;
|
||||
|
||||
const uint8 GetItemType() const { return m_item ? m_item->ItemType : 255; } // Return 255 so you know there's no valid item
|
||||
|
||||
int16 GetCharges() const { return m_charges; }
|
||||
void SetCharges(int16 charges) { m_charges = charges; }
|
||||
|
||||
@@ -171,12 +181,13 @@ namespace EQ
|
||||
void SetAttuned(bool flag) { m_attuned = flag; }
|
||||
|
||||
std::string GetCustomDataString() const;
|
||||
std::string GetCustomData(std::string identifier);
|
||||
void SetCustomData(std::string identifier, std::string value);
|
||||
void SetCustomData(std::string identifier, int value);
|
||||
void SetCustomData(std::string identifier, float value);
|
||||
void SetCustomData(std::string identifier, bool value);
|
||||
void DeleteCustomData(std::string identifier);
|
||||
std::string GetCustomData(const std::string &identifier);
|
||||
void SetCustomDataString(const std::string& str);
|
||||
void SetCustomData(const std::string &identifier, const std::string& value);
|
||||
void SetCustomData(const std::string &identifier, int value);
|
||||
void SetCustomData(const std::string &identifier, float value);
|
||||
void SetCustomData(const std::string &identifier, bool value);
|
||||
void DeleteCustomData(const std::string& identifier);
|
||||
|
||||
// Allows treatment of this object as though it were a pointer to m_item
|
||||
operator bool() const { return (m_item != nullptr); }
|
||||
@@ -229,6 +240,13 @@ namespace EQ
|
||||
void StopTimer(std::string name);
|
||||
void ClearTimers();
|
||||
|
||||
int GetTaskDeliveredCount() const { return m_task_delivered_count; }
|
||||
void SetTaskDeliveredCount(int count) { m_task_delivered_count = count; }
|
||||
// This function should only be used by trade return apis
|
||||
// Removes delivered task items from stack count and returns remaining count
|
||||
// Return value should be used to determine if an item still exists (for stackable and non-stackable)
|
||||
int RemoveTaskDeliveredItems();
|
||||
|
||||
// Get a total of a stat, including augs
|
||||
// These functions should be used in place of other code manually totaling
|
||||
// to centralize where it is done to make future changes easier (ex. whenever powersources come around)
|
||||
@@ -292,33 +310,33 @@ namespace EQ
|
||||
|
||||
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
|
||||
|
||||
ItemInstTypes m_use_type; // Usage type for item
|
||||
const ItemData* m_item; // Ptr to item data
|
||||
int16 m_charges; // # of charges for chargeable items
|
||||
uint32 m_price; // Bazaar /trader price
|
||||
uint32 m_color;
|
||||
uint32 m_merchantslot;
|
||||
int16 m_currentslot;
|
||||
bool m_attuned;
|
||||
int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
|
||||
int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
|
||||
uint32 m_exp;
|
||||
int8 m_evolveLvl;
|
||||
bool m_activated;
|
||||
ItemData* m_scaledItem;
|
||||
::EvolveInfo* m_evolveInfo;
|
||||
bool m_scaling;
|
||||
uint32 m_ornamenticon;
|
||||
uint32 m_ornamentidfile;
|
||||
uint32 m_new_id_file;
|
||||
uint32 m_ornament_hero_model;
|
||||
uint32 m_recast_timestamp;
|
||||
ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item
|
||||
const ItemData* m_item {nullptr}; // Ptr to item data
|
||||
int16 m_charges {0}; // # of charges for chargeable items
|
||||
uint32 m_price {0}; // Bazaar /trader price
|
||||
uint32 m_color {0};
|
||||
uint32 m_merchantslot {0};
|
||||
int16 m_currentslot {0};
|
||||
bool m_attuned {false};
|
||||
int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited
|
||||
int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar.
|
||||
uint32 m_exp {0};
|
||||
int8 m_evolveLvl {0};
|
||||
bool m_activated {false};
|
||||
ItemData* m_scaledItem {nullptr};
|
||||
::EvolveInfo* m_evolveInfo {nullptr};
|
||||
bool m_scaling {false};
|
||||
uint32 m_ornamenticon {0};
|
||||
uint32 m_ornamentidfile {0};
|
||||
uint32 m_new_id_file {0};
|
||||
uint32 m_ornament_hero_model {0};
|
||||
uint32 m_recast_timestamp {0};
|
||||
int m_task_delivered_count {0};
|
||||
|
||||
//
|
||||
// Items inside of this item (augs or contents);
|
||||
std::map<uint8, ItemInstance*> m_contents; // Zero-based index: min=0, max=9
|
||||
std::map<std::string, std::string> m_custom_data;
|
||||
std::map<std::string, ::Timer> m_timers;
|
||||
// Items inside of this item (augs or contents) {};
|
||||
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
|
||||
std::map<std::string, std::string> m_custom_data {};
|
||||
std::map<std::string, ::Timer> m_timers {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -41,7 +41,7 @@ namespace EQ
|
||||
MemoryBuffer& operator+=(const MemoryBuffer &rhs);
|
||||
friend MemoryBuffer operator+(MemoryBuffer lhs, const MemoryBuffer& rhs) { return lhs += rhs; }
|
||||
~MemoryBuffer();
|
||||
|
||||
|
||||
uchar& operator[](size_t pos);
|
||||
const uchar& operator[](size_t pos) const;
|
||||
|
||||
@@ -64,20 +64,20 @@ namespace EQ
|
||||
size_t Size() const;
|
||||
size_t Capacity();
|
||||
size_t Capacity() const;
|
||||
|
||||
|
||||
void Resize(size_t sz);
|
||||
void Clear();
|
||||
void Zero();
|
||||
|
||||
template<typename T>
|
||||
void Write(T val) {
|
||||
static_assert(std::is_pod<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
|
||||
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
|
||||
Write((const char*)&val, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Read() {
|
||||
static_assert(std::is_pod<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
|
||||
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
|
||||
T temp;
|
||||
Read((uchar*)&temp, sizeof(T));
|
||||
return temp;
|
||||
@@ -102,7 +102,7 @@ namespace EQ
|
||||
read_pos_ += len + 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Write(const char *val, size_t len);
|
||||
void Read(uchar *buf, size_t len);
|
||||
void Read(char *str);
|
||||
@@ -113,7 +113,7 @@ namespace EQ
|
||||
inline size_t GetReadPosition() { return read_pos_; }
|
||||
inline void SetReadPosition(size_t rp) { read_pos_ = rp; }
|
||||
inline void ReadSkipBytes(size_t skip) { read_pos_ += skip; }
|
||||
|
||||
|
||||
private:
|
||||
uchar *buffer_;
|
||||
size_t size_;
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace EQ {
|
||||
|
||||
struct MemoryMappedFile::Implementation {
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
#include "misc.h"
|
||||
#include "types.h"
|
||||
#include <cstring>
|
||||
#include "strings.h"
|
||||
|
||||
std::map<int,std::string> DBFieldNames;
|
||||
|
||||
@@ -150,7 +151,7 @@ static char *temp=nullptr;
|
||||
return false;
|
||||
}
|
||||
ptr++;
|
||||
uint32 id = atoi(field[id_pos].c_str());
|
||||
uint32 id = Strings::ToUnsignedInt(field[id_pos]);
|
||||
items[id]=field;
|
||||
|
||||
for(i=0;i<10;i++) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "misc_functions.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "strings.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
@@ -130,7 +131,7 @@ bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf
|
||||
if (*oIP == 0)
|
||||
return false;
|
||||
if (oPort)
|
||||
*oPort = atoi(sep.arg[1]);
|
||||
*oPort = Strings::ToUnsignedInt(sep.arg[1]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -7,7 +7,7 @@ EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
|
||||
m_server = std::make_unique<EQ::Net::TCPServer>();
|
||||
m_server->Listen(addr, port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
ConsoleServerConnection *c = new ConsoleServerConnection(this, connection);
|
||||
m_connections.insert(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c)));
|
||||
m_connections.emplace(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../event/task.h"
|
||||
#include "../data_verification.h"
|
||||
#include "crc32.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include <zlib.h>
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
@@ -96,7 +97,7 @@ void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int po
|
||||
m_on_new_connection(connection);
|
||||
}
|
||||
|
||||
m_connections.insert(std::make_pair(std::make_pair(addr, port), connection));
|
||||
m_connections.emplace(std::make_pair(std::make_pair(addr, port), connection));
|
||||
}
|
||||
|
||||
void EQ::Net::DaybreakConnectionManager::Process()
|
||||
@@ -233,7 +234,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi
|
||||
if (m_on_new_connection) {
|
||||
m_on_new_connection(connection);
|
||||
}
|
||||
m_connections.insert(std::make_pair(std::make_pair(endpoint, port), connection));
|
||||
m_connections.emplace(std::make_pair(std::make_pair(endpoint, port), connection));
|
||||
connection->ProcessPacket(p);
|
||||
}
|
||||
else if (data[1] != OP_OutOfSession) {
|
||||
@@ -308,6 +309,8 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
|
||||
m_combined[1] = OP_Combined;
|
||||
m_last_session_stats = Clock::now();
|
||||
m_outgoing_budget = owner->m_options.outgoing_data_rate;
|
||||
|
||||
LogNetcode("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
|
||||
}
|
||||
|
||||
//new connection made as client
|
||||
@@ -466,7 +469,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeXOR:
|
||||
if (temp.GetInt8(0) == 0)
|
||||
if (temp.GetInt8(0) == 0)
|
||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Decode(temp, 1, temp.Length() - 1);
|
||||
@@ -524,7 +527,7 @@ void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Pac
|
||||
DynamicPacket *out = new DynamicPacket();
|
||||
out->PutPacket(0, p);
|
||||
|
||||
s->packet_queue.insert(std::make_pair(seq, out));
|
||||
s->packet_queue.emplace(std::make_pair(seq, out));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,6 +633,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
DynamicPacket p;
|
||||
p.PutSerialize(0, reply);
|
||||
InternalSend(p);
|
||||
|
||||
LogNetcode("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -647,6 +652,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
|
||||
m_max_packet_size = reply.max_packet_size;
|
||||
ChangeStatus(StatusConnected);
|
||||
|
||||
LogNetcode(
|
||||
"[OP_SessionResponse] Session [{}] refresh with encode key [{}]",
|
||||
m_connect_code,
|
||||
HostToNetwork(m_encode_key)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -771,6 +782,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
SendDisconnect();
|
||||
}
|
||||
|
||||
LogNetcode(
|
||||
"[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]",
|
||||
m_connect_code,
|
||||
HostToNetwork(m_encode_key)
|
||||
);
|
||||
|
||||
ChangeStatus(StatusDisconnecting);
|
||||
break;
|
||||
}
|
||||
@@ -835,6 +852,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
|
||||
}
|
||||
|
||||
if (p.Length() < (size_t)m_crc_bytes) {
|
||||
LogNetcode("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1078,7 +1096,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
if (m_status == DbProtocolStatus::StatusDisconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto resends = 0;
|
||||
auto now = Clock::now();
|
||||
auto s = &m_streams[stream];
|
||||
@@ -1113,7 +1131,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
|
||||
auto &p = entry.second.packet;
|
||||
if (p.Length() >= DaybreakHeader::size()) {
|
||||
@@ -1406,10 +1424,10 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
sent.first_sent = Clock::now();
|
||||
sent.times_resent = 0;
|
||||
sent.resend_delay = EQ::Clamp(
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
InternalBufferedSend(first_packet);
|
||||
@@ -1441,7 +1459,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
InternalBufferedSend(packet);
|
||||
@@ -1465,7 +1483,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
InternalBufferedSend(packet);
|
||||
|
||||
+10
-1
@@ -22,7 +22,7 @@ void EQ::Net::EQStreamManager::SetOptions(const EQStreamManagerInterfaceOptions
|
||||
void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection)
|
||||
{
|
||||
std::shared_ptr<EQStream> stream(new EQStream(this, connection));
|
||||
m_streams.insert(std::make_pair(connection, stream));
|
||||
m_streams.emplace(std::make_pair(connection, stream));
|
||||
if (m_on_new_connection) {
|
||||
m_on_new_connection(stream);
|
||||
}
|
||||
@@ -65,6 +65,15 @@ EQ::Net::EQStream::~EQStream()
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
|
||||
LogPacketServerClient(
|
||||
"[{}] [{:#06x}] Size [{}] {}",
|
||||
OpcodeManager::EmuToName(p->GetOpcode()),
|
||||
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
|
||||
p->Size(),
|
||||
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
|
||||
);
|
||||
|
||||
if (m_opcode_manager && *m_opcode_manager) {
|
||||
uint16 opcode = 0;
|
||||
if (p->GetOpcodeBypass() != 0) {
|
||||
|
||||
@@ -57,6 +57,10 @@ namespace EQ
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) {
|
||||
m_opcode_manager = opm;
|
||||
}
|
||||
virtual OpcodeManager * GetOpcodeManager() const
|
||||
{
|
||||
return (*m_opcode_manager);
|
||||
};
|
||||
|
||||
virtual Stats GetStats() const;
|
||||
virtual void ResetStats();
|
||||
|
||||
@@ -45,7 +45,7 @@ void EQ::Net::ServertalkClient::SendPacket(ServerPacket *p)
|
||||
|
||||
void EQ::Net::ServertalkClient::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
{
|
||||
m_message_callbacks.insert(std::make_pair(opcode, cb));
|
||||
m_message_callbacks.emplace(std::make_pair(opcode, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
|
||||
@@ -41,7 +41,7 @@ void EQ::Net::ServertalkLegacyClient::SendPacket(ServerPacket *p)
|
||||
|
||||
void EQ::Net::ServertalkLegacyClient::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
{
|
||||
m_message_callbacks.insert(std::make_pair(opcode, cb));
|
||||
m_message_callbacks.emplace(std::make_pair(opcode, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkLegacyClient::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
|
||||
@@ -19,12 +19,12 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
{
|
||||
m_on_ident.insert(std::make_pair(type, cb));
|
||||
m_on_ident.emplace(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
{
|
||||
m_on_disc.insert(std::make_pair(type, cb));
|
||||
m_on_disc.emplace(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
|
||||
@@ -75,7 +75,7 @@ void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection
|
||||
else {
|
||||
std::vector<std::shared_ptr<EQ::Net::ServertalkServerConnection>> vec;
|
||||
vec.push_back(*iter);
|
||||
m_ident_connections.insert(std::make_pair(conn->GetIdentifier(), vec));
|
||||
m_ident_connections.emplace(std::make_pair(conn->GetIdentifier(), vec));
|
||||
}
|
||||
|
||||
m_unident_connections.erase(iter);
|
||||
|
||||
@@ -100,7 +100,7 @@ void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p)
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
{
|
||||
m_message_callbacks.insert(std::make_pair(opcode, cb));
|
||||
m_message_callbacks.emplace(std::make_pair(opcode, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
@@ -135,7 +135,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
auto leg_opcode = *(uint16_t*)&m_buffer[current];
|
||||
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
|
||||
|
||||
//this creates a small edge case where the exact size of a
|
||||
//this creates a small edge case where the exact size of a
|
||||
//packet from the modern protocol can't be "43061256"
|
||||
//so in send we pad it one byte if that's the case
|
||||
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
|
||||
@@ -319,6 +319,16 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
|
||||
if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
|
||||
LogPacketServerToServer(
|
||||
"[{:#06x}] Size [{}] {}",
|
||||
opcode,
|
||||
packet.Length(),
|
||||
(is_detail_enabled ? "\n" + packet.ToString() : "")
|
||||
);
|
||||
}
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
|
||||
@@ -142,7 +142,7 @@ void EQ::Net::TCPConnection::Write(const char *data, size_t count)
|
||||
|
||||
WriteBaton *baton = new WriteBaton;
|
||||
baton->connection = this;
|
||||
baton->buffer = new char[count];;
|
||||
baton->buffer = new char[count];
|
||||
|
||||
uv_write_t *write_req = new uv_write_t;
|
||||
memset(write_req, 0, sizeof(uv_write_t));
|
||||
|
||||
@@ -184,6 +184,9 @@ uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
|
||||
MOpcodes.lock();
|
||||
res = emu_to_eq[emu_op];
|
||||
MOpcodes.unlock();
|
||||
|
||||
LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res);
|
||||
|
||||
#ifdef DEBUG_TRANSLATE
|
||||
fprintf(stderr, "M Translate Emu %s (%d) to EQ 0x%.4x\n", OpcodeNames[emu_op], emu_op, res);
|
||||
#endif
|
||||
|
||||
+20
-24
@@ -32,6 +32,8 @@
|
||||
#include "../inventory_profile.h"
|
||||
#include "rof_structs.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../races.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -75,12 +77,8 @@ namespace RoF
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
if (opcodes == nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
|
||||
//load up the opcode manager.
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
@@ -118,12 +116,7 @@ namespace RoF
|
||||
//we need to go to every stream and replace it's manager.
|
||||
|
||||
if (opcodes != nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
@@ -672,7 +665,7 @@ namespace RoF
|
||||
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_DeleteCharge)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
@@ -1057,7 +1050,7 @@ namespace RoF
|
||||
{
|
||||
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -1076,7 +1069,7 @@ namespace RoF
|
||||
return;
|
||||
}
|
||||
//if(gjs->action == groupActLeave)
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -1106,7 +1099,7 @@ namespace RoF
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
|
||||
if (gu2->membername[i][0] != '\0')
|
||||
{
|
||||
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
|
||||
@@ -1176,7 +1169,7 @@ namespace RoF
|
||||
return;
|
||||
|
||||
}
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
|
||||
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
|
||||
|
||||
@@ -1600,7 +1593,7 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
@@ -1758,7 +1751,7 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToRoFSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToRoFSlot(emu->to_slot);
|
||||
@@ -3838,7 +3831,9 @@ namespace RoF
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)))
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
)
|
||||
{
|
||||
PacketSize += 60;
|
||||
|
||||
@@ -3970,7 +3965,9 @@ namespace RoF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
{
|
||||
@@ -4825,7 +4822,7 @@ namespace RoF
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF::DECODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
@@ -4840,7 +4837,7 @@ namespace RoF
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF::DECODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = RoFToServerSlot(eq->from_slot);
|
||||
emu->to_slot = RoFToServerSlot(eq->to_slot);
|
||||
@@ -5221,7 +5218,6 @@ namespace RoF
|
||||
/**
|
||||
* Ornamentation
|
||||
*/
|
||||
int ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
|
||||
uint32 ornamentation_icon = (inst->GetOrnamentationIcon() ? inst->GetOrnamentationIcon() : 0);
|
||||
uint32 hero_model = 0;
|
||||
|
||||
|
||||
+33
-33
@@ -32,6 +32,9 @@
|
||||
#include "../inventory_profile.h"
|
||||
#include "rof2_structs.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../classes.h"
|
||||
#include "../races.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -76,12 +79,9 @@ namespace RoF2
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
if (opcodes == nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
|
||||
//load up the opcode manager.
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
@@ -122,12 +122,7 @@ namespace RoF2
|
||||
//we need to go to every stream and replace it's manager.
|
||||
|
||||
if (opcodes != nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
@@ -721,7 +716,7 @@ namespace RoF2
|
||||
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_DeleteCharge)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
@@ -1106,7 +1101,7 @@ namespace RoF2
|
||||
{
|
||||
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -1125,7 +1120,7 @@ namespace RoF2
|
||||
return;
|
||||
}
|
||||
//if(gjs->action == groupActLeave)
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -1155,7 +1150,7 @@ namespace RoF2
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
|
||||
if (gu2->membername[i][0] != '\0')
|
||||
{
|
||||
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
|
||||
@@ -1225,7 +1220,7 @@ namespace RoF2
|
||||
return;
|
||||
|
||||
}
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
|
||||
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
|
||||
|
||||
@@ -1649,7 +1644,7 @@ namespace RoF2
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
@@ -1807,7 +1802,7 @@ namespace RoF2
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToRoF2Slot(emu->from_slot);
|
||||
eq->to_slot = ServerToRoF2Slot(emu->to_slot);
|
||||
@@ -3951,7 +3946,7 @@ namespace RoF2
|
||||
if (strlen(emu->suffix))
|
||||
PacketSize += strlen(emu->suffix) + 1;
|
||||
|
||||
if (emu->DestructibleObject || emu->class_ == 62)
|
||||
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
|
||||
{
|
||||
if (emu->DestructibleObject)
|
||||
PacketSize = PacketSize - 4; // No bodytype
|
||||
@@ -3972,7 +3967,9 @@ namespace RoF2
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)))
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
)
|
||||
{
|
||||
PacketSize += 60;
|
||||
|
||||
@@ -4039,17 +4036,19 @@ namespace RoF2
|
||||
// actually part of bitfields
|
||||
uint8 OtherData = 0;
|
||||
|
||||
if (emu->class_ == 62) //LDoN Chest
|
||||
if (emu->class_ == LDON_TREASURE) //LDoN Chest
|
||||
{
|
||||
OtherData = OtherData | 0x04;
|
||||
|
||||
if (strlen(emu->title))
|
||||
}
|
||||
if (strlen(emu->title)) {
|
||||
OtherData = OtherData | 16;
|
||||
|
||||
if (strlen(emu->suffix))
|
||||
}
|
||||
if (strlen(emu->suffix)) {
|
||||
OtherData = OtherData | 32;
|
||||
|
||||
if (emu->DestructibleObject)
|
||||
}
|
||||
if (emu->DestructibleObject) {
|
||||
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
||||
}
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||
// float EmitterScalingRadius
|
||||
@@ -4065,7 +4064,7 @@ namespace RoF2
|
||||
// int DefaultEmitterID
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
|
||||
|
||||
if (emu->DestructibleObject || emu->class_ == 62)
|
||||
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
|
||||
{
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2);
|
||||
@@ -4173,7 +4172,9 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
{
|
||||
@@ -5022,7 +5023,7 @@ namespace RoF2
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF2::DECODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF2::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
@@ -5037,7 +5038,7 @@ namespace RoF2
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "RoF2::DECODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "RoF2::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = RoF2ToServerSlot(eq->from_slot);
|
||||
emu->to_slot = RoF2ToServerSlot(eq->to_slot);
|
||||
@@ -5476,7 +5477,6 @@ namespace RoF2
|
||||
/**
|
||||
* Ornamentation
|
||||
*/
|
||||
int ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
|
||||
uint32 ornamentation_icon = (inst->GetOrnamentationIcon() ? inst->GetOrnamentationIcon() : 0);
|
||||
uint32 hero_model = 0;
|
||||
|
||||
|
||||
@@ -2590,7 +2590,7 @@ struct GroupUpdate_Struct_Live { // New for Live
|
||||
|
||||
struct GroupMembers_Struct { // New for Live
|
||||
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
|
||||
/*0000*/ //char membername[0]; // Member Name Null Terminated
|
||||
/*0000*/ //char member_name[0]; // Member Name Null Terminated
|
||||
/*0000*/ uint8 unknown001[3]; // Seen 0
|
||||
/*0000*/ uint32 memberlevel; // Guess
|
||||
/*0000*/ uint8 unknown002[11]; // Seen 0
|
||||
@@ -2600,7 +2600,7 @@ struct GroupJoin_Struct_Live { // New for Live
|
||||
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
|
||||
/*0004*/ uint32 action;
|
||||
/*0008*/ uint8 unknown0008[5]; // Seen 0
|
||||
/*0013*/ //char membername[0]; // Null Terminated?
|
||||
/*0013*/ //char member_name[0]; // Null Terminated?
|
||||
/*0000*/ uint8 unknown0013[3]; // Seen 0
|
||||
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
|
||||
/*0000*/ uint8 unknown0020[11]; // Seen 0
|
||||
|
||||
@@ -2566,7 +2566,7 @@ struct GroupUpdate_Struct_Live { // New for Live
|
||||
|
||||
struct GroupMembers_Struct { // New for Live
|
||||
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
|
||||
/*0000*/ //char membername[0]; // Member Name Null Terminated
|
||||
/*0000*/ //char member_name[0]; // Member Name Null Terminated
|
||||
/*0000*/ uint8 unknown001[3]; // Seen 0
|
||||
/*0000*/ uint32 memberlevel; // Guess
|
||||
/*0000*/ uint8 unknown002[11]; // Seen 0
|
||||
@@ -2576,7 +2576,7 @@ struct GroupJoin_Struct_Live { // New for Live
|
||||
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
|
||||
/*0004*/ uint32 action;
|
||||
/*0008*/ uint8 unknown0008[5]; // Seen 0
|
||||
/*0013*/ //char membername[0]; // Null Terminated?
|
||||
/*0013*/ //char member_name[0]; // Null Terminated?
|
||||
/*0000*/ uint8 unknown0013[3]; // Seen 0
|
||||
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
|
||||
/*0000*/ uint8 unknown0020[11]; // Seen 0
|
||||
|
||||
+22
-24
@@ -32,6 +32,8 @@
|
||||
#include "../item_instance.h"
|
||||
#include "sod_structs.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../races.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -69,12 +71,7 @@ namespace SoD
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
if (opcodes == nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
//load up the opcode manager.
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
@@ -115,12 +112,7 @@ namespace SoD
|
||||
//we need to go to every stream and replace it's manager.
|
||||
|
||||
if (opcodes != nullptr) {
|
||||
//TODO: get this file name from the config file
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string opfile = Config->PatchDir;
|
||||
opfile += "patch_";
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
@@ -466,7 +458,7 @@ namespace SoD
|
||||
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_DeleteCharge)");
|
||||
Log(Logs::Detail, Logs::Netcode, "SoD::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
@@ -793,7 +785,7 @@ namespace SoD
|
||||
{
|
||||
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -812,7 +804,7 @@ namespace SoD
|
||||
return;
|
||||
}
|
||||
//if(gjs->action == groupActLeave)
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
|
||||
@@ -842,7 +834,7 @@ namespace SoD
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
|
||||
if (gu2->membername[i][0] != '\0')
|
||||
{
|
||||
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
|
||||
@@ -910,7 +902,7 @@ namespace SoD
|
||||
return;
|
||||
}
|
||||
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
|
||||
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
|
||||
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
|
||||
|
||||
@@ -1136,7 +1128,7 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "SoD::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
@@ -1285,7 +1277,7 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "SoD::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToSoDSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToSoDSlot(emu->to_slot);
|
||||
@@ -2475,7 +2467,9 @@ namespace SoD
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)))
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
)
|
||||
{
|
||||
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
|
||||
|
||||
@@ -2672,7 +2666,9 @@ namespace SoD
|
||||
|
||||
Buffer += sizeof(structs::Spawn_Struct_Position);
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
{
|
||||
@@ -2697,7 +2693,9 @@ namespace SoD
|
||||
}
|
||||
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
)
|
||||
{
|
||||
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
|
||||
|
||||
@@ -3228,7 +3226,7 @@ namespace SoD
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::DECODE(OP_LootItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "SoD::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
@@ -3243,7 +3241,7 @@ namespace SoD
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::DECODE(OP_MoveItem)");
|
||||
Log(Logs::Detail, Logs::Netcode, "SoD::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = SoDToServerSlot(eq->from_slot);
|
||||
emu->to_slot = SoDToServerSlot(eq->to_slot);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user