Initial commit
This commit is contained in:
commit
de493310e7
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.vs
|
||||||
|
.vscode
|
||||||
|
build/
|
33
.gitmodules
vendored
Normal file
33
.gitmodules
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
[submodule "deps/GSL"]
|
||||||
|
path = deps/GSL
|
||||||
|
url = https://github.com/Microsoft/GSL.git
|
||||||
|
[submodule "deps/asmjit"]
|
||||||
|
path = deps/asmjit
|
||||||
|
url = https://github.com/asmjit/asmjit
|
||||||
|
[submodule "deps/udis86"]
|
||||||
|
path = deps/udis86
|
||||||
|
url = https://github.com/vmt/udis86.git
|
||||||
|
[submodule "deps/minhook"]
|
||||||
|
path = deps/minhook
|
||||||
|
url = https://github.com/TsudaKageyu/minhook.git
|
||||||
|
[submodule "deps/libtommath"]
|
||||||
|
path = deps/libtommath
|
||||||
|
url = https://github.com/libtom/libtommath.git
|
||||||
|
branch = develop
|
||||||
|
[submodule "deps/libtomcrypt"]
|
||||||
|
path = deps/libtomcrypt
|
||||||
|
url = https://github.com/libtom/libtomcrypt.git
|
||||||
|
branch = develop
|
||||||
|
[submodule "deps/zlib"]
|
||||||
|
path = deps/zlib
|
||||||
|
url = https://github.com/madler/zlib.git
|
||||||
|
branch = develop
|
||||||
|
[submodule "deps/stb"]
|
||||||
|
path = deps/stb
|
||||||
|
url = https://github.com/nothings/stb.git
|
||||||
|
[submodule "deps/zstd"]
|
||||||
|
path = deps/zstd
|
||||||
|
url = https://github.com/facebook/zstd.git
|
||||||
|
[submodule "deps/rapidjson"]
|
||||||
|
path = deps/rapidjson
|
||||||
|
url = https://github.com/Tencent/rapidjson.git
|
1
deps/GSL
vendored
Submodule
1
deps/GSL
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit da01eb28dbb75bed11a51acff0f80ecedd622573
|
1
deps/asmjit
vendored
Submodule
1
deps/asmjit
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit a4cb51b532af0f8137c4182914244c3b05d7745f
|
5946
deps/extra/udis86/libudis86/itab.c
vendored
Normal file
5946
deps/extra/udis86/libudis86/itab.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
939
deps/extra/udis86/libudis86/itab.h
vendored
Normal file
939
deps/extra/udis86/libudis86/itab.h
vendored
Normal file
@ -0,0 +1,939 @@
|
|||||||
|
#ifndef UD_ITAB_H
|
||||||
|
#define UD_ITAB_H
|
||||||
|
|
||||||
|
/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
|
||||||
|
|
||||||
|
/* ud_table_type -- lookup table types (see decode.c) */
|
||||||
|
enum ud_table_type {
|
||||||
|
UD_TAB__OPC_VEX,
|
||||||
|
UD_TAB__OPC_TABLE,
|
||||||
|
UD_TAB__OPC_X87,
|
||||||
|
UD_TAB__OPC_MOD,
|
||||||
|
UD_TAB__OPC_RM,
|
||||||
|
UD_TAB__OPC_OSIZE,
|
||||||
|
UD_TAB__OPC_MODE,
|
||||||
|
UD_TAB__OPC_VEX_L,
|
||||||
|
UD_TAB__OPC_3DNOW,
|
||||||
|
UD_TAB__OPC_REG,
|
||||||
|
UD_TAB__OPC_ASIZE,
|
||||||
|
UD_TAB__OPC_VEX_W,
|
||||||
|
UD_TAB__OPC_SSE,
|
||||||
|
UD_TAB__OPC_VENDOR
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ud_mnemonic -- mnemonic constants */
|
||||||
|
enum ud_mnemonic_code {
|
||||||
|
UD_Iaaa,
|
||||||
|
UD_Iaad,
|
||||||
|
UD_Iaam,
|
||||||
|
UD_Iaas,
|
||||||
|
UD_Iadc,
|
||||||
|
UD_Iadd,
|
||||||
|
UD_Iaddpd,
|
||||||
|
UD_Iaddps,
|
||||||
|
UD_Iaddsd,
|
||||||
|
UD_Iaddss,
|
||||||
|
UD_Iaddsubpd,
|
||||||
|
UD_Iaddsubps,
|
||||||
|
UD_Iaesdec,
|
||||||
|
UD_Iaesdeclast,
|
||||||
|
UD_Iaesenc,
|
||||||
|
UD_Iaesenclast,
|
||||||
|
UD_Iaesimc,
|
||||||
|
UD_Iaeskeygenassist,
|
||||||
|
UD_Iand,
|
||||||
|
UD_Iandnpd,
|
||||||
|
UD_Iandnps,
|
||||||
|
UD_Iandpd,
|
||||||
|
UD_Iandps,
|
||||||
|
UD_Iarpl,
|
||||||
|
UD_Iblendpd,
|
||||||
|
UD_Iblendps,
|
||||||
|
UD_Iblendvpd,
|
||||||
|
UD_Iblendvps,
|
||||||
|
UD_Ibound,
|
||||||
|
UD_Ibsf,
|
||||||
|
UD_Ibsr,
|
||||||
|
UD_Ibswap,
|
||||||
|
UD_Ibt,
|
||||||
|
UD_Ibtc,
|
||||||
|
UD_Ibtr,
|
||||||
|
UD_Ibts,
|
||||||
|
UD_Icall,
|
||||||
|
UD_Icbw,
|
||||||
|
UD_Icdq,
|
||||||
|
UD_Icdqe,
|
||||||
|
UD_Iclc,
|
||||||
|
UD_Icld,
|
||||||
|
UD_Iclflush,
|
||||||
|
UD_Iclgi,
|
||||||
|
UD_Icli,
|
||||||
|
UD_Iclts,
|
||||||
|
UD_Icmc,
|
||||||
|
UD_Icmova,
|
||||||
|
UD_Icmovae,
|
||||||
|
UD_Icmovb,
|
||||||
|
UD_Icmovbe,
|
||||||
|
UD_Icmovg,
|
||||||
|
UD_Icmovge,
|
||||||
|
UD_Icmovl,
|
||||||
|
UD_Icmovle,
|
||||||
|
UD_Icmovno,
|
||||||
|
UD_Icmovnp,
|
||||||
|
UD_Icmovns,
|
||||||
|
UD_Icmovnz,
|
||||||
|
UD_Icmovo,
|
||||||
|
UD_Icmovp,
|
||||||
|
UD_Icmovs,
|
||||||
|
UD_Icmovz,
|
||||||
|
UD_Icmp,
|
||||||
|
UD_Icmppd,
|
||||||
|
UD_Icmpps,
|
||||||
|
UD_Icmpsb,
|
||||||
|
UD_Icmpsd,
|
||||||
|
UD_Icmpsq,
|
||||||
|
UD_Icmpss,
|
||||||
|
UD_Icmpsw,
|
||||||
|
UD_Icmpxchg,
|
||||||
|
UD_Icmpxchg16b,
|
||||||
|
UD_Icmpxchg8b,
|
||||||
|
UD_Icomisd,
|
||||||
|
UD_Icomiss,
|
||||||
|
UD_Icpuid,
|
||||||
|
UD_Icqo,
|
||||||
|
UD_Icrc32,
|
||||||
|
UD_Icvtdq2pd,
|
||||||
|
UD_Icvtdq2ps,
|
||||||
|
UD_Icvtpd2dq,
|
||||||
|
UD_Icvtpd2pi,
|
||||||
|
UD_Icvtpd2ps,
|
||||||
|
UD_Icvtpi2pd,
|
||||||
|
UD_Icvtpi2ps,
|
||||||
|
UD_Icvtps2dq,
|
||||||
|
UD_Icvtps2pd,
|
||||||
|
UD_Icvtps2pi,
|
||||||
|
UD_Icvtsd2si,
|
||||||
|
UD_Icvtsd2ss,
|
||||||
|
UD_Icvtsi2sd,
|
||||||
|
UD_Icvtsi2ss,
|
||||||
|
UD_Icvtss2sd,
|
||||||
|
UD_Icvtss2si,
|
||||||
|
UD_Icvttpd2dq,
|
||||||
|
UD_Icvttpd2pi,
|
||||||
|
UD_Icvttps2dq,
|
||||||
|
UD_Icvttps2pi,
|
||||||
|
UD_Icvttsd2si,
|
||||||
|
UD_Icvttss2si,
|
||||||
|
UD_Icwd,
|
||||||
|
UD_Icwde,
|
||||||
|
UD_Idaa,
|
||||||
|
UD_Idas,
|
||||||
|
UD_Idec,
|
||||||
|
UD_Idiv,
|
||||||
|
UD_Idivpd,
|
||||||
|
UD_Idivps,
|
||||||
|
UD_Idivsd,
|
||||||
|
UD_Idivss,
|
||||||
|
UD_Idppd,
|
||||||
|
UD_Idpps,
|
||||||
|
UD_Iemms,
|
||||||
|
UD_Ienter,
|
||||||
|
UD_Iextractps,
|
||||||
|
UD_If2xm1,
|
||||||
|
UD_Ifabs,
|
||||||
|
UD_Ifadd,
|
||||||
|
UD_Ifaddp,
|
||||||
|
UD_Ifbld,
|
||||||
|
UD_Ifbstp,
|
||||||
|
UD_Ifchs,
|
||||||
|
UD_Ifclex,
|
||||||
|
UD_Ifcmovb,
|
||||||
|
UD_Ifcmovbe,
|
||||||
|
UD_Ifcmove,
|
||||||
|
UD_Ifcmovnb,
|
||||||
|
UD_Ifcmovnbe,
|
||||||
|
UD_Ifcmovne,
|
||||||
|
UD_Ifcmovnu,
|
||||||
|
UD_Ifcmovu,
|
||||||
|
UD_Ifcom,
|
||||||
|
UD_Ifcom2,
|
||||||
|
UD_Ifcomi,
|
||||||
|
UD_Ifcomip,
|
||||||
|
UD_Ifcomp,
|
||||||
|
UD_Ifcomp3,
|
||||||
|
UD_Ifcomp5,
|
||||||
|
UD_Ifcompp,
|
||||||
|
UD_Ifcos,
|
||||||
|
UD_Ifdecstp,
|
||||||
|
UD_Ifdiv,
|
||||||
|
UD_Ifdivp,
|
||||||
|
UD_Ifdivr,
|
||||||
|
UD_Ifdivrp,
|
||||||
|
UD_Ifemms,
|
||||||
|
UD_Iffree,
|
||||||
|
UD_Iffreep,
|
||||||
|
UD_Ifiadd,
|
||||||
|
UD_Ificom,
|
||||||
|
UD_Ificomp,
|
||||||
|
UD_Ifidiv,
|
||||||
|
UD_Ifidivr,
|
||||||
|
UD_Ifild,
|
||||||
|
UD_Ifimul,
|
||||||
|
UD_Ifincstp,
|
||||||
|
UD_Ifist,
|
||||||
|
UD_Ifistp,
|
||||||
|
UD_Ifisttp,
|
||||||
|
UD_Ifisub,
|
||||||
|
UD_Ifisubr,
|
||||||
|
UD_Ifld,
|
||||||
|
UD_Ifld1,
|
||||||
|
UD_Ifldcw,
|
||||||
|
UD_Ifldenv,
|
||||||
|
UD_Ifldl2e,
|
||||||
|
UD_Ifldl2t,
|
||||||
|
UD_Ifldlg2,
|
||||||
|
UD_Ifldln2,
|
||||||
|
UD_Ifldpi,
|
||||||
|
UD_Ifldz,
|
||||||
|
UD_Ifmul,
|
||||||
|
UD_Ifmulp,
|
||||||
|
UD_Ifndisi,
|
||||||
|
UD_Ifneni,
|
||||||
|
UD_Ifninit,
|
||||||
|
UD_Ifnop,
|
||||||
|
UD_Ifnsave,
|
||||||
|
UD_Ifnsetpm,
|
||||||
|
UD_Ifnstcw,
|
||||||
|
UD_Ifnstenv,
|
||||||
|
UD_Ifnstsw,
|
||||||
|
UD_Ifpatan,
|
||||||
|
UD_Ifprem,
|
||||||
|
UD_Ifprem1,
|
||||||
|
UD_Ifptan,
|
||||||
|
UD_Ifrndint,
|
||||||
|
UD_Ifrstor,
|
||||||
|
UD_Ifrstpm,
|
||||||
|
UD_Ifscale,
|
||||||
|
UD_Ifsin,
|
||||||
|
UD_Ifsincos,
|
||||||
|
UD_Ifsqrt,
|
||||||
|
UD_Ifst,
|
||||||
|
UD_Ifstp,
|
||||||
|
UD_Ifstp1,
|
||||||
|
UD_Ifstp8,
|
||||||
|
UD_Ifstp9,
|
||||||
|
UD_Ifsub,
|
||||||
|
UD_Ifsubp,
|
||||||
|
UD_Ifsubr,
|
||||||
|
UD_Ifsubrp,
|
||||||
|
UD_Iftst,
|
||||||
|
UD_Ifucom,
|
||||||
|
UD_Ifucomi,
|
||||||
|
UD_Ifucomip,
|
||||||
|
UD_Ifucomp,
|
||||||
|
UD_Ifucompp,
|
||||||
|
UD_Ifxam,
|
||||||
|
UD_Ifxch,
|
||||||
|
UD_Ifxch4,
|
||||||
|
UD_Ifxch7,
|
||||||
|
UD_Ifxrstor,
|
||||||
|
UD_Ifxsave,
|
||||||
|
UD_Ifxtract,
|
||||||
|
UD_Ifyl2x,
|
||||||
|
UD_Ifyl2xp1,
|
||||||
|
UD_Igetsec,
|
||||||
|
UD_Ihaddpd,
|
||||||
|
UD_Ihaddps,
|
||||||
|
UD_Ihlt,
|
||||||
|
UD_Ihsubpd,
|
||||||
|
UD_Ihsubps,
|
||||||
|
UD_Iidiv,
|
||||||
|
UD_Iimul,
|
||||||
|
UD_Iin,
|
||||||
|
UD_Iinc,
|
||||||
|
UD_Iinsb,
|
||||||
|
UD_Iinsd,
|
||||||
|
UD_Iinsertps,
|
||||||
|
UD_Iinsw,
|
||||||
|
UD_Iint,
|
||||||
|
UD_Iint1,
|
||||||
|
UD_Iint3,
|
||||||
|
UD_Iinto,
|
||||||
|
UD_Iinvd,
|
||||||
|
UD_Iinvept,
|
||||||
|
UD_Iinvlpg,
|
||||||
|
UD_Iinvlpga,
|
||||||
|
UD_Iinvvpid,
|
||||||
|
UD_Iiretd,
|
||||||
|
UD_Iiretq,
|
||||||
|
UD_Iiretw,
|
||||||
|
UD_Ija,
|
||||||
|
UD_Ijae,
|
||||||
|
UD_Ijb,
|
||||||
|
UD_Ijbe,
|
||||||
|
UD_Ijcxz,
|
||||||
|
UD_Ijecxz,
|
||||||
|
UD_Ijg,
|
||||||
|
UD_Ijge,
|
||||||
|
UD_Ijl,
|
||||||
|
UD_Ijle,
|
||||||
|
UD_Ijmp,
|
||||||
|
UD_Ijno,
|
||||||
|
UD_Ijnp,
|
||||||
|
UD_Ijns,
|
||||||
|
UD_Ijnz,
|
||||||
|
UD_Ijo,
|
||||||
|
UD_Ijp,
|
||||||
|
UD_Ijrcxz,
|
||||||
|
UD_Ijs,
|
||||||
|
UD_Ijz,
|
||||||
|
UD_Ilahf,
|
||||||
|
UD_Ilar,
|
||||||
|
UD_Ilddqu,
|
||||||
|
UD_Ildmxcsr,
|
||||||
|
UD_Ilds,
|
||||||
|
UD_Ilea,
|
||||||
|
UD_Ileave,
|
||||||
|
UD_Iles,
|
||||||
|
UD_Ilfence,
|
||||||
|
UD_Ilfs,
|
||||||
|
UD_Ilgdt,
|
||||||
|
UD_Ilgs,
|
||||||
|
UD_Ilidt,
|
||||||
|
UD_Illdt,
|
||||||
|
UD_Ilmsw,
|
||||||
|
UD_Ilock,
|
||||||
|
UD_Ilodsb,
|
||||||
|
UD_Ilodsd,
|
||||||
|
UD_Ilodsq,
|
||||||
|
UD_Ilodsw,
|
||||||
|
UD_Iloop,
|
||||||
|
UD_Iloope,
|
||||||
|
UD_Iloopne,
|
||||||
|
UD_Ilsl,
|
||||||
|
UD_Ilss,
|
||||||
|
UD_Iltr,
|
||||||
|
UD_Imaskmovdqu,
|
||||||
|
UD_Imaskmovq,
|
||||||
|
UD_Imaxpd,
|
||||||
|
UD_Imaxps,
|
||||||
|
UD_Imaxsd,
|
||||||
|
UD_Imaxss,
|
||||||
|
UD_Imfence,
|
||||||
|
UD_Iminpd,
|
||||||
|
UD_Iminps,
|
||||||
|
UD_Iminsd,
|
||||||
|
UD_Iminss,
|
||||||
|
UD_Imonitor,
|
||||||
|
UD_Imontmul,
|
||||||
|
UD_Imov,
|
||||||
|
UD_Imovapd,
|
||||||
|
UD_Imovaps,
|
||||||
|
UD_Imovbe,
|
||||||
|
UD_Imovd,
|
||||||
|
UD_Imovddup,
|
||||||
|
UD_Imovdq2q,
|
||||||
|
UD_Imovdqa,
|
||||||
|
UD_Imovdqu,
|
||||||
|
UD_Imovhlps,
|
||||||
|
UD_Imovhpd,
|
||||||
|
UD_Imovhps,
|
||||||
|
UD_Imovlhps,
|
||||||
|
UD_Imovlpd,
|
||||||
|
UD_Imovlps,
|
||||||
|
UD_Imovmskpd,
|
||||||
|
UD_Imovmskps,
|
||||||
|
UD_Imovntdq,
|
||||||
|
UD_Imovntdqa,
|
||||||
|
UD_Imovnti,
|
||||||
|
UD_Imovntpd,
|
||||||
|
UD_Imovntps,
|
||||||
|
UD_Imovntq,
|
||||||
|
UD_Imovq,
|
||||||
|
UD_Imovq2dq,
|
||||||
|
UD_Imovsb,
|
||||||
|
UD_Imovsd,
|
||||||
|
UD_Imovshdup,
|
||||||
|
UD_Imovsldup,
|
||||||
|
UD_Imovsq,
|
||||||
|
UD_Imovss,
|
||||||
|
UD_Imovsw,
|
||||||
|
UD_Imovsx,
|
||||||
|
UD_Imovsxd,
|
||||||
|
UD_Imovupd,
|
||||||
|
UD_Imovups,
|
||||||
|
UD_Imovzx,
|
||||||
|
UD_Impsadbw,
|
||||||
|
UD_Imul,
|
||||||
|
UD_Imulpd,
|
||||||
|
UD_Imulps,
|
||||||
|
UD_Imulsd,
|
||||||
|
UD_Imulss,
|
||||||
|
UD_Imwait,
|
||||||
|
UD_Ineg,
|
||||||
|
UD_Inop,
|
||||||
|
UD_Inot,
|
||||||
|
UD_Ior,
|
||||||
|
UD_Iorpd,
|
||||||
|
UD_Iorps,
|
||||||
|
UD_Iout,
|
||||||
|
UD_Ioutsb,
|
||||||
|
UD_Ioutsd,
|
||||||
|
UD_Ioutsw,
|
||||||
|
UD_Ipabsb,
|
||||||
|
UD_Ipabsd,
|
||||||
|
UD_Ipabsw,
|
||||||
|
UD_Ipackssdw,
|
||||||
|
UD_Ipacksswb,
|
||||||
|
UD_Ipackusdw,
|
||||||
|
UD_Ipackuswb,
|
||||||
|
UD_Ipaddb,
|
||||||
|
UD_Ipaddd,
|
||||||
|
UD_Ipaddq,
|
||||||
|
UD_Ipaddsb,
|
||||||
|
UD_Ipaddsw,
|
||||||
|
UD_Ipaddusb,
|
||||||
|
UD_Ipaddusw,
|
||||||
|
UD_Ipaddw,
|
||||||
|
UD_Ipalignr,
|
||||||
|
UD_Ipand,
|
||||||
|
UD_Ipandn,
|
||||||
|
UD_Ipavgb,
|
||||||
|
UD_Ipavgusb,
|
||||||
|
UD_Ipavgw,
|
||||||
|
UD_Ipblendvb,
|
||||||
|
UD_Ipblendw,
|
||||||
|
UD_Ipclmulqdq,
|
||||||
|
UD_Ipcmpeqb,
|
||||||
|
UD_Ipcmpeqd,
|
||||||
|
UD_Ipcmpeqq,
|
||||||
|
UD_Ipcmpeqw,
|
||||||
|
UD_Ipcmpestri,
|
||||||
|
UD_Ipcmpestrm,
|
||||||
|
UD_Ipcmpgtb,
|
||||||
|
UD_Ipcmpgtd,
|
||||||
|
UD_Ipcmpgtq,
|
||||||
|
UD_Ipcmpgtw,
|
||||||
|
UD_Ipcmpistri,
|
||||||
|
UD_Ipcmpistrm,
|
||||||
|
UD_Ipextrb,
|
||||||
|
UD_Ipextrd,
|
||||||
|
UD_Ipextrq,
|
||||||
|
UD_Ipextrw,
|
||||||
|
UD_Ipf2id,
|
||||||
|
UD_Ipf2iw,
|
||||||
|
UD_Ipfacc,
|
||||||
|
UD_Ipfadd,
|
||||||
|
UD_Ipfcmpeq,
|
||||||
|
UD_Ipfcmpge,
|
||||||
|
UD_Ipfcmpgt,
|
||||||
|
UD_Ipfmax,
|
||||||
|
UD_Ipfmin,
|
||||||
|
UD_Ipfmul,
|
||||||
|
UD_Ipfnacc,
|
||||||
|
UD_Ipfpnacc,
|
||||||
|
UD_Ipfrcp,
|
||||||
|
UD_Ipfrcpit1,
|
||||||
|
UD_Ipfrcpit2,
|
||||||
|
UD_Ipfrsqit1,
|
||||||
|
UD_Ipfrsqrt,
|
||||||
|
UD_Ipfsub,
|
||||||
|
UD_Ipfsubr,
|
||||||
|
UD_Iphaddd,
|
||||||
|
UD_Iphaddsw,
|
||||||
|
UD_Iphaddw,
|
||||||
|
UD_Iphminposuw,
|
||||||
|
UD_Iphsubd,
|
||||||
|
UD_Iphsubsw,
|
||||||
|
UD_Iphsubw,
|
||||||
|
UD_Ipi2fd,
|
||||||
|
UD_Ipi2fw,
|
||||||
|
UD_Ipinsrb,
|
||||||
|
UD_Ipinsrd,
|
||||||
|
UD_Ipinsrq,
|
||||||
|
UD_Ipinsrw,
|
||||||
|
UD_Ipmaddubsw,
|
||||||
|
UD_Ipmaddwd,
|
||||||
|
UD_Ipmaxsb,
|
||||||
|
UD_Ipmaxsd,
|
||||||
|
UD_Ipmaxsw,
|
||||||
|
UD_Ipmaxub,
|
||||||
|
UD_Ipmaxud,
|
||||||
|
UD_Ipmaxuw,
|
||||||
|
UD_Ipminsb,
|
||||||
|
UD_Ipminsd,
|
||||||
|
UD_Ipminsw,
|
||||||
|
UD_Ipminub,
|
||||||
|
UD_Ipminud,
|
||||||
|
UD_Ipminuw,
|
||||||
|
UD_Ipmovmskb,
|
||||||
|
UD_Ipmovsxbd,
|
||||||
|
UD_Ipmovsxbq,
|
||||||
|
UD_Ipmovsxbw,
|
||||||
|
UD_Ipmovsxdq,
|
||||||
|
UD_Ipmovsxwd,
|
||||||
|
UD_Ipmovsxwq,
|
||||||
|
UD_Ipmovzxbd,
|
||||||
|
UD_Ipmovzxbq,
|
||||||
|
UD_Ipmovzxbw,
|
||||||
|
UD_Ipmovzxdq,
|
||||||
|
UD_Ipmovzxwd,
|
||||||
|
UD_Ipmovzxwq,
|
||||||
|
UD_Ipmuldq,
|
||||||
|
UD_Ipmulhrsw,
|
||||||
|
UD_Ipmulhrw,
|
||||||
|
UD_Ipmulhuw,
|
||||||
|
UD_Ipmulhw,
|
||||||
|
UD_Ipmulld,
|
||||||
|
UD_Ipmullw,
|
||||||
|
UD_Ipmuludq,
|
||||||
|
UD_Ipop,
|
||||||
|
UD_Ipopa,
|
||||||
|
UD_Ipopad,
|
||||||
|
UD_Ipopcnt,
|
||||||
|
UD_Ipopfd,
|
||||||
|
UD_Ipopfq,
|
||||||
|
UD_Ipopfw,
|
||||||
|
UD_Ipor,
|
||||||
|
UD_Iprefetch,
|
||||||
|
UD_Iprefetchnta,
|
||||||
|
UD_Iprefetcht0,
|
||||||
|
UD_Iprefetcht1,
|
||||||
|
UD_Iprefetcht2,
|
||||||
|
UD_Ipsadbw,
|
||||||
|
UD_Ipshufb,
|
||||||
|
UD_Ipshufd,
|
||||||
|
UD_Ipshufhw,
|
||||||
|
UD_Ipshuflw,
|
||||||
|
UD_Ipshufw,
|
||||||
|
UD_Ipsignb,
|
||||||
|
UD_Ipsignd,
|
||||||
|
UD_Ipsignw,
|
||||||
|
UD_Ipslld,
|
||||||
|
UD_Ipslldq,
|
||||||
|
UD_Ipsllq,
|
||||||
|
UD_Ipsllw,
|
||||||
|
UD_Ipsrad,
|
||||||
|
UD_Ipsraw,
|
||||||
|
UD_Ipsrld,
|
||||||
|
UD_Ipsrldq,
|
||||||
|
UD_Ipsrlq,
|
||||||
|
UD_Ipsrlw,
|
||||||
|
UD_Ipsubb,
|
||||||
|
UD_Ipsubd,
|
||||||
|
UD_Ipsubq,
|
||||||
|
UD_Ipsubsb,
|
||||||
|
UD_Ipsubsw,
|
||||||
|
UD_Ipsubusb,
|
||||||
|
UD_Ipsubusw,
|
||||||
|
UD_Ipsubw,
|
||||||
|
UD_Ipswapd,
|
||||||
|
UD_Iptest,
|
||||||
|
UD_Ipunpckhbw,
|
||||||
|
UD_Ipunpckhdq,
|
||||||
|
UD_Ipunpckhqdq,
|
||||||
|
UD_Ipunpckhwd,
|
||||||
|
UD_Ipunpcklbw,
|
||||||
|
UD_Ipunpckldq,
|
||||||
|
UD_Ipunpcklqdq,
|
||||||
|
UD_Ipunpcklwd,
|
||||||
|
UD_Ipush,
|
||||||
|
UD_Ipusha,
|
||||||
|
UD_Ipushad,
|
||||||
|
UD_Ipushfd,
|
||||||
|
UD_Ipushfq,
|
||||||
|
UD_Ipushfw,
|
||||||
|
UD_Ipxor,
|
||||||
|
UD_Ircl,
|
||||||
|
UD_Ircpps,
|
||||||
|
UD_Ircpss,
|
||||||
|
UD_Ircr,
|
||||||
|
UD_Irdmsr,
|
||||||
|
UD_Irdpmc,
|
||||||
|
UD_Irdrand,
|
||||||
|
UD_Irdtsc,
|
||||||
|
UD_Irdtscp,
|
||||||
|
UD_Irep,
|
||||||
|
UD_Irepne,
|
||||||
|
UD_Iret,
|
||||||
|
UD_Iretf,
|
||||||
|
UD_Irol,
|
||||||
|
UD_Iror,
|
||||||
|
UD_Iroundpd,
|
||||||
|
UD_Iroundps,
|
||||||
|
UD_Iroundsd,
|
||||||
|
UD_Iroundss,
|
||||||
|
UD_Irsm,
|
||||||
|
UD_Irsqrtps,
|
||||||
|
UD_Irsqrtss,
|
||||||
|
UD_Isahf,
|
||||||
|
UD_Isalc,
|
||||||
|
UD_Isar,
|
||||||
|
UD_Isbb,
|
||||||
|
UD_Iscasb,
|
||||||
|
UD_Iscasd,
|
||||||
|
UD_Iscasq,
|
||||||
|
UD_Iscasw,
|
||||||
|
UD_Iseta,
|
||||||
|
UD_Isetae,
|
||||||
|
UD_Isetb,
|
||||||
|
UD_Isetbe,
|
||||||
|
UD_Isetg,
|
||||||
|
UD_Isetge,
|
||||||
|
UD_Isetl,
|
||||||
|
UD_Isetle,
|
||||||
|
UD_Isetno,
|
||||||
|
UD_Isetnp,
|
||||||
|
UD_Isetns,
|
||||||
|
UD_Isetnz,
|
||||||
|
UD_Iseto,
|
||||||
|
UD_Isetp,
|
||||||
|
UD_Isets,
|
||||||
|
UD_Isetz,
|
||||||
|
UD_Isfence,
|
||||||
|
UD_Isgdt,
|
||||||
|
UD_Ishl,
|
||||||
|
UD_Ishld,
|
||||||
|
UD_Ishr,
|
||||||
|
UD_Ishrd,
|
||||||
|
UD_Ishufpd,
|
||||||
|
UD_Ishufps,
|
||||||
|
UD_Isidt,
|
||||||
|
UD_Iskinit,
|
||||||
|
UD_Isldt,
|
||||||
|
UD_Ismsw,
|
||||||
|
UD_Isqrtpd,
|
||||||
|
UD_Isqrtps,
|
||||||
|
UD_Isqrtsd,
|
||||||
|
UD_Isqrtss,
|
||||||
|
UD_Istc,
|
||||||
|
UD_Istd,
|
||||||
|
UD_Istgi,
|
||||||
|
UD_Isti,
|
||||||
|
UD_Istmxcsr,
|
||||||
|
UD_Istosb,
|
||||||
|
UD_Istosd,
|
||||||
|
UD_Istosq,
|
||||||
|
UD_Istosw,
|
||||||
|
UD_Istr,
|
||||||
|
UD_Isub,
|
||||||
|
UD_Isubpd,
|
||||||
|
UD_Isubps,
|
||||||
|
UD_Isubsd,
|
||||||
|
UD_Isubss,
|
||||||
|
UD_Iswapgs,
|
||||||
|
UD_Isyscall,
|
||||||
|
UD_Isysenter,
|
||||||
|
UD_Isysexit,
|
||||||
|
UD_Isysret,
|
||||||
|
UD_Itest,
|
||||||
|
UD_Iucomisd,
|
||||||
|
UD_Iucomiss,
|
||||||
|
UD_Iud2,
|
||||||
|
UD_Iunpckhpd,
|
||||||
|
UD_Iunpckhps,
|
||||||
|
UD_Iunpcklpd,
|
||||||
|
UD_Iunpcklps,
|
||||||
|
UD_Ivaddpd,
|
||||||
|
UD_Ivaddps,
|
||||||
|
UD_Ivaddsd,
|
||||||
|
UD_Ivaddss,
|
||||||
|
UD_Ivaddsubpd,
|
||||||
|
UD_Ivaddsubps,
|
||||||
|
UD_Ivaesdec,
|
||||||
|
UD_Ivaesdeclast,
|
||||||
|
UD_Ivaesenc,
|
||||||
|
UD_Ivaesenclast,
|
||||||
|
UD_Ivaesimc,
|
||||||
|
UD_Ivaeskeygenassist,
|
||||||
|
UD_Ivandnpd,
|
||||||
|
UD_Ivandnps,
|
||||||
|
UD_Ivandpd,
|
||||||
|
UD_Ivandps,
|
||||||
|
UD_Ivblendpd,
|
||||||
|
UD_Ivblendps,
|
||||||
|
UD_Ivblendvpd,
|
||||||
|
UD_Ivblendvps,
|
||||||
|
UD_Ivbroadcastsd,
|
||||||
|
UD_Ivbroadcastss,
|
||||||
|
UD_Ivcmppd,
|
||||||
|
UD_Ivcmpps,
|
||||||
|
UD_Ivcmpsd,
|
||||||
|
UD_Ivcmpss,
|
||||||
|
UD_Ivcomisd,
|
||||||
|
UD_Ivcomiss,
|
||||||
|
UD_Ivcvtdq2pd,
|
||||||
|
UD_Ivcvtdq2ps,
|
||||||
|
UD_Ivcvtpd2dq,
|
||||||
|
UD_Ivcvtpd2ps,
|
||||||
|
UD_Ivcvtps2dq,
|
||||||
|
UD_Ivcvtps2pd,
|
||||||
|
UD_Ivcvtsd2si,
|
||||||
|
UD_Ivcvtsd2ss,
|
||||||
|
UD_Ivcvtsi2sd,
|
||||||
|
UD_Ivcvtsi2ss,
|
||||||
|
UD_Ivcvtss2sd,
|
||||||
|
UD_Ivcvtss2si,
|
||||||
|
UD_Ivcvttpd2dq,
|
||||||
|
UD_Ivcvttps2dq,
|
||||||
|
UD_Ivcvttsd2si,
|
||||||
|
UD_Ivcvttss2si,
|
||||||
|
UD_Ivdivpd,
|
||||||
|
UD_Ivdivps,
|
||||||
|
UD_Ivdivsd,
|
||||||
|
UD_Ivdivss,
|
||||||
|
UD_Ivdppd,
|
||||||
|
UD_Ivdpps,
|
||||||
|
UD_Iverr,
|
||||||
|
UD_Iverw,
|
||||||
|
UD_Ivextractf128,
|
||||||
|
UD_Ivextractps,
|
||||||
|
UD_Ivhaddpd,
|
||||||
|
UD_Ivhaddps,
|
||||||
|
UD_Ivhsubpd,
|
||||||
|
UD_Ivhsubps,
|
||||||
|
UD_Ivinsertf128,
|
||||||
|
UD_Ivinsertps,
|
||||||
|
UD_Ivlddqu,
|
||||||
|
UD_Ivmaskmovdqu,
|
||||||
|
UD_Ivmaskmovpd,
|
||||||
|
UD_Ivmaskmovps,
|
||||||
|
UD_Ivmaxpd,
|
||||||
|
UD_Ivmaxps,
|
||||||
|
UD_Ivmaxsd,
|
||||||
|
UD_Ivmaxss,
|
||||||
|
UD_Ivmcall,
|
||||||
|
UD_Ivmclear,
|
||||||
|
UD_Ivminpd,
|
||||||
|
UD_Ivminps,
|
||||||
|
UD_Ivminsd,
|
||||||
|
UD_Ivminss,
|
||||||
|
UD_Ivmlaunch,
|
||||||
|
UD_Ivmload,
|
||||||
|
UD_Ivmmcall,
|
||||||
|
UD_Ivmovapd,
|
||||||
|
UD_Ivmovaps,
|
||||||
|
UD_Ivmovd,
|
||||||
|
UD_Ivmovddup,
|
||||||
|
UD_Ivmovdqa,
|
||||||
|
UD_Ivmovdqu,
|
||||||
|
UD_Ivmovhlps,
|
||||||
|
UD_Ivmovhpd,
|
||||||
|
UD_Ivmovhps,
|
||||||
|
UD_Ivmovlhps,
|
||||||
|
UD_Ivmovlpd,
|
||||||
|
UD_Ivmovlps,
|
||||||
|
UD_Ivmovmskpd,
|
||||||
|
UD_Ivmovmskps,
|
||||||
|
UD_Ivmovntdq,
|
||||||
|
UD_Ivmovntdqa,
|
||||||
|
UD_Ivmovntpd,
|
||||||
|
UD_Ivmovntps,
|
||||||
|
UD_Ivmovq,
|
||||||
|
UD_Ivmovsd,
|
||||||
|
UD_Ivmovshdup,
|
||||||
|
UD_Ivmovsldup,
|
||||||
|
UD_Ivmovss,
|
||||||
|
UD_Ivmovupd,
|
||||||
|
UD_Ivmovups,
|
||||||
|
UD_Ivmpsadbw,
|
||||||
|
UD_Ivmptrld,
|
||||||
|
UD_Ivmptrst,
|
||||||
|
UD_Ivmread,
|
||||||
|
UD_Ivmresume,
|
||||||
|
UD_Ivmrun,
|
||||||
|
UD_Ivmsave,
|
||||||
|
UD_Ivmulpd,
|
||||||
|
UD_Ivmulps,
|
||||||
|
UD_Ivmulsd,
|
||||||
|
UD_Ivmulss,
|
||||||
|
UD_Ivmwrite,
|
||||||
|
UD_Ivmxoff,
|
||||||
|
UD_Ivmxon,
|
||||||
|
UD_Ivorpd,
|
||||||
|
UD_Ivorps,
|
||||||
|
UD_Ivpabsb,
|
||||||
|
UD_Ivpabsd,
|
||||||
|
UD_Ivpabsw,
|
||||||
|
UD_Ivpackssdw,
|
||||||
|
UD_Ivpacksswb,
|
||||||
|
UD_Ivpackusdw,
|
||||||
|
UD_Ivpackuswb,
|
||||||
|
UD_Ivpaddb,
|
||||||
|
UD_Ivpaddd,
|
||||||
|
UD_Ivpaddq,
|
||||||
|
UD_Ivpaddsb,
|
||||||
|
UD_Ivpaddsw,
|
||||||
|
UD_Ivpaddusb,
|
||||||
|
UD_Ivpaddusw,
|
||||||
|
UD_Ivpaddw,
|
||||||
|
UD_Ivpalignr,
|
||||||
|
UD_Ivpand,
|
||||||
|
UD_Ivpandn,
|
||||||
|
UD_Ivpavgb,
|
||||||
|
UD_Ivpavgw,
|
||||||
|
UD_Ivpblendvb,
|
||||||
|
UD_Ivpblendw,
|
||||||
|
UD_Ivpclmulqdq,
|
||||||
|
UD_Ivpcmpeqb,
|
||||||
|
UD_Ivpcmpeqd,
|
||||||
|
UD_Ivpcmpeqq,
|
||||||
|
UD_Ivpcmpeqw,
|
||||||
|
UD_Ivpcmpestri,
|
||||||
|
UD_Ivpcmpestrm,
|
||||||
|
UD_Ivpcmpgtb,
|
||||||
|
UD_Ivpcmpgtd,
|
||||||
|
UD_Ivpcmpgtq,
|
||||||
|
UD_Ivpcmpgtw,
|
||||||
|
UD_Ivpcmpistri,
|
||||||
|
UD_Ivpcmpistrm,
|
||||||
|
UD_Ivperm2f128,
|
||||||
|
UD_Ivpermilpd,
|
||||||
|
UD_Ivpermilps,
|
||||||
|
UD_Ivpextrb,
|
||||||
|
UD_Ivpextrd,
|
||||||
|
UD_Ivpextrq,
|
||||||
|
UD_Ivpextrw,
|
||||||
|
UD_Ivphaddd,
|
||||||
|
UD_Ivphaddsw,
|
||||||
|
UD_Ivphaddw,
|
||||||
|
UD_Ivphminposuw,
|
||||||
|
UD_Ivphsubd,
|
||||||
|
UD_Ivphsubsw,
|
||||||
|
UD_Ivphsubw,
|
||||||
|
UD_Ivpinsrb,
|
||||||
|
UD_Ivpinsrd,
|
||||||
|
UD_Ivpinsrq,
|
||||||
|
UD_Ivpinsrw,
|
||||||
|
UD_Ivpmaddubsw,
|
||||||
|
UD_Ivpmaddwd,
|
||||||
|
UD_Ivpmaxsb,
|
||||||
|
UD_Ivpmaxsd,
|
||||||
|
UD_Ivpmaxsw,
|
||||||
|
UD_Ivpmaxub,
|
||||||
|
UD_Ivpmaxud,
|
||||||
|
UD_Ivpmaxuw,
|
||||||
|
UD_Ivpminsb,
|
||||||
|
UD_Ivpminsd,
|
||||||
|
UD_Ivpminsw,
|
||||||
|
UD_Ivpminub,
|
||||||
|
UD_Ivpminud,
|
||||||
|
UD_Ivpminuw,
|
||||||
|
UD_Ivpmovmskb,
|
||||||
|
UD_Ivpmovsxbd,
|
||||||
|
UD_Ivpmovsxbq,
|
||||||
|
UD_Ivpmovsxbw,
|
||||||
|
UD_Ivpmovsxwd,
|
||||||
|
UD_Ivpmovsxwq,
|
||||||
|
UD_Ivpmovzxbd,
|
||||||
|
UD_Ivpmovzxbq,
|
||||||
|
UD_Ivpmovzxbw,
|
||||||
|
UD_Ivpmovzxdq,
|
||||||
|
UD_Ivpmovzxwd,
|
||||||
|
UD_Ivpmovzxwq,
|
||||||
|
UD_Ivpmuldq,
|
||||||
|
UD_Ivpmulhrsw,
|
||||||
|
UD_Ivpmulhuw,
|
||||||
|
UD_Ivpmulhw,
|
||||||
|
UD_Ivpmulld,
|
||||||
|
UD_Ivpmullw,
|
||||||
|
UD_Ivpor,
|
||||||
|
UD_Ivpsadbw,
|
||||||
|
UD_Ivpshufb,
|
||||||
|
UD_Ivpshufd,
|
||||||
|
UD_Ivpshufhw,
|
||||||
|
UD_Ivpshuflw,
|
||||||
|
UD_Ivpsignb,
|
||||||
|
UD_Ivpsignd,
|
||||||
|
UD_Ivpsignw,
|
||||||
|
UD_Ivpslld,
|
||||||
|
UD_Ivpslldq,
|
||||||
|
UD_Ivpsllq,
|
||||||
|
UD_Ivpsllw,
|
||||||
|
UD_Ivpsrad,
|
||||||
|
UD_Ivpsraw,
|
||||||
|
UD_Ivpsrld,
|
||||||
|
UD_Ivpsrldq,
|
||||||
|
UD_Ivpsrlq,
|
||||||
|
UD_Ivpsrlw,
|
||||||
|
UD_Ivpsubb,
|
||||||
|
UD_Ivpsubd,
|
||||||
|
UD_Ivpsubq,
|
||||||
|
UD_Ivpsubsb,
|
||||||
|
UD_Ivpsubsw,
|
||||||
|
UD_Ivpsubusb,
|
||||||
|
UD_Ivpsubusw,
|
||||||
|
UD_Ivpsubw,
|
||||||
|
UD_Ivptest,
|
||||||
|
UD_Ivpunpckhbw,
|
||||||
|
UD_Ivpunpckhdq,
|
||||||
|
UD_Ivpunpckhqdq,
|
||||||
|
UD_Ivpunpckhwd,
|
||||||
|
UD_Ivpunpcklbw,
|
||||||
|
UD_Ivpunpckldq,
|
||||||
|
UD_Ivpunpcklqdq,
|
||||||
|
UD_Ivpunpcklwd,
|
||||||
|
UD_Ivpxor,
|
||||||
|
UD_Ivrcpps,
|
||||||
|
UD_Ivrcpss,
|
||||||
|
UD_Ivroundpd,
|
||||||
|
UD_Ivroundps,
|
||||||
|
UD_Ivroundsd,
|
||||||
|
UD_Ivroundss,
|
||||||
|
UD_Ivrsqrtps,
|
||||||
|
UD_Ivrsqrtss,
|
||||||
|
UD_Ivshufpd,
|
||||||
|
UD_Ivshufps,
|
||||||
|
UD_Ivsqrtpd,
|
||||||
|
UD_Ivsqrtps,
|
||||||
|
UD_Ivsqrtsd,
|
||||||
|
UD_Ivsqrtss,
|
||||||
|
UD_Ivstmxcsr,
|
||||||
|
UD_Ivsubpd,
|
||||||
|
UD_Ivsubps,
|
||||||
|
UD_Ivsubsd,
|
||||||
|
UD_Ivsubss,
|
||||||
|
UD_Ivtestpd,
|
||||||
|
UD_Ivtestps,
|
||||||
|
UD_Ivucomisd,
|
||||||
|
UD_Ivucomiss,
|
||||||
|
UD_Ivunpckhpd,
|
||||||
|
UD_Ivunpckhps,
|
||||||
|
UD_Ivunpcklpd,
|
||||||
|
UD_Ivunpcklps,
|
||||||
|
UD_Ivxorpd,
|
||||||
|
UD_Ivxorps,
|
||||||
|
UD_Ivzeroall,
|
||||||
|
UD_Ivzeroupper,
|
||||||
|
UD_Iwait,
|
||||||
|
UD_Iwbinvd,
|
||||||
|
UD_Iwrmsr,
|
||||||
|
UD_Ixadd,
|
||||||
|
UD_Ixchg,
|
||||||
|
UD_Ixcryptcbc,
|
||||||
|
UD_Ixcryptcfb,
|
||||||
|
UD_Ixcryptctr,
|
||||||
|
UD_Ixcryptecb,
|
||||||
|
UD_Ixcryptofb,
|
||||||
|
UD_Ixgetbv,
|
||||||
|
UD_Ixlatb,
|
||||||
|
UD_Ixor,
|
||||||
|
UD_Ixorpd,
|
||||||
|
UD_Ixorps,
|
||||||
|
UD_Ixrstor,
|
||||||
|
UD_Ixsave,
|
||||||
|
UD_Ixsetbv,
|
||||||
|
UD_Ixsha1,
|
||||||
|
UD_Ixsha256,
|
||||||
|
UD_Ixstore,
|
||||||
|
UD_Iinvalid,
|
||||||
|
UD_I3dnow,
|
||||||
|
UD_Inone,
|
||||||
|
UD_Idb,
|
||||||
|
UD_Ipause,
|
||||||
|
UD_MAX_MNEMONIC_CODE
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char * ud_mnemonics_str[];
|
||||||
|
|
||||||
|
#endif /* UD_ITAB_H */
|
1
deps/libtomcrypt
vendored
Submodule
1
deps/libtomcrypt
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 06a81aeb227424182125363f7554fad5146d6d2a
|
1
deps/libtommath
vendored
Submodule
1
deps/libtommath
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4b47368501321c795d5b54d87a5bab35a21a7940
|
1
deps/minhook
vendored
Submodule
1
deps/minhook
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4a455528f61b5a375b1f9d44e7d296d47f18bb18
|
34
deps/premake/asmjit.lua
vendored
Normal file
34
deps/premake/asmjit.lua
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
asmjit = {
|
||||||
|
source = path.join(dependencies.basePath, "asmjit"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function asmjit.import()
|
||||||
|
links { "asmjit" }
|
||||||
|
asmjit.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function asmjit.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(asmjit.source, "src")
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"ASMJIT_STATIC"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function asmjit.project()
|
||||||
|
project "asmjit"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
asmjit.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(asmjit.source, "src/**.cpp"),
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, asmjit)
|
19
deps/premake/gsl.lua
vendored
Normal file
19
deps/premake/gsl.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
gsl = {
|
||||||
|
source = path.join(dependencies.basePath, "GSL"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function gsl.import()
|
||||||
|
gsl.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function gsl.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(gsl.source, "include")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function gsl.project()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, gsl)
|
61
deps/premake/libtomcrypt.lua
vendored
Normal file
61
deps/premake/libtomcrypt.lua
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
libtomcrypt = {
|
||||||
|
source = path.join(dependencies.basePath, "libtomcrypt"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function libtomcrypt.import()
|
||||||
|
links {
|
||||||
|
"libtomcrypt"
|
||||||
|
}
|
||||||
|
|
||||||
|
libtomcrypt.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function libtomcrypt.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(libtomcrypt.source, "src/headers")
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"LTC_NO_FAST",
|
||||||
|
"LTC_NO_PROTOTYPES",
|
||||||
|
"LTC_NO_RSA_BLINDING",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function libtomcrypt.project()
|
||||||
|
project "libtomcrypt"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
libtomcrypt.includes()
|
||||||
|
libtommath.import()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(libtomcrypt.source, "src/**.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
removefiles {
|
||||||
|
path.join(libtomcrypt.source, "src/**/*tab.c"),
|
||||||
|
path.join(libtomcrypt.source, "src/encauth/ocb3/**.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_CRT_SECURE_NO_WARNINGS",
|
||||||
|
"LTC_SOURCE",
|
||||||
|
"_LIB",
|
||||||
|
"USE_LTM"
|
||||||
|
}
|
||||||
|
|
||||||
|
removedefines {
|
||||||
|
"_DLL",
|
||||||
|
"_USRDLL"
|
||||||
|
}
|
||||||
|
|
||||||
|
linkoptions {
|
||||||
|
"-IGNORE:4221"
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, libtomcrypt)
|
52
deps/premake/libtommath.lua
vendored
Normal file
52
deps/premake/libtommath.lua
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
libtommath = {
|
||||||
|
source = path.join(dependencies.basePath, "libtommath"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function libtommath.import()
|
||||||
|
links {
|
||||||
|
"libtommath"
|
||||||
|
}
|
||||||
|
|
||||||
|
libtommath.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function libtommath.includes()
|
||||||
|
includedirs {
|
||||||
|
libtommath.source
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"LTM_DESC",
|
||||||
|
"__STDC_IEC_559__",
|
||||||
|
"MP_NO_DEV_URANDOM",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function libtommath.project()
|
||||||
|
project "libtommath"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
libtommath.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(libtommath.source, "*.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_LIB"
|
||||||
|
}
|
||||||
|
|
||||||
|
removedefines {
|
||||||
|
"_DLL",
|
||||||
|
"_USRDLL"
|
||||||
|
}
|
||||||
|
|
||||||
|
linkoptions {
|
||||||
|
"-IGNORE:4221"
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, libtommath)
|
31
deps/premake/minhook.lua
vendored
Normal file
31
deps/premake/minhook.lua
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
minhook = {
|
||||||
|
source = path.join(dependencies.basePath, "minhook"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function minhook.import()
|
||||||
|
links { "minhook" }
|
||||||
|
minhook.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function minhook.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(minhook.source, "include")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function minhook.project()
|
||||||
|
project "minhook"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
minhook.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(minhook.source, "src/**.h"),
|
||||||
|
path.join(minhook.source, "src/**.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, minhook)
|
43
deps/premake/minizip.lua
vendored
Normal file
43
deps/premake/minizip.lua
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
minizip = {
|
||||||
|
source = path.join(dependencies.basePath, "zlib/contrib/minizip"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function minizip.import()
|
||||||
|
links { "minizip" }
|
||||||
|
zlib.import()
|
||||||
|
minizip.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function minizip.includes()
|
||||||
|
includedirs {
|
||||||
|
minizip.source
|
||||||
|
}
|
||||||
|
|
||||||
|
zlib.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function minizip.project()
|
||||||
|
project "minizip"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
minizip.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(minizip.source, "*.h"),
|
||||||
|
path.join(minizip.source, "*.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
removefiles {
|
||||||
|
path.join(minizip.source, "miniunz.c"),
|
||||||
|
path.join(minizip.source, "minizip.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_CRT_SECURE_NO_DEPRECATE",
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, minizip)
|
19
deps/premake/rapidjson.lua
vendored
Normal file
19
deps/premake/rapidjson.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
rapidjson = {
|
||||||
|
source = path.join(dependencies.basePath, "rapidjson"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function rapidjson.import()
|
||||||
|
rapidjson.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function rapidjson.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(rapidjson.source, "include"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function rapidjson.project()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, rapidjson)
|
19
deps/premake/stb.lua
vendored
Normal file
19
deps/premake/stb.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
stb = {
|
||||||
|
source = path.join(dependencies.basePath, "stb"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function stb.import()
|
||||||
|
stb.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function stb.includes()
|
||||||
|
includedirs {
|
||||||
|
stb.source
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function stb.project()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, stb)
|
37
deps/premake/udis86.lua
vendored
Normal file
37
deps/premake/udis86.lua
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
udis86 = {
|
||||||
|
source = path.join(dependencies.basePath, "udis86"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function udis86.import()
|
||||||
|
links {
|
||||||
|
"udis86"
|
||||||
|
}
|
||||||
|
|
||||||
|
udis86.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function udis86.includes()
|
||||||
|
includedirs {
|
||||||
|
udis86.source,
|
||||||
|
path.join(udis86.source, "libudis86"),
|
||||||
|
path.join(dependencies.basePath, "extra/udis86"),
|
||||||
|
path.join(dependencies.basePath, "extra/udis86/libudis86"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function udis86.project()
|
||||||
|
project "udis86"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
udis86.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(udis86.source, "libudis86/*.c"),
|
||||||
|
path.join(dependencies.basePath, "extra/udis86/libudis86/*.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, udis86)
|
39
deps/premake/zlib.lua
vendored
Normal file
39
deps/premake/zlib.lua
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
zlib = {
|
||||||
|
source = path.join(dependencies.basePath, "zlib"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function zlib.import()
|
||||||
|
links { "zlib" }
|
||||||
|
zlib.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function zlib.includes()
|
||||||
|
includedirs {
|
||||||
|
zlib.source
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"ZLIB_CONST",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function zlib.project()
|
||||||
|
project "zlib"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
zlib.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(zlib.source, "*.h"),
|
||||||
|
path.join(zlib.source, "*.c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_CRT_SECURE_NO_DEPRECATE",
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, zlib)
|
1
deps/rapidjson
vendored
Submodule
1
deps/rapidjson
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 2b2c80450031028439ba2a17a09ef5aa10f2159b
|
1
deps/stb
vendored
Submodule
1
deps/stb
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit af1a5bc352164740c1cc1354942b1c6b72eacb8a
|
1
deps/udis86
vendored
Submodule
1
deps/udis86
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 56ff6c87c11de0ffa725b14339004820556e343d
|
1
deps/zlib
vendored
Submodule
1
deps/zlib
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit ec3df00224d4b396e2ac6586ab5d25f673caa4c2
|
1
deps/zstd
vendored
Submodule
1
deps/zstd
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit f349d18776001f39791323e59ef2395983c1cd2e
|
3
generate.bat
Normal file
3
generate.bat
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
git submodule update --init --recursive
|
||||||
|
tools\premake5 %* vs2022
|
369
premake5.lua
Normal file
369
premake5.lua
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
gitVersioningCommand = "git describe --tags --dirty --always"
|
||||||
|
gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD"
|
||||||
|
|
||||||
|
-- Quote the given string input as a C string
|
||||||
|
function cstrquote(value)
|
||||||
|
if value == nil then
|
||||||
|
return "\"\""
|
||||||
|
end
|
||||||
|
result = value:gsub("\\", "\\\\")
|
||||||
|
result = result:gsub("\"", "\\\"")
|
||||||
|
result = result:gsub("\n", "\\n")
|
||||||
|
result = result:gsub("\t", "\\t")
|
||||||
|
result = result:gsub("\r", "\\r")
|
||||||
|
result = result:gsub("\a", "\\a")
|
||||||
|
result = result:gsub("\b", "\\b")
|
||||||
|
result = "\"" .. result .. "\""
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Converts tags in "vX.X.X" format and given revision number Y to an array of numbers {X,X,X,Y}.
|
||||||
|
-- In the case where the format does not work fall back to padding with zeroes and just ending with the revision number.
|
||||||
|
-- partscount can be either 3 or 4.
|
||||||
|
function vertonumarr(value, vernumber, partscount)
|
||||||
|
vernum = {}
|
||||||
|
for num in string.gmatch(value or "", "%d+") do
|
||||||
|
if #vernum < 3 then
|
||||||
|
table.insert(vernum, tonumber(num))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
while #vernum < 3 do
|
||||||
|
table.insert(vernum, 0)
|
||||||
|
end
|
||||||
|
if #vernum < partscount then
|
||||||
|
table.insert(vernum, tonumber(vernumber))
|
||||||
|
end
|
||||||
|
return vernum
|
||||||
|
end
|
||||||
|
|
||||||
|
dependencies = {
|
||||||
|
basePath = "./deps"
|
||||||
|
}
|
||||||
|
|
||||||
|
function dependencies.load()
|
||||||
|
dir = path.join(dependencies.basePath, "premake/*.lua")
|
||||||
|
deps = os.matchfiles(dir)
|
||||||
|
|
||||||
|
for i, dep in pairs(deps) do
|
||||||
|
dep = dep:gsub(".lua", "")
|
||||||
|
require(dep)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dependencies.imports()
|
||||||
|
for i, proj in pairs(dependencies) do
|
||||||
|
if type(i) == 'number' then
|
||||||
|
proj.import()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dependencies.projects()
|
||||||
|
for i, proj in pairs(dependencies) do
|
||||||
|
if type(i) == 'number' then
|
||||||
|
proj.project()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "copy-to",
|
||||||
|
description = "Optional, copy the EXE to a custom folder after build, define the path here if wanted.",
|
||||||
|
value = "PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "dev-build",
|
||||||
|
description = "Enable development builds of the client."
|
||||||
|
}
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "inject-host-as-lib",
|
||||||
|
description = "Decide whether to load the game as lib or to inject it"
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "version",
|
||||||
|
description = "Returns the version string for the current commit of the source code.",
|
||||||
|
onWorkspace = function(wks)
|
||||||
|
-- get current version via git
|
||||||
|
local proc = assert(io.popen(gitVersioningCommand, "r"))
|
||||||
|
local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
proc:close()
|
||||||
|
local version = gitDescribeOutput
|
||||||
|
|
||||||
|
proc = assert(io.popen(gitCurrentBranchCommand, "r"))
|
||||||
|
local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
local gitCurrentBranchSuccess = proc:close()
|
||||||
|
if gitCurrentBranchSuccess then
|
||||||
|
-- We got a branch name, check if it is a feature branch
|
||||||
|
if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then
|
||||||
|
version = version .. "-" .. gitCurrentBranchOutput
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print(version)
|
||||||
|
os.exit(0)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "generate-buildinfo",
|
||||||
|
description = "Sets up build information file like version.h.",
|
||||||
|
onWorkspace = function(wks)
|
||||||
|
-- get old version number from version.hpp if any
|
||||||
|
local oldVersion = "(none)"
|
||||||
|
local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r")
|
||||||
|
if oldVersionHeader ~= nil then
|
||||||
|
local oldVersionHeaderContent = assert(oldVersionHeader:read('*l'))
|
||||||
|
while oldVersionHeaderContent do
|
||||||
|
m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$")
|
||||||
|
if m ~= nil then
|
||||||
|
oldVersion = m
|
||||||
|
end
|
||||||
|
|
||||||
|
oldVersionHeaderContent = oldVersionHeader:read('*l')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- get current version via git
|
||||||
|
local proc = assert(io.popen(gitVersioningCommand, "r"))
|
||||||
|
local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
proc:close()
|
||||||
|
|
||||||
|
-- generate version.hpp with a revision number if not equal
|
||||||
|
gitDescribeOutputQuoted = cstrquote(gitDescribeOutput)
|
||||||
|
if oldVersion ~= gitDescribeOutputQuoted then
|
||||||
|
-- get current git hash and write to version.txt (used by the preliminary updater)
|
||||||
|
-- TODO - remove once proper updater and release versioning exists
|
||||||
|
local proc = assert(io.popen("git rev-parse HEAD", "r"))
|
||||||
|
local gitCommitHash = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
proc:close()
|
||||||
|
|
||||||
|
-- get whether this is a clean revision (no uncommitted changes)
|
||||||
|
proc = assert(io.popen("git status --porcelain", "r"))
|
||||||
|
local revDirty = (assert(proc:read('*a')) ~= "")
|
||||||
|
if revDirty then revDirty = 1 else revDirty = 0 end
|
||||||
|
proc:close()
|
||||||
|
|
||||||
|
-- get current tag name
|
||||||
|
proc = assert(io.popen("git describe --tags --abbrev=0"))
|
||||||
|
local tagName = proc:read('*l')
|
||||||
|
|
||||||
|
-- get current branch name
|
||||||
|
proc = assert(io.popen("git branch --show-current"))
|
||||||
|
local branchName = proc:read('*l')
|
||||||
|
|
||||||
|
-- branch for ci
|
||||||
|
if branchName == nil or branchName == '' then
|
||||||
|
proc = assert(io.popen("git show -s --pretty=%d HEAD"))
|
||||||
|
local branchInfo = proc:read('*l')
|
||||||
|
m = string.match(branchInfo, ".+,.+, ([^)]+)")
|
||||||
|
if m ~= nil then
|
||||||
|
branchName = m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if branchName == nil then
|
||||||
|
branchName = "develop"
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Detected branch: " .. branchName)
|
||||||
|
|
||||||
|
-- get revision number via git
|
||||||
|
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
||||||
|
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
|
||||||
|
print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted)
|
||||||
|
|
||||||
|
-- write to version.txt for preliminary updater
|
||||||
|
-- NOTE - remove this once we have a proper updater and proper release versioning
|
||||||
|
local versionFile = assert(io.open(wks.location .. "/version.txt", "w"))
|
||||||
|
versionFile:write(gitCommitHash)
|
||||||
|
versionFile:close()
|
||||||
|
|
||||||
|
-- write version header
|
||||||
|
local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w"))
|
||||||
|
versionHeader:write("/*\n")
|
||||||
|
versionHeader:write(" * Automatically generated by premake5.\n")
|
||||||
|
versionHeader:write(" * Do not touch!\n")
|
||||||
|
versionHeader:write(" */\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n")
|
||||||
|
versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n")
|
||||||
|
versionHeader:write("#define GIT_HASH " .. cstrquote(gitCommitHash) .. "\n")
|
||||||
|
versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n")
|
||||||
|
versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("// Version transformed for RC files\n")
|
||||||
|
versionHeader:write("#define VERSION_PRODUCT_RC " .. table.concat(vertonumarr(tagName, revNumber, 3), ",") .. "\n")
|
||||||
|
versionHeader:write("#define VERSION_PRODUCT " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 3), ".")) .. "\n")
|
||||||
|
versionHeader:write("#define VERSION_FILE_RC " .. table.concat(vertonumarr(tagName, revNumber, 4), ",") .. "\n")
|
||||||
|
versionHeader:write("#define VERSION_FILE " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 4), ".")) .. "\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("// Alias definitions\n")
|
||||||
|
versionHeader:write("#define VERSION GIT_DESCRIBE\n")
|
||||||
|
versionHeader:write("#define SHORTVERSION VERSION_PRODUCT\n")
|
||||||
|
versionHeader:close()
|
||||||
|
local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
|
||||||
|
versionHeader:write("/*\n")
|
||||||
|
versionHeader:write(" * Automatically generated by premake5.\n")
|
||||||
|
versionHeader:write(" * Do not touch!\n")
|
||||||
|
versionHeader:write(" *\n")
|
||||||
|
versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n")
|
||||||
|
versionHeader:write(" *\n")
|
||||||
|
versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n")
|
||||||
|
versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n")
|
||||||
|
versionHeader:write(" */\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("#include \".\\version.h\"\n")
|
||||||
|
versionHeader:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies.load()
|
||||||
|
|
||||||
|
workspace "iw7-mod"
|
||||||
|
startproject "client"
|
||||||
|
location "./build"
|
||||||
|
objdir "%{wks.location}/obj"
|
||||||
|
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
|
||||||
|
|
||||||
|
configurations {"Debug", "Release"}
|
||||||
|
|
||||||
|
language "C++"
|
||||||
|
cppdialect "C++20"
|
||||||
|
|
||||||
|
architecture "x86_64"
|
||||||
|
platforms "x64"
|
||||||
|
|
||||||
|
systemversion "latest"
|
||||||
|
symbols "On"
|
||||||
|
staticruntime "On"
|
||||||
|
editandcontinue "Off"
|
||||||
|
warnings "Extra"
|
||||||
|
characterset "ASCII"
|
||||||
|
|
||||||
|
if _OPTIONS["dev-build"] then
|
||||||
|
defines {"DEV_BUILD"}
|
||||||
|
end
|
||||||
|
|
||||||
|
if os.getenv("CI") then
|
||||||
|
defines {"CI"}
|
||||||
|
end
|
||||||
|
|
||||||
|
flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"}
|
||||||
|
|
||||||
|
filter "platforms:x64"
|
||||||
|
defines {"_WINDOWS", "WIN32"}
|
||||||
|
filter {}
|
||||||
|
|
||||||
|
filter "configurations:Release"
|
||||||
|
optimize "Size"
|
||||||
|
buildoptions {"/GL"}
|
||||||
|
linkoptions { "/IGNORE:4702", "/LTCG" }
|
||||||
|
defines {"NDEBUG"}
|
||||||
|
flags {"FatalCompileWarnings"}
|
||||||
|
filter {}
|
||||||
|
|
||||||
|
filter "configurations:Debug"
|
||||||
|
optimize "Debug"
|
||||||
|
buildoptions {"/bigobj"}
|
||||||
|
defines {"DEBUG", "_DEBUG"}
|
||||||
|
filter {}
|
||||||
|
|
||||||
|
project "common"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {"./src/common/**.hpp", "./src/common/**.cpp"}
|
||||||
|
|
||||||
|
includedirs {"./src/common", "%{prj.location}/src"}
|
||||||
|
|
||||||
|
resincludedirs {"$(ProjectDir)src"}
|
||||||
|
|
||||||
|
dependencies.imports()
|
||||||
|
|
||||||
|
project "runner"
|
||||||
|
kind "WindowedApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"}
|
||||||
|
|
||||||
|
includedirs {"./src/runner", "./src/common", "%{prj.location}/src"}
|
||||||
|
|
||||||
|
resincludedirs {"$(ProjectDir)src"}
|
||||||
|
|
||||||
|
links {"common"}
|
||||||
|
|
||||||
|
dependencies.imports()
|
||||||
|
|
||||||
|
project "client"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
targetname "iw7-mod"
|
||||||
|
|
||||||
|
pchheader "std_include.hpp"
|
||||||
|
pchsource "src/client/std_include.cpp"
|
||||||
|
|
||||||
|
if _OPTIONS["no-inject-host-as-lib"] then
|
||||||
|
linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"}
|
||||||
|
else
|
||||||
|
defines {"INJECT_HOST_AS_LIB"}
|
||||||
|
linkoptions {"/IGNORE:4254", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/PDBCompress"}
|
||||||
|
end
|
||||||
|
|
||||||
|
files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"}
|
||||||
|
|
||||||
|
includedirs {"./src/client", "./src/common", "%{prj.location}/src"}
|
||||||
|
|
||||||
|
resincludedirs {"$(ProjectDir)src"}
|
||||||
|
|
||||||
|
dependson {"tlsdll", "runner"}
|
||||||
|
|
||||||
|
links {"common"}
|
||||||
|
|
||||||
|
prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"}
|
||||||
|
|
||||||
|
if _OPTIONS["copy-to"] then
|
||||||
|
postbuildcommands {"copy /y \"$(TargetPath)\" \"" .. _OPTIONS["copy-to"] .. "\""}
|
||||||
|
end
|
||||||
|
|
||||||
|
if _OPTIONS["debug-dir"] then
|
||||||
|
debugdir ( _OPTIONS["debug-dir"] )
|
||||||
|
end
|
||||||
|
|
||||||
|
dependencies.imports()
|
||||||
|
|
||||||
|
project "tlsdll"
|
||||||
|
kind "SharedLib"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"}
|
||||||
|
|
||||||
|
includedirs {"./src/tlsdll", "%{prj.location}/src"}
|
||||||
|
|
||||||
|
links {"common"}
|
||||||
|
|
||||||
|
resincludedirs {"$(ProjectDir)src"}
|
||||||
|
|
||||||
|
project "runner"
|
||||||
|
kind "WindowedApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"}
|
||||||
|
|
||||||
|
includedirs {"./src/runner", "./src/common", "%{prj.location}/src"}
|
||||||
|
|
||||||
|
links {"common"}
|
||||||
|
|
||||||
|
resincludedirs {"$(ProjectDir)src"}
|
||||||
|
|
||||||
|
links {"common"}
|
||||||
|
|
||||||
|
dependencies.imports()
|
||||||
|
|
||||||
|
group "Dependencies"
|
||||||
|
dependencies.projects()
|
169
src/client/component/arxan.cpp
Normal file
169
src/client/component/arxan.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
//#include "scheduler.hpp"
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
namespace arxan
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::hook::detour nt_close_hook;
|
||||||
|
utils::hook::detour nt_query_information_process_hook;
|
||||||
|
|
||||||
|
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
|
||||||
|
const PVOID info,
|
||||||
|
const ULONG info_length, const PULONG ret_length)
|
||||||
|
{
|
||||||
|
auto* orig = static_cast<decltype(NtQueryInformationProcess)*>(nt_query_information_process_hook.
|
||||||
|
get_original());
|
||||||
|
const auto status = orig(handle, info_class, info, info_length, ret_length);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
{
|
||||||
|
if (info_class == ProcessBasicInformation)
|
||||||
|
{
|
||||||
|
static DWORD explorer_pid = 0;
|
||||||
|
if (!explorer_pid)
|
||||||
|
{
|
||||||
|
auto* const shell_window = GetShellWindow();
|
||||||
|
GetWindowThreadProcessId(shell_window, &explorer_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_cast<PPROCESS_BASIC_INFORMATION>(info)->Reserved3 = PVOID(DWORD64(explorer_pid));
|
||||||
|
}
|
||||||
|
else if (info_class == 30) // ProcessDebugObjectHandle
|
||||||
|
{
|
||||||
|
*static_cast<HANDLE*>(info) = nullptr;
|
||||||
|
|
||||||
|
return 0xC0000353;
|
||||||
|
}
|
||||||
|
else if (info_class == 7) // ProcessDebugPort
|
||||||
|
{
|
||||||
|
*static_cast<HANDLE*>(info) = nullptr;
|
||||||
|
}
|
||||||
|
else if (info_class == 31)
|
||||||
|
{
|
||||||
|
*static_cast<ULONG*>(info) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS NTAPI nt_close_stub(const HANDLE handle)
|
||||||
|
{
|
||||||
|
char info[16];
|
||||||
|
if (NtQueryObject(handle, OBJECT_INFORMATION_CLASS(4), &info, 2, nullptr) >= 0 && size_t(handle) != 0x12345)
|
||||||
|
{
|
||||||
|
auto* orig = static_cast<decltype(NtClose)*>(nt_close_hook.get_original());
|
||||||
|
return orig(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info)
|
||||||
|
{
|
||||||
|
if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hide_being_debugged()
|
||||||
|
{
|
||||||
|
auto* const peb = PPEB(__readgsqword(0x60));
|
||||||
|
peb->BeingDebugged = false;
|
||||||
|
*reinterpret_cast<PDWORD>(LPSTR(peb) + 0xBC) &= ~0x70;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_hardware_breakpoints()
|
||||||
|
{
|
||||||
|
CONTEXT context;
|
||||||
|
ZeroMemory(&context, sizeof(context));
|
||||||
|
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||||
|
|
||||||
|
auto* const thread = GetCurrentThread();
|
||||||
|
GetThreadContext(thread, &context);
|
||||||
|
|
||||||
|
context.Dr0 = 0;
|
||||||
|
context.Dr1 = 0;
|
||||||
|
context.Dr2 = 0;
|
||||||
|
context.Dr3 = 0;
|
||||||
|
context.Dr6 = 0;
|
||||||
|
context.Dr7 = 0;
|
||||||
|
|
||||||
|
SetThreadContext(thread, &context);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI set_thread_context_stub(const HANDLE thread, CONTEXT* context)
|
||||||
|
{
|
||||||
|
return SetThreadContext(thread, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour doexit_hook;
|
||||||
|
void doexit_stub()
|
||||||
|
{
|
||||||
|
MessageBoxA(0, "doexit", "", 0);
|
||||||
|
return doexit_hook.invoke<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour integrity_check1_hook;
|
||||||
|
__int64 integrity_check1_stub_hook(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
|
||||||
|
{
|
||||||
|
__int64 result;
|
||||||
|
doexit_hook.disable();
|
||||||
|
integrity_check1_hook.disable();
|
||||||
|
|
||||||
|
printf("[ arxan ]: integrity check 1 bypassing...\n");
|
||||||
|
result = integrity_check1_hook.invoke<__int64>(a1, a2, a3, a4, a5);
|
||||||
|
printf("[ arxan ]: integrity check 1 passed!\n");
|
||||||
|
|
||||||
|
doexit_hook.enable();
|
||||||
|
integrity_check1_hook.enable();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* load_import(const std::string& library, const std::string& function) override
|
||||||
|
{
|
||||||
|
if (function == "SetThreadContext")
|
||||||
|
{
|
||||||
|
//return set_thread_context_stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
hide_being_debugged();
|
||||||
|
//scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
|
||||||
|
|
||||||
|
const utils::nt::library ntdll("ntdll.dll");
|
||||||
|
nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub);
|
||||||
|
nt_query_information_process_hook.create(ntdll.get_proc<void*>("NtQueryInformationProcess"),
|
||||||
|
nt_query_information_process_stub);
|
||||||
|
// https://www.geoffchappell.com/studies/windows/win32/ntdll/api/index.htm
|
||||||
|
AddVectoredExceptionHandler(1, exception_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
doexit_hook.create(0x12D7348_b, doexit_stub);
|
||||||
|
|
||||||
|
integrity_check1_hook.create(0xC6D8B0_b, integrity_check1_stub_hook); // SV_SpawnServer
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(arxan::component)
|
106
src/client/component/auth.cpp
Normal file
106
src/client/component/auth.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "auth.hpp"
|
||||||
|
//#include "command.hpp"
|
||||||
|
//#include "network.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/smbios.hpp>
|
||||||
|
#include <utils/info_string.hpp>
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "steam/steam.hpp"
|
||||||
|
|
||||||
|
namespace auth
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string get_hdd_serial()
|
||||||
|
{
|
||||||
|
DWORD serial{};
|
||||||
|
if (!GetVolumeInformationA("C:\\", nullptr, 0, &serial, nullptr, nullptr, nullptr, 0))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::string::va("%08X", serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_hw_profile_guid()
|
||||||
|
{
|
||||||
|
HW_PROFILE_INFO info;
|
||||||
|
if (!GetCurrentHwProfileA(&info))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string{info.szHwProfileGuid, sizeof(info.szHwProfileGuid)};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_protected_data()
|
||||||
|
{
|
||||||
|
std::string input = "X-Labs-H1Mod-Auth";
|
||||||
|
|
||||||
|
DATA_BLOB data_in{}, data_out{};
|
||||||
|
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
|
||||||
|
data_in.cbData = static_cast<DWORD>(input.size());
|
||||||
|
if (CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto size = std::min(data_out.cbData, 52ul);
|
||||||
|
std::string result{reinterpret_cast<char*>(data_out.pbData), size};
|
||||||
|
LocalFree(data_out.pbData);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_key_entropy()
|
||||||
|
{
|
||||||
|
std::string entropy{};
|
||||||
|
entropy.append(utils::smbios::get_uuid());
|
||||||
|
entropy.append(get_hw_profile_guid());
|
||||||
|
entropy.append(get_protected_data());
|
||||||
|
entropy.append(get_hdd_serial());
|
||||||
|
|
||||||
|
if (entropy.empty())
|
||||||
|
{
|
||||||
|
entropy.resize(32);
|
||||||
|
utils::cryptography::random::get_data(entropy.data(), entropy.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return entropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::cryptography::ecc::key& get_key()
|
||||||
|
{
|
||||||
|
static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t get_guid()
|
||||||
|
{
|
||||||
|
if (game::environment::is_dedi())
|
||||||
|
{
|
||||||
|
return 0x110000100000000 | (::utils::cryptography::random::get_integer() & ~0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_key().get_hash();
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(auth::component)
|
6
src/client/component/auth.hpp
Normal file
6
src/client/component/auth.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace auth
|
||||||
|
{
|
||||||
|
uint64_t get_guid();
|
||||||
|
}
|
89
src/client/component/console.cpp
Normal file
89
src/client/component/console.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
//#include "command.hpp"
|
||||||
|
|
||||||
|
namespace game_console
|
||||||
|
{
|
||||||
|
void print(int type, const std::string& data);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace console
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static bool ingame = false;
|
||||||
|
static bool exit = false;
|
||||||
|
|
||||||
|
DWORD WINAPI console(LPVOID)
|
||||||
|
{
|
||||||
|
ShowWindow(GetConsoleWindow(), SW_SHOW);
|
||||||
|
SetConsoleTitle("IW7-Mod");
|
||||||
|
|
||||||
|
std::string cmd;
|
||||||
|
exit = false;
|
||||||
|
|
||||||
|
while (!exit)
|
||||||
|
{
|
||||||
|
std::getline(std::cin, cmd);
|
||||||
|
if (ingame)
|
||||||
|
{
|
||||||
|
game::Cbuf_AddText(0, cmd.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string format(va_list* ap, const char* message)
|
||||||
|
{
|
||||||
|
static thread_local char buffer[0x1000];
|
||||||
|
|
||||||
|
const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap);
|
||||||
|
|
||||||
|
if (count < 0) return {};
|
||||||
|
return { buffer, static_cast<size_t>(count) };
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatch_message(const int type, const std::string& message)
|
||||||
|
{
|
||||||
|
printf("%s\n", message.data());
|
||||||
|
|
||||||
|
//game_console::print(type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(const int type, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
const auto result = format(&ap, fmt);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
dispatch_message(type, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_start() override
|
||||||
|
{
|
||||||
|
CreateThread(0, 0, console, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
ingame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_destroy() override
|
||||||
|
{
|
||||||
|
ingame = false;
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(console::component)
|
44
src/client/component/console.hpp
Normal file
44
src/client/component/console.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace console
|
||||||
|
{
|
||||||
|
HWND get_window();
|
||||||
|
void set_title(std::string title);
|
||||||
|
void set_size(int width, int height);
|
||||||
|
|
||||||
|
enum console_type
|
||||||
|
{
|
||||||
|
con_type_error = 1,
|
||||||
|
con_type_debug = 2,
|
||||||
|
con_type_warning = 3,
|
||||||
|
con_type_info = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
void print(int type, const char* fmt, ...);
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void error(const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
print(con_type_error, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void debug(const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
print(con_type_debug, fmt, std::forward<Args>(args)...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warn(const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
print(con_type_warning, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void info(const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
print(con_type_info, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
666
src/client/component/demonware.cpp
Normal file
666
src/client/component/demonware.cpp
Normal file
@ -0,0 +1,666 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/thread.hpp>
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include <game/dvars.hpp>
|
||||||
|
#include "game/demonware/servers/lobby_server.hpp"
|
||||||
|
#include "game/demonware/servers/auth3_server.hpp"
|
||||||
|
#include "game/demonware/servers/stun_server.hpp"
|
||||||
|
#include "game/demonware/servers/umbrella_server.hpp"
|
||||||
|
#include "game/demonware/server_registry.hpp"
|
||||||
|
|
||||||
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#define TCP_BLOCKING true
|
||||||
|
#define UDP_BLOCKING false
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
volatile bool exit_server;
|
||||||
|
std::thread server_thread;
|
||||||
|
utils::concurrency::container<std::unordered_map<SOCKET, bool>> blocking_sockets;
|
||||||
|
utils::concurrency::container<std::unordered_map<SOCKET, tcp_server*>> socket_map;
|
||||||
|
server_registry<tcp_server> tcp_servers;
|
||||||
|
server_registry<udp_server> udp_servers;
|
||||||
|
|
||||||
|
tcp_server* find_server(const SOCKET socket)
|
||||||
|
{
|
||||||
|
return socket_map.access<tcp_server*>([&](const std::unordered_map<SOCKET, tcp_server*>& map) -> tcp_server*
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry == map.end())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool socket_link(const SOCKET socket, const uint32_t address)
|
||||||
|
{
|
||||||
|
auto* server = tcp_servers.find(address);
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& map)
|
||||||
|
{
|
||||||
|
map[socket] = server;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void socket_unlink(const SOCKET socket)
|
||||||
|
{
|
||||||
|
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& map)
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry != map.end())
|
||||||
|
{
|
||||||
|
map.erase(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_socket_blocking(const SOCKET socket, const bool def)
|
||||||
|
{
|
||||||
|
return blocking_sockets.access<bool>([&](std::unordered_map<SOCKET, bool>& map)
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry == map.end())
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_blocking_socket(const SOCKET socket)
|
||||||
|
{
|
||||||
|
blocking_sockets.access([&](std::unordered_map<SOCKET, bool>& map)
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry != map.end())
|
||||||
|
{
|
||||||
|
map.erase(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_blocking_socket(const SOCKET socket, const bool block)
|
||||||
|
{
|
||||||
|
blocking_sockets.access([&](std::unordered_map<SOCKET, bool>& map)
|
||||||
|
{
|
||||||
|
map[socket] = block;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void server_main()
|
||||||
|
{
|
||||||
|
exit_server = false;
|
||||||
|
|
||||||
|
while (!exit_server)
|
||||||
|
{
|
||||||
|
tcp_servers.frame();
|
||||||
|
udp_servers.frame();
|
||||||
|
std::this_thread::sleep_for(50ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace io
|
||||||
|
{
|
||||||
|
int getaddrinfo_stub(const char* name, const char* service,
|
||||||
|
const addrinfo* hints, addrinfo** res)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[ network ]: [getaddrinfo]: \"%s\" \"%s\"\n", name, service);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base_server* server = tcp_servers.find(name);
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
server = udp_servers.find(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
return getaddrinfo(name, service, hints, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto address = utils::memory::get_allocator()->allocate<sockaddr>();
|
||||||
|
const auto ai = utils::memory::get_allocator()->allocate<addrinfo>();
|
||||||
|
|
||||||
|
auto in_addr = reinterpret_cast<sockaddr_in*>(address);
|
||||||
|
in_addr->sin_addr.s_addr = server->get_address();
|
||||||
|
in_addr->sin_family = AF_INET;
|
||||||
|
|
||||||
|
ai->ai_family = AF_INET;
|
||||||
|
ai->ai_socktype = SOCK_STREAM;
|
||||||
|
ai->ai_addr = address;
|
||||||
|
ai->ai_addrlen = sizeof(sockaddr);
|
||||||
|
ai->ai_next = nullptr;
|
||||||
|
ai->ai_flags = 0;
|
||||||
|
ai->ai_protocol = 0;
|
||||||
|
ai->ai_canonname = const_cast<char*>(name);
|
||||||
|
|
||||||
|
*res = ai;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeaddrinfo_stub(addrinfo* ai)
|
||||||
|
{
|
||||||
|
if (!utils::memory::get_allocator()->find(ai))
|
||||||
|
{
|
||||||
|
return freeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::memory::get_allocator()->free(ai->ai_addr);
|
||||||
|
utils::memory::get_allocator()->free(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getpeername_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen)
|
||||||
|
{
|
||||||
|
auto* server = find_server(s);
|
||||||
|
|
||||||
|
printf("getpeername\n");
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
{
|
||||||
|
auto in_addr = reinterpret_cast<sockaddr_in*>(addr);
|
||||||
|
in_addr->sin_addr.s_addr = server->get_address();
|
||||||
|
in_addr->sin_family = AF_INET;
|
||||||
|
*addrlen = sizeof(sockaddr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getpeername(s, addr, addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getsockname_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen)
|
||||||
|
{
|
||||||
|
auto* server = find_server(s);
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
{
|
||||||
|
auto in_addr = reinterpret_cast<sockaddr_in*>(addr);
|
||||||
|
in_addr->sin_addr.s_addr = server->get_address();
|
||||||
|
in_addr->sin_family = AF_INET;
|
||||||
|
*addrlen = sizeof(sockaddr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getsockname(s, addr, addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostent* gethostbyname_stub(const char* name)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[ network ]: [gethostbyname]: \"%s\"\n", name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base_server* server = tcp_servers.find(name);
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
server = udp_servers.find(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4996)
|
||||||
|
return gethostbyname(name);
|
||||||
|
#pragma warning(pop)
|
||||||
|
}
|
||||||
|
|
||||||
|
static thread_local in_addr address{};
|
||||||
|
address.s_addr = server->get_address();
|
||||||
|
|
||||||
|
static thread_local in_addr* addr_list[2]{};
|
||||||
|
addr_list[0] = &address;
|
||||||
|
addr_list[1] = nullptr;
|
||||||
|
|
||||||
|
static thread_local hostent host{};
|
||||||
|
host.h_name = const_cast<char*>(name);
|
||||||
|
host.h_aliases = nullptr;
|
||||||
|
host.h_addrtype = AF_INET;
|
||||||
|
host.h_length = sizeof(in_addr);
|
||||||
|
host.h_addr_list = reinterpret_cast<char**>(addr_list);
|
||||||
|
|
||||||
|
return &host;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connect_stub(const SOCKET s, const struct sockaddr* addr, const int len)
|
||||||
|
{
|
||||||
|
if (len == sizeof(sockaddr_in))
|
||||||
|
{
|
||||||
|
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(addr);
|
||||||
|
if (socket_link(s, in_addr->sin_addr.s_addr)) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return connect(s, addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int closesocket_stub(const SOCKET s)
|
||||||
|
{
|
||||||
|
remove_blocking_socket(s);
|
||||||
|
socket_unlink(s);
|
||||||
|
|
||||||
|
return closesocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_stub(const SOCKET s, const char* buf, const int len, const int flags)
|
||||||
|
{
|
||||||
|
auto* server = find_server(s);
|
||||||
|
|
||||||
|
printf("send: %s\n", buf);
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
{
|
||||||
|
server->handle_input(buf, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return send(s, buf, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int recv_stub(const SOCKET s, char* buf, const int len, const int flags)
|
||||||
|
{
|
||||||
|
auto* server = find_server(s);
|
||||||
|
|
||||||
|
printf("recv: %s\n", buf);
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
{
|
||||||
|
if (server->pending_data())
|
||||||
|
{
|
||||||
|
return static_cast<int>(server->handle_output(buf, len));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WSASetLastError(WSAEWOULDBLOCK);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recv(s, buf, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to,
|
||||||
|
const int tolen)
|
||||||
|
{
|
||||||
|
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(to);
|
||||||
|
auto* server = udp_servers.find(in_addr->sin_addr.s_addr);
|
||||||
|
|
||||||
|
printf("sendto: %s\n", buf);
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
{
|
||||||
|
server->handle_input(buf, len, { s, to, tolen });
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendto(s, buf, len, flags, to, tolen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, struct sockaddr* from,
|
||||||
|
int* fromlen)
|
||||||
|
{
|
||||||
|
//printf("recvfrom: %s\n", buf);
|
||||||
|
|
||||||
|
// Not supported yet
|
||||||
|
if (is_socket_blocking(s, UDP_BLOCKING))
|
||||||
|
{
|
||||||
|
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t result = 0;
|
||||||
|
udp_servers.for_each([&](udp_server& server)
|
||||||
|
{
|
||||||
|
if (server.pending_data(s))
|
||||||
|
{
|
||||||
|
result = server.handle_output(
|
||||||
|
s, buf, static_cast<size_t>(len), from, fromlen);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return static_cast<int>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
|
||||||
|
struct timeval* timeout)
|
||||||
|
{
|
||||||
|
if (exit_server)
|
||||||
|
{
|
||||||
|
return select(nfds, readfds, writefds, exceptfds, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = 0;
|
||||||
|
std::vector<SOCKET> read_sockets;
|
||||||
|
std::vector<SOCKET> write_sockets;
|
||||||
|
|
||||||
|
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& sockets)
|
||||||
|
{
|
||||||
|
for (auto& s : sockets)
|
||||||
|
{
|
||||||
|
if (readfds)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(s.first, readfds))
|
||||||
|
{
|
||||||
|
if (s.second->pending_data())
|
||||||
|
{
|
||||||
|
read_sockets.push_back(s.first);
|
||||||
|
FD_CLR(s.first, readfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writefds)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(s.first, writefds))
|
||||||
|
{
|
||||||
|
write_sockets.push_back(s.first);
|
||||||
|
FD_CLR(s.first, writefds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exceptfds)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(s.first, exceptfds))
|
||||||
|
{
|
||||||
|
FD_CLR(s.first, exceptfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0))
|
||||||
|
{
|
||||||
|
timeout->tv_sec = 0;
|
||||||
|
timeout->tv_usec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = select(nfds, readfds, writefds, exceptfds, timeout);
|
||||||
|
if (result < 0) result = 0;
|
||||||
|
|
||||||
|
for (const auto& socket : read_sockets)
|
||||||
|
{
|
||||||
|
if (readfds)
|
||||||
|
{
|
||||||
|
FD_SET(socket, readfds);
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& socket : write_sockets)
|
||||||
|
{
|
||||||
|
if (writefds)
|
||||||
|
{
|
||||||
|
FD_SET(socket, writefds);
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp)
|
||||||
|
{
|
||||||
|
if (static_cast<unsigned long>(cmd) == (FIONBIO))
|
||||||
|
{
|
||||||
|
add_blocking_socket(s, *argp == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioctlsocket(s, cmd, argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL internet_get_connected_state_stub(LPDWORD, DWORD)
|
||||||
|
{
|
||||||
|
// Allow offline play
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bd_logger_stub(int type, const char* const /*channelName*/, const char* /*fileLoc*/, const char* const /*file*/,
|
||||||
|
const char* const function, const unsigned int /*line*/, const char* const msg, ...)
|
||||||
|
{
|
||||||
|
//static auto* enabled =
|
||||||
|
// game::Dvar_RegisterBool("bd_logger", false, game::DVAR_FLAG_SAVED, "Log bd info to the console.");
|
||||||
|
//if (!enabled->current.enabled)
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
char buffer[2048];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
|
||||||
|
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
|
||||||
|
console::print(type, "%s: %s", function, buffer);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#ifdef DEBUG
|
||||||
|
void a(unsigned int n)
|
||||||
|
{
|
||||||
|
printf("bdAuth: Auth task failed with HTTP code [%u]\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void b(unsigned int n)
|
||||||
|
{
|
||||||
|
printf("bdAuth: Decoded client ticket of unexpected size [%u]\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void c(unsigned int n)
|
||||||
|
{
|
||||||
|
printf("bdAuth: Decoded server ticket of unexpected size [%u]\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void d()
|
||||||
|
{
|
||||||
|
printf("bdAuth: Auth ticket magic number mismatch\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void e()
|
||||||
|
{
|
||||||
|
printf("bdAuth: Cross Authentication completed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
printf("bdAuth: Auth task reply contains invalid data / format\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void g(unsigned int n)
|
||||||
|
{
|
||||||
|
printf("bdAuth: Auth task returned with error code [%u]\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void h(unsigned int n)
|
||||||
|
{
|
||||||
|
printf("bdAuth: Invalid or No Task ID [%u] in Auth reply\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void i()
|
||||||
|
{
|
||||||
|
printf("bdAuth: Received reply from DemonWare Auth server\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void l()
|
||||||
|
{
|
||||||
|
printf("bdAuth: Unknown error\n");
|
||||||
|
}
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
utils::hook::detour handle_auth_reply_hook;
|
||||||
|
bool handle_auth_reply_stub(void* a1, void* a2, void* a3)
|
||||||
|
{
|
||||||
|
// Skip bdAuth::validateResponseSignature
|
||||||
|
//utils::hook::set(0x7D4AB0_b, 0xC301B0);
|
||||||
|
// Skip bdAuth::processPlatformData
|
||||||
|
//utils::hook::set(0x7D55C0_b, 0xC301B0);
|
||||||
|
|
||||||
|
//return handle_auth_reply_hook.invoke<bool>(a1, a2, a3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void request_start_match_stub()
|
||||||
|
{
|
||||||
|
//const auto* args = "StartServer";
|
||||||
|
//utils::hook::invoke<void>(0x1E35B0_b, 0, &args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
component()
|
||||||
|
{
|
||||||
|
udp_servers.create<stun_server>("genesis.stun.us.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("genesis.stun.eu.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("genesis.stun.jp.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("genesis.stun.au.demonware.net");
|
||||||
|
|
||||||
|
udp_servers.create<stun_server>("stun.us.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("stun.eu.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("stun.jp.demonware.net");
|
||||||
|
udp_servers.create<stun_server>("stun.au.demonware.net");
|
||||||
|
|
||||||
|
tcp_servers.create<auth3_server>("iw-pc-steam-auth3.prod.demonware.net");
|
||||||
|
tcp_servers.create<lobby_server>("iw-pc-steam-lobby.prod.demonware.net");
|
||||||
|
//tcp_servers.create<qbl_server>("iw-pc-steam-qbl.prod.demonware.net");
|
||||||
|
tcp_servers.create<umbrella_server>("prod.umbrella.demonware.net");
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
server_thread = utils::thread::create_named_thread("Demonware", server_main);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* load_import(const std::string& library, const std::string& function) override
|
||||||
|
{
|
||||||
|
if (library == "WS2_32.dll")
|
||||||
|
{
|
||||||
|
if (function == "#3") return io::closesocket_stub;
|
||||||
|
if (function == "#4") return io::connect_stub;
|
||||||
|
if (function == "#5") return io::getpeername_stub;
|
||||||
|
if (function == "#6") return io::getsockname_stub;
|
||||||
|
if (function == "#10") return io::ioctlsocket_stub;
|
||||||
|
if (function == "#16") return io::recv_stub;
|
||||||
|
if (function == "#17") return io::recvfrom_stub;
|
||||||
|
if (function == "#18") return io::select_stub;
|
||||||
|
if (function == "#19") return io::send_stub;
|
||||||
|
if (function == "#20") return io::sendto_stub;
|
||||||
|
if (function == "#52") return io::gethostbyname_stub;
|
||||||
|
if (function == "getaddrinfo") return io::getaddrinfo_stub;
|
||||||
|
if (function == "freeaddrinfo") return io::freeaddrinfo_stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function == "InternetGetConnectedState")
|
||||||
|
{
|
||||||
|
return io::internet_get_connected_state_stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
/*utils::hook::jump(0x1285040_b, bd_logger_stub, true);
|
||||||
|
|
||||||
|
utils::hook::set<uint8_t>(0xB5BB96F_b, 0x0); // CURLOPT_SSL_VERIFYPEER
|
||||||
|
utils::hook::set<uint8_t>(0xB7C6CB1_b, 0xAF); // CURLOPT_SSL_VERIFYHOST
|
||||||
|
utils::hook::set<uint8_t>(0x15E4650_b, 0x0); // HTTPS -> HTTP
|
||||||
|
|
||||||
|
// umbrella dev
|
||||||
|
const char* umbrella_dev = "http://dev.umbrella.demonware.net";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8010_b), 0, strlen(umbrella_dev) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8010_b),
|
||||||
|
umbrella_dev, strlen(umbrella_dev));
|
||||||
|
|
||||||
|
// umbrella cert
|
||||||
|
const char* umbrella_cert = "http://cert.umbrella.demonware.net";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8038_b), 0, strlen(umbrella_cert) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8038_b),
|
||||||
|
umbrella_cert, strlen(umbrella_cert));
|
||||||
|
|
||||||
|
// umbrella prod
|
||||||
|
const char* umbrella_prod = "http://prod.umbrella.demonware.net";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8060_b), 0, strlen(umbrella_prod) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8060_b),
|
||||||
|
umbrella_prod, strlen(umbrella_prod));
|
||||||
|
|
||||||
|
// uno dev
|
||||||
|
const char* uno_dev = "http://dev.uno.demonware.net/v1.0";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8418_b), 0, strlen(uno_dev) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8418_b),
|
||||||
|
uno_dev, strlen(uno_dev));
|
||||||
|
|
||||||
|
// uno cert
|
||||||
|
const char* uno_cert = "http://cert.uno.demonware.net/v1.0";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8440_b), 0, strlen(uno_cert) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8440_b),
|
||||||
|
uno_cert, strlen(uno_cert));
|
||||||
|
|
||||||
|
// uno prod
|
||||||
|
const char* uno = "http://prod.uno.demonware.net/v1.0";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E8468_b), 0, strlen(uno) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E8468_b),
|
||||||
|
uno, strlen(uno));
|
||||||
|
|
||||||
|
// auth
|
||||||
|
const char* auth = "http://%s:%d/auth/";
|
||||||
|
std::memset(reinterpret_cast<void*>(0x15E3600_b), 0, strlen(auth) + 1);
|
||||||
|
std::memcpy(reinterpret_cast<void*>(0x15E3600_b), auth, strlen(auth));*/
|
||||||
|
|
||||||
|
// utils::hook::set<uint8_t>(0x19F8C0_b, 0xC3); // SV_SendMatchData, not sure
|
||||||
|
//utils::hook::nop(0x19BB67_b, 5); // LiveStorage_SendMatchDataComplete
|
||||||
|
//utils::hook::set<uint8_t>(0x1A3340_b, 0xC3); // Live_CheckForFullDisconnect
|
||||||
|
|
||||||
|
// Remove some while loop that freezes the rendering for a few secs while connecting
|
||||||
|
//utils::hook::nop(0x625555_b, 5);
|
||||||
|
|
||||||
|
//handle_auth_reply_hook.create(0x7AC600_b, handle_auth_reply_stub);
|
||||||
|
|
||||||
|
// Skip update check in Live_SyncOnlineDataFlags
|
||||||
|
//utils::hook::set(0x47A6D0_b, 0xC301B0);
|
||||||
|
// Remove update failed popup
|
||||||
|
//utils::hook::set(0x47B2B0_b, 0xC301B0);
|
||||||
|
|
||||||
|
// xpartygo -> just start the match
|
||||||
|
//utils::hook::jump(0x355B80_b, request_start_match_stub, true);
|
||||||
|
|
||||||
|
//utils::hook::set(0x396AD0_b, 0xC301B0); // DB_IsZoneLoaded("ffotd")
|
||||||
|
//utils::hook::set(0x4DD600_b, 0xC300B0); // dont use ffotd
|
||||||
|
//utils::hook::set(0x4DD5B0_b, 0xC300B0); // dont dl ffotd
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_destroy() override
|
||||||
|
{
|
||||||
|
exit_server = true;
|
||||||
|
if (server_thread.joinable())
|
||||||
|
{
|
||||||
|
server_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(demonware::component)
|
6
src/client/component/demonware.hpp
Normal file
6
src/client/component/demonware.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
123
src/client/component/game_module.cpp
Normal file
123
src/client/component/game_module.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "game_module.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <game/game.hpp>
|
||||||
|
|
||||||
|
namespace game_module
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::hook::detour handle_a_hook;
|
||||||
|
utils::hook::detour handle_w_hook;
|
||||||
|
utils::hook::detour handle_ex_a_hook;
|
||||||
|
utils::hook::detour handle_ex_w_hook;
|
||||||
|
utils::hook::detour file_name_a_hook;
|
||||||
|
utils::hook::detour file_name_w_hook;
|
||||||
|
|
||||||
|
HMODULE __stdcall get_module_handle_a(const LPCSTR module_name)
|
||||||
|
{
|
||||||
|
if (!module_name)
|
||||||
|
{
|
||||||
|
return get_game_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_a_hook.invoke<HMODULE>(module_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE __stdcall get_module_handle_w(const LPWSTR module_name)
|
||||||
|
{
|
||||||
|
if (!module_name)
|
||||||
|
{
|
||||||
|
return get_game_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_w_hook.invoke<HMODULE>(module_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL __stdcall get_module_handle_ex_a(const DWORD flags, const LPCSTR module_name, HMODULE* hmodule)
|
||||||
|
{
|
||||||
|
if (!module_name)
|
||||||
|
{
|
||||||
|
*hmodule = get_game_module();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_ex_a_hook.invoke<BOOL>(flags, module_name, hmodule);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL __stdcall get_module_handle_ex_w(const DWORD flags, const LPCWSTR module_name, HMODULE* hmodule)
|
||||||
|
{
|
||||||
|
if (!module_name)
|
||||||
|
{
|
||||||
|
*hmodule = get_game_module();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_ex_w_hook.invoke<BOOL>(flags, module_name, hmodule);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD __stdcall get_module_file_name_a(HMODULE hmodule, const LPSTR filename, const DWORD size)
|
||||||
|
{
|
||||||
|
if (!hmodule)
|
||||||
|
{
|
||||||
|
hmodule = get_game_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_name_a_hook.invoke<DWORD>(hmodule, filename, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD __stdcall get_module_file_name_w(HMODULE hmodule, const LPWSTR filename, const DWORD size)
|
||||||
|
{
|
||||||
|
if (!hmodule)
|
||||||
|
{
|
||||||
|
hmodule = get_game_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_name_w_hook.invoke<DWORD>(hmodule, filename, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook_module_resolving()
|
||||||
|
{
|
||||||
|
handle_a_hook.create(&GetModuleHandleA, &get_module_handle_a);
|
||||||
|
handle_w_hook.create(&GetModuleHandleW, &get_module_handle_w);
|
||||||
|
handle_ex_w_hook.create(&GetModuleHandleExA, &get_module_handle_ex_a);
|
||||||
|
handle_ex_w_hook.create(&GetModuleHandleExW, &get_module_handle_ex_w);
|
||||||
|
file_name_a_hook.create(&GetModuleFileNameA, &get_module_file_name_a);
|
||||||
|
file_name_w_hook.create(&GetModuleFileNameW, &get_module_file_name_w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::nt::library get_game_module()
|
||||||
|
{
|
||||||
|
static utils::nt::library game{HMODULE(game::base_address)};
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::nt::library get_host_module()
|
||||||
|
{
|
||||||
|
static utils::nt::library host{};
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_start() override
|
||||||
|
{
|
||||||
|
get_host_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
#ifdef INJECT_HOST_AS_LIB
|
||||||
|
hook_module_resolving();
|
||||||
|
#else
|
||||||
|
assert(get_host_module() == get_game_module());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(game_module::component)
|
9
src/client/component/game_module.hpp
Normal file
9
src/client/component/game_module.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
|
namespace game_module
|
||||||
|
{
|
||||||
|
utils::nt::library get_game_module();
|
||||||
|
utils::nt::library get_host_module();
|
||||||
|
}
|
70
src/client/component/resources.cpp
Normal file
70
src/client/component/resources.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
|
namespace resources
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
HICON icon;
|
||||||
|
HANDLE splash, logo;
|
||||||
|
|
||||||
|
HANDLE WINAPI load_image_a(const HINSTANCE handle, LPCSTR name, const UINT type, const int c_x, const int c_y,
|
||||||
|
const UINT load)
|
||||||
|
{
|
||||||
|
const utils::nt::library self;
|
||||||
|
if (!IS_INTRESOURCE(name) && name == "logo.bmp"s) return logo;
|
||||||
|
if (self.get_handle() == handle && name == LPCSTR(0x64)) return splash;
|
||||||
|
|
||||||
|
return LoadImageA(handle, name, type, c_x, c_y, load);
|
||||||
|
}
|
||||||
|
|
||||||
|
HICON WINAPI load_icon_a(const HINSTANCE handle, const LPCSTR name)
|
||||||
|
{
|
||||||
|
const utils::nt::library self;
|
||||||
|
if (self.get_handle() == handle && name == LPCSTR(2)) return icon;
|
||||||
|
|
||||||
|
return LoadIconA(handle, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~component() override
|
||||||
|
{
|
||||||
|
if (icon) DestroyIcon(icon);
|
||||||
|
if (logo) DeleteObject(logo);
|
||||||
|
if (splash) DeleteObject(splash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_start() override
|
||||||
|
{
|
||||||
|
const utils::nt::library self;
|
||||||
|
|
||||||
|
icon = LoadIconA(self.get_handle(), MAKEINTRESOURCEA(ID_ICON));
|
||||||
|
logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE);
|
||||||
|
splash = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_SPLASH), 0, 0, 0, LR_COPYFROMRESOURCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* load_import(const std::string& library, const std::string& function) override
|
||||||
|
{
|
||||||
|
if (library == "USER32.dll")
|
||||||
|
{
|
||||||
|
if (function == "LoadIconA")
|
||||||
|
{
|
||||||
|
return load_icon_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function == "LoadImageA")
|
||||||
|
{
|
||||||
|
return load_image_a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(resources::component)
|
182
src/client/game/demonware/bit_buffer.cpp
Normal file
182
src/client/game/demonware/bit_buffer.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "bit_buffer.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output)
|
||||||
|
{
|
||||||
|
return this->read(bytes * 8, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::read_bool(bool* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->read(1, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::read_uint32(unsigned int* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(8))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->read(32, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::read_data_type(const char expected)
|
||||||
|
{
|
||||||
|
char data_type = 0;
|
||||||
|
|
||||||
|
if (!this->use_data_types_) return true;
|
||||||
|
if (this->read(5, &data_type))
|
||||||
|
{
|
||||||
|
return (data_type == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_bytes(const unsigned int bytes, const char* data)
|
||||||
|
{
|
||||||
|
return this->write_bytes(bytes, reinterpret_cast<const unsigned char*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_bytes(const unsigned int bytes, const unsigned char* data)
|
||||||
|
{
|
||||||
|
return this->write(bytes * 8, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_bool(bool data)
|
||||||
|
{
|
||||||
|
if (this->write_data_type(1))
|
||||||
|
{
|
||||||
|
return this->write(1, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_int32(int data)
|
||||||
|
{
|
||||||
|
if (this->write_data_type(7))
|
||||||
|
{
|
||||||
|
return this->write(32, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_uint32(unsigned int data)
|
||||||
|
{
|
||||||
|
if (this->write_data_type(8))
|
||||||
|
{
|
||||||
|
return this->write(32, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write_data_type(char data)
|
||||||
|
{
|
||||||
|
if (!this->use_data_types_)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->write(5, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::read(unsigned int bits, void* output)
|
||||||
|
{
|
||||||
|
if (bits == 0) return false;
|
||||||
|
if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false;
|
||||||
|
|
||||||
|
int cur_byte = this->current_bit_ >> 3;
|
||||||
|
auto cur_out = 0;
|
||||||
|
|
||||||
|
const char* bytes = this->buffer_.data();
|
||||||
|
const auto output_bytes = static_cast<unsigned char*>(output);
|
||||||
|
|
||||||
|
while (bits > 0)
|
||||||
|
{
|
||||||
|
const int min_bit = (bits < 8) ? bits : 8;
|
||||||
|
const auto this_byte = bytes[cur_byte++] & 0xFF;
|
||||||
|
const int remain = this->current_bit_ & 7;
|
||||||
|
|
||||||
|
if ((min_bit + remain) <= 8)
|
||||||
|
{
|
||||||
|
output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output_bytes[cur_out] = BYTE(
|
||||||
|
(0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain));
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_out++;
|
||||||
|
this->current_bit_ += min_bit;
|
||||||
|
bits -= min_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit_buffer::write(const unsigned int bits, const void* data)
|
||||||
|
{
|
||||||
|
if (bits == 0) return false;
|
||||||
|
this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1);
|
||||||
|
|
||||||
|
int bit = bits;
|
||||||
|
const auto bytes = const_cast<char*>(this->buffer_.data());
|
||||||
|
const auto* input_bytes = static_cast<const unsigned char*>(data);
|
||||||
|
|
||||||
|
while (bit > 0)
|
||||||
|
{
|
||||||
|
const int bit_pos = this->current_bit_ & 7;
|
||||||
|
auto rem_bit = 8 - bit_pos;
|
||||||
|
const auto this_write = (bit < rem_bit) ? bit : rem_bit;
|
||||||
|
|
||||||
|
const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write)));
|
||||||
|
const int byte_pos = this->current_bit_ >> 3;
|
||||||
|
|
||||||
|
const BYTE temp_byte = (mask & bytes[byte_pos]);
|
||||||
|
const BYTE this_bit = ((bits - bit) & 7);
|
||||||
|
const auto this_byte = (bits - bit) >> 3;
|
||||||
|
|
||||||
|
auto this_data = input_bytes[this_byte];
|
||||||
|
|
||||||
|
const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0;
|
||||||
|
|
||||||
|
this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit));
|
||||||
|
|
||||||
|
const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte);
|
||||||
|
bytes[byte_pos] = out_byte;
|
||||||
|
|
||||||
|
this->current_bit_ += this_write;
|
||||||
|
bit -= this_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bit_buffer::set_use_data_types(const bool use_data_types)
|
||||||
|
{
|
||||||
|
this->use_data_types_ = use_data_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int bit_buffer::size() const
|
||||||
|
{
|
||||||
|
return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& bit_buffer::get_buffer()
|
||||||
|
{
|
||||||
|
this->buffer_.resize(this->size());
|
||||||
|
return this->buffer_;
|
||||||
|
}
|
||||||
|
}
|
40
src/client/game/demonware/bit_buffer.hpp
Normal file
40
src/client/game/demonware/bit_buffer.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bit_buffer final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bit_buffer() = default;
|
||||||
|
|
||||||
|
explicit bit_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_bytes(unsigned int bytes, unsigned char* output);
|
||||||
|
bool read_bool(bool* output);
|
||||||
|
bool read_uint32(unsigned int* output);
|
||||||
|
bool read_data_type(char expected);
|
||||||
|
|
||||||
|
bool write_bytes(unsigned int bytes, const char* data);
|
||||||
|
bool write_bytes(unsigned int bytes, const unsigned char* data);
|
||||||
|
bool write_bool(bool data);
|
||||||
|
bool write_int32(int data);
|
||||||
|
bool write_uint32(unsigned int data);
|
||||||
|
bool write_data_type(char data);
|
||||||
|
|
||||||
|
bool read(unsigned int bits, void* output);
|
||||||
|
bool write(unsigned int bits, const void* data);
|
||||||
|
|
||||||
|
void set_use_data_types(bool use_data_types);
|
||||||
|
|
||||||
|
unsigned int size() const;
|
||||||
|
|
||||||
|
std::string& get_buffer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string buffer_{};
|
||||||
|
unsigned int current_bit_ = 0;
|
||||||
|
bool use_data_types_ = true;
|
||||||
|
};
|
||||||
|
}
|
308
src/client/game/demonware/byte_buffer.cpp
Normal file
308
src/client/game/demonware/byte_buffer.cpp
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "byte_buffer.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bool byte_buffer::read_byte(unsigned char* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(3)) return false;
|
||||||
|
return this->read(1, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_bool(bool* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(1)) return false;
|
||||||
|
return this->read(1, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_int16(short* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(5)) return false;
|
||||||
|
return this->read(2, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_uint16(unsigned short* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(6)) return false;
|
||||||
|
return this->read(2, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_int32(int* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(7)) return false;
|
||||||
|
return this->read(4, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_uint32(unsigned int* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(8)) return false;
|
||||||
|
return this->read(4, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_int64(__int64* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(9)) return false;
|
||||||
|
return this->read(8, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_uint64(unsigned __int64* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(10)) return false;
|
||||||
|
return this->read(8, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_float(float* output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(13)) return false;
|
||||||
|
return this->read(4, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_string(std::string* output)
|
||||||
|
{
|
||||||
|
char* out_data;
|
||||||
|
if (this->read_string(&out_data))
|
||||||
|
{
|
||||||
|
output->clear();
|
||||||
|
output->append(out_data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_string(char** output)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(16)) return false;
|
||||||
|
|
||||||
|
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||||
|
this->current_byte_ += strlen(*output) + 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_string(char* output, const int length)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(16)) return false;
|
||||||
|
|
||||||
|
strcpy_s(output, length, const_cast<char*>(this->buffer_.data()) + this->current_byte_);
|
||||||
|
this->current_byte_ += strlen(output) + 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_blob(std::string* output)
|
||||||
|
{
|
||||||
|
char* out_data;
|
||||||
|
int length;
|
||||||
|
if (this->read_blob(&out_data, &length))
|
||||||
|
{
|
||||||
|
output->clear();
|
||||||
|
output->append(out_data, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_blob(char** output, int* length)
|
||||||
|
{
|
||||||
|
if (!this->read_data_type(0x13))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size;
|
||||||
|
this->read_uint32(&size);
|
||||||
|
|
||||||
|
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||||
|
*length = static_cast<int>(size);
|
||||||
|
|
||||||
|
this->current_byte_ += size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_data_type(const char expected)
|
||||||
|
{
|
||||||
|
if (!this->use_data_types_) return true;
|
||||||
|
|
||||||
|
char type;
|
||||||
|
this->read(1, &type);
|
||||||
|
return type == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count,
|
||||||
|
unsigned int* element_size)
|
||||||
|
{
|
||||||
|
if (element_count) *element_count = 0;
|
||||||
|
if (element_size) *element_size = 0;
|
||||||
|
|
||||||
|
if (!this->read_data_type(expected + 100)) return false;
|
||||||
|
|
||||||
|
uint32_t array_size, el_count;
|
||||||
|
if (!this->read_uint32(&array_size)) return false;
|
||||||
|
|
||||||
|
this->set_use_data_types(false);
|
||||||
|
this->read_uint32(&el_count);
|
||||||
|
this->set_use_data_types(true);
|
||||||
|
|
||||||
|
if (element_count) *element_count = el_count;
|
||||||
|
if (element_size) *element_size = array_size / el_count;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_byte(char data)
|
||||||
|
{
|
||||||
|
this->write_data_type(3);
|
||||||
|
return this->write(1, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_bool(bool data)
|
||||||
|
{
|
||||||
|
this->write_data_type(1);
|
||||||
|
return this->write(1, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_int16(short data)
|
||||||
|
{
|
||||||
|
this->write_data_type(5);
|
||||||
|
return this->write(2, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_uint16(unsigned short data)
|
||||||
|
{
|
||||||
|
this->write_data_type(6);
|
||||||
|
return this->write(2, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_int32(int data)
|
||||||
|
{
|
||||||
|
this->write_data_type(7);
|
||||||
|
return this->write(4, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_uint32(unsigned int data)
|
||||||
|
{
|
||||||
|
this->write_data_type(8);
|
||||||
|
return this->write(4, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_int64(__int64 data)
|
||||||
|
{
|
||||||
|
this->write_data_type(9);
|
||||||
|
return this->write(8, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_uint64(unsigned __int64 data)
|
||||||
|
{
|
||||||
|
this->write_data_type(10);
|
||||||
|
return this->write(8, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_data_type(char data)
|
||||||
|
{
|
||||||
|
if (!this->use_data_types_) return true;
|
||||||
|
return this->write(1, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_float(float data)
|
||||||
|
{
|
||||||
|
this->write_data_type(13);
|
||||||
|
return this->write(4, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_string(const std::string& data)
|
||||||
|
{
|
||||||
|
return this->write_string(data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_string(const char* data)
|
||||||
|
{
|
||||||
|
this->write_data_type(16);
|
||||||
|
return this->write(static_cast<int>(strlen(data)) + 1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_blob(const std::string& data)
|
||||||
|
{
|
||||||
|
return this->write_blob(data.data(), INT(data.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_blob(const char* data, const int length)
|
||||||
|
{
|
||||||
|
this->write_data_type(0x13);
|
||||||
|
this->write_uint32(length);
|
||||||
|
|
||||||
|
return this->write(length, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count,
|
||||||
|
const unsigned int element_size)
|
||||||
|
{
|
||||||
|
const auto using_types = this->is_using_data_types();
|
||||||
|
this->set_use_data_types(false);
|
||||||
|
|
||||||
|
auto result = this->write_byte(type + 100);
|
||||||
|
|
||||||
|
this->set_use_data_types(true);
|
||||||
|
result &= this->write_uint32(element_count * element_size);
|
||||||
|
this->set_use_data_types(false);
|
||||||
|
|
||||||
|
result &= this->write_uint32(element_count);
|
||||||
|
|
||||||
|
this->set_use_data_types(using_types);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::read(const int bytes, void* output)
|
||||||
|
{
|
||||||
|
if (bytes + this->current_byte_ > this->buffer_.size()) return false;
|
||||||
|
|
||||||
|
std::memmove(output, this->buffer_.data() + this->current_byte_, bytes);
|
||||||
|
this->current_byte_ += bytes;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write(const int bytes, const void* data)
|
||||||
|
{
|
||||||
|
this->buffer_.append(static_cast<const char*>(data), bytes);
|
||||||
|
this->current_byte_ += bytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::write(const std::string& data)
|
||||||
|
{
|
||||||
|
return this->write(static_cast<int>(data.size()), data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void byte_buffer::set_use_data_types(const bool use_data_types)
|
||||||
|
{
|
||||||
|
this->use_data_types_ = use_data_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t byte_buffer::size() const
|
||||||
|
{
|
||||||
|
return this->buffer_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::is_using_data_types() const
|
||||||
|
{
|
||||||
|
return use_data_types_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& byte_buffer::get_buffer()
|
||||||
|
{
|
||||||
|
return this->buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string byte_buffer::get_remaining()
|
||||||
|
{
|
||||||
|
return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool byte_buffer::has_more_data() const
|
||||||
|
{
|
||||||
|
return this->buffer_.size() > this->current_byte_;
|
||||||
|
}
|
||||||
|
}
|
69
src/client/game/demonware/byte_buffer.hpp
Normal file
69
src/client/game/demonware/byte_buffer.hpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class byte_buffer final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
byte_buffer() = default;
|
||||||
|
|
||||||
|
explicit byte_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_byte(unsigned char* output);
|
||||||
|
bool read_bool(bool* output);
|
||||||
|
bool read_int16(short* output);
|
||||||
|
bool read_uint16(unsigned short* output);
|
||||||
|
bool read_int32(int* output);
|
||||||
|
bool read_uint32(unsigned int* output);
|
||||||
|
bool read_int64(__int64* output);
|
||||||
|
bool read_uint64(unsigned __int64* output);
|
||||||
|
bool read_float(float* output);
|
||||||
|
bool read_string(char** output);
|
||||||
|
bool read_string(char* output, int length);
|
||||||
|
bool read_string(std::string* output);
|
||||||
|
bool read_blob(char** output, int* length);
|
||||||
|
bool read_blob(std::string* output);
|
||||||
|
bool read_data_type(char expected);
|
||||||
|
|
||||||
|
bool read_array_header(unsigned char expected, unsigned int* element_count,
|
||||||
|
unsigned int* element_size = nullptr);
|
||||||
|
|
||||||
|
bool write_byte(char data);
|
||||||
|
bool write_bool(bool data);
|
||||||
|
bool write_int16(short data);
|
||||||
|
bool write_uint16(unsigned short data);
|
||||||
|
bool write_int32(int data);
|
||||||
|
bool write_uint32(unsigned int data);
|
||||||
|
bool write_int64(__int64 data);
|
||||||
|
bool write_uint64(unsigned __int64 data);
|
||||||
|
bool write_data_type(char data);
|
||||||
|
bool write_float(float data);
|
||||||
|
bool write_string(const char* data);
|
||||||
|
bool write_string(const std::string& data);
|
||||||
|
bool write_blob(const char* data, int length);
|
||||||
|
bool write_blob(const std::string& data);
|
||||||
|
|
||||||
|
bool write_array_header(unsigned char type, unsigned int element_count, unsigned int element_size);
|
||||||
|
|
||||||
|
bool read(int bytes, void* output);
|
||||||
|
bool write(int bytes, const void* data);
|
||||||
|
bool write(const std::string& data);
|
||||||
|
|
||||||
|
void set_use_data_types(bool use_data_types);
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
bool is_using_data_types() const;
|
||||||
|
|
||||||
|
std::string& get_buffer();
|
||||||
|
std::string get_remaining();
|
||||||
|
|
||||||
|
bool has_more_data() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string buffer_;
|
||||||
|
size_t current_byte_ = 0;
|
||||||
|
bool use_data_types_ = true;
|
||||||
|
};
|
||||||
|
}
|
210
src/client/game/demonware/data_types.hpp
Normal file
210
src/client/game/demonware/data_types.hpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "byte_buffer.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~bdTaskResult() = default;
|
||||||
|
|
||||||
|
virtual void serialize(byte_buffer*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void deserialize(byte_buffer*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdFileData final : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string file_data;
|
||||||
|
|
||||||
|
explicit bdFileData(std::string buffer) : file_data(std::move(buffer))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_blob(this->file_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_blob(&this->file_data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdFileInfo final : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint64_t file_id;
|
||||||
|
uint32_t create_time;
|
||||||
|
uint32_t modified_time;
|
||||||
|
bool priv;
|
||||||
|
uint64_t owner_id;
|
||||||
|
std::string filename;
|
||||||
|
uint32_t file_size;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_uint32(this->file_size);
|
||||||
|
buffer->write_uint64(this->file_id);
|
||||||
|
buffer->write_uint32(this->create_time);
|
||||||
|
buffer->write_uint32(this->modified_time);
|
||||||
|
buffer->write_bool(this->priv);
|
||||||
|
buffer->write_uint64(this->owner_id);
|
||||||
|
buffer->write_string(this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_uint32(&this->file_size);
|
||||||
|
buffer->read_uint64(&this->file_id);
|
||||||
|
buffer->read_uint32(&this->create_time);
|
||||||
|
buffer->read_uint32(&this->modified_time);
|
||||||
|
buffer->read_bool(&this->priv);
|
||||||
|
buffer->read_uint64(&this->owner_id);
|
||||||
|
buffer->read_string(&this->filename);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdTimeStamp final : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t unix_time;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_uint32(this->unix_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_uint32(&this->unix_time);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdDMLInfo : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string country_code; // Char [3]
|
||||||
|
std::string country; // Char [65]
|
||||||
|
std::string region; // Char [65]
|
||||||
|
std::string city; // Char [129]
|
||||||
|
float latitude;
|
||||||
|
float longitude;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_string(this->country_code);
|
||||||
|
buffer->write_string(this->country);
|
||||||
|
buffer->write_string(this->region);
|
||||||
|
buffer->write_string(this->city);
|
||||||
|
buffer->write_float(this->latitude);
|
||||||
|
buffer->write_float(this->longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_string(&this->country_code);
|
||||||
|
buffer->read_string(&this->country);
|
||||||
|
buffer->read_string(&this->region);
|
||||||
|
buffer->read_string(&this->city);
|
||||||
|
buffer->read_float(&this->latitude);
|
||||||
|
buffer->read_float(&this->longitude);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdDMLRawData final : public bdDMLInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t asn; // Autonomous System Number.
|
||||||
|
std::string timezone;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
bdDMLInfo::serialize(buffer);
|
||||||
|
|
||||||
|
buffer->write_uint32(this->asn);
|
||||||
|
buffer->write_string(this->timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
bdDMLInfo::deserialize(buffer);
|
||||||
|
|
||||||
|
buffer->read_uint32(&this->asn);
|
||||||
|
buffer->read_string(&this->timezone);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// made up name
|
||||||
|
class bdFile final : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint64_t owner_id;
|
||||||
|
std::string platform;
|
||||||
|
std::string filename;
|
||||||
|
uint32_t unk;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_uint64(this->owner_id);
|
||||||
|
buffer->write_string(this->platform);
|
||||||
|
buffer->write_string(this->filename);
|
||||||
|
buffer->write_uint32(this->unk);
|
||||||
|
buffer->write_blob(this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_uint64(&this->owner_id);
|
||||||
|
buffer->read_string(&this->platform);
|
||||||
|
buffer->read_string(&this->filename);
|
||||||
|
buffer->read_uint32(&this->unk);
|
||||||
|
buffer->read_blob(&this->data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bdFile2 final : public bdTaskResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t unk1;
|
||||||
|
uint32_t unk2;
|
||||||
|
uint32_t unk3;
|
||||||
|
bool priv;
|
||||||
|
uint64_t owner_id;
|
||||||
|
std::string platform;
|
||||||
|
std::string filename;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
void serialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->write_uint32(this->unk1);
|
||||||
|
buffer->write_uint32(this->unk2);
|
||||||
|
buffer->write_uint32(this->unk3);
|
||||||
|
buffer->write_bool(this->priv);
|
||||||
|
buffer->write_uint64(this->owner_id);
|
||||||
|
buffer->write_string(this->platform);
|
||||||
|
buffer->write_string(this->filename);
|
||||||
|
buffer->write_blob(this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(byte_buffer* buffer) override
|
||||||
|
{
|
||||||
|
buffer->read_uint32(&this->unk1);
|
||||||
|
buffer->read_uint32(&this->unk2);
|
||||||
|
buffer->read_uint32(&this->unk3);
|
||||||
|
buffer->read_bool(&this->priv);
|
||||||
|
buffer->read_uint64(&this->owner_id);
|
||||||
|
buffer->read_string(&this->platform);
|
||||||
|
buffer->read_string(&this->filename);
|
||||||
|
buffer->read_blob(&this->data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
130
src/client/game/demonware/keys.cpp
Normal file
130
src/client/game/demonware/keys.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "keys.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
struct data_t
|
||||||
|
{
|
||||||
|
char m_session_key[24];
|
||||||
|
char m_response[8];
|
||||||
|
char m_hmac_key[20];
|
||||||
|
char m_enc_key[16];
|
||||||
|
char m_dec_key[16];
|
||||||
|
} data{};
|
||||||
|
|
||||||
|
std::string packet_buffer;
|
||||||
|
|
||||||
|
void calculate_hmacs_s1(const char* data_, const unsigned int data_size, const char* key,
|
||||||
|
const unsigned int key_size,
|
||||||
|
char* dst, const unsigned int dst_size)
|
||||||
|
{
|
||||||
|
char buffer[64];
|
||||||
|
unsigned int pos = 0;
|
||||||
|
unsigned int out_offset = 0;
|
||||||
|
char count = 1;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
// buffer add key
|
||||||
|
std::memcpy(&buffer[pos], key, key_size);
|
||||||
|
pos += key_size;
|
||||||
|
|
||||||
|
// buffer add count
|
||||||
|
buffer[pos] = count;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
// calculate hmac
|
||||||
|
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size));
|
||||||
|
|
||||||
|
// save output
|
||||||
|
std::memcpy(dst, result.data(), std::min(20u, (dst_size - out_offset)));
|
||||||
|
out_offset = 20;
|
||||||
|
|
||||||
|
// second loop
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// if we filled the output buffer, exit
|
||||||
|
if (out_offset >= dst_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// buffer add last result
|
||||||
|
pos = 0;
|
||||||
|
std::memcpy(&buffer[pos], result.data(), 20);
|
||||||
|
pos += 20;
|
||||||
|
|
||||||
|
// buffer add key
|
||||||
|
std::memcpy(&buffer[pos], key, key_size);
|
||||||
|
pos += key_size;
|
||||||
|
|
||||||
|
// buffer add count
|
||||||
|
count++;
|
||||||
|
buffer[pos] = count;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
// calculate hmac
|
||||||
|
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size));
|
||||||
|
|
||||||
|
// save output
|
||||||
|
std::memcpy(dst + out_offset, result.data(), std::min(20u, (dst_size - out_offset)));
|
||||||
|
out_offset += 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void derive_keys_s1()
|
||||||
|
{
|
||||||
|
const auto out_1 = utils::cryptography::sha1::compute(packet_buffer); // out_1 size 20
|
||||||
|
|
||||||
|
auto data_3 = utils::cryptography::hmac_sha1::compute(data.m_session_key, out_1);
|
||||||
|
|
||||||
|
char out_2[16];
|
||||||
|
calculate_hmacs_s1(data_3.data(), 20, "CLIENTCHAL", 10, out_2, 16);
|
||||||
|
|
||||||
|
char out_3[72];
|
||||||
|
calculate_hmacs_s1(data_3.data(), 20, "BDDATA", 6, out_3, 72);
|
||||||
|
|
||||||
|
std::memcpy(data.m_response, &out_2[8], 8);
|
||||||
|
std::memcpy(data.m_hmac_key, &out_3[20], 20);
|
||||||
|
std::memcpy(data.m_dec_key, &out_3[40], 16);
|
||||||
|
std::memcpy(data.m_enc_key, &out_3[56], 16);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW] Response id: %s\n", utils::string::dump_hex(std::string(&out_2[8], 8)).data());
|
||||||
|
printf("[DW] Hash verify: %s\n", utils::string::dump_hex(std::string(&out_3[20], 20)).data());
|
||||||
|
printf("[DW] AES dec key: %s\n", utils::string::dump_hex(std::string(&out_3[40], 16)).data());
|
||||||
|
printf("[DW] AES enc key: %s\n", utils::string::dump_hex(std::string(&out_3[56], 16)).data());
|
||||||
|
printf("[DW] Bravo 6, going dark.\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_packet_to_hash(const std::string& packet)
|
||||||
|
{
|
||||||
|
packet_buffer.append(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_session_key(const std::string& key)
|
||||||
|
{
|
||||||
|
std::memcpy(data.m_session_key, key.data(), 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_decrypt_key()
|
||||||
|
{
|
||||||
|
return std::string(data.m_dec_key, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_encrypt_key()
|
||||||
|
{
|
||||||
|
return std::string(data.m_enc_key, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_hmac_key()
|
||||||
|
{
|
||||||
|
return std::string(data.m_hmac_key, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_response_id()
|
||||||
|
{
|
||||||
|
return std::string(data.m_response, 8);
|
||||||
|
}
|
||||||
|
}
|
12
src/client/game/demonware/keys.hpp
Normal file
12
src/client/game/demonware/keys.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void derive_keys_s1();
|
||||||
|
void queue_packet_to_hash(const std::string& packet);
|
||||||
|
void set_session_key(const std::string& key);
|
||||||
|
std::string get_decrypt_key();
|
||||||
|
std::string get_encrypt_key();
|
||||||
|
std::string get_hmac_key();
|
||||||
|
std::string get_response_id();
|
||||||
|
}
|
87
src/client/game/demonware/reply.cpp
Normal file
87
src/client/game/demonware/reply.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "keys.hpp"
|
||||||
|
#include "reply.hpp"
|
||||||
|
#include "servers/service_server.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
std::string unencrypted_reply::data()
|
||||||
|
{
|
||||||
|
byte_buffer result;
|
||||||
|
result.set_use_data_types(false);
|
||||||
|
|
||||||
|
result.write_int32(static_cast<int>(this->buffer_.size()) + 2);
|
||||||
|
result.write_bool(false);
|
||||||
|
result.write_byte(this->type());
|
||||||
|
result.write(this->buffer_);
|
||||||
|
|
||||||
|
return result.get_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string encrypted_reply::data()
|
||||||
|
{
|
||||||
|
byte_buffer result;
|
||||||
|
result.set_use_data_types(false);
|
||||||
|
|
||||||
|
byte_buffer enc_buffer;
|
||||||
|
enc_buffer.set_use_data_types(false);
|
||||||
|
|
||||||
|
enc_buffer.write_uint32(static_cast<unsigned int>(this->buffer_.size())); // service data size CHECKTHIS!!
|
||||||
|
enc_buffer.write_byte(this->type()); // TASK_REPLY type
|
||||||
|
enc_buffer.write(this->buffer_); // service data
|
||||||
|
|
||||||
|
auto aligned_data = enc_buffer.get_buffer();
|
||||||
|
auto size = aligned_data.size();
|
||||||
|
size = ~15 & (size + 15); // 16 byte align
|
||||||
|
aligned_data.resize(size);
|
||||||
|
|
||||||
|
// seed
|
||||||
|
std::string seed("\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED", 16);
|
||||||
|
|
||||||
|
// encrypt
|
||||||
|
const auto enc_data = utils::cryptography::aes::encrypt(aligned_data, seed, demonware::get_encrypt_key());
|
||||||
|
|
||||||
|
// header : encrypted service data : hash
|
||||||
|
static auto msg_count = 0;
|
||||||
|
msg_count++;
|
||||||
|
|
||||||
|
byte_buffer response;
|
||||||
|
response.set_use_data_types(false);
|
||||||
|
|
||||||
|
response.write_int32(30 + static_cast<int>(enc_data.size()));
|
||||||
|
response.write_byte(static_cast<char>(0xAB));
|
||||||
|
response.write_byte(static_cast<char>(0x85));
|
||||||
|
response.write_int32(msg_count);
|
||||||
|
response.write(16, seed.data());
|
||||||
|
response.write(enc_data);
|
||||||
|
|
||||||
|
// hash entire packet and append end
|
||||||
|
auto hash_data = utils::cryptography::hmac_sha1::compute(response.get_buffer(), demonware::get_hmac_key());
|
||||||
|
hash_data.resize(8);
|
||||||
|
response.write(8, hash_data.data());
|
||||||
|
|
||||||
|
return response.get_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remote_reply::send(bit_buffer* buffer, const bool encrypted)
|
||||||
|
{
|
||||||
|
std::unique_ptr<typed_reply> reply;
|
||||||
|
|
||||||
|
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||||
|
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||||
|
|
||||||
|
this->server_->send_reply(reply.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void remote_reply::send(byte_buffer* buffer, const bool encrypted)
|
||||||
|
{
|
||||||
|
std::unique_ptr<typed_reply> reply;
|
||||||
|
|
||||||
|
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||||
|
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||||
|
|
||||||
|
this->server_->send_reply(reply.get());
|
||||||
|
}
|
||||||
|
}
|
164
src/client/game/demonware/reply.hpp
Normal file
164
src/client/game/demonware/reply.hpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bit_buffer.hpp"
|
||||||
|
#include "byte_buffer.hpp"
|
||||||
|
#include "data_types.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class reply
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
reply() = default;
|
||||||
|
|
||||||
|
reply(reply&&) = delete;
|
||||||
|
reply(const reply&) = delete;
|
||||||
|
reply& operator=(reply&&) = delete;
|
||||||
|
reply& operator=(const reply&) = delete;
|
||||||
|
|
||||||
|
virtual ~reply() = default;
|
||||||
|
virtual std::string data() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class raw_reply : public reply
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::string buffer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
raw_reply() = default;
|
||||||
|
|
||||||
|
explicit raw_reply(std::string data) : buffer_(std::move(data))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data() override
|
||||||
|
{
|
||||||
|
return this->buffer_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class typed_reply : public raw_reply
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typed_reply(const uint8_t _type) : type_(_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t type() const { return this->type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class encrypted_reply final : public typed_reply
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type)
|
||||||
|
{
|
||||||
|
this->buffer_.append(bbuffer->get_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type)
|
||||||
|
{
|
||||||
|
this->buffer_.append(bbuffer->get_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class unencrypted_reply final : public typed_reply
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unencrypted_reply(const uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type)
|
||||||
|
{
|
||||||
|
this->buffer_.append(bbuffer->get_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
unencrypted_reply(const uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type)
|
||||||
|
{
|
||||||
|
this->buffer_.append(bbuffer->get_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class service_server;
|
||||||
|
|
||||||
|
class remote_reply final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
remote_reply(service_server* server, uint8_t _type) : type_(_type), server_(server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(bit_buffer* buffer, bool encrypted);
|
||||||
|
void send(byte_buffer* buffer, bool encrypted);
|
||||||
|
|
||||||
|
uint8_t type() const { return this->type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t type_;
|
||||||
|
service_server* server_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class service_reply final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
service_reply(service_server* _server, const uint8_t _type, const uint32_t _error)
|
||||||
|
: type_(_type), error_(_error), reply_(_server, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t send()
|
||||||
|
{
|
||||||
|
static uint64_t id = 0x0000000000000000;
|
||||||
|
const auto transaction_id = ++id;
|
||||||
|
|
||||||
|
byte_buffer buffer;
|
||||||
|
buffer.write_uint64(transaction_id);
|
||||||
|
buffer.write_uint32(this->error_);
|
||||||
|
buffer.write_byte(this->type_);
|
||||||
|
|
||||||
|
if (!this->error_)
|
||||||
|
{
|
||||||
|
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||||
|
if (!this->objects_.empty())
|
||||||
|
{
|
||||||
|
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||||
|
|
||||||
|
for (auto& object : this->objects_)
|
||||||
|
{
|
||||||
|
object->serialize(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->objects_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.write_uint64(transaction_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->reply_.send(&buffer, true);
|
||||||
|
return transaction_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const std::shared_ptr<bdTaskResult>& object)
|
||||||
|
{
|
||||||
|
this->objects_.push_back(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(bdTaskResult* object)
|
||||||
|
{
|
||||||
|
this->add(std::shared_ptr<bdTaskResult>(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t type_;
|
||||||
|
uint32_t error_;
|
||||||
|
remote_reply reply_;
|
||||||
|
std::vector<std::shared_ptr<bdTaskResult>> objects_;
|
||||||
|
};
|
||||||
|
}
|
60
src/client/game/demonware/server_registry.hpp
Normal file
60
src/client/game/demonware/server_registry.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "servers/base_server.hpp"
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class server_registry
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<base_server, T>::value, "Invalid server registry type");
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename S, typename ...Args>
|
||||||
|
void create(Args&&... args)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<T, S>::value, "Invalid server type");
|
||||||
|
|
||||||
|
auto server = std::make_unique<S>(std::forward<Args>(args)...);
|
||||||
|
const auto address = server->get_address();
|
||||||
|
servers_[address] = std::move(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_each(const std::function<void(T&)>& callback) const
|
||||||
|
{
|
||||||
|
for (auto& server : servers_)
|
||||||
|
{
|
||||||
|
callback(*server.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T* find(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto address = utils::cryptography::jenkins_one_at_a_time::compute(name);
|
||||||
|
return find(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
T* find(const uint32_t address)
|
||||||
|
{
|
||||||
|
const auto it = servers_.find(address);
|
||||||
|
if (it == servers_.end())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void frame()
|
||||||
|
{
|
||||||
|
for (auto& server : servers_)
|
||||||
|
{
|
||||||
|
server.second->frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<uint32_t, std::unique_ptr<T>> servers_;
|
||||||
|
};
|
||||||
|
}
|
168
src/client/game/demonware/servers/auth3_server.cpp
Normal file
168
src/client/game/demonware/servers/auth3_server.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
|
||||||
|
#include "auth3_server.hpp"
|
||||||
|
#include "../keys.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct auth_ticket
|
||||||
|
{
|
||||||
|
unsigned int m_magicNumber;
|
||||||
|
char m_type;
|
||||||
|
unsigned int m_titleID;
|
||||||
|
unsigned int m_timeIssued;
|
||||||
|
unsigned int m_timeExpires;
|
||||||
|
unsigned __int64 m_licenseID;
|
||||||
|
unsigned __int64 m_userID;
|
||||||
|
char m_username[64];
|
||||||
|
char m_sessionKey[24];
|
||||||
|
char m_usingHashMagicNumber[3];
|
||||||
|
char m_hash[4];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
}
|
||||||
|
|
||||||
|
void auth3_server::send_reply(reply* data)
|
||||||
|
{
|
||||||
|
if (!data) return;
|
||||||
|
this->send(data->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void auth3_server::handle(const std::string& packet)
|
||||||
|
{
|
||||||
|
if (packet.starts_with("POST /auth/"))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [auth]: user requested authentication.\n");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int title_id = 0;
|
||||||
|
unsigned int iv_seed = 0;
|
||||||
|
std::string identity{};
|
||||||
|
std::string token{};
|
||||||
|
|
||||||
|
rapidjson::Document j;
|
||||||
|
j.Parse(packet.data(), packet.size());
|
||||||
|
|
||||||
|
if (j.HasMember("title_id") && j["title_id"].IsString())
|
||||||
|
{
|
||||||
|
title_id = std::stoul(j["title_id"].GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j.HasMember("iv_seed") && j["iv_seed"].IsString())
|
||||||
|
{
|
||||||
|
iv_seed = std::stoul(j["iv_seed"].GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j.HasMember("identity") && j["identity"].IsString())
|
||||||
|
{
|
||||||
|
identity = j["identity"].GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j.HasMember("extra_data") && j["extra_data"].IsString())
|
||||||
|
{
|
||||||
|
rapidjson::Document extra_data;
|
||||||
|
auto& ed = j["extra_data"];
|
||||||
|
extra_data.Parse(ed.GetString(), ed.GetStringLength());
|
||||||
|
|
||||||
|
if (extra_data.HasMember("token") && extra_data["token"].IsString())
|
||||||
|
{
|
||||||
|
auto& token_field = extra_data["token"];
|
||||||
|
std::string token_b64(token_field.GetString(), token_field.GetStringLength());
|
||||||
|
token = utils::cryptography::base64::decode(token_b64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [auth]: authenticating user %s\n", token.data() + 64);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string auth_key(reinterpret_cast<char*>(token.data() + 32), 24);
|
||||||
|
std::string session_key(
|
||||||
|
"\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24);
|
||||||
|
|
||||||
|
// client_ticket
|
||||||
|
auth_ticket ticket{};
|
||||||
|
std::memset(&ticket, 0x0, sizeof ticket);
|
||||||
|
ticket.m_magicNumber = 0x0EFBDADDE;
|
||||||
|
ticket.m_type = 0;
|
||||||
|
ticket.m_titleID = title_id;
|
||||||
|
ticket.m_timeIssued = static_cast<uint32_t>(time(nullptr));
|
||||||
|
ticket.m_timeExpires = ticket.m_timeIssued + 30000;
|
||||||
|
ticket.m_licenseID = 0;
|
||||||
|
ticket.m_userID = reinterpret_cast<uint64_t>(token.data() + 56);
|
||||||
|
strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast<char*>(token.data() + 64), 64);
|
||||||
|
std::memcpy(ticket.m_sessionKey, session_key.data(), 24);
|
||||||
|
|
||||||
|
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv_seed), 4));
|
||||||
|
const auto ticket_enc = utils::cryptography::des3::encrypt(
|
||||||
|
std::string(reinterpret_cast<char*>(&ticket), sizeof(ticket)), iv, auth_key);
|
||||||
|
const auto ticket_b64 = utils::cryptography::base64::encode(
|
||||||
|
reinterpret_cast<const unsigned char*>(ticket_enc.data()), 128);
|
||||||
|
|
||||||
|
// server_ticket
|
||||||
|
uint8_t auth_data[128];
|
||||||
|
std::memset(&auth_data, 0, sizeof auth_data);
|
||||||
|
std::memcpy(auth_data, session_key.data(), 24);
|
||||||
|
const auto auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128);
|
||||||
|
|
||||||
|
demonware::set_session_key(session_key);
|
||||||
|
|
||||||
|
// header time
|
||||||
|
char date[64];
|
||||||
|
const auto now = time(nullptr);
|
||||||
|
tm gmtm{};
|
||||||
|
gmtime_s(&gmtm, &now);
|
||||||
|
strftime(date, 64, "%a, %d %b %G %T", &gmtm);
|
||||||
|
|
||||||
|
// json content
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.SetObject();
|
||||||
|
|
||||||
|
doc.AddMember("auth_task", "29", doc.GetAllocator());
|
||||||
|
doc.AddMember("code", "700", doc.GetAllocator());
|
||||||
|
|
||||||
|
auto seed = std::to_string(iv_seed);
|
||||||
|
doc.AddMember("iv_seed", rapidjson::StringRef(seed.data(), seed.size()), doc.GetAllocator());
|
||||||
|
doc.AddMember("client_ticket", rapidjson::StringRef(ticket_b64.data(), ticket_b64.size()), doc.GetAllocator());
|
||||||
|
doc.AddMember("server_ticket", rapidjson::StringRef(auth_data_b64.data(), auth_data_b64.size()),
|
||||||
|
doc.GetAllocator());
|
||||||
|
doc.AddMember("client_id", "", doc.GetAllocator());
|
||||||
|
doc.AddMember("account_type", "steam", doc.GetAllocator());
|
||||||
|
doc.AddMember("crossplay_enabled", false, doc.GetAllocator());
|
||||||
|
doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator());
|
||||||
|
|
||||||
|
rapidjson::Value value{};
|
||||||
|
doc.AddMember("lsg_endpoint", value, doc.GetAllocator());
|
||||||
|
|
||||||
|
rapidjson::StringBuffer buffer{};
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<>>
|
||||||
|
writer(buffer);
|
||||||
|
doc.Accept(writer);
|
||||||
|
|
||||||
|
// http stuff
|
||||||
|
std::string result;
|
||||||
|
result.append("HTTP/1.1 200 OK\r\n");
|
||||||
|
result.append("Server: TornadoServer/4.5.3\r\n");
|
||||||
|
result.append("Content-Type: application/json\r\n");
|
||||||
|
result.append(utils::string::va("Date: %s GMT\r\n", date));
|
||||||
|
result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength()));
|
||||||
|
result.append(buffer.GetString(), buffer.GetLength());
|
||||||
|
|
||||||
|
raw_reply reply(result);
|
||||||
|
|
||||||
|
this->send_reply(&reply);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [auth]: user successfully authenticated.\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
16
src/client/game/demonware/servers/auth3_server.hpp
Normal file
16
src/client/game/demonware/servers/auth3_server.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tcp_server.hpp"
|
||||||
|
#include "../reply.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class auth3_server : public tcp_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using tcp_server::tcp_server;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void send_reply(reply* data);
|
||||||
|
void handle(const std::string& packet) override;
|
||||||
|
};
|
||||||
|
}
|
22
src/client/game/demonware/servers/base_server.cpp
Normal file
22
src/client/game/demonware/servers/base_server.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "base_server.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
base_server::base_server(std::string name): name_(std::move(name))
|
||||||
|
{
|
||||||
|
this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& base_server::get_name() const
|
||||||
|
{
|
||||||
|
return this->name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t base_server::get_address() const
|
||||||
|
{
|
||||||
|
return this->address_;
|
||||||
|
}
|
||||||
|
}
|
30
src/client/game/demonware/servers/base_server.hpp
Normal file
30
src/client/game/demonware/servers/base_server.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class base_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using stream_queue = std::queue<char>;
|
||||||
|
using data_queue = std::queue<std::string>;
|
||||||
|
|
||||||
|
base_server(std::string name);
|
||||||
|
|
||||||
|
base_server(base_server&&) = delete;
|
||||||
|
base_server(const base_server&) = delete;
|
||||||
|
base_server& operator=(base_server&&) = delete;
|
||||||
|
base_server& operator=(const base_server&) = delete;
|
||||||
|
|
||||||
|
virtual ~base_server() = default;
|
||||||
|
|
||||||
|
const std::string& get_name() const;
|
||||||
|
|
||||||
|
uint32_t get_address() const;
|
||||||
|
|
||||||
|
virtual void frame() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
std::uint32_t address_ = 0;
|
||||||
|
};
|
||||||
|
}
|
178
src/client/game/demonware/servers/lobby_server.cpp
Normal file
178
src/client/game/demonware/servers/lobby_server.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "lobby_server.hpp"
|
||||||
|
|
||||||
|
#include "../services.hpp"
|
||||||
|
#include "../keys.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
lobby_server::lobby_server(std::string name) : tcp_server(std::move(name))
|
||||||
|
{
|
||||||
|
this->register_service<bdAnticheat>();
|
||||||
|
this->register_service<bdBandwidthTest>();
|
||||||
|
this->register_service<bdContentStreaming>();
|
||||||
|
this->register_service<bdDML>();
|
||||||
|
this->register_service<bdEventLog>();
|
||||||
|
this->register_service<bdGroups>();
|
||||||
|
this->register_service<bdStats>();
|
||||||
|
this->register_service<bdStorage>();
|
||||||
|
this->register_service<bdTitleUtilities>();
|
||||||
|
this->register_service<bdProfiles>();
|
||||||
|
this->register_service<bdRichPresence>();
|
||||||
|
this->register_service<bdFacebook>();
|
||||||
|
this->register_service<bdUNK63>();
|
||||||
|
this->register_service<bdUNK80>();
|
||||||
|
this->register_service<bdUNK95>();
|
||||||
|
this->register_service<bdPresence>();
|
||||||
|
this->register_service<bdMarketingComms>();
|
||||||
|
this->register_service<bdMatchMaking2>();
|
||||||
|
this->register_service<bdMarketing>();
|
||||||
|
};
|
||||||
|
|
||||||
|
void lobby_server::send_reply(reply* data)
|
||||||
|
{
|
||||||
|
if (!data) return;
|
||||||
|
this->send(data->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void lobby_server::handle(const std::string& packet)
|
||||||
|
{
|
||||||
|
byte_buffer buffer(packet);
|
||||||
|
buffer.set_use_data_types(false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (buffer.has_more_data())
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
buffer.read_int32(&size);
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
{
|
||||||
|
const std::string zero("\x00\x00\x00\x00", 4);
|
||||||
|
raw_reply reply(zero);
|
||||||
|
this->send_reply(&reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (size == 0xC8)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [lobby]: received client_header_ack.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int c8;
|
||||||
|
buffer.read_int32(&c8);
|
||||||
|
std::string packet_1 = buffer.get_remaining();
|
||||||
|
demonware::queue_packet_to_hash(packet_1);
|
||||||
|
|
||||||
|
const std::string packet_2(
|
||||||
|
"\x16\x00\x00\x00\xab\x81\xd2\x00\x00\x00\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37",
|
||||||
|
26);
|
||||||
|
demonware::queue_packet_to_hash(packet_2);
|
||||||
|
|
||||||
|
raw_reply reply(packet_2);
|
||||||
|
this->send_reply(&reply);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [lobby]: sending server_header_ack.\n");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.size() < size_t(size)) return;
|
||||||
|
|
||||||
|
uint8_t check_ab;
|
||||||
|
buffer.read_byte(&check_ab);
|
||||||
|
if (check_ab == 0xAB)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
buffer.read_byte(&type);
|
||||||
|
|
||||||
|
if (type == 0x82)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [lobby]: received client_auth.\n");
|
||||||
|
#endif
|
||||||
|
std::string packet_3(packet.data(), packet.size() - 8); // this 8 are client hash check?
|
||||||
|
|
||||||
|
demonware::queue_packet_to_hash(packet_3);
|
||||||
|
demonware::derive_keys_s1();
|
||||||
|
|
||||||
|
char buff[14] = "\x0A\x00\x00\x00\xAB\x83";
|
||||||
|
std::memcpy(&buff[6], demonware::get_response_id().data(), 8);
|
||||||
|
std::string response(buff, 14);
|
||||||
|
|
||||||
|
raw_reply reply(response);
|
||||||
|
this->send_reply(&reply);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [lobby]: sending server_auth_done.\n");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type == 0x85)
|
||||||
|
{
|
||||||
|
uint32_t msg_count;
|
||||||
|
buffer.read_uint32(&msg_count);
|
||||||
|
|
||||||
|
char seed[16];
|
||||||
|
buffer.read(16, &seed);
|
||||||
|
|
||||||
|
std::string enc = buffer.get_remaining();
|
||||||
|
|
||||||
|
char hash[8];
|
||||||
|
std::memcpy(hash, &(enc.data()[enc.size() - 8]), 8);
|
||||||
|
|
||||||
|
std::string dec = utils::cryptography::aes::decrypt(
|
||||||
|
std::string(enc.data(), enc.size() - 8), std::string(seed, 16),
|
||||||
|
demonware::get_decrypt_key());
|
||||||
|
|
||||||
|
byte_buffer serv(dec);
|
||||||
|
serv.set_use_data_types(false);
|
||||||
|
|
||||||
|
uint32_t serv_size;
|
||||||
|
serv.read_uint32(&serv_size);
|
||||||
|
|
||||||
|
uint8_t magic; // 0x86
|
||||||
|
serv.read_byte(&magic);
|
||||||
|
|
||||||
|
uint8_t service_id;
|
||||||
|
serv.read_byte(&service_id);
|
||||||
|
|
||||||
|
this->call_service(service_id, serv.get_remaining());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[DW]: [lobby]: ERROR! received unk message.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lobby_server::call_service(const uint8_t id, const std::string& data)
|
||||||
|
{
|
||||||
|
const auto& it = this->services_.find(id);
|
||||||
|
|
||||||
|
if (it != this->services_.end())
|
||||||
|
{
|
||||||
|
it->second->exec_task(this, data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("[DW]: [lobby]: missing service '%s'\n", utils::string::va("%d", id));
|
||||||
|
|
||||||
|
// return no error
|
||||||
|
byte_buffer buffer(data);
|
||||||
|
uint8_t task_id;
|
||||||
|
buffer.read_byte(&task_id);
|
||||||
|
|
||||||
|
this->create_reply(task_id)->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/client/game/demonware/servers/lobby_server.hpp
Normal file
33
src/client/game/demonware/servers/lobby_server.hpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tcp_server.hpp"
|
||||||
|
#include "service_server.hpp"
|
||||||
|
#include "../service.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class lobby_server : public tcp_server, service_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lobby_server(std::string name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void register_service()
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<service, T>::value, "service must inherit from service");
|
||||||
|
|
||||||
|
auto service = std::make_unique<T>();
|
||||||
|
const uint8_t id = service->id();
|
||||||
|
|
||||||
|
this->services_[id] = std::move(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_reply(reply* data) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<uint8_t, std::unique_ptr<service>> services_;
|
||||||
|
|
||||||
|
void handle(const std::string& packet) override;
|
||||||
|
void call_service(uint8_t id, const std::string& data);
|
||||||
|
};
|
||||||
|
}
|
27
src/client/game/demonware/servers/service_server.hpp
Normal file
27
src/client/game/demonware/servers/service_server.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../reply.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class service_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~service_server() = default;
|
||||||
|
|
||||||
|
virtual std::shared_ptr<remote_reply> create_message(uint8_t type)
|
||||||
|
{
|
||||||
|
auto reply = std::make_shared<remote_reply>(this, type);
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual std::shared_ptr<service_reply> create_reply(uint8_t type, uint32_t error = 0)
|
||||||
|
{
|
||||||
|
auto reply = std::make_shared<service_reply>(this, type, error);
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void send_reply(reply* data) = 0;
|
||||||
|
};
|
||||||
|
}
|
62
src/client/game/demonware/servers/stun_server.cpp
Normal file
62
src/client/game/demonware/servers/stun_server.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "stun_server.hpp"
|
||||||
|
|
||||||
|
#include "../byte_buffer.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void stun_server::handle(const endpoint_data& endpoint, const std::string& packet)
|
||||||
|
{
|
||||||
|
uint8_t type, version, padding;
|
||||||
|
|
||||||
|
byte_buffer buffer(packet);
|
||||||
|
buffer.set_use_data_types(false);
|
||||||
|
buffer.read_byte(&type);
|
||||||
|
buffer.read_byte(&version);
|
||||||
|
buffer.read_byte(&padding);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 30:
|
||||||
|
this->ip_discovery(endpoint);
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
this->nat_discovery(endpoint);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stun_server::ip_discovery(const endpoint_data& endpoint)
|
||||||
|
{
|
||||||
|
const uint32_t ip = 0x0100007f;
|
||||||
|
|
||||||
|
byte_buffer buffer;
|
||||||
|
buffer.set_use_data_types(false);
|
||||||
|
buffer.write_byte(31); // type
|
||||||
|
buffer.write_byte(2); // version
|
||||||
|
buffer.write_byte(0); // version
|
||||||
|
buffer.write_uint32(ip); // external ip
|
||||||
|
buffer.write_uint16(3074); // port
|
||||||
|
|
||||||
|
this->send(endpoint, buffer.get_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void stun_server::nat_discovery(const endpoint_data& endpoint)
|
||||||
|
{
|
||||||
|
const uint32_t ip = 0x0100007f;
|
||||||
|
|
||||||
|
byte_buffer buffer;
|
||||||
|
buffer.set_use_data_types(false);
|
||||||
|
buffer.write_byte(21); // type
|
||||||
|
buffer.write_byte(2); // version
|
||||||
|
buffer.write_byte(0); // version
|
||||||
|
buffer.write_uint32(ip); // external ip
|
||||||
|
buffer.write_uint16(3074); // port
|
||||||
|
buffer.write_uint32(this->get_address()); // server ip
|
||||||
|
buffer.write_uint16(3074); // server port
|
||||||
|
|
||||||
|
this->send(endpoint, buffer.get_buffer());
|
||||||
|
}
|
||||||
|
}
|
18
src/client/game/demonware/servers/stun_server.hpp
Normal file
18
src/client/game/demonware/servers/stun_server.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "udp_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class stun_server : public udp_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using udp_server::udp_server;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle(const endpoint_data& endpoint, const std::string& packet) override;
|
||||||
|
|
||||||
|
void ip_discovery(const endpoint_data& endpoint);
|
||||||
|
void nat_discovery(const endpoint_data& endpoint);
|
||||||
|
};
|
||||||
|
}
|
84
src/client/game/demonware/servers/tcp_server.cpp
Normal file
84
src/client/game/demonware/servers/tcp_server.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "tcp_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void tcp_server::handle_input(const char* buf, size_t size)
|
||||||
|
{
|
||||||
|
in_queue_.access([&](data_queue& queue)
|
||||||
|
{
|
||||||
|
queue.emplace(buf, size);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t tcp_server::handle_output(char* buf, size_t size)
|
||||||
|
{
|
||||||
|
if (out_queue_.get_raw().empty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_queue_.access<size_t>([&](stream_queue& queue)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
if (queue.empty())
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = queue.front();
|
||||||
|
queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tcp_server::pending_data()
|
||||||
|
{
|
||||||
|
return !this->out_queue_.get_raw().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_server::frame()
|
||||||
|
{
|
||||||
|
if (this->in_queue_.get_raw().empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::string packet{};
|
||||||
|
const auto result = this->in_queue_.access<bool>([&](data_queue& queue)
|
||||||
|
{
|
||||||
|
if (queue.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->handle(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_server::send(const std::string& data)
|
||||||
|
{
|
||||||
|
out_queue_.access([&](stream_queue& queue)
|
||||||
|
{
|
||||||
|
for (const auto& val : data)
|
||||||
|
{
|
||||||
|
queue.push(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
27
src/client/game/demonware/servers/tcp_server.hpp
Normal file
27
src/client/game/demonware/servers/tcp_server.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_server.hpp"
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class tcp_server : public base_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using base_server::base_server;
|
||||||
|
|
||||||
|
void handle_input(const char* buf, size_t size);
|
||||||
|
size_t handle_output(char* buf, size_t size);
|
||||||
|
bool pending_data();
|
||||||
|
void frame() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void handle(const std::string& data) = 0;
|
||||||
|
|
||||||
|
void send(const std::string& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::concurrency::container<data_queue> in_queue_;
|
||||||
|
utils::concurrency::container<stream_queue> out_queue_;
|
||||||
|
};
|
||||||
|
}
|
103
src/client/game/demonware/servers/udp_server.cpp
Normal file
103
src/client/game/demonware/servers/udp_server.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "udp_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void udp_server::handle_input(const char* buf, size_t size, endpoint_data endpoint)
|
||||||
|
{
|
||||||
|
in_queue_.access([&](in_queue& queue)
|
||||||
|
{
|
||||||
|
in_packet p;
|
||||||
|
p.data = std::string{buf, size};
|
||||||
|
p.endpoint = std::move(endpoint);
|
||||||
|
|
||||||
|
queue.emplace(std::move(p));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t udp_server::handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen)
|
||||||
|
{
|
||||||
|
return out_queue_.access<size_t>([&](socket_queue_map& map) -> size_t
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry == map.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& queue = entry->second;
|
||||||
|
|
||||||
|
if (queue.empty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
|
||||||
|
const auto copy_size = std::min(size, data.data.size());
|
||||||
|
std::memcpy(buf, data.data.data(), copy_size);
|
||||||
|
std::memcpy(address, &data.address, sizeof(data.address));
|
||||||
|
*addrlen = sizeof(data.address);
|
||||||
|
|
||||||
|
return copy_size;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool udp_server::pending_data(SOCKET socket)
|
||||||
|
{
|
||||||
|
return this->out_queue_.access<bool>([&](const socket_queue_map& map)
|
||||||
|
{
|
||||||
|
const auto entry = map.find(socket);
|
||||||
|
if (entry == map.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !entry->second.empty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_server::send(const endpoint_data& endpoint, std::string data)
|
||||||
|
{
|
||||||
|
out_queue_.access([&](socket_queue_map& map)
|
||||||
|
{
|
||||||
|
out_packet p;
|
||||||
|
p.data = std::move(data);
|
||||||
|
p.address = endpoint.address;
|
||||||
|
|
||||||
|
map[endpoint.socket].emplace(std::move(p));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_server::frame()
|
||||||
|
{
|
||||||
|
if (this->in_queue_.get_raw().empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
in_packet packet{};
|
||||||
|
const auto result = this->in_queue_.access<bool>([&](in_queue& queue)
|
||||||
|
{
|
||||||
|
if (queue.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->handle(packet.endpoint, std::move(packet.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/client/game/demonware/servers/udp_server.hpp
Normal file
62
src/client/game/demonware/servers/udp_server.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_server.hpp"
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class udp_server : public base_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct endpoint_data
|
||||||
|
{
|
||||||
|
SOCKET socket{};
|
||||||
|
sockaddr_in address{};
|
||||||
|
|
||||||
|
endpoint_data() = default;
|
||||||
|
|
||||||
|
endpoint_data(const SOCKET sock, const sockaddr* addr, const int size)
|
||||||
|
{
|
||||||
|
if (size != sizeof(this->address))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid size");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->socket = sock;
|
||||||
|
std::memcpy(&this->address, addr, sizeof(this->address));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using base_server::base_server;
|
||||||
|
|
||||||
|
void handle_input(const char* buf, size_t size, endpoint_data endpoint);
|
||||||
|
size_t handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen);
|
||||||
|
bool pending_data(SOCKET socket);
|
||||||
|
|
||||||
|
void frame() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void handle(const endpoint_data& endpoint, const std::string& data) = 0;
|
||||||
|
void send(const endpoint_data& endpoint, std::string data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct in_packet
|
||||||
|
{
|
||||||
|
std::string data;
|
||||||
|
endpoint_data endpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct out_packet
|
||||||
|
{
|
||||||
|
std::string data;
|
||||||
|
sockaddr_in address;
|
||||||
|
};
|
||||||
|
|
||||||
|
using in_queue = std::queue<in_packet>;
|
||||||
|
using out_queue = std::queue<out_packet>;
|
||||||
|
using socket_queue_map = std::unordered_map<SOCKET, out_queue>;
|
||||||
|
|
||||||
|
utils::concurrency::container<in_queue> in_queue_;
|
||||||
|
utils::concurrency::container<socket_queue_map> out_queue_;
|
||||||
|
};
|
||||||
|
}
|
11
src/client/game/demonware/servers/umbrella_server.cpp
Normal file
11
src/client/game/demonware/servers/umbrella_server.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
|
||||||
|
#include "umbrella_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void umbrella_server::handle(const std::string& packet)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/servers/umbrella_server.hpp
Normal file
14
src/client/game/demonware/servers/umbrella_server.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tcp_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class umbrella_server : public tcp_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using tcp_server::tcp_server;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle(const std::string& packet) override;
|
||||||
|
};
|
||||||
|
}
|
89
src/client/game/demonware/service.hpp
Normal file
89
src/client/game/demonware/service.hpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include "servers/service_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class service
|
||||||
|
{
|
||||||
|
using callback_t = std::function<void(service_server*, byte_buffer*)>;
|
||||||
|
|
||||||
|
uint8_t id_;
|
||||||
|
std::string name_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
uint8_t task_id_;
|
||||||
|
std::map<uint8_t, callback_t> tasks_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~service() = default;
|
||||||
|
service(service&&) = delete;
|
||||||
|
service(const service&) = delete;
|
||||||
|
service& operator=(const service&) = delete;
|
||||||
|
|
||||||
|
service(const uint8_t id, std::string name) : id_(id), name_(std::move(name)), task_id_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t id() const
|
||||||
|
{
|
||||||
|
return this->id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& name() const
|
||||||
|
{
|
||||||
|
return this->name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t task_id() const
|
||||||
|
{
|
||||||
|
return this->task_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void exec_task(service_server* server, const std::string& data)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->mutex_);
|
||||||
|
|
||||||
|
byte_buffer buffer(data);
|
||||||
|
|
||||||
|
buffer.read_byte(&this->task_id_);
|
||||||
|
|
||||||
|
const auto& it = this->tasks_.find(this->task_id_);
|
||||||
|
|
||||||
|
if (it != this->tasks_.end())
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW] %s: executing task '%d'\n", name_.data(), this->task_id_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
it->second(server, &buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("[DW] %s: missing task '%d'\n", name_.data(), this->task_id_);
|
||||||
|
|
||||||
|
// return no error
|
||||||
|
server->create_reply(this->task_id_)->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
template <typename Class, typename T, typename... Args>
|
||||||
|
void register_task(const uint8_t id, T (Class::* callback)(Args ...) const)
|
||||||
|
{
|
||||||
|
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||||
|
{
|
||||||
|
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Class, typename T, typename... Args>
|
||||||
|
void register_task(const uint8_t id, T (Class::* callback)(Args ...))
|
||||||
|
{
|
||||||
|
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||||
|
{
|
||||||
|
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
36
src/client/game/demonware/services.hpp
Normal file
36
src/client/game/demonware/services.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bit_buffer.hpp"
|
||||||
|
#include "byte_buffer.hpp"
|
||||||
|
#include "data_types.hpp"
|
||||||
|
#include "reply.hpp"
|
||||||
|
#include "service.hpp"
|
||||||
|
#include "servers/service_server.hpp"
|
||||||
|
|
||||||
|
//#include "services/bdTeams.hpp" // 3
|
||||||
|
#include "services/bdStats.hpp" // 4
|
||||||
|
//#include "services/bdMessaging.hpp" // 6
|
||||||
|
#include "services/bdProfiles.hpp" // 8
|
||||||
|
#include "services/bdStorage.hpp" // 10
|
||||||
|
#include "services/bdTitleUtilities.hpp" // 12
|
||||||
|
#include "services/bdBandwidthTest.hpp" // 18
|
||||||
|
//#include "services/bdMatchMaking.hpp" // 21
|
||||||
|
#include "services/bdCounters.hpp" // 23
|
||||||
|
#include "services/bdDML.hpp" // 27
|
||||||
|
#include "services/bdGroups.hpp" // 28
|
||||||
|
//#include "services/bdCMail.hpp" // 29
|
||||||
|
#include "services/bdFacebook.hpp" // 36
|
||||||
|
#include "services/bdAnticheat.hpp" // 38
|
||||||
|
#include "services/bdContentStreaming.hpp" // 50
|
||||||
|
//#include "services/bdTags.hpp" // 52
|
||||||
|
#include "services/bdUNK63.hpp" // 63
|
||||||
|
#include "services/bdEventLog.hpp" // 67
|
||||||
|
#include "services/bdRichPresence.hpp" // 68
|
||||||
|
//#include "services/bdTitleUtilities2.hpp" // 72
|
||||||
|
#include "services/bdUNK80.hpp"
|
||||||
|
#include "services/bdUNK95.hpp"
|
||||||
|
// AccountLinking // 86
|
||||||
|
#include "services/bdPresence.hpp" //103
|
||||||
|
#include "services/bdMarketingComms.hpp" //104
|
||||||
|
#include "services/bdMatchMaking2.hpp" //138
|
||||||
|
#include "services/bdMarketing.hpp" //139
|
25
src/client/game/demonware/services/bdAnticheat.cpp
Normal file
25
src/client/game/demonware/services/bdAnticheat.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdAnticheat::bdAnticheat() : service(38, "bdAnticheat")
|
||||||
|
{
|
||||||
|
this->register_task(2, &bdAnticheat::unk2);
|
||||||
|
this->register_task(4, &bdAnticheat::report_console_details);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdAnticheat::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO: Read data as soon as needed
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdAnticheat::report_console_details(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO: Read data as soon as needed
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdAnticheat.hpp
Normal file
14
src/client/game/demonware/services/bdAnticheat.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdAnticheat final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdAnticheat();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void report_console_details(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
27
src/client/game/demonware/services/bdBandwidthTest.cpp
Normal file
27
src/client/game/demonware/services/bdBandwidthTest.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
static uint8_t bandwidth_iw6[51] =
|
||||||
|
{
|
||||||
|
0x0F, 0xC1, 0x1C, 0x37, 0xB8, 0xEF, 0x7C, 0xD6, 0x00, 0x00, 0x04,
|
||||||
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0xD0, 0x07,
|
||||||
|
0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x88, 0x13, 0x00, 0x00, 0xF4, 0x01,
|
||||||
|
0x00, 0x00, 0x02, 0x0C, 0x88, 0xB3, 0x04, 0x65, 0x89, 0xBF, 0xC3, 0x6A,
|
||||||
|
0x27, 0x94, 0xD4, 0x8F
|
||||||
|
};
|
||||||
|
|
||||||
|
bdBandwidthTest::bdBandwidthTest() : service(18, "bdBandwidthTest")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdBandwidthTest::exec_task(service_server* server, const std::string& data)
|
||||||
|
{
|
||||||
|
byte_buffer buffer;
|
||||||
|
buffer.write(sizeof bandwidth_iw6, bandwidth_iw6);
|
||||||
|
|
||||||
|
auto reply = server->create_message(5);
|
||||||
|
reply->send(&buffer, true);
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdBandwidthTest.hpp
Normal file
13
src/client/game/demonware/services/bdBandwidthTest.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdBandwidthTest final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdBandwidthTest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void exec_task(service_server* server, const std::string& data) override;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdContentStreaming.cpp
Normal file
25
src/client/game/demonware/services/bdContentStreaming.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdContentStreaming::bdContentStreaming() : service(50, "bdContentStreaming")
|
||||||
|
{
|
||||||
|
this->register_task(2, &bdContentStreaming::unk2);
|
||||||
|
this->register_task(3, &bdContentStreaming::unk3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdContentStreaming::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdContentStreaming::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdContentStreaming.hpp
Normal file
14
src/client/game/demonware/services/bdContentStreaming.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdContentStreaming final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdContentStreaming();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdCounters.cpp
Normal file
25
src/client/game/demonware/services/bdCounters.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdCounters::bdCounters() : service(23, "bdCounters")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdCounters::unk1);
|
||||||
|
this->register_task(2, &bdCounters::unk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdCounters::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdCounters::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdCounters.hpp
Normal file
14
src/client/game/demonware/services/bdCounters.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdCounters final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdCounters();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
28
src/client/game/demonware/services/bdDML.cpp
Normal file
28
src/client/game/demonware/services/bdDML.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdDML::bdDML() : service(27, "bdDML")
|
||||||
|
{
|
||||||
|
this->register_task(2, &bdDML::get_user_raw_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdDML::get_user_raw_data(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
auto result = new bdDMLRawData;
|
||||||
|
result->country_code = "US";
|
||||||
|
result->country_code = "'Murica";
|
||||||
|
result->region = "New York";
|
||||||
|
result->city = "New York";
|
||||||
|
result->latitude = 0;
|
||||||
|
result->longitude = 0;
|
||||||
|
|
||||||
|
result->asn = 0x2119;
|
||||||
|
result->timezone = "+01:00";
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->add(result);
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdDML.hpp
Normal file
13
src/client/game/demonware/services/bdDML.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdDML final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdDML();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void get_user_raw_data(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
17
src/client/game/demonware/services/bdEventLog.cpp
Normal file
17
src/client/game/demonware/services/bdEventLog.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdEventLog::bdEventLog() : service(67, "bdEventLog")
|
||||||
|
{
|
||||||
|
this->register_task(6, &bdEventLog::unk6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdEventLog::unk6(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdEventLog.hpp
Normal file
13
src/client/game/demonware/services/bdEventLog.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdEventLog final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdEventLog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk6(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
41
src/client/game/demonware/services/bdFacebook.cpp
Normal file
41
src/client/game/demonware/services/bdFacebook.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdFacebook::bdFacebook() : service(36, "bdFacebook")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdFacebook::unk1);
|
||||||
|
this->register_task(3, &bdFacebook::unk3);
|
||||||
|
this->register_task(7, &bdFacebook::unk7);
|
||||||
|
this->register_task(8, &bdFacebook::unk8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdFacebook::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdFacebook::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdFacebook::unk7(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdFacebook::unk8(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
16
src/client/game/demonware/services/bdFacebook.hpp
Normal file
16
src/client/game/demonware/services/bdFacebook.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdFacebook final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdFacebook();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk7(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk8(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdGroups.cpp
Normal file
25
src/client/game/demonware/services/bdGroups.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdGroups::bdGroups() : service(28, "bdGroup")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdGroups::set_groups);
|
||||||
|
this->register_task(4, &bdGroups::unk4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdGroups::set_groups(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdGroups::unk4(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdGroups.hpp
Normal file
14
src/client/game/demonware/services/bdGroups.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdGroups final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdGroups();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_groups(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk4(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdMarketing.cpp
Normal file
25
src/client/game/demonware/services/bdMarketing.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdMarketing::bdMarketing() : service(139, "bdMarketing")
|
||||||
|
{
|
||||||
|
this->register_task(2, &bdMarketing::unk2);
|
||||||
|
this->register_task(3, &bdMarketing::unk3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMarketing::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMarketing::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdMarketing.hpp
Normal file
14
src/client/game/demonware/services/bdMarketing.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdMarketing final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdMarketing();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
17
src/client/game/demonware/services/bdMarketingComms.cpp
Normal file
17
src/client/game/demonware/services/bdMarketingComms.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdMarketingComms::bdMarketingComms() : service(104, "bdMarketingComms")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdMarketingComms::get_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMarketingComms::get_messages(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdMarketingComms.hpp
Normal file
13
src/client/game/demonware/services/bdMarketingComms.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdMarketingComms final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdMarketingComms();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void get_messages(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
57
src/client/game/demonware/services/bdMatchMaking2.cpp
Normal file
57
src/client/game/demonware/services/bdMatchMaking2.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdMatchMaking2::bdMatchMaking2() : service(138, "bdMatchMaking2")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdMatchMaking2::unk1);
|
||||||
|
this->register_task(2, &bdMatchMaking2::unk2);
|
||||||
|
this->register_task(3, &bdMatchMaking2::unk3);
|
||||||
|
this->register_task(5, &bdMatchMaking2::unk5);
|
||||||
|
this->register_task(10, &bdMatchMaking2::unk10);
|
||||||
|
this->register_task(16, &bdMatchMaking2::unk16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk5(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk10(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdMatchMaking2::unk16(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
18
src/client/game/demonware/services/bdMatchMaking2.hpp
Normal file
18
src/client/game/demonware/services/bdMatchMaking2.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdMatchMaking2 final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdMatchMaking2();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk5(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk10(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk16(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdPresence.cpp
Normal file
25
src/client/game/demonware/services/bdPresence.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdPresence::bdPresence() : service(103, "bdPresence")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdPresence::unk1);
|
||||||
|
this->register_task(3, &bdPresence::unk3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdPresence::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdPresence.hpp
Normal file
14
src/client/game/demonware/services/bdPresence.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdPresence final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdPresence();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
17
src/client/game/demonware/services/bdProfiles.cpp
Normal file
17
src/client/game/demonware/services/bdProfiles.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdProfiles::bdProfiles() : service(8, "bdProfiles")
|
||||||
|
{
|
||||||
|
this->register_task(3, &bdProfiles::unk3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdProfiles::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdProfiles.hpp
Normal file
13
src/client/game/demonware/services/bdProfiles.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdProfiles final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdProfiles();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
25
src/client/game/demonware/services/bdRichPresence.cpp
Normal file
25
src/client/game/demonware/services/bdRichPresence.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdRichPresence::bdRichPresence() : service(68, "bdRichPresence")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdRichPresence::unk1);
|
||||||
|
this->register_task(2, &bdRichPresence::unk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdRichPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdRichPresence::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
14
src/client/game/demonware/services/bdRichPresence.hpp
Normal file
14
src/client/game/demonware/services/bdRichPresence.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdRichPresence final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdRichPresence();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
49
src/client/game/demonware/services/bdStats.cpp
Normal file
49
src/client/game/demonware/services/bdStats.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdStats::bdStats() : service(4, "bdStats")
|
||||||
|
{
|
||||||
|
this->register_task(1, &bdStats::unk1);
|
||||||
|
this->register_task(3, &bdStats::unk3); // leaderboards
|
||||||
|
this->register_task(4, &bdStats::unk4);
|
||||||
|
this->register_task(8, &bdStats::unk8);
|
||||||
|
this->register_task(11, &bdStats::unk11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStats::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStats::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStats::unk4(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStats::unk8(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStats::unk11(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
17
src/client/game/demonware/services/bdStats.hpp
Normal file
17
src/client/game/demonware/services/bdStats.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdStats final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdStats();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk4(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk8(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk11(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
266
src/client/game/demonware/services/bdStorage.cpp
Normal file
266
src/client/game/demonware/services/bdStorage.cpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdStorage::bdStorage() : service(10, "bdStorage")
|
||||||
|
{
|
||||||
|
this->register_task(20, &bdStorage::list_publisher_files);
|
||||||
|
this->register_task(21, &bdStorage::get_publisher_file);
|
||||||
|
this->register_task(24, &bdStorage::set_user_file);
|
||||||
|
this->register_task(16, &bdStorage::get_user_file);
|
||||||
|
this->register_task(12, &bdStorage::unk12);
|
||||||
|
|
||||||
|
this->map_publisher_resource("motd-.*\\.txt", DW_MOTD);
|
||||||
|
// this->map_publisher_resource("ffotd-.*\\.ff", DW_FASTFILE);
|
||||||
|
this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::map_publisher_resource(const std::string& expression, const INT id)
|
||||||
|
{
|
||||||
|
auto data = utils::nt::load_resource(id);
|
||||||
|
this->map_publisher_resource_variant(expression, std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::map_publisher_resource_variant(const std::string& expression, resource_variant resource)
|
||||||
|
{
|
||||||
|
if (resource.valueless_by_exception())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Publisher resource variant is empty!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->publisher_resources_.emplace_back(std::regex{expression}, std::move(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bdStorage::load_publisher_resource(const std::string& name, std::string& buffer)
|
||||||
|
{
|
||||||
|
for (const auto& resource : this->publisher_resources_)
|
||||||
|
{
|
||||||
|
if (std::regex_match(name, resource.first))
|
||||||
|
{
|
||||||
|
if (std::holds_alternative<std::string>(resource.second))
|
||||||
|
{
|
||||||
|
buffer = std::get<std::string>(resource.second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer = std::get<callback>(resource.second)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: missing publisher file: %s\n", name.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::list_publisher_files(service_server* server, byte_buffer* buffer)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
utils::io::write_file("demonware/bdStorage/list_publisher_files", buffer->get_buffer());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t date;
|
||||||
|
uint16_t num_results, offset;
|
||||||
|
std::string unk, filename, data;
|
||||||
|
|
||||||
|
buffer->read_string(&unk);
|
||||||
|
buffer->read_uint32(&date);
|
||||||
|
buffer->read_uint16(&num_results);
|
||||||
|
buffer->read_uint16(&offset);
|
||||||
|
buffer->read_string(&filename);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: list publisher files: %s\n", filename.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
if (this->load_publisher_resource(filename, data))
|
||||||
|
{
|
||||||
|
auto* info = new bdFileInfo;
|
||||||
|
|
||||||
|
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||||
|
info->filename = filename;
|
||||||
|
info->create_time = 0;
|
||||||
|
info->modified_time = info->create_time;
|
||||||
|
info->file_size = uint32_t(data.size());
|
||||||
|
info->owner_id = 0;
|
||||||
|
info->priv = false;
|
||||||
|
|
||||||
|
reply->add(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::get_publisher_file(service_server* server, byte_buffer* buffer)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
utils::io::write_file("demonware/bdStorage/get_publisher_file", buffer->get_buffer());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string unk, filename;
|
||||||
|
buffer->read_string(&unk);
|
||||||
|
buffer->read_string(&filename);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: loading publisher file: %s\n", filename.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
if (this->load_publisher_resource(filename, data))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: sending publisher file: %s, size: %lld\n", filename.data(), data.size());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->add(new bdFileData(data));
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server->create_reply(this->task_id(), game::BD_NO_FILE)->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bdStorage::get_user_file_path(const std::string& name)
|
||||||
|
{
|
||||||
|
return "players2/user/" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::set_user_file(service_server* server, byte_buffer* buffer) const
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
utils::io::write_file("demonware/bdStorage/set_user_file", buffer->get_buffer());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t owner;
|
||||||
|
uint32_t numfiles;
|
||||||
|
std::string game, platform;
|
||||||
|
|
||||||
|
buffer->read_string(&game);
|
||||||
|
buffer->read_uint64(&owner);
|
||||||
|
buffer->read_string(&platform);
|
||||||
|
buffer->read_uint32(&numfiles);
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numfiles; i++)
|
||||||
|
{
|
||||||
|
std::string filename, data;
|
||||||
|
uint32_t unk;
|
||||||
|
bool priv;
|
||||||
|
|
||||||
|
buffer->read_string(&filename);
|
||||||
|
buffer->read_blob(&data);
|
||||||
|
buffer->read_uint32(&unk);
|
||||||
|
buffer->read_bool(&priv);
|
||||||
|
|
||||||
|
const auto path = get_user_file_path(filename);
|
||||||
|
utils::io::write_file(path, data);
|
||||||
|
|
||||||
|
auto* info = new bdFile2;
|
||||||
|
|
||||||
|
info->unk1 = 0;
|
||||||
|
info->unk2 = 0;
|
||||||
|
info->unk3 = 0;
|
||||||
|
info->priv = false;
|
||||||
|
info->owner_id = owner;
|
||||||
|
info->platform = platform;
|
||||||
|
info->filename = filename;
|
||||||
|
info->data = data;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: set user file: %s\n", filename.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
reply->add(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::get_user_file(service_server* server, byte_buffer* buffer) const
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
utils::io::write_file("demonware/bdStorage/get_user_file", buffer->get_buffer());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t unk32_0;
|
||||||
|
uint32_t numfiles, count = 0;
|
||||||
|
uint64_t owner;
|
||||||
|
std::string game, platform;
|
||||||
|
|
||||||
|
buffer->read_string(&game);
|
||||||
|
buffer->read_uint32(&unk32_0);
|
||||||
|
buffer->read_uint64(&owner);
|
||||||
|
buffer->read_string(&platform);
|
||||||
|
buffer->read_uint64(&owner);
|
||||||
|
buffer->read_string(&platform);
|
||||||
|
buffer->read_uint32(&numfiles);
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numfiles; i++)
|
||||||
|
{
|
||||||
|
std::string filename, data;
|
||||||
|
buffer->read_string(&filename);
|
||||||
|
|
||||||
|
const auto path = get_user_file_path(filename);
|
||||||
|
if (!utils::io::read_file(path, &data))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: get user file: missing file: %s, %s, %s\n", game.data(), filename.data(), platform.data());
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto response = new bdFile;
|
||||||
|
response->owner_id = owner;
|
||||||
|
response->unk = 0;
|
||||||
|
response->platform = platform;
|
||||||
|
response->filename = filename;
|
||||||
|
response->data = data;
|
||||||
|
|
||||||
|
reply->add(response);
|
||||||
|
++count;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[DW]: [bdStorage]: get user file: %s, %s, %s\n", game.data(), filename.data(), platform.data());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == numfiles)
|
||||||
|
{
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server->create_reply(this->task_id(), game::BD_NO_FILE)->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdStorage::unk12(service_server* server, byte_buffer* buffer) const
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
utils::io::write_file("demonware/bdStorage/unk12", buffer->get_buffer());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
27
src/client/game/demonware/services/bdStorage.hpp
Normal file
27
src/client/game/demonware/services/bdStorage.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdStorage final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdStorage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
using callback = std::function<std::string()>;
|
||||||
|
using resource_variant = std::variant<std::string, callback>;
|
||||||
|
std::vector<std::pair<std::regex, resource_variant>> publisher_resources_;
|
||||||
|
|
||||||
|
void map_publisher_resource(const std::string& expression, INT id);
|
||||||
|
void map_publisher_resource_variant(const std::string& expression, resource_variant resource);
|
||||||
|
bool load_publisher_resource(const std::string& name, std::string& buffer);
|
||||||
|
|
||||||
|
void list_publisher_files(service_server* server, byte_buffer* buffer);
|
||||||
|
void get_publisher_file(service_server* server, byte_buffer* buffer);
|
||||||
|
void set_user_file(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void get_user_file(service_server* server, byte_buffer* buffer) const;
|
||||||
|
void unk12(service_server* server, byte_buffer* buffer) const;
|
||||||
|
|
||||||
|
static std::string get_user_file_path(const std::string& name);
|
||||||
|
};
|
||||||
|
}
|
20
src/client/game/demonware/services/bdTitleUtilities.cpp
Normal file
20
src/client/game/demonware/services/bdTitleUtilities.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdTitleUtilities::bdTitleUtilities() : service(12, "bdTitleUtilities")
|
||||||
|
{
|
||||||
|
this->register_task(6, &bdTitleUtilities::get_server_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdTitleUtilities::get_server_time(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
auto* const time_result = new bdTimeStamp;
|
||||||
|
time_result->unix_time = uint32_t(time(nullptr));
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->add(time_result);
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdTitleUtilities.hpp
Normal file
13
src/client/game/demonware/services/bdTitleUtilities.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdTitleUtilities final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdTitleUtilities();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void get_server_time(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
17
src/client/game/demonware/services/bdUNK63.cpp
Normal file
17
src/client/game/demonware/services/bdUNK63.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdUNK63::bdUNK63() : service(63, "bdUNK63")
|
||||||
|
{
|
||||||
|
//this->register_task(6, "unk6", &bdUNK63::unk6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK63::unk(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
13
src/client/game/demonware/services/bdUNK63.hpp
Normal file
13
src/client/game/demonware/services/bdUNK63.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class bdUNK63 final : public service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bdUNK63();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unk(service_server* server, byte_buffer* buffer) const;
|
||||||
|
};
|
||||||
|
}
|
66
src/client/game/demonware/services/bdUNK80.cpp
Normal file
66
src/client/game/demonware/services/bdUNK80.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../services.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
bdUNK80::bdUNK80() : service(80, "bdUNK80")
|
||||||
|
{
|
||||||
|
this->register_task(42, &bdUNK80::unk42); // COD POINTS purchase ?
|
||||||
|
// this->register_task(43, &bdUNK80::unk43); COD POINTS purchase ?
|
||||||
|
this->register_task(49, &bdUNK80::unk49);
|
||||||
|
this->register_task(60, &bdUNK80::unk60);
|
||||||
|
this->register_task(130, &bdUNK80::unk130);
|
||||||
|
this->register_task(165, &bdUNK80::unk165);
|
||||||
|
this->register_task(193, &bdUNK80::unk193);
|
||||||
|
this->register_task(232, &bdUNK80::unk232);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk42(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk49(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk60(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk130(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk165(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk193(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdUNK80::unk232(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user