commit 215030f626ee7b2c5e9b9b6c61d4e4457f2f5472 Author: Jack Back Date: Mon Jan 15 12:14:55 2024 +0100 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..130a33a --- /dev/null +++ b/.gitignore @@ -0,0 +1,150 @@ +### Windows + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Shortcuts +*.lnk + +### OSX + +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Visual Studio + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +build + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +### IDA +*.id0 +*.id1 +*.id2 +*.nam +*.til + +### Custom user files +# User scripts +user*.bat + +# Premake binary +#premake5.exe \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..adeb262 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,37 @@ +[submodule "deps/asmjit"] + path = deps/asmjit + url = https://github.com/asmjit/asmjit.git +[submodule "deps/discord-rpc"] + path = deps/discord-rpc + url = https://git.alterware.dev/AlterWare/discord-rpc.git +[submodule "deps/gsc-tool"] + path = deps/gsc-tool + url = https://github.com/xensik/gsc-tool.git +[submodule "deps/GSL"] + path = deps/GSL + url = https://github.com/microsoft/GSL.git +[submodule "deps/libtomcrypt"] + path = deps/libtomcrypt + url = https://github.com/libtom/libtomcrypt.git +[submodule "deps/libtommath"] + path = deps/libtommath + url = https://github.com/libtom/libtommath.git +[submodule "deps/minhook"] + path = deps/minhook + url = https://github.com/TsudaKageyu/minhook.git +[submodule "deps/protobuf"] + path = deps/protobuf + url = https://github.com/protocolbuffers/protobuf.git + branch = 3.20.x +[submodule "deps/rapidjson"] + path = deps/rapidjson + url = https://github.com/Tencent/rapidjson.git +[submodule "deps/udis86"] + path = deps/udis86 + url = https://github.com/vmt/udis86.git +[submodule "deps/WinToast"] + path = deps/WinToast + url = https://github.com/mohabouje/WinToast.git +[submodule "deps/zlib"] + path = deps/zlib + url = https://github.com/madler/zlib.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f1e7d86 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# S1: Client + +This is a client modification for S1! +**NOTE**: You must legally own Call of Duty®: Advanced Warfare® to run this mod. Cracked/Pirated versions of the game are **NOT** supported. + +## Build +- Install [Visual Studio 2022][vs-link] and enable `Desktop development with C++` +- Install [Premake5][premake5-link] and add it to your system PATH +- Clone this repository using [Git][git-link] +- Update the submodules using ``git submodule update --init --recursive`` +- Run Premake with this options ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported. +- Build via solution file in `build\s1-mod.sln`. + +Only x64 is supported. Do not attempt to build for Windows ARM 64. + +### Premake arguments + +| Argument | Description | +|:----------------------------|:-----------------------------------------------| +| `--copy-to=PATH` | Optional, copy the EXE to a custom folder after build, define the path here if wanted. | +| `--dev-build` | Enable development builds of the client. | + +Contributions are welcome! Please follow the guidelines below: + +- Sign [AlterWare CLA][cla-link] and send a pull request or email your patch at patches@alterware.dev +- Make sure that PRs have only one commit, and deal with one issue only + +## Disclaimer + +This software has been created purely for the purposes of +academic research. It is not intended to be used to attack +other systems. Project maintainers are not responsible or +liable for misuse of the software. Use responsibly. + +[premake5-link]: https://premake.github.io +[git-link]: https://git-scm.com +[vs-link]: https://visualstudio.microsoft.com/vs +[cla-link]: https://alterware.dev/cla diff --git a/deps/GSL b/deps/GSL new file mode 160000 index 0000000..e64c97f --- /dev/null +++ b/deps/GSL @@ -0,0 +1 @@ +Subproject commit e64c97fc2cfc11992098bb38eda932de275e3f4d diff --git a/deps/WinToast b/deps/WinToast new file mode 160000 index 0000000..821c481 --- /dev/null +++ b/deps/WinToast @@ -0,0 +1 @@ +Subproject commit 821c4818ade1aa4da56ac753285c159ce26fd597 diff --git a/deps/asmjit b/deps/asmjit new file mode 160000 index 0000000..118ae6c --- /dev/null +++ b/deps/asmjit @@ -0,0 +1 @@ +Subproject commit 118ae6ced160f68dd142a0d758aa7efb4356196a diff --git a/deps/discord-rpc b/deps/discord-rpc new file mode 160000 index 0000000..963aa9f --- /dev/null +++ b/deps/discord-rpc @@ -0,0 +1 @@ +Subproject commit 963aa9f3e5ce81a4682c6ca3d136cddda614db33 diff --git a/deps/extra/udis86/libudis86/itab.c b/deps/extra/udis86/libudis86/itab.c new file mode 100644 index 0000000..953f3e5 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.c @@ -0,0 +1,5946 @@ +/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ +#include "decode.h" + +#define GROUP(n) (0x8000 | (n)) +#define INVALID 0 + + +const uint16_t ud_itab__0[] = { + /* 0 */ 15, 16, 17, 18, + /* 4 */ 19, 20, GROUP(1), GROUP(2), + /* 8 */ 964, 965, 966, 967, + /* c */ 968, 969, GROUP(3), GROUP(4), + /* 10 */ 5, 6, 7, 8, + /* 14 */ 9, 10, GROUP(284), GROUP(285), + /* 18 */ 1336, 1337, 1338, 1339, + /* 1c */ 1340, 1341, GROUP(286), GROUP(287), + /* 20 */ 49, 50, 51, 52, + /* 24 */ 53, 54, INVALID, GROUP(288), + /* 28 */ 1407, 1408, 1409, 1410, + /* 2c */ 1411, 1412, INVALID, GROUP(289), + /* 30 */ 1487, 1488, 1489, 1490, + /* 34 */ 1491, 1492, INVALID, GROUP(290), + /* 38 */ 100, 101, 102, 103, + /* 3c */ 104, 105, INVALID, GROUP(291), + /* 40 */ 699, 700, 701, 702, + /* 44 */ 703, 704, 705, 706, + /* 48 */ 175, 176, 177, 178, + /* 4c */ 179, 180, 181, 182, + /* 50 */ 1246, 1247, 1248, 1249, + /* 54 */ 1250, 1251, 1252, 1253, + /* 58 */ 1101, 1102, 1103, 1104, + /* 5c */ 1105, 1106, 1107, 1108, + /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ 1254, 697, 1256, 698, + /* 6c */ 709, GROUP(300), 982, GROUP(301), + /* 70 */ 726, 728, 730, 732, + /* 74 */ 734, 736, 738, 740, + /* 78 */ 742, 744, 746, 748, + /* 7c */ 750, 752, 754, 756, + /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313), + /* 84 */ 1433, 1434, 1475, 1476, + /* 88 */ 828, 829, 830, 831, + /* 8c */ 832, 770, 833, GROUP(314), + /* 90 */ 1477, 1478, 1479, 1480, + /* 94 */ 1481, 1482, 1483, 1484, + /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1470, + /* 9c */ GROUP(318), GROUP(322), 1310, 766, + /* a0 */ 834, 835, 836, 837, + /* a4 */ 922, GROUP(326), 114, GROUP(327), + /* a8 */ 1435, 1436, 1402, GROUP(328), + /* ac */ 790, GROUP(329), 1346, GROUP(330), + /* b0 */ 838, 839, 840, 841, + /* b4 */ 842, 843, 844, 845, + /* b8 */ 846, 847, 848, 849, + /* bc */ 850, 851, 852, 853, + /* c0 */ GROUP(331), GROUP(332), 1301, 1302, + /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406), + /* c8 */ 200, 776, 1303, 1304, + /* cc */ 713, 714, GROUP(407), GROUP(408), + /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412), + /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1486, + /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425), + /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437), + /* e0 */ 794, 795, 796, GROUP(440), + /* e4 */ 690, 691, 978, 979, + /* e8 */ 72, 763, GROUP(441), 765, + /* ec */ 692, 693, 980, 981, + /* f0 */ 789, 712, 1299, 1300, + /* f4 */ 687, 83, GROUP(442), GROUP(443), + /* f8 */ 77, 1395, 81, 1398, + /* fc */ 78, 1396, GROUP(444), GROUP(445), +}; + +static const uint16_t ud_itab__1[] = { + /* 0 */ 1240, INVALID, +}; + +static const uint16_t ud_itab__2[] = { + /* 0 */ 1096, INVALID, +}; + +static const uint16_t ud_itab__3[] = { + /* 0 */ 1241, INVALID, +}; + +static const uint16_t ud_itab__4[] = { + /* 0 */ GROUP(5), GROUP(6), 767, 797, + /* 4 */ INVALID, 1426, 82, 1431, + /* 8 */ 716, 1471, INVALID, 1444, + /* c */ INVALID, GROUP(27), 430, GROUP(28), + /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34), + /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40), + /* 18 */ GROUP(41), 955, 956, 957, + /* 1c */ 958, 959, 960, 961, + /* 20 */ 854, 855, 856, 857, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45), + /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49), + /* 30 */ 1472, 1297, 1295, 1296, + /* 34 */ GROUP(50), GROUP(52), INVALID, 1514, + /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 84, 85, 86, 87, + /* 44 */ 88, 89, 90, 91, + /* 48 */ 92, 93, 94, 95, + /* 4c */ 96, 97, 98, 99, + /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146), + /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150), + /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154), + /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158), + /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162), + /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166), + /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170), + /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176), + /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186), + /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199, + /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID, + /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201), + /* 80 */ 727, 729, 731, 733, + /* 84 */ 735, 737, 739, 741, + /* 88 */ 743, 745, 747, 749, + /* 8c */ 751, 753, 755, 757, + /* 90 */ 1350, 1351, 1352, 1353, + /* 94 */ 1354, 1355, 1356, 1357, + /* 98 */ 1358, 1359, 1360, 1361, + /* 9c */ 1362, 1363, 1364, 1365, + /* a0 */ 1245, 1100, 131, 1670, + /* a4 */ 1375, 1376, GROUP(202), GROUP(207), + /* a8 */ 1244, 1099, 1305, 1675, + /* ac */ 1377, 1378, GROUP(215), 694, + /* b0 */ 122, 123, 775, 1673, + /* b4 */ 772, 773, 940, 941, + /* b8 */ GROUP(221), INVALID, GROUP(222), 1671, + /* bc */ 1659, 1660, 930, 931, + /* c0 */ 1473, 1474, GROUP(223), 904, + /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227), + /* c8 */ 1661, 1662, 1663, 1664, + /* cc */ 1665, 1666, 1667, 1668, + /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239), + /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243), + /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247), + /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251), + /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255), + /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259), + /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263), + /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267), + /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271), + /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275), + /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280), + /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID, +}; + +static const uint16_t ud_itab__5[] = { + /* 0 */ 1384, 1406, 786, 798, + /* 4 */ 1453, 1454, INVALID, INVALID, +}; + +static const uint16_t ud_itab__6[] = { + /* 0 */ GROUP(7), GROUP(8), +}; + +static const uint16_t ud_itab__7[] = { + /* 0 */ 1374, 1383, 785, 774, + /* 4 */ 1385, INVALID, 787, 719, +}; + +static const uint16_t ud_itab__8[] = { + /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16), + /* 4 */ 1386, INVALID, 788, GROUP(25), +}; + +static const uint16_t ud_itab__9[] = { + /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12), + /* 4 */ GROUP(13), INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__10[] = { + /* 0 */ INVALID, 1455, INVALID, +}; + +static const uint16_t ud_itab__11[] = { + /* 0 */ INVALID, 1461, INVALID, +}; + +static const uint16_t ud_itab__12[] = { + /* 0 */ INVALID, 1462, INVALID, +}; + +static const uint16_t ud_itab__13[] = { + /* 0 */ INVALID, 1463, INVALID, +}; + +static const uint16_t ud_itab__14[] = { + /* 0 */ 824, 952, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__15[] = { + /* 0 */ 1485, 1508, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__16[] = { + /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20), + /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24), +}; + +static const uint16_t ud_itab__17[] = { + /* 0 */ 1466, INVALID, INVALID, +}; + +static const uint16_t ud_itab__18[] = { + /* 0 */ 1467, INVALID, INVALID, +}; + +static const uint16_t ud_itab__19[] = { + /* 0 */ 1468, INVALID, INVALID, +}; + +static const uint16_t ud_itab__20[] = { + /* 0 */ 1469, INVALID, INVALID, +}; + +static const uint16_t ud_itab__21[] = { + /* 0 */ 1397, INVALID, INVALID, +}; + +static const uint16_t ud_itab__22[] = { + /* 0 */ 80, INVALID, INVALID, +}; + +static const uint16_t ud_itab__23[] = { + /* 0 */ 1399, INVALID, INVALID, +}; + +static const uint16_t ud_itab__24[] = { + /* 0 */ 720, INVALID, INVALID, +}; + +static const uint16_t ud_itab__25[] = { + /* 0 */ 1425, GROUP(26), INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__26[] = { + /* 0 */ 1298, INVALID, INVALID, +}; + +static const uint16_t ud_itab__27[] = { + /* 0 */ 1119, 1120, 1121, 1122, + /* 4 */ 1123, 1124, 1125, 1126, +}; + +static const uint16_t ud_itab__28[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ 1216, 1217, INVALID, INVALID, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ 1218, 1219, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, 1220, INVALID, + /* 8c */ INVALID, INVALID, 1221, INVALID, + /* 90 */ 1222, INVALID, INVALID, INVALID, + /* 94 */ 1223, INVALID, 1224, 1225, + /* 98 */ INVALID, INVALID, 1226, INVALID, + /* 9c */ INVALID, INVALID, 1227, INVALID, + /* a0 */ 1228, INVALID, INVALID, INVALID, + /* a4 */ 1229, INVALID, 1230, 1231, + /* a8 */ INVALID, INVALID, 1232, INVALID, + /* ac */ INVALID, INVALID, 1233, INVALID, + /* b0 */ 1234, INVALID, INVALID, INVALID, + /* b4 */ 1235, INVALID, 1236, 1237, + /* b8 */ INVALID, INVALID, INVALID, 1238, + /* bc */ INVALID, INVALID, INVALID, 1239, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__29[] = { + /* 0 */ 936, 925, 928, 932, +}; + +static const uint16_t ud_itab__30[] = { + /* 0 */ 938, 926, 929, 934, +}; + +static const uint16_t ud_itab__31[] = { + /* 0 */ GROUP(32), GROUP(33), +}; + +static const uint16_t ud_itab__32[] = { + /* 0 */ 892, 1563, 1571, 888, +}; + +static const uint16_t ud_itab__33[] = { + /* 0 */ 896, 1561, 1569, INVALID, +}; + +static const uint16_t ud_itab__34[] = { + /* 0 */ 894, INVALID, INVALID, 890, +}; + +static const uint16_t ud_itab__35[] = { + /* 0 */ 1449, INVALID, INVALID, 1451, +}; + +static const uint16_t ud_itab__36[] = { + /* 0 */ 1447, INVALID, INVALID, 1445, +}; + +static const uint16_t ud_itab__37[] = { + /* 0 */ GROUP(38), GROUP(39), +}; + +static const uint16_t ud_itab__38[] = { + /* 0 */ 882, INVALID, 1567, 878, +}; + +static const uint16_t ud_itab__39[] = { + /* 0 */ 886, INVALID, 1565, INVALID, +}; + +static const uint16_t ud_itab__40[] = { + /* 0 */ 884, INVALID, INVALID, 880, +}; + +static const uint16_t ud_itab__41[] = { + /* 0 */ 1127, 1128, 1129, 1130, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__42[] = { + /* 0 */ 862, INVALID, INVALID, 858, +}; + +static const uint16_t ud_itab__43[] = { + /* 0 */ 864, INVALID, INVALID, 860, +}; + +static const uint16_t ud_itab__44[] = { + /* 0 */ 141, 152, 154, 142, +}; + +static const uint16_t ud_itab__45[] = { + /* 0 */ 907, INVALID, INVALID, 905, +}; + +static const uint16_t ud_itab__46[] = { + /* 0 */ 165, 166, 168, 162, +}; + +static const uint16_t ud_itab__47[] = { + /* 0 */ 147, 148, 158, 138, +}; + +static const uint16_t ud_itab__48[] = { + /* 0 */ 1442, INVALID, INVALID, 1440, +}; + +static const uint16_t ud_itab__49[] = { + /* 0 */ 129, INVALID, INVALID, 127, +}; + +static const uint16_t ud_itab__50[] = { + /* 0 */ 1427, GROUP(51), +}; + +static const uint16_t ud_itab__51[] = { + /* 0 */ INVALID, 1428, INVALID, +}; + +static const uint16_t ud_itab__52[] = { + /* 0 */ 1429, GROUP(53), +}; + +static const uint16_t ud_itab__53[] = { + /* 0 */ INVALID, 1430, INVALID, +}; + +static const uint16_t ud_itab__54[] = { + /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64), + /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90), + /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72), + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(73), INVALID, INVALID, INVALID, + /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID, + /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84), + /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID, + /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74), + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94), + /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97), + /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101), + /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105), + /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, GROUP(109), + /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__55[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(56), +}; + +static const uint16_t ud_itab__56[] = { + /* 0 */ GROUP(57), GROUP(58), +}; + +static const uint16_t ud_itab__57[] = { + /* 0 */ INVALID, 717, INVALID, +}; + +static const uint16_t ud_itab__58[] = { + /* 0 */ INVALID, 718, INVALID, +}; + +static const uint16_t ud_itab__59[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(60), +}; + +static const uint16_t ud_itab__60[] = { + /* 0 */ GROUP(61), GROUP(62), +}; + +static const uint16_t ud_itab__61[] = { + /* 0 */ INVALID, 721, INVALID, +}; + +static const uint16_t ud_itab__62[] = { + /* 0 */ INVALID, 722, INVALID, +}; + +static const uint16_t ud_itab__63[] = { + /* 0 */ 1588, INVALID, INVALID, 1589, +}; + +static const uint16_t ud_itab__64[] = { + /* 0 */ 1591, INVALID, INVALID, 1592, +}; + +static const uint16_t ud_itab__65[] = { + /* 0 */ 1594, INVALID, INVALID, 1595, +}; + +static const uint16_t ud_itab__66[] = { + /* 0 */ 1597, INVALID, INVALID, 1598, +}; + +static const uint16_t ud_itab__67[] = { + /* 0 */ 1582, INVALID, INVALID, 1583, +}; + +static const uint16_t ud_itab__68[] = { + /* 0 */ 1585, INVALID, INVALID, 1586, +}; + +static const uint16_t ud_itab__69[] = { + /* 0 */ 1606, INVALID, INVALID, 1607, +}; + +static const uint16_t ud_itab__70[] = { + /* 0 */ 1612, INVALID, INVALID, 1613, +}; + +static const uint16_t ud_itab__71[] = { + /* 0 */ 1609, INVALID, INVALID, 1610, +}; + +static const uint16_t ud_itab__72[] = { + /* 0 */ 1615, INVALID, INVALID, 1616, +}; + +static const uint16_t ud_itab__73[] = { + /* 0 */ INVALID, INVALID, INVALID, 1621, +}; + +static const uint16_t ud_itab__74[] = { + /* 0 */ INVALID, INVALID, INVALID, 1683, +}; + +static const uint16_t ud_itab__75[] = { + /* 0 */ INVALID, INVALID, INVALID, 1657, +}; + +static const uint16_t ud_itab__76[] = { + /* 0 */ INVALID, INVALID, INVALID, 1656, +}; + +static const uint16_t ud_itab__77[] = { + /* 0 */ INVALID, INVALID, INVALID, 1711, +}; + +static const uint16_t ud_itab__78[] = { + /* 0 */ 1573, INVALID, INVALID, 1574, +}; + +static const uint16_t ud_itab__79[] = { + /* 0 */ 1576, INVALID, INVALID, 1577, +}; + +static const uint16_t ud_itab__80[] = { + /* 0 */ 1579, INVALID, INVALID, 1580, +}; + +static const uint16_t ud_itab__81[] = { + /* 0 */ INVALID, INVALID, INVALID, 1685, +}; + +static const uint16_t ud_itab__82[] = { + /* 0 */ INVALID, INVALID, INVALID, 1687, +}; + +static const uint16_t ud_itab__83[] = { + /* 0 */ INVALID, INVALID, INVALID, 1689, +}; + +static const uint16_t ud_itab__84[] = { + /* 0 */ INVALID, INVALID, INVALID, 1691, +}; + +static const uint16_t ud_itab__85[] = { + /* 0 */ INVALID, INVALID, INVALID, 1693, +}; + +static const uint16_t ud_itab__86[] = { + /* 0 */ 1600, INVALID, INVALID, 1601, +}; + +static const uint16_t ud_itab__87[] = { + /* 0 */ INVALID, INVALID, INVALID, 1622, +}; + +static const uint16_t ud_itab__88[] = { + /* 0 */ INVALID, INVALID, INVALID, 1708, +}; + +static const uint16_t ud_itab__89[] = { + /* 0 */ INVALID, INVALID, INVALID, 1681, +}; + +static const uint16_t ud_itab__90[] = { + /* 0 */ 1603, INVALID, INVALID, 1604, +}; + +static const uint16_t ud_itab__91[] = { + /* 0 */ INVALID, INVALID, INVALID, 1696, +}; + +static const uint16_t ud_itab__92[] = { + /* 0 */ INVALID, INVALID, INVALID, 1698, +}; + +static const uint16_t ud_itab__93[] = { + /* 0 */ INVALID, INVALID, INVALID, 1700, +}; + +static const uint16_t ud_itab__94[] = { + /* 0 */ INVALID, INVALID, INVALID, 1702, +}; + +static const uint16_t ud_itab__95[] = { + /* 0 */ INVALID, INVALID, INVALID, 1704, +}; + +static const uint16_t ud_itab__96[] = { + /* 0 */ INVALID, INVALID, INVALID, 1706, +}; + +static const uint16_t ud_itab__97[] = { + /* 0 */ INVALID, INVALID, INVALID, 1717, +}; + +static const uint16_t ud_itab__98[] = { + /* 0 */ INVALID, INVALID, INVALID, 1624, +}; + +static const uint16_t ud_itab__99[] = { + /* 0 */ INVALID, INVALID, INVALID, 1626, +}; + +static const uint16_t ud_itab__100[] = { + /* 0 */ INVALID, INVALID, INVALID, 1628, +}; + +static const uint16_t ud_itab__101[] = { + /* 0 */ INVALID, INVALID, INVALID, 1630, +}; + +static const uint16_t ud_itab__102[] = { + /* 0 */ INVALID, INVALID, INVALID, 1632, +}; + +static const uint16_t ud_itab__103[] = { + /* 0 */ INVALID, INVALID, INVALID, 1634, +}; + +static const uint16_t ud_itab__104[] = { + /* 0 */ INVALID, INVALID, INVALID, 1638, +}; + +static const uint16_t ud_itab__105[] = { + /* 0 */ INVALID, INVALID, INVALID, 1636, +}; + +static const uint16_t ud_itab__106[] = { + /* 0 */ INVALID, INVALID, INVALID, 1640, +}; + +static const uint16_t ud_itab__107[] = { + /* 0 */ INVALID, INVALID, INVALID, 1642, +}; + +static const uint16_t ud_itab__108[] = { + /* 0 */ INVALID, INVALID, INVALID, 1695, +}; + +static const uint16_t ud_itab__109[] = { + /* 0 */ INVALID, INVALID, INVALID, 45, +}; + +static const uint16_t ud_itab__110[] = { + /* 0 */ INVALID, INVALID, INVALID, 41, +}; + +static const uint16_t ud_itab__111[] = { + /* 0 */ INVALID, INVALID, INVALID, 43, +}; + +static const uint16_t ud_itab__112[] = { + /* 0 */ INVALID, INVALID, INVALID, 37, +}; + +static const uint16_t ud_itab__113[] = { + /* 0 */ INVALID, INVALID, INVALID, 39, +}; + +static const uint16_t ud_itab__114[] = { + /* 0 */ 1723, 1725, INVALID, INVALID, +}; + +static const uint16_t ud_itab__115[] = { + /* 0 */ 1724, 1726, INVALID, INVALID, +}; + +static const uint16_t ud_itab__116[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120), + /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID, + /* 44 */ GROUP(137), INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, GROUP(138), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__117[] = { + /* 0 */ INVALID, INVALID, INVALID, 1644, +}; + +static const uint16_t ud_itab__118[] = { + /* 0 */ INVALID, INVALID, INVALID, 1646, +}; + +static const uint16_t ud_itab__119[] = { + /* 0 */ INVALID, INVALID, INVALID, 1648, +}; + +static const uint16_t ud_itab__120[] = { + /* 0 */ INVALID, INVALID, INVALID, 1650, +}; + +static const uint16_t ud_itab__121[] = { + /* 0 */ INVALID, INVALID, INVALID, 1654, +}; + +static const uint16_t ud_itab__122[] = { + /* 0 */ INVALID, INVALID, INVALID, 1652, +}; + +static const uint16_t ud_itab__123[] = { + /* 0 */ INVALID, INVALID, INVALID, 1677, +}; + +static const uint16_t ud_itab__124[] = { + /* 0 */ 1618, INVALID, INVALID, 1619, +}; + +static const uint16_t ud_itab__125[] = { + /* 0 */ INVALID, INVALID, INVALID, 1045, +}; + +static const uint16_t ud_itab__126[] = { + /* 0 */ INVALID, INVALID, INVALID, 1056, +}; + +static const uint16_t ud_itab__127[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(128), +}; + +static const uint16_t ud_itab__128[] = { + /* 0 */ 1047, 1049, 1051, +}; + +static const uint16_t ud_itab__129[] = { + /* 0 */ INVALID, INVALID, INVALID, 201, +}; + +static const uint16_t ud_itab__130[] = { + /* 0 */ INVALID, INVALID, INVALID, 1058, +}; + +static const uint16_t ud_itab__131[] = { + /* 0 */ INVALID, INVALID, INVALID, 1557, +}; + +static const uint16_t ud_itab__132[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(133), +}; + +static const uint16_t ud_itab__133[] = { + /* 0 */ 1062, 1063, 1064, +}; + +static const uint16_t ud_itab__134[] = { + /* 0 */ INVALID, INVALID, INVALID, 197, +}; + +static const uint16_t ud_itab__135[] = { + /* 0 */ INVALID, INVALID, INVALID, 195, +}; + +static const uint16_t ud_itab__136[] = { + /* 0 */ INVALID, INVALID, INVALID, 1679, +}; + +static const uint16_t ud_itab__137[] = { + /* 0 */ INVALID, INVALID, INVALID, 1512, +}; + +static const uint16_t ud_itab__138[] = { + /* 0 */ INVALID, INVALID, INVALID, 47, +}; + +static const uint16_t ud_itab__139[] = { + /* 0 */ INVALID, INVALID, INVALID, 1715, +}; + +static const uint16_t ud_itab__140[] = { + /* 0 */ INVALID, INVALID, INVALID, 1713, +}; + +static const uint16_t ud_itab__141[] = { + /* 0 */ INVALID, INVALID, INVALID, 1721, +}; + +static const uint16_t ud_itab__142[] = { + /* 0 */ INVALID, INVALID, INVALID, 1719, +}; + +static const uint16_t ud_itab__143[] = { + /* 0 */ 900, INVALID, INVALID, 898, +}; + +static const uint16_t ud_itab__144[] = { + /* 0 */ 1387, 1391, 1393, 1389, +}; + +static const uint16_t ud_itab__145[] = { + /* 0 */ 1306, INVALID, 1308, INVALID, +}; + +static const uint16_t ud_itab__146[] = { + /* 0 */ 1291, INVALID, 1293, INVALID, +}; + +static const uint16_t ud_itab__147[] = { + /* 0 */ 61, INVALID, INVALID, 59, +}; + +static const uint16_t ud_itab__148[] = { + /* 0 */ 65, INVALID, INVALID, 63, +}; + +static const uint16_t ud_itab__149[] = { + /* 0 */ 976, INVALID, INVALID, 974, +}; + +static const uint16_t ud_itab__150[] = { + /* 0 */ 1499, INVALID, INVALID, 1497, +}; + +static const uint16_t ud_itab__151[] = { + /* 0 */ 27, 29, 31, 25, +}; + +static const uint16_t ud_itab__152[] = { + /* 0 */ 946, 948, 950, 944, +}; + +static const uint16_t ud_itab__153[] = { + /* 0 */ 145, 150, 156, 139, +}; + +static const uint16_t ud_itab__154[] = { + /* 0 */ 134, INVALID, 163, 143, +}; + +static const uint16_t ud_itab__155[] = { + /* 0 */ 1419, 1421, 1423, 1417, +}; + +static const uint16_t ud_itab__156[] = { + /* 0 */ 818, 820, 822, 816, +}; + +static const uint16_t ud_itab__157[] = { + /* 0 */ 189, 191, 193, 187, +}; + +static const uint16_t ud_itab__158[] = { + /* 0 */ 802, 804, 806, 800, +}; + +static const uint16_t ud_itab__159[] = { + /* 0 */ 1209, INVALID, INVALID, 1207, +}; + +static const uint16_t ud_itab__160[] = { + /* 0 */ 1212, INVALID, INVALID, 1210, +}; + +static const uint16_t ud_itab__161[] = { + /* 0 */ 1215, INVALID, INVALID, 1213, +}; + +static const uint16_t ud_itab__162[] = { + /* 0 */ 987, INVALID, INVALID, 985, +}; + +static const uint16_t ud_itab__163[] = { + /* 0 */ 1038, INVALID, INVALID, 1036, +}; + +static const uint16_t ud_itab__164[] = { + /* 0 */ 1041, INVALID, INVALID, 1039, +}; + +static const uint16_t ud_itab__165[] = { + /* 0 */ 1044, INVALID, INVALID, 1042, +}; + +static const uint16_t ud_itab__166[] = { + /* 0 */ 993, INVALID, INVALID, 991, +}; + +static const uint16_t ud_itab__167[] = { + /* 0 */ 1200, INVALID, INVALID, 1198, +}; + +static const uint16_t ud_itab__168[] = { + /* 0 */ 1203, INVALID, INVALID, 1201, +}; + +static const uint16_t ud_itab__169[] = { + /* 0 */ 1206, INVALID, INVALID, 1204, +}; + +static const uint16_t ud_itab__170[] = { + /* 0 */ 990, INVALID, INVALID, 988, +}; + +static const uint16_t ud_itab__171[] = { + /* 0 */ INVALID, INVALID, INVALID, 1547, +}; + +static const uint16_t ud_itab__172[] = { + /* 0 */ INVALID, INVALID, INVALID, 1545, +}; + +static const uint16_t ud_itab__173[] = { + /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175), +}; + +static const uint16_t ud_itab__174[] = { + /* 0 */ 866, 867, 910, +}; + +static const uint16_t ud_itab__175[] = { + /* 0 */ 868, 870, 911, +}; + +static const uint16_t ud_itab__176[] = { + /* 0 */ 920, INVALID, 1522, 1517, +}; + +static const uint16_t ud_itab__177[] = { + /* 0 */ 1134, 1537, 1535, 1539, +}; + +static const uint16_t ud_itab__178[] = { + /* 0 */ INVALID, INVALID, GROUP(179), INVALID, + /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID, +}; + +static const uint16_t ud_itab__179[] = { + /* 0 */ 1159, INVALID, INVALID, 1163, +}; + +static const uint16_t ud_itab__180[] = { + /* 0 */ 1152, INVALID, INVALID, 1150, +}; + +static const uint16_t ud_itab__181[] = { + /* 0 */ 1138, INVALID, INVALID, 1137, +}; + +static const uint16_t ud_itab__182[] = { + /* 0 */ INVALID, INVALID, GROUP(183), INVALID, + /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID, +}; + +static const uint16_t ud_itab__183[] = { + /* 0 */ 1165, INVALID, INVALID, 1169, +}; + +static const uint16_t ud_itab__184[] = { + /* 0 */ 1153, INVALID, INVALID, 1157, +}; + +static const uint16_t ud_itab__185[] = { + /* 0 */ 1142, INVALID, INVALID, 1141, +}; + +static const uint16_t ud_itab__186[] = { + /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188), + /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190), +}; + +static const uint16_t ud_itab__187[] = { + /* 0 */ 1171, INVALID, INVALID, 1175, +}; + +static const uint16_t ud_itab__188[] = { + /* 0 */ INVALID, INVALID, INVALID, 1543, +}; + +static const uint16_t ud_itab__189[] = { + /* 0 */ 1146, INVALID, INVALID, 1145, +}; + +static const uint16_t ud_itab__190[] = { + /* 0 */ INVALID, INVALID, INVALID, 1541, +}; + +static const uint16_t ud_itab__191[] = { + /* 0 */ 1027, INVALID, INVALID, 1028, +}; + +static const uint16_t ud_itab__192[] = { + /* 0 */ 1030, INVALID, INVALID, 1031, +}; + +static const uint16_t ud_itab__193[] = { + /* 0 */ 1033, INVALID, INVALID, 1034, +}; + +static const uint16_t ud_itab__194[] = { + /* 0 */ INVALID, 1464, INVALID, +}; + +static const uint16_t ud_itab__195[] = { + /* 0 */ INVALID, 1465, INVALID, +}; + +static const uint16_t ud_itab__196[] = { + /* 0 */ INVALID, 1551, INVALID, 1549, +}; + +static const uint16_t ud_itab__197[] = { + /* 0 */ INVALID, 1555, INVALID, 1553, +}; + +static const uint16_t ud_itab__198[] = { + /* 0 */ GROUP(199), INVALID, 916, GROUP(200), +}; + +static const uint16_t ud_itab__199[] = { + /* 0 */ 872, 873, 913, +}; + +static const uint16_t ud_itab__200[] = { + /* 0 */ 874, 876, 914, +}; + +static const uint16_t ud_itab__201[] = { + /* 0 */ 921, INVALID, 1524, 1515, +}; + +static const uint16_t ud_itab__202[] = { + /* 0 */ INVALID, GROUP(203), +}; + +static const uint16_t ud_itab__203[] = { + /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__204[] = { + /* 0 */ 825, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__205[] = { + /* 0 */ 1509, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__206[] = { + /* 0 */ 1510, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__207[] = { + /* 0 */ INVALID, GROUP(208), +}; + +static const uint16_t ud_itab__208[] = { + /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212), + /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID, +}; + +static const uint16_t ud_itab__209[] = { + /* 0 */ 1511, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__210[] = { + /* 0 */ 1501, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__211[] = { + /* 0 */ 1502, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__212[] = { + /* 0 */ 1503, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__213[] = { + /* 0 */ 1504, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__214[] = { + /* 0 */ 1505, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__215[] = { + /* 0 */ GROUP(216), GROUP(217), +}; + +static const uint16_t ud_itab__216[] = { + /* 0 */ 683, 682, 768, 1400, + /* 4 */ 1507, 1506, INVALID, 79, +}; + +static const uint16_t ud_itab__217[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220), +}; + +static const uint16_t ud_itab__218[] = { + /* 0 */ 777, 778, 779, 780, + /* 4 */ 781, 782, 783, 784, +}; + +static const uint16_t ud_itab__219[] = { + /* 0 */ 808, 809, 810, 811, + /* 4 */ 812, 813, 814, 815, +}; + +static const uint16_t ud_itab__220[] = { + /* 0 */ 1366, 1367, 1368, 1369, + /* 4 */ 1370, 1371, 1372, 1373, +}; + +static const uint16_t ud_itab__221[] = { + /* 0 */ INVALID, INVALID, 1710, INVALID, +}; + +static const uint16_t ud_itab__222[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ 1669, 1676, 1674, 1672, +}; + +static const uint16_t ud_itab__223[] = { + /* 0 */ 112, 117, 120, 110, +}; + +static const uint16_t ud_itab__224[] = { + /* 0 */ 1059, INVALID, INVALID, 1060, +}; + +static const uint16_t ud_itab__225[] = { + /* 0 */ 1055, INVALID, INVALID, 1053, +}; + +static const uint16_t ud_itab__226[] = { + /* 0 */ 1381, INVALID, INVALID, 1379, +}; + +static const uint16_t ud_itab__227[] = { + /* 0 */ GROUP(228), GROUP(235), +}; + +static const uint16_t ud_itab__228[] = { + /* 0 */ INVALID, GROUP(229), INVALID, INVALID, + /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234), +}; + +static const uint16_t ud_itab__229[] = { + /* 0 */ 124, 125, 126, +}; + +static const uint16_t ud_itab__230[] = { + /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233), +}; + +static const uint16_t ud_itab__231[] = { + /* 0 */ INVALID, 1459, INVALID, +}; + +static const uint16_t ud_itab__232[] = { + /* 0 */ INVALID, 1458, INVALID, +}; + +static const uint16_t ud_itab__233[] = { + /* 0 */ INVALID, 1457, INVALID, +}; + +static const uint16_t ud_itab__234[] = { + /* 0 */ INVALID, 1460, INVALID, +}; + +static const uint16_t ud_itab__235[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, 1456, INVALID, +}; + +static const uint16_t ud_itab__236[] = { + /* 0 */ INVALID, 35, INVALID, 33, +}; + +static const uint16_t ud_itab__237[] = { + /* 0 */ 1160, INVALID, INVALID, 1161, +}; + +static const uint16_t ud_itab__238[] = { + /* 0 */ 1166, INVALID, INVALID, 1167, +}; + +static const uint16_t ud_itab__239[] = { + /* 0 */ 1172, INVALID, INVALID, 1173, +}; + +static const uint16_t ud_itab__240[] = { + /* 0 */ 1527, INVALID, INVALID, 1528, +}; + +static const uint16_t ud_itab__241[] = { + /* 0 */ 1093, INVALID, INVALID, 1094, +}; + +static const uint16_t ud_itab__242[] = { + /* 0 */ INVALID, 1521, 1526, 918, +}; + +static const uint16_t ud_itab__243[] = { + /* 0 */ 1086, INVALID, INVALID, 1084, +}; + +static const uint16_t ud_itab__244[] = { + /* 0 */ 1192, INVALID, INVALID, 1193, +}; + +static const uint16_t ud_itab__245[] = { + /* 0 */ 1195, INVALID, INVALID, 1196, +}; + +static const uint16_t ud_itab__246[] = { + /* 0 */ 1083, INVALID, INVALID, 1081, +}; + +static const uint16_t ud_itab__247[] = { + /* 0 */ 1017, INVALID, INVALID, 1015, +}; + +static const uint16_t ud_itab__248[] = { + /* 0 */ 1009, INVALID, INVALID, 1010, +}; + +static const uint16_t ud_itab__249[] = { + /* 0 */ 1012, INVALID, INVALID, 1013, +}; + +static const uint16_t ud_itab__250[] = { + /* 0 */ 1075, INVALID, INVALID, 1076, +}; + +static const uint16_t ud_itab__251[] = { + /* 0 */ 1020, INVALID, INVALID, 1018, +}; + +static const uint16_t ud_itab__252[] = { + /* 0 */ 1023, INVALID, INVALID, 1021, +}; + +static const uint16_t ud_itab__253[] = { + /* 0 */ 1147, INVALID, INVALID, 1148, +}; + +static const uint16_t ud_itab__254[] = { + /* 0 */ 1156, INVALID, INVALID, 1154, +}; + +static const uint16_t ud_itab__255[] = { + /* 0 */ 1026, INVALID, INVALID, 1024, +}; + +static const uint16_t ud_itab__256[] = { + /* 0 */ 1087, INVALID, INVALID, 1088, +}; + +static const uint16_t ud_itab__257[] = { + /* 0 */ 1092, INVALID, INVALID, 1090, +}; + +static const uint16_t ud_itab__258[] = { + /* 0 */ INVALID, 136, 132, 160, +}; + +static const uint16_t ud_itab__259[] = { + /* 0 */ 909, INVALID, INVALID, 902, +}; + +static const uint16_t ud_itab__260[] = { + /* 0 */ 1186, INVALID, INVALID, 1187, +}; + +static const uint16_t ud_itab__261[] = { + /* 0 */ 1189, INVALID, INVALID, 1190, +}; + +static const uint16_t ud_itab__262[] = { + /* 0 */ 1080, INVALID, INVALID, 1078, +}; + +static const uint16_t ud_itab__263[] = { + /* 0 */ 1118, INVALID, INVALID, 1116, +}; + +static const uint16_t ud_itab__264[] = { + /* 0 */ 1003, INVALID, INVALID, 1004, +}; + +static const uint16_t ud_itab__265[] = { + /* 0 */ 1006, INVALID, INVALID, 1007, +}; + +static const uint16_t ud_itab__266[] = { + /* 0 */ 1074, INVALID, INVALID, 1072, +}; + +static const uint16_t ud_itab__267[] = { + /* 0 */ 1266, INVALID, INVALID, 1264, +}; + +static const uint16_t ud_itab__268[] = { + /* 0 */ INVALID, 1559, INVALID, INVALID, +}; + +static const uint16_t ud_itab__269[] = { + /* 0 */ 1136, INVALID, INVALID, 1135, +}; + +static const uint16_t ud_itab__270[] = { + /* 0 */ 1140, INVALID, INVALID, 1139, +}; + +static const uint16_t ud_itab__271[] = { + /* 0 */ 1144, INVALID, INVALID, 1143, +}; + +static const uint16_t ud_itab__272[] = { + /* 0 */ 1533, INVALID, INVALID, 1534, +}; + +static const uint16_t ud_itab__273[] = { + /* 0 */ 1069, INVALID, INVALID, 1070, +}; + +static const uint16_t ud_itab__274[] = { + /* 0 */ 1133, INVALID, INVALID, 1131, +}; + +static const uint16_t ud_itab__275[] = { + /* 0 */ INVALID, GROUP(276), +}; + +static const uint16_t ud_itab__276[] = { + /* 0 */ 799, INVALID, INVALID, 1519, +}; + +static const uint16_t ud_itab__277[] = { + /* 0 */ 1179, INVALID, INVALID, 1177, +}; + +static const uint16_t ud_itab__278[] = { + /* 0 */ 1182, INVALID, INVALID, 1180, +}; + +static const uint16_t ud_itab__279[] = { + /* 0 */ 1183, INVALID, INVALID, 1184, +}; + +static const uint16_t ud_itab__280[] = { + /* 0 */ 1532, INVALID, INVALID, 1530, +}; + +static const uint16_t ud_itab__281[] = { + /* 0 */ 996, INVALID, INVALID, 994, +}; + +static const uint16_t ud_itab__282[] = { + /* 0 */ 997, INVALID, INVALID, 998, +}; + +static const uint16_t ud_itab__283[] = { + /* 0 */ 1000, INVALID, INVALID, 1001, +}; + +static const uint16_t ud_itab__284[] = { + /* 0 */ 1242, INVALID, +}; + +static const uint16_t ud_itab__285[] = { + /* 0 */ 1097, INVALID, +}; + +static const uint16_t ud_itab__286[] = { + /* 0 */ 1243, INVALID, +}; + +static const uint16_t ud_itab__287[] = { + /* 0 */ 1098, INVALID, +}; + +static const uint16_t ud_itab__288[] = { + /* 0 */ 173, INVALID, +}; + +static const uint16_t ud_itab__289[] = { + /* 0 */ 174, INVALID, +}; + +static const uint16_t ud_itab__290[] = { + /* 0 */ 1, INVALID, +}; + +static const uint16_t ud_itab__291[] = { + /* 0 */ 4, INVALID, +}; + +static const uint16_t ud_itab__292[] = { + /* 0 */ GROUP(293), GROUP(294), INVALID, +}; + +static const uint16_t ud_itab__293[] = { + /* 0 */ 1257, INVALID, +}; + +static const uint16_t ud_itab__294[] = { + /* 0 */ 1258, INVALID, +}; + +static const uint16_t ud_itab__295[] = { + /* 0 */ GROUP(296), GROUP(297), INVALID, +}; + +static const uint16_t ud_itab__296[] = { + /* 0 */ 1110, INVALID, +}; + +static const uint16_t ud_itab__297[] = { + /* 0 */ 1111, INVALID, +}; + +static const uint16_t ud_itab__298[] = { + /* 0 */ 1658, INVALID, +}; + +static const uint16_t ud_itab__299[] = { + /* 0 */ 67, 68, +}; + +static const uint16_t ud_itab__300[] = { + /* 0 */ 710, 711, INVALID, +}; + +static const uint16_t ud_itab__301[] = { + /* 0 */ 983, 984, INVALID, +}; + +static const uint16_t ud_itab__302[] = { + /* 0 */ 21, 970, 11, 1342, + /* 4 */ 55, 1413, 1493, 106, +}; + +static const uint16_t ud_itab__303[] = { + /* 0 */ 23, 971, 13, 1343, + /* 4 */ 57, 1414, 1494, 108, +}; + +static const uint16_t ud_itab__304[] = { + /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308), + /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312), +}; + +static const uint16_t ud_itab__305[] = { + /* 0 */ 22, INVALID, +}; + +static const uint16_t ud_itab__306[] = { + /* 0 */ 972, INVALID, +}; + +static const uint16_t ud_itab__307[] = { + /* 0 */ 12, INVALID, +}; + +static const uint16_t ud_itab__308[] = { + /* 0 */ 1344, INVALID, +}; + +static const uint16_t ud_itab__309[] = { + /* 0 */ 56, INVALID, +}; + +static const uint16_t ud_itab__310[] = { + /* 0 */ 1415, INVALID, +}; + +static const uint16_t ud_itab__311[] = { + /* 0 */ 1495, INVALID, +}; + +static const uint16_t ud_itab__312[] = { + /* 0 */ 107, INVALID, +}; + +static const uint16_t ud_itab__313[] = { + /* 0 */ 24, 973, 14, 1345, + /* 4 */ 58, 1416, 1496, 109, +}; + +static const uint16_t ud_itab__314[] = { + /* 0 */ 1109, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__315[] = { + /* 0 */ 74, 75, 76, +}; + +static const uint16_t ud_itab__316[] = { + /* 0 */ 170, 171, 172, +}; + +static const uint16_t ud_itab__317[] = { + /* 0 */ 73, INVALID, +}; + +static const uint16_t ud_itab__318[] = { + /* 0 */ GROUP(319), GROUP(320), GROUP(321), +}; + +static const uint16_t ud_itab__319[] = { + /* 0 */ 1259, 1260, +}; + +static const uint16_t ud_itab__320[] = { + /* 0 */ 1261, 1262, +}; + +static const uint16_t ud_itab__321[] = { + /* 0 */ INVALID, 1263, +}; + +static const uint16_t ud_itab__322[] = { + /* 0 */ GROUP(323), GROUP(324), GROUP(325), +}; + +static const uint16_t ud_itab__323[] = { + /* 0 */ 1112, INVALID, +}; + +static const uint16_t ud_itab__324[] = { + /* 0 */ 1113, 1114, +}; + +static const uint16_t ud_itab__325[] = { + /* 0 */ INVALID, 1115, +}; + +static const uint16_t ud_itab__326[] = { + /* 0 */ 923, 924, 927, +}; + +static const uint16_t ud_itab__327[] = { + /* 0 */ 115, 116, 119, +}; + +static const uint16_t ud_itab__328[] = { + /* 0 */ 1403, 1404, 1405, +}; + +static const uint16_t ud_itab__329[] = { + /* 0 */ 791, 792, 793, +}; + +static const uint16_t ud_itab__330[] = { + /* 0 */ 1347, 1348, 1349, +}; + +static const uint16_t ud_itab__331[] = { + /* 0 */ 1279, 1286, 1267, 1275, + /* 4 */ 1327, 1334, 1318, 1313, +}; + +static const uint16_t ud_itab__332[] = { + /* 0 */ 1284, 1287, 1268, 1274, + /* 4 */ 1323, 1330, 1319, 1315, +}; + +static const uint16_t ud_itab__333[] = { + /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__334[] = { + /* 0 */ 771, INVALID, +}; + +static const uint16_t ud_itab__335[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 937, 939, GROUP(336), 895, + /* 14 */ 1450, 1448, GROUP(337), 885, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 863, 865, INVALID, 908, + /* 2c */ INVALID, INVALID, 1443, 130, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 901, 1388, 1307, 1292, + /* 54 */ 62, 66, 977, 1500, + /* 58 */ 28, 947, 146, 135, + /* 5c */ 1420, 819, 190, 803, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, GROUP(340), + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, GROUP(338), INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 113, INVALID, + /* c4 */ INVALID, INVALID, 1382, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__336[] = { + /* 0 */ 893, 897, +}; + +static const uint16_t ud_itab__337[] = { + /* 0 */ 883, 887, +}; + +static const uint16_t ud_itab__338[] = { + /* 0 */ GROUP(339), INVALID, +}; + +static const uint16_t ud_itab__339[] = { + /* 0 */ INVALID, INVALID, INVALID, 1401, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__340[] = { + /* 0 */ 1742, 1743, +}; + +static const uint16_t ud_itab__341[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 933, 935, GROUP(342), 891, + /* 14 */ 1452, 1446, GROUP(343), 881, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 859, 861, INVALID, 906, + /* 2c */ INVALID, INVALID, 1441, 128, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 899, 1390, INVALID, INVALID, + /* 54 */ 60, 64, 975, 1498, + /* 58 */ 26, 945, 140, 144, + /* 5c */ 1418, 817, 188, 801, + /* 60 */ 1208, 1211, 1214, 986, + /* 64 */ 1037, 1040, 1043, 992, + /* 68 */ 1199, 1202, 1205, 989, + /* 6c */ 1548, 1546, GROUP(344), 1518, + /* 70 */ 1540, GROUP(345), GROUP(347), GROUP(349), + /* 74 */ 1029, 1032, 1035, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1550, 1554, GROUP(351), 1516, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 111, INVALID, + /* c4 */ 1061, 1054, 1380, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 34, 1162, 1168, 1174, + /* d4 */ 1529, 1095, 919, GROUP(352), + /* d8 */ 1194, 1197, 1082, 1016, + /* dc */ 1011, 1014, 1077, 1019, + /* e0 */ 1022, 1149, 1155, 1025, + /* e4 */ 1089, 1091, 161, 903, + /* e8 */ 1188, 1191, 1079, 1117, + /* ec */ 1005, 1008, 1073, 1265, + /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355), + /* f4 */ INVALID, 1071, 1132, GROUP(356), + /* f8 */ 1178, 1181, 1185, 1531, + /* fc */ 995, 999, 1002, INVALID, +}; + +static const uint16_t ud_itab__342[] = { + /* 0 */ 889, INVALID, +}; + +static const uint16_t ud_itab__343[] = { + /* 0 */ 879, INVALID, +}; + +static const uint16_t ud_itab__344[] = { + /* 0 */ 869, 871, 912, +}; + +static const uint16_t ud_itab__345[] = { + /* 0 */ INVALID, INVALID, 1164, INVALID, + /* 4 */ 1151, INVALID, GROUP(346), INVALID, +}; + +static const uint16_t ud_itab__346[] = { + /* 0 */ 1756, INVALID, +}; + +static const uint16_t ud_itab__347[] = { + /* 0 */ INVALID, INVALID, 1170, INVALID, + /* 4 */ 1158, INVALID, GROUP(348), INVALID, +}; + +static const uint16_t ud_itab__348[] = { + /* 0 */ 1758, INVALID, +}; + +static const uint16_t ud_itab__349[] = { + /* 0 */ INVALID, INVALID, 1176, 1544, + /* 4 */ INVALID, INVALID, GROUP(350), 1542, +}; + +static const uint16_t ud_itab__350[] = { + /* 0 */ 1760, INVALID, +}; + +static const uint16_t ud_itab__351[] = { + /* 0 */ 875, 877, 915, +}; + +static const uint16_t ud_itab__352[] = { + /* 0 */ 1085, INVALID, +}; + +static const uint16_t ud_itab__353[] = { + /* 0 */ 1755, INVALID, +}; + +static const uint16_t ud_itab__354[] = { + /* 0 */ 1757, INVALID, +}; + +static const uint16_t ud_itab__355[] = { + /* 0 */ 1759, INVALID, +}; + +static const uint16_t ud_itab__356[] = { + /* 0 */ INVALID, 1520, +}; + +static const uint16_t ud_itab__357[] = { + /* 0 */ 1584, 1587, 1590, 1593, + /* 4 */ 1596, 1599, 1602, 1605, + /* 8 */ 1608, 1614, 1611, 1617, + /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, 1712, + /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID, + /* 1c */ 1575, 1578, 1581, INVALID, + /* 20 */ 1686, 1688, 1690, 1692, + /* 24 */ 1694, INVALID, INVALID, INVALID, + /* 28 */ 1623, 1709, 1682, 1684, + /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368), + /* 30 */ 1697, 1699, 1701, 1703, + /* 34 */ 1705, 1707, INVALID, 1718, + /* 38 */ 1625, 1627, 1629, 1631, + /* 3c */ 1633, 1635, 1639, 1637, + /* 40 */ 1641, 1643, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, 46, + /* dc */ 42, 44, 38, 40, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__358[] = { + /* 0 */ 1737, INVALID, +}; + +static const uint16_t ud_itab__359[] = { + /* 0 */ 1735, INVALID, +}; + +static const uint16_t ud_itab__360[] = { + /* 0 */ 1740, INVALID, +}; + +static const uint16_t ud_itab__361[] = { + /* 0 */ 1741, INVALID, +}; + +static const uint16_t ud_itab__362[] = { + /* 0 */ 1727, INVALID, +}; + +static const uint16_t ud_itab__363[] = { + /* 0 */ GROUP(364), INVALID, +}; + +static const uint16_t ud_itab__364[] = { + /* 0 */ INVALID, 1728, +}; + +static const uint16_t ud_itab__365[] = { + /* 0 */ 1731, INVALID, +}; + +static const uint16_t ud_itab__366[] = { + /* 0 */ 1733, INVALID, +}; + +static const uint16_t ud_itab__367[] = { + /* 0 */ 1732, INVALID, +}; + +static const uint16_t ud_itab__368[] = { + /* 0 */ 1734, INVALID, +}; + +static const uint16_t ud_itab__369[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID, + /* 8 */ 1645, 1647, 1649, 1651, + /* c */ 1655, 1653, 1678, 1620, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(374), 1057, GROUP(375), 202, + /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(383), 1558, GROUP(385), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 198, 196, 1680, INVALID, + /* 44 */ 1513, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392), + /* 4c */ GROUP(393), INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ 1716, 1714, 1722, 1720, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, 48, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__370[] = { + /* 0 */ 1738, INVALID, +}; + +static const uint16_t ud_itab__371[] = { + /* 0 */ 1736, INVALID, +}; + +static const uint16_t ud_itab__372[] = { + /* 0 */ GROUP(373), INVALID, +}; + +static const uint16_t ud_itab__373[] = { + /* 0 */ INVALID, 1739, +}; + +static const uint16_t ud_itab__374[] = { + /* 0 */ 1046, INVALID, +}; + +static const uint16_t ud_itab__375[] = { + /* 0 */ GROUP(376), GROUP(377), GROUP(378), +}; + +static const uint16_t ud_itab__376[] = { + /* 0 */ 1048, INVALID, +}; + +static const uint16_t ud_itab__377[] = { + /* 0 */ 1050, INVALID, +}; + +static const uint16_t ud_itab__378[] = { + /* 0 */ INVALID, 1052, +}; + +static const uint16_t ud_itab__379[] = { + /* 0 */ GROUP(380), INVALID, +}; + +static const uint16_t ud_itab__380[] = { + /* 0 */ INVALID, 1730, +}; + +static const uint16_t ud_itab__381[] = { + /* 0 */ GROUP(382), INVALID, +}; + +static const uint16_t ud_itab__382[] = { + /* 0 */ INVALID, 1729, +}; + +static const uint16_t ud_itab__383[] = { + /* 0 */ GROUP(384), INVALID, +}; + +static const uint16_t ud_itab__384[] = { + /* 0 */ 1065, INVALID, +}; + +static const uint16_t ud_itab__385[] = { + /* 0 */ GROUP(386), GROUP(388), +}; + +static const uint16_t ud_itab__386[] = { + /* 0 */ GROUP(387), INVALID, +}; + +static const uint16_t ud_itab__387[] = { + /* 0 */ 1066, INVALID, +}; + +static const uint16_t ud_itab__388[] = { + /* 0 */ GROUP(389), GROUP(390), +}; + +static const uint16_t ud_itab__389[] = { + /* 0 */ 1067, INVALID, +}; + +static const uint16_t ud_itab__390[] = { + /* 0 */ 1068, INVALID, +}; + +static const uint16_t ud_itab__391[] = { + /* 0 */ 1745, INVALID, +}; + +static const uint16_t ud_itab__392[] = { + /* 0 */ 1744, INVALID, +}; + +static const uint16_t ud_itab__393[] = { + /* 0 */ 1754, INVALID, +}; + +static const uint16_t ud_itab__394[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID, + /* 14 */ INVALID, INVALID, GROUP(398), INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 155, INVALID, + /* 2c */ 169, 159, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1394, 1309, 1294, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 32, 951, 157, 164, + /* 5c */ 1424, 823, 194, 807, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, 1523, + /* 70 */ 1536, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, 917, 1525, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 121, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 133, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__395[] = { + /* 0 */ 1751, 1750, +}; + +static const uint16_t ud_itab__396[] = { + /* 0 */ 1753, 1752, +}; + +static const uint16_t ud_itab__397[] = { + /* 0 */ 1572, 1570, +}; + +static const uint16_t ud_itab__398[] = { + /* 0 */ 1568, 1566, +}; + +static const uint16_t ud_itab__399[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 153, INVALID, + /* 2c */ 167, 149, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1392, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 30, 949, 151, INVALID, + /* 5c */ 1422, 821, 192, 805, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ 1538, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1552, 1556, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 118, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 36, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 137, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ 1560, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__400[] = { + /* 0 */ 1749, 1748, +}; + +static const uint16_t ud_itab__401[] = { + /* 0 */ 1564, 1562, +}; + +static const uint16_t ud_itab__402[] = { + /* 0 */ 1747, 1746, +}; + +static const uint16_t ud_itab__403[] = { + /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__404[] = { + /* 0 */ 769, INVALID, +}; + +static const uint16_t ud_itab__405[] = { + /* 0 */ 826, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__406[] = { + /* 0 */ 827, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__407[] = { + /* 0 */ 715, INVALID, +}; + +static const uint16_t ud_itab__408[] = { + /* 0 */ 723, 724, 725, +}; + +static const uint16_t ud_itab__409[] = { + /* 0 */ 1280, 1285, 1269, 1273, + /* 4 */ 1326, 1333, 1320, 1314, +}; + +static const uint16_t ud_itab__410[] = { + /* 0 */ 1281, 1288, 1272, 1276, + /* 4 */ 1325, 1332, 1329, 1312, +}; + +static const uint16_t ud_itab__411[] = { + /* 0 */ 1282, 1289, 1270, 1277, + /* 4 */ 1324, 1331, 1321, 1316, +}; + +static const uint16_t ud_itab__412[] = { + /* 0 */ 1283, 1290, 1271, 1278, + /* 4 */ 1328, 1335, 1322, 1317, +}; + +static const uint16_t ud_itab__413[] = { + /* 0 */ 3, INVALID, +}; + +static const uint16_t ud_itab__414[] = { + /* 0 */ 2, INVALID, +}; + +static const uint16_t ud_itab__415[] = { + /* 0 */ 1311, INVALID, +}; + +static const uint16_t ud_itab__416[] = { + /* 0 */ GROUP(417), GROUP(418), +}; + +static const uint16_t ud_itab__417[] = { + /* 0 */ 206, 503, 307, 357, + /* 4 */ 587, 630, 387, 413, +}; + +static const uint16_t ud_itab__418[] = { + /* 0 */ 215, 216, 217, 218, + /* 4 */ 219, 220, 221, 222, + /* 8 */ 504, 505, 506, 507, + /* c */ 508, 509, 510, 511, + /* 10 */ 309, 310, 311, 312, + /* 14 */ 313, 314, 315, 316, + /* 18 */ 359, 360, 361, 362, + /* 1c */ 363, 364, 365, 366, + /* 20 */ 589, 590, 591, 592, + /* 24 */ 593, 594, 595, 596, + /* 28 */ 614, 615, 616, 617, + /* 2c */ 618, 619, 620, 621, + /* 30 */ 388, 389, 390, 391, + /* 34 */ 392, 393, 394, 395, + /* 38 */ 414, 415, 416, 417, + /* 3c */ 418, 419, 420, 421, +}; + +static const uint16_t ud_itab__419[] = { + /* 0 */ GROUP(420), GROUP(421), +}; + +static const uint16_t ud_itab__420[] = { + /* 0 */ 476, INVALID, 573, 540, + /* 4 */ 493, 492, 584, 583, +}; + +static const uint16_t ud_itab__421[] = { + /* 0 */ 477, 478, 479, 480, + /* 4 */ 481, 482, 483, 484, + /* 8 */ 658, 659, 660, 661, + /* c */ 662, 663, 664, 665, + /* 10 */ 522, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ 549, 550, 551, 552, + /* 1c */ 553, 554, 555, 556, + /* 20 */ 233, 204, INVALID, INVALID, + /* 24 */ 639, 657, INVALID, INVALID, + /* 28 */ 485, 486, 487, 488, + /* 2c */ 489, 490, 491, INVALID, + /* 30 */ 203, 685, 529, 526, + /* 34 */ 684, 528, 377, 454, + /* 38 */ 527, 686, 537, 536, + /* 3c */ 530, 534, 535, 376, +}; + +static const uint16_t ud_itab__422[] = { + /* 0 */ GROUP(423), GROUP(424), +}; + +static const uint16_t ud_itab__423[] = { + /* 0 */ 456, 520, 448, 450, + /* 4 */ 462, 464, 460, 458, +}; + +static const uint16_t ud_itab__424[] = { + /* 0 */ 235, 236, 237, 238, + /* 4 */ 239, 240, 241, 242, + /* 8 */ 243, 244, 245, 246, + /* c */ 247, 248, 249, 250, + /* 10 */ 251, 252, 253, 254, + /* 14 */ 255, 256, 257, 258, + /* 18 */ 259, 260, 261, 262, + /* 1c */ 263, 264, 265, 266, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, 656, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__425[] = { + /* 0 */ GROUP(426), GROUP(427), +}; + +static const uint16_t ud_itab__426[] = { + /* 0 */ 453, 471, 467, 470, + /* 4 */ INVALID, 474, INVALID, 538, +}; + +static const uint16_t ud_itab__427[] = { + /* 0 */ 267, 268, 269, 270, + /* 4 */ 271, 272, 273, 274, + /* 8 */ 275, 276, 277, 278, + /* c */ 279, 280, 281, 282, + /* 10 */ 283, 284, 285, 286, + /* 14 */ 287, 288, 289, 290, + /* 18 */ 291, 292, 293, 294, + /* 1c */ 295, 296, 297, 298, + /* 20 */ 524, 523, 234, 455, + /* 24 */ 525, 532, INVALID, INVALID, + /* 28 */ 299, 300, 301, 302, + /* 2c */ 303, 304, 305, 306, + /* 30 */ 333, 334, 335, 336, + /* 34 */ 337, 338, 339, 340, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__428[] = { + /* 0 */ GROUP(429), GROUP(430), +}; + +static const uint16_t ud_itab__429[] = { + /* 0 */ 205, 494, 308, 358, + /* 4 */ 588, 613, 378, 404, +}; + +static const uint16_t ud_itab__430[] = { + /* 0 */ 207, 208, 209, 210, + /* 4 */ 211, 212, 213, 214, + /* 8 */ 495, 496, 497, 498, + /* c */ 499, 500, 501, 502, + /* 10 */ 317, 318, 319, 320, + /* 14 */ 321, 322, 323, 324, + /* 18 */ 325, 326, 327, 328, + /* 1c */ 329, 330, 331, 332, + /* 20 */ 622, 623, 624, 625, + /* 24 */ 626, 627, 628, 629, + /* 28 */ 597, 598, 599, 600, + /* 2c */ 601, 602, 603, 604, + /* 30 */ 405, 406, 407, 408, + /* 34 */ 409, 410, 411, 412, + /* 38 */ 379, 380, 381, 382, + /* 3c */ 383, 384, 385, 386, +}; + +static const uint16_t ud_itab__431[] = { + /* 0 */ GROUP(432), GROUP(433), +}; + +static const uint16_t ud_itab__432[] = { + /* 0 */ 475, 472, 574, 539, + /* 4 */ 531, INVALID, 533, 585, +}; + +static const uint16_t ud_itab__433[] = { + /* 0 */ 431, 432, 433, 434, + /* 4 */ 435, 436, 437, 438, + /* 8 */ 666, 667, 668, 669, + /* c */ 670, 671, 672, 673, + /* 10 */ 575, 576, 577, 578, + /* 14 */ 579, 580, 581, 582, + /* 18 */ 541, 542, 543, 544, + /* 1c */ 545, 546, 547, 548, + /* 20 */ 640, 641, 642, 643, + /* 24 */ 644, 645, 646, 647, + /* 28 */ 648, 649, 650, 651, + /* 2c */ 652, 653, 654, 655, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__434[] = { + /* 0 */ GROUP(435), GROUP(436), +}; + +static const uint16_t ud_itab__435[] = { + /* 0 */ 457, 521, 447, 449, + /* 4 */ 463, 465, 461, 459, +}; + +static const uint16_t ud_itab__436[] = { + /* 0 */ 223, 224, 225, 226, + /* 4 */ 227, 228, 229, 230, + /* 8 */ 512, 513, 514, 515, + /* c */ 516, 517, 518, 519, + /* 10 */ 367, 368, 369, 370, + /* 14 */ 371, 372, 373, 374, + /* 18 */ INVALID, 375, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ 631, 632, 633, 634, + /* 24 */ 635, 636, 637, 638, + /* 28 */ 605, 606, 607, 608, + /* 2c */ 609, 610, 611, 612, + /* 30 */ 422, 423, 424, 425, + /* 34 */ 426, 427, 428, 429, + /* 38 */ 396, 397, 398, 399, + /* 3c */ 400, 401, 402, 403, +}; + +static const uint16_t ud_itab__437[] = { + /* 0 */ GROUP(438), GROUP(439), +}; + +static const uint16_t ud_itab__438[] = { + /* 0 */ 451, 473, 466, 468, + /* 4 */ 231, 452, 232, 469, +}; + +static const uint16_t ud_itab__439[] = { + /* 0 */ 439, 440, 441, 442, + /* 4 */ 443, 444, 445, 446, + /* 8 */ 674, 675, 676, 677, + /* c */ 678, 679, 680, 681, + /* 10 */ 557, 558, 559, 560, + /* 14 */ 561, 562, 563, 564, + /* 18 */ 565, 566, 567, 568, + /* 1c */ 569, 570, 571, 572, + /* 20 */ 586, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 341, 342, 343, 344, + /* 2c */ 345, 346, 347, 348, + /* 30 */ 349, 350, 351, 352, + /* 34 */ 353, 354, 355, 356, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__440[] = { + /* 0 */ 758, 759, 760, +}; + +static const uint16_t ud_itab__441[] = { + /* 0 */ 764, INVALID, +}; + +static const uint16_t ud_itab__442[] = { + /* 0 */ 1432, 1437, 962, 953, + /* 4 */ 942, 695, 186, 689, +}; + +static const uint16_t ud_itab__443[] = { + /* 0 */ 1438, 1439, 963, 954, + /* 4 */ 943, 696, 185, 688, +}; + +static const uint16_t ud_itab__444[] = { + /* 0 */ 708, 183, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__445[] = { + /* 0 */ 707, 184, GROUP(446), 71, + /* 4 */ 761, 762, 1255, INVALID, +}; + +static const uint16_t ud_itab__446[] = { + /* 0 */ 69, 70, +}; + + +struct ud_lookup_table_list_entry ud_lookup_table_list[] = { + /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" }, + /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, + /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, + /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" }, + /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" }, + /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" }, + /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" }, + /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" }, + /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" }, + /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" }, + /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" }, + /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" }, + /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" }, + /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" }, + /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" }, + /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" }, + /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" }, + /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" }, + /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" }, + /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" }, + /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" }, + /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" }, + /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" }, + /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" }, + /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" }, + /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" }, + /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" }, + /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" }, + /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" }, + /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" }, + /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" }, + /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" }, + /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" }, + /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" }, + /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" }, + /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" }, + /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" }, + /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" }, + /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" }, + /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" }, + /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" }, + /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" }, + /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" }, + /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" }, + /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" }, + /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" }, + /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" }, + /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" }, + /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" }, + /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" }, + /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" }, + /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" }, + /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" }, + /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" }, + /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" }, + /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" }, + /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" }, + /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" }, + /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" }, + /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" }, + /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" }, + /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" }, + /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" }, + /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" }, + /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" }, + /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" }, + /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" }, + /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" }, + /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" }, + /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" }, + /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" }, + /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" }, + /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" }, + /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" }, + /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" }, + /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" }, + /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" }, + /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" }, + /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" }, + /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" }, + /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" }, + /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" }, + /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" }, + /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" }, + /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" }, + /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" }, + /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" }, + /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" }, + /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" }, + /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" }, + /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" }, + /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" }, + /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" }, + /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" }, + /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" }, + /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" }, + /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" }, + /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" }, + /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" }, + /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" }, + /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" }, + /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" }, + /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" }, + /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" }, + /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" }, + /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" }, + /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" }, + /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" }, + /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" }, + /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" }, + /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" }, + /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" }, + /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" }, + /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" }, + /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" }, + /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" }, + /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" }, + /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" }, + /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" }, + /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" }, + /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" }, + /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" }, + /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" }, + /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" }, + /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" }, + /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" }, + /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" }, + /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" }, + /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" }, + /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" }, + /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" }, + /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" }, + /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" }, + /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" }, + /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" }, + /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" }, + /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" }, + /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" }, + /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" }, + /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" }, + /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" }, + /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" }, + /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" }, + /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" }, + /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" }, + /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" }, + /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" }, + /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" }, + /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" }, + /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" }, + /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" }, + /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" }, + /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" }, + /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" }, + /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" }, + /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" }, + /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" }, + /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" }, + /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" }, + /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" }, + /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" }, + /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" }, + /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" }, + /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" }, + /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" }, + /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" }, + /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" }, + /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" }, + /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" }, + /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" }, + /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" }, + /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" }, + /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" }, + /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" }, + /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" }, + /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" }, + /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" }, + /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" }, + /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" }, + /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" }, + /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" }, + /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" }, + /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" }, + /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" }, + /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" }, + /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" }, + /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" }, + /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" }, + /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" }, + /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" }, + /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" }, + /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" }, + /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" }, + /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" }, + /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" }, + /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" }, + /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" }, + /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" }, + /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" }, + /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" }, + /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" }, + /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" }, + /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" }, + /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" }, + /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" }, + /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" }, + /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" }, + /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" }, + /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" }, + /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" }, + /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" }, + /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" }, + /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" }, + /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" }, + /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" }, + /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" }, + /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" }, + /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" }, + /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" }, + /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" }, + /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" }, + /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" }, + /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" }, + /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" }, + /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" }, + /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" }, + /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" }, + /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" }, + /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" }, + /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" }, + /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" }, + /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" }, + /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" }, + /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" }, + /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" }, + /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" }, + /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" }, + /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" }, + /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" }, + /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" }, + /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" }, + /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" }, + /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" }, + /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" }, + /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" }, + /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" }, + /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" }, + /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" }, + /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" }, + /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" }, + /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" }, + /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" }, + /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" }, + /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" }, + /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" }, + /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" }, + /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" }, + /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" }, + /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" }, + /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" }, + /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" }, + /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" }, + /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" }, + /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" }, + /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" }, + /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" }, + /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" }, + /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" }, + /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" }, + /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" }, + /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" }, + /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" }, + /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" }, + /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" }, + /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" }, + /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" }, + /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" }, + /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" }, + /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" }, + /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" }, + /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" }, + /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" }, + /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" }, + /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" }, + /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" }, + /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" }, + /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" }, + /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" }, + /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" }, + /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" }, + /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" }, + /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" }, + /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" }, + /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" }, + /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" }, + /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" }, + /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" }, + /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" }, + /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" }, + /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" }, + /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" }, + /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" }, + /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" }, + /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" }, + /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" }, + /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" }, + /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" }, + /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" }, + /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" }, + /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" }, + /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" }, + /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" }, + /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" }, + /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" }, + /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" }, + /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" }, + /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" }, + /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" }, + /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" }, + /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" }, + /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" }, + /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" }, + /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" }, + /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" }, + /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" }, + /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" }, + /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" }, + /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" }, + /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" }, + /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" }, + /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" }, + /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" }, + /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" }, + /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" }, + /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" }, + /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" }, + /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" }, + /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" }, + /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" }, + /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" }, + /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" }, + /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" }, + /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" }, + /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" }, + /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" }, + /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" }, + /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" }, + /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" }, + /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" }, + /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" }, + /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" }, + /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" }, + /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" }, + /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" }, + /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" }, + /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" }, + /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" }, + /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" }, + /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" }, + /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" }, + /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" }, + /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" }, + /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" }, + /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" }, + /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" }, + /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" }, + /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" }, + /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" }, + /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" }, + /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" }, + /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" }, + /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" }, + /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" }, + /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" }, + /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" }, + /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" }, + /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" }, + /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" }, + /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" }, + /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" }, + /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" }, +}; + +/* itab entry operand definitions (for readability) */ +#define O_AL { OP_AL, SZ_B } +#define O_AX { OP_AX, SZ_W } +#define O_Av { OP_A, SZ_V } +#define O_C { OP_C, SZ_NA } +#define O_CL { OP_CL, SZ_B } +#define O_CS { OP_CS, SZ_NA } +#define O_CX { OP_CX, SZ_W } +#define O_D { OP_D, SZ_NA } +#define O_DL { OP_DL, SZ_B } +#define O_DS { OP_DS, SZ_NA } +#define O_DX { OP_DX, SZ_W } +#define O_E { OP_E, SZ_NA } +#define O_ES { OP_ES, SZ_NA } +#define O_Eb { OP_E, SZ_B } +#define O_Ed { OP_E, SZ_D } +#define O_Eq { OP_E, SZ_Q } +#define O_Ev { OP_E, SZ_V } +#define O_Ew { OP_E, SZ_W } +#define O_Ey { OP_E, SZ_Y } +#define O_Ez { OP_E, SZ_Z } +#define O_FS { OP_FS, SZ_NA } +#define O_Fv { OP_F, SZ_V } +#define O_G { OP_G, SZ_NA } +#define O_GS { OP_GS, SZ_NA } +#define O_Gb { OP_G, SZ_B } +#define O_Gd { OP_G, SZ_D } +#define O_Gq { OP_G, SZ_Q } +#define O_Gv { OP_G, SZ_V } +#define O_Gw { OP_G, SZ_W } +#define O_Gy { OP_G, SZ_Y } +#define O_Gz { OP_G, SZ_Z } +#define O_H { OP_H, SZ_X } +#define O_Hqq { OP_H, SZ_QQ } +#define O_Hx { OP_H, SZ_X } +#define O_I1 { OP_I1, SZ_NA } +#define O_I3 { OP_I3, SZ_NA } +#define O_Ib { OP_I, SZ_B } +#define O_Iv { OP_I, SZ_V } +#define O_Iw { OP_I, SZ_W } +#define O_Iz { OP_I, SZ_Z } +#define O_Jb { OP_J, SZ_B } +#define O_Jv { OP_J, SZ_V } +#define O_Jz { OP_J, SZ_Z } +#define O_L { OP_L, SZ_O } +#define O_Lx { OP_L, SZ_X } +#define O_M { OP_M, SZ_NA } +#define O_Mb { OP_M, SZ_B } +#define O_MbRd { OP_MR, SZ_BD } +#define O_MbRv { OP_MR, SZ_BV } +#define O_Md { OP_M, SZ_D } +#define O_MdRy { OP_MR, SZ_DY } +#define O_MdU { OP_MU, SZ_DO } +#define O_Mdq { OP_M, SZ_DQ } +#define O_Mo { OP_M, SZ_O } +#define O_Mq { OP_M, SZ_Q } +#define O_MqU { OP_MU, SZ_QO } +#define O_Ms { OP_M, SZ_W } +#define O_Mt { OP_M, SZ_T } +#define O_Mv { OP_M, SZ_V } +#define O_Mw { OP_M, SZ_W } +#define O_MwRd { OP_MR, SZ_WD } +#define O_MwRv { OP_MR, SZ_WV } +#define O_MwRy { OP_MR, SZ_WY } +#define O_MwU { OP_MU, SZ_WO } +#define O_N { OP_N, SZ_Q } +#define O_NONE { OP_NONE, SZ_NA } +#define O_Ob { OP_O, SZ_B } +#define O_Ov { OP_O, SZ_V } +#define O_Ow { OP_O, SZ_W } +#define O_P { OP_P, SZ_Q } +#define O_Q { OP_Q, SZ_Q } +#define O_R { OP_R, SZ_RDQ } +#define O_R0b { OP_R0, SZ_B } +#define O_R0v { OP_R0, SZ_V } +#define O_R0w { OP_R0, SZ_W } +#define O_R0y { OP_R0, SZ_Y } +#define O_R0z { OP_R0, SZ_Z } +#define O_R1b { OP_R1, SZ_B } +#define O_R1v { OP_R1, SZ_V } +#define O_R1w { OP_R1, SZ_W } +#define O_R1y { OP_R1, SZ_Y } +#define O_R1z { OP_R1, SZ_Z } +#define O_R2b { OP_R2, SZ_B } +#define O_R2v { OP_R2, SZ_V } +#define O_R2w { OP_R2, SZ_W } +#define O_R2y { OP_R2, SZ_Y } +#define O_R2z { OP_R2, SZ_Z } +#define O_R3b { OP_R3, SZ_B } +#define O_R3v { OP_R3, SZ_V } +#define O_R3w { OP_R3, SZ_W } +#define O_R3y { OP_R3, SZ_Y } +#define O_R3z { OP_R3, SZ_Z } +#define O_R4b { OP_R4, SZ_B } +#define O_R4v { OP_R4, SZ_V } +#define O_R4w { OP_R4, SZ_W } +#define O_R4y { OP_R4, SZ_Y } +#define O_R4z { OP_R4, SZ_Z } +#define O_R5b { OP_R5, SZ_B } +#define O_R5v { OP_R5, SZ_V } +#define O_R5w { OP_R5, SZ_W } +#define O_R5y { OP_R5, SZ_Y } +#define O_R5z { OP_R5, SZ_Z } +#define O_R6b { OP_R6, SZ_B } +#define O_R6v { OP_R6, SZ_V } +#define O_R6w { OP_R6, SZ_W } +#define O_R6y { OP_R6, SZ_Y } +#define O_R6z { OP_R6, SZ_Z } +#define O_R7b { OP_R7, SZ_B } +#define O_R7v { OP_R7, SZ_V } +#define O_R7w { OP_R7, SZ_W } +#define O_R7y { OP_R7, SZ_Y } +#define O_R7z { OP_R7, SZ_Z } +#define O_S { OP_S, SZ_W } +#define O_SS { OP_SS, SZ_NA } +#define O_ST0 { OP_ST0, SZ_NA } +#define O_ST1 { OP_ST1, SZ_NA } +#define O_ST2 { OP_ST2, SZ_NA } +#define O_ST3 { OP_ST3, SZ_NA } +#define O_ST4 { OP_ST4, SZ_NA } +#define O_ST5 { OP_ST5, SZ_NA } +#define O_ST6 { OP_ST6, SZ_NA } +#define O_ST7 { OP_ST7, SZ_NA } +#define O_U { OP_U, SZ_O } +#define O_Ux { OP_U, SZ_X } +#define O_V { OP_V, SZ_DQ } +#define O_Vdq { OP_V, SZ_DQ } +#define O_Vqq { OP_V, SZ_QQ } +#define O_Vsd { OP_V, SZ_Q } +#define O_Vx { OP_V, SZ_X } +#define O_W { OP_W, SZ_DQ } +#define O_Wdq { OP_W, SZ_DQ } +#define O_Wqq { OP_W, SZ_QQ } +#define O_Wsd { OP_W, SZ_Q } +#define O_Wx { OP_W, SZ_X } +#define O_eAX { OP_eAX, SZ_Z } +#define O_eCX { OP_eCX, SZ_Z } +#define O_eDX { OP_eDX, SZ_Z } +#define O_rAX { OP_rAX, SZ_V } +#define O_rCX { OP_rCX, SZ_V } +#define O_rDX { OP_rDX, SZ_V } +#define O_sIb { OP_sI, SZ_B } +#define O_sIv { OP_sI, SZ_V } +#define O_sIz { OP_sI, SZ_Z } + +struct ud_itab_entry ud_itab[] = { + /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso }, + /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg }, + /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 }, + /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0523 */ { UD_Ifndisi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0524 */ { UD_Ifneni, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0525 */ { UD_Ifnsetpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0526 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0527 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0528 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0529 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0530 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0531 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0532 */ { UD_Ifrstpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0533 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0534 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0535 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0536 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0537 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0538 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0539 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0540 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0541 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0542 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0543 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0544 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0545 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0546 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0547 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0548 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0549 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0550 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0551 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0552 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0553 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0554 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0555 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0556 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0557 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0558 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0559 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0560 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0561 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0562 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0563 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0564 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0565 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0566 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0567 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0568 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0569 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0570 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0571 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0572 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0573 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0574 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0575 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0576 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0577 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0578 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0579 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0580 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0581 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0582 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0583 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0584 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0585 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0586 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none }, + /* 0587 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0588 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0589 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0590 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0591 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0592 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0593 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0594 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0595 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0596 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0597 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0598 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0599 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0600 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0601 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0602 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0603 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0604 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0605 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0606 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0607 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0608 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0609 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0610 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0611 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0612 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0613 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0614 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0615 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0616 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0617 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0618 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0619 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0620 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0621 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0622 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0623 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0624 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0625 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0626 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0627 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0628 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0629 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0630 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0631 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0632 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0633 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0634 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0635 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0636 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0637 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0638 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0639 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0640 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0641 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0642 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0643 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0644 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0645 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0646 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0647 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0648 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0649 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0650 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0651 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0652 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0653 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0654 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0655 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0656 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0657 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0658 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0659 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0660 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0661 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0662 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0663 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0664 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0665 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0666 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0667 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0668 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0669 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0670 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0671 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0672 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0673 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0674 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0675 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0676 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0677 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0678 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0679 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0680 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0681 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0682 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0683 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0684 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0685 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0686 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0687 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0688 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0689 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0690 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0691 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso }, + /* 0692 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none }, + /* 0693 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso }, + /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0695 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0696 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0697 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0698 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0699 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0700 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0701 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0702 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0703 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0704 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0705 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0706 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0707 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0708 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0709 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0710 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0711 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0712 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0713 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0714 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0715 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0716 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0717 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0718 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0719 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0720 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0721 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0722 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0723 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0724 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0725 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0726 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0727 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0728 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0729 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0730 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0731 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0732 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0733 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0734 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0735 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0736 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0737 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0738 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0739 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0740 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0741 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0742 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0743 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0744 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0745 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0746 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0747 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0748 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0749 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0750 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0751 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0752 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0753 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0754 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0755 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0756 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0757 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0758 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0759 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0760 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0761 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0762 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0763 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0764 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0765 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 }, + /* 0766 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0767 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0768 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0769 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0770 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0771 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0772 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0773 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0774 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0775 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0776 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0781 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0782 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0783 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0784 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0785 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0786 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0787 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0788 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0789 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0790 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0791 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0792 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0793 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0794 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0795 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0796 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0797 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0798 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0799 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0800 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0801 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0802 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0803 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0804 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0805 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0806 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0807 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0812 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0813 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0814 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0815 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0816 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0817 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0818 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0819 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0820 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0821 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0822 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0823 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0824 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0825 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0826 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0827 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0828 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0829 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0830 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0831 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0832 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0833 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0834 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none }, + /* 0835 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0836 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none }, + /* 0837 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0838 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0839 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0840 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0841 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0842 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0843 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0844 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0845 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0846 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0847 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0848 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0849 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0850 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0851 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0852 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0853 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0854 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0855 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0856 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0857 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0858 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0859 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0860 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0861 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0862 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0863 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0864 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0865 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0866 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0867 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0868 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0869 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0870 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0871 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0872 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0873 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0874 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0875 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0876 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0877 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0878 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0879 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0880 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0881 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0882 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0883 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0884 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0885 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0886 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0887 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0888 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0889 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0890 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0891 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0892 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0893 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0894 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0895 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0896 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0897 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0898 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0899 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl }, + /* 0900 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0901 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0902 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0903 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0904 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0905 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0906 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0907 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0908 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0909 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0910 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0911 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0912 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0913 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0914 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0915 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0916 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0917 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0918 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0919 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0920 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0921 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0922 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0923 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0924 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0925 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0926 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0927 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0928 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0929 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0930 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0931 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0932 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0933 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0934 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0935 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0936 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0937 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0938 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0939 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0940 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0941 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0942 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0943 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0944 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0945 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0946 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0947 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0948 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0949 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0950 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0951 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0952 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0953 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0954 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0958 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0959 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0960 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0961 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0962 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0963 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0964 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0965 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0966 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0967 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0968 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0969 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0970 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0971 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0972 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0973 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0974 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0975 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0976 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0977 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0978 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none }, + /* 0979 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0980 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none }, + /* 0981 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0982 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0983 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0984 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0985 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0986 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0987 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0988 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0989 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0990 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0991 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0992 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0993 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0994 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0995 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0996 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0997 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0998 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0999 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1000 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1001 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1002 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1003 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1004 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1005 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1006 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1007 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1008 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1009 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1010 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1011 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1012 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1013 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1014 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1015 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1016 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1017 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1018 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1019 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1020 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1021 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1022 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1023 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1024 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1025 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1026 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1027 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1028 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1029 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1030 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1031 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1032 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1033 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1034 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1035 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1036 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1037 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1038 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1039 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1040 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1041 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1042 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1043 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1044 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1045 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1046 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1047 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1048 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1049 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1050 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1051 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1052 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1053 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1054 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1055 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1056 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1057 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1058 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1059 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1060 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1061 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1062 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1063 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1064 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1065 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1066 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1067 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1068 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1069 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1070 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1071 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1072 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1073 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1074 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1075 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1076 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1077 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1078 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1079 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1080 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1081 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1082 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1083 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1084 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1085 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1086 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1087 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1088 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1089 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1090 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1091 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1092 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1093 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1094 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1095 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1096 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1097 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1098 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1099 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1100 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1101 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1102 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1103 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1104 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1105 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1106 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1107 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1108 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1109 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1110 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1111 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1112 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1113 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1114 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1115 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1116 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1117 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1118 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1123 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1124 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1125 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1126 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1127 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1128 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1129 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1130 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1131 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1132 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1133 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1134 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1135 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1136 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1137 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1138 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1139 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1140 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1141 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1142 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1143 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1144 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1145 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1146 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1147 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1148 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1149 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1150 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1151 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1152 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1153 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1154 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1155 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1156 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1157 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1158 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1159 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1160 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1161 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1162 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1163 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1164 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1165 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1166 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1167 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1168 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1169 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1170 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1171 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1172 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1173 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1174 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1175 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1176 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1177 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1178 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1179 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1180 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1181 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1182 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1183 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1184 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1185 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1186 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1187 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1188 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1189 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1190 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1191 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1192 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1193 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1194 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1195 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1196 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1197 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1198 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1199 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1200 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1201 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1202 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1203 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1204 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1205 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1206 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1207 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1208 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1209 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1210 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1211 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1212 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1213 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1214 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1215 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1216 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1217 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1218 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1219 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1220 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1221 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1222 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1223 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1224 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1225 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1226 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1227 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1228 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1229 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1230 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1231 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1232 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1233 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1234 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1235 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1236 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1237 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1238 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1239 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1240 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1241 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1242 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1243 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1244 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1245 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1246 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1247 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1248 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1249 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1250 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1251 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1252 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1253 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1254 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1255 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1256 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1257 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1258 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1259 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1260 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1261 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1262 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1263 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1264 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1265 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1266 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1267 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1268 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1269 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1270 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1271 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1272 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1273 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1274 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1275 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1276 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1277 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1278 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1279 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1280 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1281 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1282 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1283 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1284 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1285 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1286 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1287 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1288 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1289 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1290 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1291 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1292 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1293 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1294 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1295 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1296 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1297 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1298 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1299 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1300 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1301 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1302 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1303 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1304 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1305 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1306 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1307 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1308 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1309 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1310 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1311 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1312 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1313 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1314 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1315 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1316 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1317 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1318 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1320 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1321 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1322 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1323 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1324 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1326 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1327 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1328 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1329 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1330 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1331 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1332 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1333 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1334 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1335 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1336 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1337 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1338 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1339 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1340 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1341 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1342 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1343 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1344 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1345 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1346 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz }, + /* 1347 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1348 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1349 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1350 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1351 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1352 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1353 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1354 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1355 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1356 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1357 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1358 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1359 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1360 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1361 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1362 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1363 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1364 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1365 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1370 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1371 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1372 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1373 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1374 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1375 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1376 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1377 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1378 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1379 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1380 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1381 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1382 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1383 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1384 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1385 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1386 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1387 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1388 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1389 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1390 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1391 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1392 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1393 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1394 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1395 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1396 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1397 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1398 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1399 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1400 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1401 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1402 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 1403 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1404 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1405 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1406 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1407 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1408 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1409 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1410 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1411 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1412 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1413 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1414 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1415 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1416 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1417 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1418 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1419 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1420 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1421 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1422 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1423 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1424 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1425 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1426 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1427 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1428 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1429 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1430 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1431 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1432 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1433 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1434 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1435 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1436 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1437 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1438 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1439 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1440 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1441 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1442 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1443 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1444 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1445 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1446 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1447 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1448 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1449 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1450 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1451 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1452 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1453 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1454 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1455 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1456 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1457 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1458 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1459 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1460 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1461 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1462 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1463 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1464 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1465 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1466 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1467 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1468 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1469 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1470 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1471 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1472 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1473 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 1474 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1475 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1476 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1477 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1478 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1479 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1480 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1481 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1482 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1483 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1484 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1485 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1486 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg }, + /* 1487 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1488 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1489 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1490 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1491 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1492 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1493 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1494 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1495 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1496 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1497 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1498 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1499 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1500 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1501 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1502 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1503 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1504 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1505 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1506 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1507 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1508 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1509 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1510 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1511 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1512 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1513 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1514 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1515 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1516 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1517 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1518 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1519 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1520 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1521 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb }, + /* 1522 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1523 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1524 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1525 */ { UD_Ivmovdqu, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1526 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr }, + /* 1527 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1528 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1529 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1530 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1531 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1532 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1533 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1534 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1535 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1536 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1537 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1538 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1539 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1540 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1541 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1542 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1543 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1544 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1545 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1546 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1547 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1548 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1549 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1550 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1551 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1552 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1553 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1554 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1555 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1556 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1557 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1558 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1559 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1560 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1561 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1562 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1563 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1564 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1565 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1566 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1567 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1568 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1569 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1570 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1571 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1572 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1573 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1574 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1575 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1576 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1577 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1578 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1579 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1580 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1581 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1582 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1583 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1584 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1585 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1586 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1587 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1588 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1589 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1590 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1591 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1592 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1593 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1594 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1595 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1596 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1597 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1598 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1599 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1600 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1601 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1602 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1603 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1604 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1605 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1606 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1607 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1608 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1609 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1610 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1611 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1612 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1613 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1614 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1615 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1616 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1617 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1618 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1619 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1620 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1621 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1622 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1623 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1624 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1625 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1626 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1627 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1628 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1629 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1630 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1631 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1632 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1633 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1634 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1635 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1636 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1637 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1638 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1639 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1640 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1641 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1642 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1643 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1644 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1645 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1646 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1647 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1648 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1649 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1650 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1651 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1652 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1653 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1654 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1655 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1656 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1657 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1658 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 1659 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1660 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1661 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1662 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1663 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1664 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1665 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1666 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1667 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1668 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1669 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1670 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1671 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1672 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1673 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1674 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1675 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1676 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1677 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1678 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1679 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1680 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1681 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1682 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1683 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1684 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1685 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1686 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1687 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1688 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1689 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1690 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1691 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1692 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1693 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1694 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1695 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1696 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1697 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1698 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1699 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1700 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1701 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1702 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1703 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1704 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1705 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1706 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1707 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1708 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1709 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1710 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1711 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1712 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1713 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1714 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1715 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1716 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1717 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1718 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1719 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1720 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1721 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1722 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1723 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1724 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1725 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1726 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1727 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1728 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1729 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1730 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1731 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1732 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1733 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1734 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1735 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1736 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1737 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1738 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1739 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1740 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1741 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1742 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1743 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1744 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1745 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1746 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1747 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1748 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1749 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1750 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1751 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1752 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1753 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1754 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1755 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1756 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1757 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1758 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1759 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1760 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + + +const char* ud_mnemonics_str[] = { + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "aesdec", + "aesdeclast", + "aesenc", + "aesenclast", + "aesimc", + "aeskeygenassist", + "and", + "andnpd", + "andnps", + "andpd", + "andps", + "arpl", + "blendpd", + "blendps", + "blendvpd", + "blendvps", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cdq", + "cdqe", + "clc", + "cld", + "clflush", + "clgi", + "cli", + "clts", + "cmc", + "cmova", + "cmovae", + "cmovb", + "cmovbe", + "cmovg", + "cmovge", + "cmovl", + "cmovle", + "cmovno", + "cmovnp", + "cmovns", + "cmovnz", + "cmovo", + "cmovp", + "cmovs", + "cmovz", + "cmp", + "cmppd", + "cmpps", + "cmpsb", + "cmpsd", + "cmpsq", + "cmpss", + "cmpsw", + "cmpxchg", + "cmpxchg16b", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cqo", + "crc32", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2pd", + "cvtpi2ps", + "cvtps2dq", + "cvtps2pd", + "cvtps2pi", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2sd", + "cvtsi2ss", + "cvtss2sd", + "cvtss2si", + "cvttpd2dq", + "cvttpd2pi", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvttss2si", + "cwd", + "cwde", + "daa", + "das", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "dppd", + "dpps", + "emms", + "enter", + "extractps", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcom2", + "fcomi", + "fcomip", + "fcomp", + "fcomp3", + "fcomp5", + "fcompp", + "fcos", + "fdecstp", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fndisi", + "fneni", + "fninit", + "fnop", + "fnsave", + "fnsetpm", + "fnstcw", + "fnstenv", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "frstpm", + "fscale", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstp1", + "fstp8", + "fstp9", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxch4", + "fxch7", + "fxrstor", + "fxsave", + "fxtract", + "fyl2x", + "fyl2xp1", + "getsec", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "idiv", + "imul", + "in", + "inc", + "insb", + "insd", + "insertps", + "insw", + "int", + "int1", + "int3", + "into", + "invd", + "invept", + "invlpg", + "invlpga", + "invvpid", + "iretd", + "iretq", + "iretw", + "ja", + "jae", + "jb", + "jbe", + "jcxz", + "jecxz", + "jg", + "jge", + "jl", + "jle", + "jmp", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jrcxz", + "js", + "jz", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "leave", + "les", + "lfence", + "lfs", + "lgdt", + "lgs", + "lidt", + "lldt", + "lmsw", + "lock", + "lodsb", + "lodsd", + "lodsq", + "lodsw", + "loop", + "loope", + "loopne", + "lsl", + "lss", + "ltr", + "maskmovdqu", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "montmul", + "mov", + "movapd", + "movaps", + "movbe", + "movd", + "movddup", + "movdq2q", + "movdqa", + "movdqu", + "movhlps", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movmskpd", + "movmskps", + "movntdq", + "movntdqa", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movq2dq", + "movsb", + "movsd", + "movshdup", + "movsldup", + "movsq", + "movss", + "movsw", + "movsx", + "movsxd", + "movupd", + "movups", + "movzx", + "mpsadbw", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsd", + "outsw", + "pabsb", + "pabsd", + "pabsw", + "packssdw", + "packsswb", + "packusdw", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "palignr", + "pand", + "pandn", + "pavgb", + "pavgusb", + "pavgw", + "pblendvb", + "pblendw", + "pclmulqdq", + "pcmpeqb", + "pcmpeqd", + "pcmpeqq", + "pcmpeqw", + "pcmpestri", + "pcmpestrm", + "pcmpgtb", + "pcmpgtd", + "pcmpgtq", + "pcmpgtw", + "pcmpistri", + "pcmpistrm", + "pextrb", + "pextrd", + "pextrq", + "pextrw", + "pf2id", + "pf2iw", + "pfacc", + "pfadd", + "pfcmpeq", + "pfcmpge", + "pfcmpgt", + "pfmax", + "pfmin", + "pfmul", + "pfnacc", + "pfpnacc", + "pfrcp", + "pfrcpit1", + "pfrcpit2", + "pfrsqit1", + "pfrsqrt", + "pfsub", + "pfsubr", + "phaddd", + "phaddsw", + "phaddw", + "phminposuw", + "phsubd", + "phsubsw", + "phsubw", + "pi2fd", + "pi2fw", + "pinsrb", + "pinsrd", + "pinsrq", + "pinsrw", + "pmaddubsw", + "pmaddwd", + "pmaxsb", + "pmaxsd", + "pmaxsw", + "pmaxub", + "pmaxud", + "pmaxuw", + "pminsb", + "pminsd", + "pminsw", + "pminub", + "pminud", + "pminuw", + "pmovmskb", + "pmovsxbd", + "pmovsxbq", + "pmovsxbw", + "pmovsxdq", + "pmovsxwd", + "pmovsxwq", + "pmovzxbd", + "pmovzxbq", + "pmovzxbw", + "pmovzxdq", + "pmovzxwd", + "pmovzxwq", + "pmuldq", + "pmulhrsw", + "pmulhrw", + "pmulhuw", + "pmulhw", + "pmulld", + "pmullw", + "pmuludq", + "pop", + "popa", + "popad", + "popcnt", + "popfd", + "popfq", + "popfw", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "psadbw", + "pshufb", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "psignb", + "psignd", + "psignw", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "pswapd", + "ptest", + "punpckhbw", + "punpckhdq", + "punpckhqdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklqdq", + "punpcklwd", + "push", + "pusha", + "pushad", + "pushfd", + "pushfq", + "pushfw", + "pxor", + "rcl", + "rcpps", + "rcpss", + "rcr", + "rdmsr", + "rdpmc", + "rdrand", + "rdtsc", + "rdtscp", + "rep", + "repne", + "ret", + "retf", + "rol", + "ror", + "roundpd", + "roundps", + "roundsd", + "roundss", + "rsm", + "rsqrtps", + "rsqrtss", + "sahf", + "salc", + "sar", + "sbb", + "scasb", + "scasd", + "scasq", + "scasw", + "seta", + "setae", + "setb", + "setbe", + "setg", + "setge", + "setl", + "setle", + "setno", + "setnp", + "setns", + "setnz", + "seto", + "setp", + "sets", + "setz", + "sfence", + "sgdt", + "shl", + "shld", + "shr", + "shrd", + "shufpd", + "shufps", + "sidt", + "skinit", + "sldt", + "smsw", + "sqrtpd", + "sqrtps", + "sqrtsd", + "sqrtss", + "stc", + "std", + "stgi", + "sti", + "stmxcsr", + "stosb", + "stosd", + "stosq", + "stosw", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "swapgs", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud2", + "unpckhpd", + "unpckhps", + "unpcklpd", + "unpcklps", + "vaddpd", + "vaddps", + "vaddsd", + "vaddss", + "vaddsubpd", + "vaddsubps", + "vaesdec", + "vaesdeclast", + "vaesenc", + "vaesenclast", + "vaesimc", + "vaeskeygenassist", + "vandnpd", + "vandnps", + "vandpd", + "vandps", + "vblendpd", + "vblendps", + "vblendvpd", + "vblendvps", + "vbroadcastsd", + "vbroadcastss", + "vcmppd", + "vcmpps", + "vcmpsd", + "vcmpss", + "vcomisd", + "vcomiss", + "vcvtdq2pd", + "vcvtdq2ps", + "vcvtpd2dq", + "vcvtpd2ps", + "vcvtps2dq", + "vcvtps2pd", + "vcvtsd2si", + "vcvtsd2ss", + "vcvtsi2sd", + "vcvtsi2ss", + "vcvtss2sd", + "vcvtss2si", + "vcvttpd2dq", + "vcvttps2dq", + "vcvttsd2si", + "vcvttss2si", + "vdivpd", + "vdivps", + "vdivsd", + "vdivss", + "vdppd", + "vdpps", + "verr", + "verw", + "vextractf128", + "vextractps", + "vhaddpd", + "vhaddps", + "vhsubpd", + "vhsubps", + "vinsertf128", + "vinsertps", + "vlddqu", + "vmaskmovdqu", + "vmaskmovpd", + "vmaskmovps", + "vmaxpd", + "vmaxps", + "vmaxsd", + "vmaxss", + "vmcall", + "vmclear", + "vminpd", + "vminps", + "vminsd", + "vminss", + "vmlaunch", + "vmload", + "vmmcall", + "vmovapd", + "vmovaps", + "vmovd", + "vmovddup", + "vmovdqa", + "vmovdqu", + "vmovhlps", + "vmovhpd", + "vmovhps", + "vmovlhps", + "vmovlpd", + "vmovlps", + "vmovmskpd", + "vmovmskps", + "vmovntdq", + "vmovntdqa", + "vmovntpd", + "vmovntps", + "vmovq", + "vmovsd", + "vmovshdup", + "vmovsldup", + "vmovss", + "vmovupd", + "vmovups", + "vmpsadbw", + "vmptrld", + "vmptrst", + "vmread", + "vmresume", + "vmrun", + "vmsave", + "vmulpd", + "vmulps", + "vmulsd", + "vmulss", + "vmwrite", + "vmxoff", + "vmxon", + "vorpd", + "vorps", + "vpabsb", + "vpabsd", + "vpabsw", + "vpackssdw", + "vpacksswb", + "vpackusdw", + "vpackuswb", + "vpaddb", + "vpaddd", + "vpaddq", + "vpaddsb", + "vpaddsw", + "vpaddusb", + "vpaddusw", + "vpaddw", + "vpalignr", + "vpand", + "vpandn", + "vpavgb", + "vpavgw", + "vpblendvb", + "vpblendw", + "vpclmulqdq", + "vpcmpeqb", + "vpcmpeqd", + "vpcmpeqq", + "vpcmpeqw", + "vpcmpestri", + "vpcmpestrm", + "vpcmpgtb", + "vpcmpgtd", + "vpcmpgtq", + "vpcmpgtw", + "vpcmpistri", + "vpcmpistrm", + "vperm2f128", + "vpermilpd", + "vpermilps", + "vpextrb", + "vpextrd", + "vpextrq", + "vpextrw", + "vphaddd", + "vphaddsw", + "vphaddw", + "vphminposuw", + "vphsubd", + "vphsubsw", + "vphsubw", + "vpinsrb", + "vpinsrd", + "vpinsrq", + "vpinsrw", + "vpmaddubsw", + "vpmaddwd", + "vpmaxsb", + "vpmaxsd", + "vpmaxsw", + "vpmaxub", + "vpmaxud", + "vpmaxuw", + "vpminsb", + "vpminsd", + "vpminsw", + "vpminub", + "vpminud", + "vpminuw", + "vpmovmskb", + "vpmovsxbd", + "vpmovsxbq", + "vpmovsxbw", + "vpmovsxwd", + "vpmovsxwq", + "vpmovzxbd", + "vpmovzxbq", + "vpmovzxbw", + "vpmovzxdq", + "vpmovzxwd", + "vpmovzxwq", + "vpmuldq", + "vpmulhrsw", + "vpmulhuw", + "vpmulhw", + "vpmulld", + "vpmullw", + "vpor", + "vpsadbw", + "vpshufb", + "vpshufd", + "vpshufhw", + "vpshuflw", + "vpsignb", + "vpsignd", + "vpsignw", + "vpslld", + "vpslldq", + "vpsllq", + "vpsllw", + "vpsrad", + "vpsraw", + "vpsrld", + "vpsrldq", + "vpsrlq", + "vpsrlw", + "vpsubb", + "vpsubd", + "vpsubq", + "vpsubsb", + "vpsubsw", + "vpsubusb", + "vpsubusw", + "vpsubw", + "vptest", + "vpunpckhbw", + "vpunpckhdq", + "vpunpckhqdq", + "vpunpckhwd", + "vpunpcklbw", + "vpunpckldq", + "vpunpcklqdq", + "vpunpcklwd", + "vpxor", + "vrcpps", + "vrcpss", + "vroundpd", + "vroundps", + "vroundsd", + "vroundss", + "vrsqrtps", + "vrsqrtss", + "vshufpd", + "vshufps", + "vsqrtpd", + "vsqrtps", + "vsqrtsd", + "vsqrtss", + "vstmxcsr", + "vsubpd", + "vsubps", + "vsubsd", + "vsubss", + "vtestpd", + "vtestps", + "vucomisd", + "vucomiss", + "vunpckhpd", + "vunpckhps", + "vunpcklpd", + "vunpcklps", + "vxorpd", + "vxorps", + "vzeroall", + "vzeroupper", + "wait", + "wbinvd", + "wrmsr", + "xadd", + "xchg", + "xcryptcbc", + "xcryptcfb", + "xcryptctr", + "xcryptecb", + "xcryptofb", + "xgetbv", + "xlatb", + "xor", + "xorpd", + "xorps", + "xrstor", + "xsave", + "xsetbv", + "xsha1", + "xsha256", + "xstore", + "invalid", + "3dnow", + "none", + "db", + "pause" +}; diff --git a/deps/extra/udis86/libudis86/itab.h b/deps/extra/udis86/libudis86/itab.h new file mode 100644 index 0000000..3d54c43 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.h @@ -0,0 +1,939 @@ +#ifndef UD_ITAB_H +#define UD_ITAB_H + +/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */ + +/* ud_table_type -- lookup table types (see decode.c) */ +enum ud_table_type { + UD_TAB__OPC_VEX, + UD_TAB__OPC_TABLE, + UD_TAB__OPC_X87, + UD_TAB__OPC_MOD, + UD_TAB__OPC_RM, + UD_TAB__OPC_OSIZE, + UD_TAB__OPC_MODE, + UD_TAB__OPC_VEX_L, + UD_TAB__OPC_3DNOW, + UD_TAB__OPC_REG, + UD_TAB__OPC_ASIZE, + UD_TAB__OPC_VEX_W, + UD_TAB__OPC_SSE, + UD_TAB__OPC_VENDOR +}; + +/* ud_mnemonic -- mnemonic constants */ +enum ud_mnemonic_code { + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iaesdec, + UD_Iaesdeclast, + UD_Iaesenc, + UD_Iaesenclast, + UD_Iaesimc, + UD_Iaeskeygenassist, + UD_Iand, + UD_Iandnpd, + UD_Iandnps, + UD_Iandpd, + UD_Iandps, + UD_Iarpl, + UD_Iblendpd, + UD_Iblendps, + UD_Iblendvpd, + UD_Iblendvps, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icdq, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmova, + UD_Icmovae, + UD_Icmovb, + UD_Icmovbe, + UD_Icmovg, + UD_Icmovge, + UD_Icmovl, + UD_Icmovle, + UD_Icmovno, + UD_Icmovnp, + UD_Icmovns, + UD_Icmovnz, + UD_Icmovo, + UD_Icmovp, + UD_Icmovs, + UD_Icmovz, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpsw, + UD_Icmpxchg, + UD_Icmpxchg16b, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icqo, + UD_Icrc32, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2pd, + UD_Icvtpi2ps, + UD_Icvtps2dq, + UD_Icvtps2pd, + UD_Icvtps2pi, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2sd, + UD_Icvtsi2ss, + UD_Icvtss2sd, + UD_Icvtss2si, + UD_Icvttpd2dq, + UD_Icvttpd2pi, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvttss2si, + UD_Icwd, + UD_Icwde, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Idppd, + UD_Idpps, + UD_Iemms, + UD_Ienter, + UD_Iextractps, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmovbe, + UD_Ifcmove, + UD_Ifcmovnb, + UD_Ifcmovnbe, + UD_Ifcmovne, + UD_Ifcmovnu, + UD_Ifcmovu, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomi, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp3, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ifiadd, + UD_Ificom, + UD_Ificomp, + UD_Ifidiv, + UD_Ifidivr, + UD_Ifild, + UD_Ifimul, + UD_Ifincstp, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifisub, + UD_Ifisubr, + UD_Ifld, + UD_Ifld1, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifldl2e, + UD_Ifldl2t, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldpi, + UD_Ifldz, + UD_Ifmul, + UD_Ifmulp, + UD_Ifndisi, + UD_Ifneni, + UD_Ifninit, + UD_Ifnop, + UD_Ifnsave, + UD_Ifnsetpm, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifrstpm, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifst, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomi, + UD_Ifucomip, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Igetsec, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iimul, + UD_Iin, + UD_Iinc, + UD_Iinsb, + UD_Iinsd, + UD_Iinsertps, + UD_Iinsw, + UD_Iint, + UD_Iint1, + UD_Iint3, + UD_Iinto, + UD_Iinvd, + UD_Iinvept, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iinvvpid, + UD_Iiretd, + UD_Iiretq, + UD_Iiretw, + UD_Ija, + UD_Ijae, + UD_Ijb, + UD_Ijbe, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijg, + UD_Ijge, + UD_Ijl, + UD_Ijle, + UD_Ijmp, + UD_Ijno, + UD_Ijnp, + UD_Ijns, + UD_Ijnz, + UD_Ijo, + UD_Ijp, + UD_Ijrcxz, + UD_Ijs, + UD_Ijz, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Ileave, + UD_Iles, + UD_Ilfence, + UD_Ilfs, + UD_Ilgdt, + UD_Ilgs, + UD_Ilidt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsd, + UD_Ilodsq, + UD_Ilodsw, + UD_Iloop, + UD_Iloope, + UD_Iloopne, + UD_Ilsl, + UD_Ilss, + UD_Iltr, + UD_Imaskmovdqu, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imontmul, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovbe, + UD_Imovd, + UD_Imovddup, + UD_Imovdq2q, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovhlps, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovntdqa, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsd, + UD_Imovshdup, + UD_Imovsldup, + UD_Imovsq, + UD_Imovss, + UD_Imovsw, + UD_Imovsx, + UD_Imovsxd, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Impsadbw, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsd, + UD_Ioutsw, + UD_Ipabsb, + UD_Ipabsd, + UD_Ipabsw, + UD_Ipackssdw, + UD_Ipacksswb, + UD_Ipackusdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddd, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipaddw, + UD_Ipalignr, + UD_Ipand, + UD_Ipandn, + UD_Ipavgb, + UD_Ipavgusb, + UD_Ipavgw, + UD_Ipblendvb, + UD_Ipblendw, + UD_Ipclmulqdq, + UD_Ipcmpeqb, + UD_Ipcmpeqd, + UD_Ipcmpeqq, + UD_Ipcmpeqw, + UD_Ipcmpestri, + UD_Ipcmpestrm, + UD_Ipcmpgtb, + UD_Ipcmpgtd, + UD_Ipcmpgtq, + UD_Ipcmpgtw, + UD_Ipcmpistri, + UD_Ipcmpistrm, + UD_Ipextrb, + UD_Ipextrd, + UD_Ipextrq, + UD_Ipextrw, + UD_Ipf2id, + UD_Ipf2iw, + UD_Ipfacc, + UD_Ipfadd, + UD_Ipfcmpeq, + UD_Ipfcmpge, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfmin, + UD_Ipfmul, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfrcp, + UD_Ipfrcpit1, + UD_Ipfrcpit2, + UD_Ipfrsqit1, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfsubr, + UD_Iphaddd, + UD_Iphaddsw, + UD_Iphaddw, + UD_Iphminposuw, + UD_Iphsubd, + UD_Iphsubsw, + UD_Iphsubw, + UD_Ipi2fd, + UD_Ipi2fw, + UD_Ipinsrb, + UD_Ipinsrd, + UD_Ipinsrq, + UD_Ipinsrw, + UD_Ipmaddubsw, + UD_Ipmaddwd, + UD_Ipmaxsb, + UD_Ipmaxsd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipmaxud, + UD_Ipmaxuw, + UD_Ipminsb, + UD_Ipminsd, + UD_Ipminsw, + UD_Ipminub, + UD_Ipminud, + UD_Ipminuw, + UD_Ipmovmskb, + UD_Ipmovsxbd, + UD_Ipmovsxbq, + UD_Ipmovsxbw, + UD_Ipmovsxdq, + UD_Ipmovsxwd, + UD_Ipmovsxwq, + UD_Ipmovzxbd, + UD_Ipmovzxbq, + UD_Ipmovzxbw, + UD_Ipmovzxdq, + UD_Ipmovzxwd, + UD_Ipmovzxwq, + UD_Ipmuldq, + UD_Ipmulhrsw, + UD_Ipmulhrw, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmulld, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopcnt, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipopfw, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufb, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipsignb, + UD_Ipsignd, + UD_Ipsignw, + UD_Ipslld, + UD_Ipslldq, + UD_Ipsllq, + UD_Ipsllw, + UD_Ipsrad, + UD_Ipsraw, + UD_Ipsrld, + UD_Ipsrldq, + UD_Ipsrlq, + UD_Ipsrlw, + UD_Ipsubb, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipsubw, + UD_Ipswapd, + UD_Iptest, + UD_Ipunpckhbw, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpckhwd, + UD_Ipunpcklbw, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipunpcklwd, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipushfw, + UD_Ipxor, + UD_Ircl, + UD_Ircpps, + UD_Ircpss, + UD_Ircr, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdrand, + UD_Irdtsc, + UD_Irdtscp, + UD_Irep, + UD_Irepne, + UD_Iret, + UD_Iretf, + UD_Irol, + UD_Iror, + UD_Iroundpd, + UD_Iroundps, + UD_Iroundsd, + UD_Iroundss, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isalc, + UD_Isar, + UD_Isbb, + UD_Iscasb, + UD_Iscasd, + UD_Iscasq, + UD_Iscasw, + UD_Iseta, + UD_Isetae, + UD_Isetb, + UD_Isetbe, + UD_Isetg, + UD_Isetge, + UD_Isetl, + UD_Isetle, + UD_Isetno, + UD_Isetnp, + UD_Isetns, + UD_Isetnz, + UD_Iseto, + UD_Isetp, + UD_Isets, + UD_Isetz, + UD_Isfence, + UD_Isgdt, + UD_Ishl, + UD_Ishld, + UD_Ishr, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Iskinit, + UD_Isldt, + UD_Ismsw, + UD_Isqrtpd, + UD_Isqrtps, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Istmxcsr, + UD_Istosb, + UD_Istosd, + UD_Istosq, + UD_Istosw, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklpd, + UD_Iunpcklps, + UD_Ivaddpd, + UD_Ivaddps, + UD_Ivaddsd, + UD_Ivaddss, + UD_Ivaddsubpd, + UD_Ivaddsubps, + UD_Ivaesdec, + UD_Ivaesdeclast, + UD_Ivaesenc, + UD_Ivaesenclast, + UD_Ivaesimc, + UD_Ivaeskeygenassist, + UD_Ivandnpd, + UD_Ivandnps, + UD_Ivandpd, + UD_Ivandps, + UD_Ivblendpd, + UD_Ivblendps, + UD_Ivblendvpd, + UD_Ivblendvps, + UD_Ivbroadcastsd, + UD_Ivbroadcastss, + UD_Ivcmppd, + UD_Ivcmpps, + UD_Ivcmpsd, + UD_Ivcmpss, + UD_Ivcomisd, + UD_Ivcomiss, + UD_Ivcvtdq2pd, + UD_Ivcvtdq2ps, + UD_Ivcvtpd2dq, + UD_Ivcvtpd2ps, + UD_Ivcvtps2dq, + UD_Ivcvtps2pd, + UD_Ivcvtsd2si, + UD_Ivcvtsd2ss, + UD_Ivcvtsi2sd, + UD_Ivcvtsi2ss, + UD_Ivcvtss2sd, + UD_Ivcvtss2si, + UD_Ivcvttpd2dq, + UD_Ivcvttps2dq, + UD_Ivcvttsd2si, + UD_Ivcvttss2si, + UD_Ivdivpd, + UD_Ivdivps, + UD_Ivdivsd, + UD_Ivdivss, + UD_Ivdppd, + UD_Ivdpps, + UD_Iverr, + UD_Iverw, + UD_Ivextractf128, + UD_Ivextractps, + UD_Ivhaddpd, + UD_Ivhaddps, + UD_Ivhsubpd, + UD_Ivhsubps, + UD_Ivinsertf128, + UD_Ivinsertps, + UD_Ivlddqu, + UD_Ivmaskmovdqu, + UD_Ivmaskmovpd, + UD_Ivmaskmovps, + UD_Ivmaxpd, + UD_Ivmaxps, + UD_Ivmaxsd, + UD_Ivmaxss, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivminpd, + UD_Ivminps, + UD_Ivminsd, + UD_Ivminss, + UD_Ivmlaunch, + UD_Ivmload, + UD_Ivmmcall, + UD_Ivmovapd, + UD_Ivmovaps, + UD_Ivmovd, + UD_Ivmovddup, + UD_Ivmovdqa, + UD_Ivmovdqu, + UD_Ivmovhlps, + UD_Ivmovhpd, + UD_Ivmovhps, + UD_Ivmovlhps, + UD_Ivmovlpd, + UD_Ivmovlps, + UD_Ivmovmskpd, + UD_Ivmovmskps, + UD_Ivmovntdq, + UD_Ivmovntdqa, + UD_Ivmovntpd, + UD_Ivmovntps, + UD_Ivmovq, + UD_Ivmovsd, + UD_Ivmovshdup, + UD_Ivmovsldup, + UD_Ivmovss, + UD_Ivmovupd, + UD_Ivmovups, + UD_Ivmpsadbw, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmread, + UD_Ivmresume, + UD_Ivmrun, + UD_Ivmsave, + UD_Ivmulpd, + UD_Ivmulps, + UD_Ivmulsd, + UD_Ivmulss, + UD_Ivmwrite, + UD_Ivmxoff, + UD_Ivmxon, + UD_Ivorpd, + UD_Ivorps, + UD_Ivpabsb, + UD_Ivpabsd, + UD_Ivpabsw, + UD_Ivpackssdw, + UD_Ivpacksswb, + UD_Ivpackusdw, + UD_Ivpackuswb, + UD_Ivpaddb, + UD_Ivpaddd, + UD_Ivpaddq, + UD_Ivpaddsb, + UD_Ivpaddsw, + UD_Ivpaddusb, + UD_Ivpaddusw, + UD_Ivpaddw, + UD_Ivpalignr, + UD_Ivpand, + UD_Ivpandn, + UD_Ivpavgb, + UD_Ivpavgw, + UD_Ivpblendvb, + UD_Ivpblendw, + UD_Ivpclmulqdq, + UD_Ivpcmpeqb, + UD_Ivpcmpeqd, + UD_Ivpcmpeqq, + UD_Ivpcmpeqw, + UD_Ivpcmpestri, + UD_Ivpcmpestrm, + UD_Ivpcmpgtb, + UD_Ivpcmpgtd, + UD_Ivpcmpgtq, + UD_Ivpcmpgtw, + UD_Ivpcmpistri, + UD_Ivpcmpistrm, + UD_Ivperm2f128, + UD_Ivpermilpd, + UD_Ivpermilps, + UD_Ivpextrb, + UD_Ivpextrd, + UD_Ivpextrq, + UD_Ivpextrw, + UD_Ivphaddd, + UD_Ivphaddsw, + UD_Ivphaddw, + UD_Ivphminposuw, + UD_Ivphsubd, + UD_Ivphsubsw, + UD_Ivphsubw, + UD_Ivpinsrb, + UD_Ivpinsrd, + UD_Ivpinsrq, + UD_Ivpinsrw, + UD_Ivpmaddubsw, + UD_Ivpmaddwd, + UD_Ivpmaxsb, + UD_Ivpmaxsd, + UD_Ivpmaxsw, + UD_Ivpmaxub, + UD_Ivpmaxud, + UD_Ivpmaxuw, + UD_Ivpminsb, + UD_Ivpminsd, + UD_Ivpminsw, + UD_Ivpminub, + UD_Ivpminud, + UD_Ivpminuw, + UD_Ivpmovmskb, + UD_Ivpmovsxbd, + UD_Ivpmovsxbq, + UD_Ivpmovsxbw, + UD_Ivpmovsxwd, + UD_Ivpmovsxwq, + UD_Ivpmovzxbd, + UD_Ivpmovzxbq, + UD_Ivpmovzxbw, + UD_Ivpmovzxdq, + UD_Ivpmovzxwd, + UD_Ivpmovzxwq, + UD_Ivpmuldq, + UD_Ivpmulhrsw, + UD_Ivpmulhuw, + UD_Ivpmulhw, + UD_Ivpmulld, + UD_Ivpmullw, + UD_Ivpor, + UD_Ivpsadbw, + UD_Ivpshufb, + UD_Ivpshufd, + UD_Ivpshufhw, + UD_Ivpshuflw, + UD_Ivpsignb, + UD_Ivpsignd, + UD_Ivpsignw, + UD_Ivpslld, + UD_Ivpslldq, + UD_Ivpsllq, + UD_Ivpsllw, + UD_Ivpsrad, + UD_Ivpsraw, + UD_Ivpsrld, + UD_Ivpsrldq, + UD_Ivpsrlq, + UD_Ivpsrlw, + UD_Ivpsubb, + UD_Ivpsubd, + UD_Ivpsubq, + UD_Ivpsubsb, + UD_Ivpsubsw, + UD_Ivpsubusb, + UD_Ivpsubusw, + UD_Ivpsubw, + UD_Ivptest, + UD_Ivpunpckhbw, + UD_Ivpunpckhdq, + UD_Ivpunpckhqdq, + UD_Ivpunpckhwd, + UD_Ivpunpcklbw, + UD_Ivpunpckldq, + UD_Ivpunpcklqdq, + UD_Ivpunpcklwd, + UD_Ivpxor, + UD_Ivrcpps, + UD_Ivrcpss, + UD_Ivroundpd, + UD_Ivroundps, + UD_Ivroundsd, + UD_Ivroundss, + UD_Ivrsqrtps, + UD_Ivrsqrtss, + UD_Ivshufpd, + UD_Ivshufps, + UD_Ivsqrtpd, + UD_Ivsqrtps, + UD_Ivsqrtsd, + UD_Ivsqrtss, + UD_Ivstmxcsr, + UD_Ivsubpd, + UD_Ivsubps, + UD_Ivsubsd, + UD_Ivsubss, + UD_Ivtestpd, + UD_Ivtestps, + UD_Ivucomisd, + UD_Ivucomiss, + UD_Ivunpckhpd, + UD_Ivunpckhps, + UD_Ivunpcklpd, + UD_Ivunpcklps, + UD_Ivxorpd, + UD_Ivxorps, + UD_Ivzeroall, + UD_Ivzeroupper, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixcryptcbc, + UD_Ixcryptcfb, + UD_Ixcryptctr, + UD_Ixcryptecb, + UD_Ixcryptofb, + UD_Ixgetbv, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Ixrstor, + UD_Ixsave, + UD_Ixsetbv, + UD_Ixsha1, + UD_Ixsha256, + UD_Ixstore, + UD_Iinvalid, + UD_I3dnow, + UD_Inone, + UD_Idb, + UD_Ipause, + UD_MAX_MNEMONIC_CODE +}; + +extern const char * ud_mnemonics_str[]; + +#endif /* UD_ITAB_H */ diff --git a/deps/gsc-tool b/deps/gsc-tool new file mode 160000 index 0000000..2dbff1a --- /dev/null +++ b/deps/gsc-tool @@ -0,0 +1 @@ +Subproject commit 2dbff1a408096e418c5b3eda01bc9a91eee6587b diff --git a/deps/libtomcrypt b/deps/libtomcrypt new file mode 160000 index 0000000..7e863d2 --- /dev/null +++ b/deps/libtomcrypt @@ -0,0 +1 @@ +Subproject commit 7e863d21429f94ed6a720e24499a12a3f852bb31 diff --git a/deps/libtommath b/deps/libtommath new file mode 160000 index 0000000..8314bde --- /dev/null +++ b/deps/libtommath @@ -0,0 +1 @@ +Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091 diff --git a/deps/minhook b/deps/minhook new file mode 160000 index 0000000..f5485b8 --- /dev/null +++ b/deps/minhook @@ -0,0 +1 @@ +Subproject commit f5485b8454544c2f034c78f8f127c1d03dea3636 diff --git a/deps/premake/asmjit.lua b/deps/premake/asmjit.lua new file mode 100644 index 0000000..ee93259 --- /dev/null +++ b/deps/premake/asmjit.lua @@ -0,0 +1,34 @@ +asmjit = { + source = path.join(dependencies.basePath, "asmjit"), +} + +function asmjit.import() + links { "asmjit" } + asmjit.includes() +end + +function asmjit.includes() + includedirs { + path.join(asmjit.source, "src") + } + + defines { + "ASMJIT_STATIC" + } +end + +function asmjit.project() + project "asmjit" + language "C++" + + asmjit.includes() + + files { + path.join(asmjit.source, "src/**.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, asmjit) diff --git a/deps/premake/discord-rpc.lua b/deps/premake/discord-rpc.lua new file mode 100644 index 0000000..ef28bcb --- /dev/null +++ b/deps/premake/discord-rpc.lua @@ -0,0 +1,39 @@ +discordrpc = { + source = path.join(dependencies.basePath, "discord-rpc"), +} + +function discordrpc.import() + links { "discord-rpc" } + discordrpc.includes() +end + +function discordrpc.includes() + includedirs { + path.join(discordrpc.source, "include"), + } +end + +function discordrpc.project() + project "discord-rpc" + language "C++" + + discordrpc.includes() + rapidjson.import(); + + files { + path.join(discordrpc.source, "src/*.h"), + path.join(discordrpc.source, "src/*.cpp"), + } + + removefiles { + path.join(discordrpc.source, "src/dllmain.cpp"), + path.join(discordrpc.source, "src/*_linux.cpp"), + path.join(discordrpc.source, "src/*_unix.cpp"), + path.join(discordrpc.source, "src/*_osx.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, discordrpc) diff --git a/deps/premake/gsc-tool.lua b/deps/premake/gsc-tool.lua new file mode 100644 index 0000000..32efc4d --- /dev/null +++ b/deps/premake/gsc-tool.lua @@ -0,0 +1,62 @@ +gsc_tool = { + source = path.join(dependencies.basePath, "gsc-tool"), +} + +function gsc_tool.import() + links { "xsk-gsc-s1", "xsk-gsc-utils" } + gsc_tool.includes() +end + +function gsc_tool.includes() + includedirs { + path.join(gsc_tool.source, "include"), + } +end + +function gsc_tool.project() + project "xsk-gsc-utils" + kind "StaticLib" + language "C++" + + files { + path.join(gsc_tool.source, "include/xsk/utils/*.hpp"), + path.join(gsc_tool.source, "src/utils/*.cpp"), + } + + includedirs { + path.join(gsc_tool.source, "include"), + } + + zlib.includes() + + project "xsk-gsc-s1" + kind "StaticLib" + language "C++" + + filter "action:vs*" + buildoptions "/Zc:__cplusplus" + filter {} + + files { + path.join(gsc_tool.source, "include/xsk/stdinc.hpp"), + + path.join(gsc_tool.source, "include/xsk/gsc/engine/s1_pc.hpp"), + path.join(gsc_tool.source, "src/gsc/engine/s1_pc.cpp"), + + path.join(gsc_tool.source, "src/gsc/engine/s1_pc_code.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/s1_pc_func.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/s1_pc_meth.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/s1_pc_token.cpp"), + + path.join(gsc_tool.source, "src/gsc/*.cpp"), + + path.join(gsc_tool.source, "src/gsc/common/*.cpp"), + path.join(gsc_tool.source, "include/xsk/gsc/common/*.hpp"), + } + + includedirs { + path.join(gsc_tool.source, "include"), + } +end + +table.insert(dependencies, gsc_tool) diff --git a/deps/premake/gsl.lua b/deps/premake/gsl.lua new file mode 100644 index 0000000..7a2daf6 --- /dev/null +++ b/deps/premake/gsl.lua @@ -0,0 +1,19 @@ +gsl = { + source = path.join(dependencies.basePath, "GSL"), +} + +function gsl.import() + gsl.includes() +end + +function gsl.includes() + includedirs { + path.join(gsl.source, "include") + } +end + +function gsl.project() + +end + +table.insert(dependencies, gsl) diff --git a/deps/premake/libtomcrypt.lua b/deps/premake/libtomcrypt.lua new file mode 100644 index 0000000..7ca3570 --- /dev/null +++ b/deps/premake/libtomcrypt.lua @@ -0,0 +1,64 @@ +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", + "LTC_NO_FILE", + "ARGTYPE=4", + } +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/**/*_test.c"), + path.join(libtomcrypt.source, "src/**/*tab.c"), + path.join(libtomcrypt.source, "src/encauth/ocb3/**.c"), + } + + defines { + "_CRT_SECURE_NO_WARNINGS", + "LTC_SOURCE", + "_LIB", + "USE_LTM" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtomcrypt) diff --git a/deps/premake/libtommath.lua b/deps/premake/libtommath.lua new file mode 100644 index 0000000..ab4cdde --- /dev/null +++ b/deps/premake/libtommath.lua @@ -0,0 +1,52 @@ +libtommath = { + source = path.join(dependencies.basePath, "libtommath"), +} + +function libtommath.import() + links { + "libtommath" + } + + libtommath.includes() +end + +function libtommath.includes() + includedirs { + libtommath.source + } + + defines { + "LTM_DESC", + "__STDC_IEC_559__", + "MP_NO_DEV_URANDOM", + } +end + +function libtommath.project() + project "libtommath" + language "C" + + libtommath.includes() + + files { + path.join(libtommath.source, "*.c"), + } + + defines { + "_LIB" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtommath) diff --git a/deps/premake/minhook.lua b/deps/premake/minhook.lua new file mode 100644 index 0000000..396d4d3 --- /dev/null +++ b/deps/premake/minhook.lua @@ -0,0 +1,31 @@ +minhook = { + source = path.join(dependencies.basePath, "minhook"), +} + +function minhook.import() + links { "minhook" } + minhook.includes() +end + +function minhook.includes() + includedirs { + path.join(minhook.source, "include") + } +end + +function minhook.project() + project "minhook" + language "C" + + minhook.includes() + + files { + path.join(minhook.source, "src/**.h"), + path.join(minhook.source, "src/**.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minhook) diff --git a/deps/premake/minizip.lua b/deps/premake/minizip.lua new file mode 100644 index 0000000..4a5754b --- /dev/null +++ b/deps/premake/minizip.lua @@ -0,0 +1,43 @@ +minizip = { + source = path.join(dependencies.basePath, "zlib/contrib/minizip"), +} + +function minizip.import() + links { "minizip" } + zlib.import() + minizip.includes() +end + +function minizip.includes() + includedirs { + minizip.source + } + + zlib.includes() +end + +function minizip.project() + project "minizip" + language "C" + + minizip.includes() + + files { + path.join(minizip.source, "*.h"), + path.join(minizip.source, "*.c"), + } + + removefiles { + path.join(minizip.source, "miniunz.c"), + path.join(minizip.source, "minizip.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minizip) diff --git a/deps/premake/protobuf.lua b/deps/premake/protobuf.lua new file mode 100644 index 0000000..1c58972 --- /dev/null +++ b/deps/premake/protobuf.lua @@ -0,0 +1,60 @@ +protobuf = { + source = path.join(dependencies.basePath, "protobuf"), +} + +function protobuf.import() + links { + "protobuf" + } + + protobuf.includes() +end + +function protobuf.includes() + includedirs { + path.join(protobuf.source, "src"), + } +end + +function protobuf.project() + project "protobuf" + language "C++" + + protobuf.includes() + + files { + path.join(protobuf.source, "src/**.cc"), + "./src/**.proto", + } + + removefiles { + path.join(protobuf.source, "src/**/*test.cc"), + path.join(protobuf.source, "src/google/protobuf/*test*.cc"), + + path.join(protobuf.source, "src/google/protobuf/testing/**.cc"), + path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"), + + path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"), + path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"), + path.join(protobuf.source, "**/*_gcc.cc"), + } + + rules { + "ProtobufCompiler" + } + + defines { + "_SCL_SECURE_NO_WARNINGS", + "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", + "_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS", + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, protobuf) diff --git a/deps/premake/rapidjson.lua b/deps/premake/rapidjson.lua new file mode 100644 index 0000000..0dc3b4b --- /dev/null +++ b/deps/premake/rapidjson.lua @@ -0,0 +1,23 @@ +rapidjson = { + source = path.join(dependencies.basePath, "rapidjson"), +} + +function rapidjson.import() + defines { + "RAPIDJSON_HAS_STDSTRING" + } + + rapidjson.includes() +end + +function rapidjson.includes() + includedirs { + path.join(rapidjson.source, "include"), + } +end + +function rapidjson.project() + +end + +table.insert(dependencies, rapidjson) diff --git a/deps/premake/udis86.lua b/deps/premake/udis86.lua new file mode 100644 index 0000000..896ec8b --- /dev/null +++ b/deps/premake/udis86.lua @@ -0,0 +1,37 @@ +udis86 = { + source = path.join(dependencies.basePath, "udis86"), +} + +function udis86.import() + links { + "udis86" + } + + udis86.includes() +end + +function udis86.includes() + includedirs { + udis86.source, + path.join(udis86.source, "libudis86"), + path.join(dependencies.basePath, "extra/udis86"), + path.join(dependencies.basePath, "extra/udis86/libudis86"), + } +end + +function udis86.project() + project "udis86" + language "C" + + udis86.includes() + + files { + path.join(udis86.source, "libudis86/*.c"), + path.join(dependencies.basePath, "extra/udis86/libudis86/*.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, udis86) diff --git a/deps/premake/wintoast.lua b/deps/premake/wintoast.lua new file mode 100644 index 0000000..deffb7c --- /dev/null +++ b/deps/premake/wintoast.lua @@ -0,0 +1,32 @@ +wintoast = { + source = path.join(dependencies.basePath, "WinToast"), +} + +function wintoast.import() + links { "WinToast" } + wintoast.includes() +end + +function wintoast.includes() + includedirs { + path.join(wintoast.source, "include"), + } +end + +function wintoast.project() + project "WinToast" + language "C++" + + wintoast.includes() + rapidjson.import(); + + files { + path.join(wintoast.source, "include/wintoastlib.h"), + path.join(wintoast.source, "src/wintoastlib.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, wintoast) diff --git a/deps/premake/zlib.lua b/deps/premake/zlib.lua new file mode 100644 index 0000000..566a707 --- /dev/null +++ b/deps/premake/zlib.lua @@ -0,0 +1,39 @@ +zlib = { + source = path.join(dependencies.basePath, "zlib"), +} + +function zlib.import() + links { "zlib" } + zlib.includes() +end + +function zlib.includes() + includedirs { + zlib.source + } + + defines { + "ZLIB_CONST", + } +end + +function zlib.project() + project "zlib" + language "C" + + zlib.includes() + + files { + path.join(zlib.source, "*.h"), + path.join(zlib.source, "*.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, zlib) diff --git a/deps/protobuf b/deps/protobuf new file mode 160000 index 0000000..5a3dac8 --- /dev/null +++ b/deps/protobuf @@ -0,0 +1 @@ +Subproject commit 5a3dac894157bf3618b2c906a8b9073b4cad62b6 diff --git a/deps/rapidjson b/deps/rapidjson new file mode 160000 index 0000000..6089180 --- /dev/null +++ b/deps/rapidjson @@ -0,0 +1 @@ +Subproject commit 6089180ecb704cb2b136777798fa1be303618975 diff --git a/deps/udis86 b/deps/udis86 new file mode 160000 index 0000000..56ff6c8 --- /dev/null +++ b/deps/udis86 @@ -0,0 +1 @@ +Subproject commit 56ff6c87c11de0ffa725b14339004820556e343d diff --git a/deps/zlib b/deps/zlib new file mode 160000 index 0000000..643e17b --- /dev/null +++ b/deps/zlib @@ -0,0 +1 @@ +Subproject commit 643e17b7498d12ab8d15565662880579692f769d diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 0000000..d502375 --- /dev/null +++ b/premake5.lua @@ -0,0 +1,362 @@ +gitVersioningCommand = "git describe --tags --dirty --always" +gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD" + +-- Quote the given string input as a C string +function cstrquote(value) + if value == nil then + return "\"\"" + end + result = value:gsub("\\", "\\\\") + result = result:gsub("\"", "\\\"") + result = result:gsub("\n", "\\n") + result = result:gsub("\t", "\\t") + result = result:gsub("\r", "\\r") + result = result:gsub("\a", "\\a") + result = result:gsub("\b", "\\b") + result = "\"" .. result .. "\"" + return result +end + +-- Converts tags in "vX.X.X" format and given revision number Y to an array of numbers {X,X,X,Y}. +-- In the case where the format does not work fall back to padding with zeroes and just ending with the revision number. +-- partscount can be either 3 or 4. +function vertonumarr(value, vernumber, partscount) + vernum = {} + for num in string.gmatch(value or "", "%d+") do + if #vernum < 3 then + table.insert(vernum, tonumber(num)) + end + end + while #vernum < 3 do + table.insert(vernum, 0) + end + if #vernum < partscount then + table.insert(vernum, tonumber(vernumber)) + end + return vernum +end + +dependencies = { + basePath = "./deps" +} + +function dependencies.load() + dir = path.join(dependencies.basePath, "premake/*.lua") + deps = os.matchfiles(dir) + + for i, dep in pairs(deps) do + dep = dep:gsub(".lua", "") + require(dep) + end +end + +function dependencies.imports() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.import() + end + end +end + +function dependencies.projects() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.project() + end + end +end + +newoption { + trigger = "copy-to", + description = "Optional, copy the EXE to a custom folder after build, define the path here if wanted.", + value = "PATH" +} + +newoption { + trigger = "dev-build", + description = "Enable development builds of the client." +} + +newaction { + trigger = "version", + description = "Returns the version string for the current commit of the source code.", + onWorkspace = function(wks) + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + local version = gitDescribeOutput + + proc = assert(io.popen(gitCurrentBranchCommand, "r")) + local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "") + local gitCurrentBranchSuccess = proc:close() + if gitCurrentBranchSuccess then + -- We got a branch name, check if it is a feature branch + if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then + version = version .. "-" .. gitCurrentBranchOutput + end + end + + print(version) + os.exit(0) + end +} + +newaction { + trigger = "generate-buildinfo", + description = "Sets up build information file like version.h.", + onWorkspace = function(wks) + -- get old version number from version.hpp if any + local oldVersion = "(none)" + local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") + if oldVersionHeader ~= nil then + local oldVersionHeaderContent = assert(oldVersionHeader:read('*l')) + while oldVersionHeaderContent do + m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$") + if m ~= nil then + oldVersion = m + end + + oldVersionHeaderContent = oldVersionHeader:read('*l') + end + end + + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- generate version.hpp with a revision number if not equal + gitDescribeOutputQuoted = cstrquote(gitDescribeOutput) + if oldVersion ~= gitDescribeOutputQuoted then + -- get current git hash and write to version.txt (used by the preliminary updater) + -- TODO - remove once proper updater and release versioning exists + local proc = assert(io.popen("git rev-parse HEAD", "r")) + local gitCommitHash = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- get whether this is a clean revision (no uncommitted changes) + proc = assert(io.popen("git status --porcelain", "r")) + local revDirty = (assert(proc:read('*a')) ~= "") + if revDirty then revDirty = 1 else revDirty = 0 end + proc:close() + + -- get current tag name + proc = assert(io.popen("git describe --tags --abbrev=0")) + local tagName = proc:read('*l') + + -- get current branch name + proc = assert(io.popen("git branch --show-current")) + local branchName = proc:read('*l') + + -- branch for ci + if branchName == nil or branchName == '' then + proc = assert(io.popen("git show -s --pretty=%d HEAD")) + local branchInfo = proc:read('*l') + m = string.match(branchInfo, ".+,.+, ([^)]+)") + if m ~= nil then + branchName = m + end + end + + if branchName == nil then + branchName = "develop" + end + + print("Detected branch: " .. branchName) + + -- get revision number via git + local proc = assert(io.popen("git rev-list --count HEAD", "r")) + local revNumber = assert(proc:read('*a')):gsub("%s+", "") + + print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted) + + -- write to version.txt for preliminary updater + -- NOTE - remove this once we have a proper updater and proper release versioning + local versionFile = assert(io.open(wks.location .. "/version.txt", "w")) + versionFile:write(gitCommitHash) + versionFile:close() + + -- write version header + local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") + versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") + versionHeader:write("#define GIT_HASH " .. cstrquote(gitCommitHash) .. "\n") + versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") + versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Version transformed for RC files\n") + versionHeader:write("#define VERSION_PRODUCT_RC " .. table.concat(vertonumarr(tagName, revNumber, 3), ",") .. "\n") + versionHeader:write("#define VERSION_PRODUCT " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 3), ".")) .. "\n") + versionHeader:write("#define VERSION_FILE_RC " .. table.concat(vertonumarr(tagName, revNumber, 4), ",") .. "\n") + versionHeader:write("#define VERSION_FILE " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 4), ".")) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Alias definitions\n") + versionHeader:write("#define VERSION GIT_DESCRIBE\n") + versionHeader:write("#define SHORTVERSION VERSION_PRODUCT\n") + versionHeader:close() + local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" *\n") + versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") + versionHeader:write(" *\n") + versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n") + versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#include \".\\version.h\"\n") + versionHeader:close() + end + end +} + +dependencies.load() + +workspace "s1-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" + 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 "WindowedApp" +language "C++" + +targetname "s1-mod" + +pchheader "std_include.hpp" +pchsource "src/client/std_include.cpp" + +linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"} + +files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"} + +includedirs {"./src/client", "./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +dependson {"tlsdll", "runner"} + +links {"common"} + +prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"} + +if _OPTIONS["copy-to"] then + postbuildcommands {"copy /y \"$(TargetPath)\" \"" .. _OPTIONS["copy-to"] .. "\""} +end + +dependencies.imports() + +project "tlsdll" +kind "SharedLib" +language "C++" + +files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"} + +includedirs {"./src/tlsdll", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +project "runner" +kind "WindowedApp" +language "C++" + +files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"} + +includedirs {"./src/runner", "./src/common", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +dependencies.imports() + +group "Dependencies" +dependencies.projects() + +rule "ProtobufCompiler" +display "Protobuf compiler" +location "./build" +fileExtension ".proto" +buildmessage "Compiling %(Identity) with protoc..." +buildcommands {'@echo off', 'path "$(SolutionDir)\\..\\tools"', + 'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"', + 'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)'} +buildoutputs {'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc', '$(ProjectDir)\\src\\proto\\%(Filename).pb.h'} diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp new file mode 100644 index 0000000..2dcdd81 --- /dev/null +++ b/src/client/component/arxan.cpp @@ -0,0 +1,163 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "game/game.hpp" + +#include + +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(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(info)->Reserved3 = PVOID(DWORD64(explorer_pid)); + } + else if (info_class == 30) // ProcessDebugObjectHandle + { + *static_cast(info) = nullptr; + + return 0xC0000353; + } + else if (info_class == 7) // ProcessDebugPort + { + *static_cast(info) = nullptr; + } + else if (info_class == 31) + { + *static_cast(info) = 1; + } + } + + 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(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(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) + { + if (!game::environment::is_sp() + && game::dwGetLogOnStatus() == game::DW_LIVE_CONNECTED + && context->ContextFlags == CONTEXT_DEBUG_REGISTERS) + { + return TRUE; + } + + return SetThreadContext(thread, context); + } + } + + 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("NtClose"), nt_close_stub); + nt_query_information_process_hook.create(ntdll.get_proc("NtQueryInformationProcess"), + nt_query_information_process_stub); + + AddVectoredExceptionHandler(1, exception_filter); + } + + void post_unpack() override + { + // cba to implement sp, not sure if it's even needed + if (game::environment::is_sp()) return; + + // HW-BP Mapping + // 1404D4F40 -> 1404D4F30 + // 140509500 -> 140509410 + // 140545F80 -> 140545EE0 + // 14053CCF0 -> 14053CCC0 // dwGetLogonStatus + + utils::hook::call(0x14053B5FE, 0x140545EE0); // some pump + utils::hook::call(0x1404D3D42, 0x140509410); // some other pump + utils::hook::jump(0x14053CCB0, 0x14053CCC0); // dwGetLogonStatus + utils::hook::call(0x14053CD04, 0x14053CCC0); // dwGetLogonStatus + + //scheduler::on_game_initialized(remove_hardware_breakpoints, scheduler::pipeline::main); + } + }; +} + +REGISTER_COMPONENT(arxan::component) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp new file mode 100644 index 0000000..0051f69 --- /dev/null +++ b/src/client/component/auth.cpp @@ -0,0 +1,229 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "steam/steam.hpp" + +#include "auth.hpp" +#include "command.hpp" +#include "network.hpp" +#include "console.hpp" + +#include +#include +#include +#include +#include + +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 = "AlterWare-S1-Auth"; + + DATA_BLOB data_in{}, data_out{}; + data_in.pbData = reinterpret_cast(input.data()); + data_in.cbData = static_cast(input.size()); + if(CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE) + { + return {}; + } + + const auto size = std::min(data_out.cbData, 52ul); + std::string result{reinterpret_cast(data_out.pbData), size}; + LocalFree(data_out.pbData); + + return result; + } + + std::string get_key_entropy() + { + std::string entropy{}; + entropy.append(utils::smbios::get_uuid()); + entropy.append(get_hw_profile_guid()); + entropy.append(get_protected_data()); + entropy.append(get_hdd_serial()); + + if (entropy.empty()) + { + entropy.resize(32); + utils::cryptography::random::get_data(entropy.data(), entropy.size()); + } + + return entropy; + } + + utils::cryptography::ecc::key& get_key() + { + static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy()); + return key; + } + + int send_connect_data_stub(game::netsrc_t sock, game::netadr_s* adr, const char* format, const int len) + { + std::string connect_string(format, len); + game::SV_Cmd_TokenizeString(connect_string.data()); + const auto _ = gsl::finally([]() + { + game::SV_Cmd_EndTokenizedString(); + }); + + const command::params_sv params; + if (params.size() < 3) + { + return false; + } + + const utils::info_string info_string{std::string{params[2]}}; + const auto challenge = info_string.get("challenge"); + + connect_string.clear(); + connect_string.append(params[0]); + connect_string.append(" "); + connect_string.append(params[1]); + connect_string.append(" "); + connect_string.append("\"" + info_string.build() + "\""); + + proto::network::connect_info info; + info.set_publickey(get_key().get_public_key()); + info.set_signature(sign_message(get_key(), challenge)); + info.set_infostring(connect_string); + + network::send(*adr, "connect", info.SerializeAsString()); + return true; + } + + void direct_connect(game::netadr_s* from, game::msg_t* msg) + { + const auto offset = sizeof("connect") + 4; + + proto::network::connect_info info; + if (msg->cursize < offset || !info.ParseFromArray(msg->data + offset, msg->cursize - offset)) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + game::SV_Cmd_EndTokenizedString(); + game::SV_Cmd_TokenizeString(info.infostring().data()); + + const command::params_sv params; + if (params.size() < 3) + { + network::send(*from, "error", "Invalid connect string!", '\n'); + return; + } + + const utils::info_string info_string{std::string{params[2]}}; + + const auto steam_id = info_string.get("xuid"); + const auto challenge = info_string.get("challenge"); + + if (steam_id.empty() || challenge.empty()) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + utils::cryptography::ecc::key key; + key.set(info.publickey()); + + const auto xuid = strtoull(steam_id.data(), nullptr, 16); + if (xuid != key.get_hash()) + { + network::send(*from, "error", utils::string::va("XUID doesn't match the certificate: %llX != %llX", xuid, key.get_hash()), '\n'); + return; + } + + if (!key.is_valid() || !verify_message(key, challenge, info.signature())) + { + network::send(*from, "error", "Challenge signature was invalid!", '\n'); + return; + } + + game::SV_DirectConnect(from); + } + + void* get_direct_connect_stub() + { + return utils::hook::assemble([](utils::hook::assembler& a) + { + a.lea(rcx, qword_ptr(rsp, 0x20)); + a.movaps(xmmword_ptr(rsp, 0x20), xmm0); + + a.pushad64(); + a.mov(rdx, rdi); + a.call_aligned(direct_connect); + a.popad64(); + + a.jmp(0x140442317); + }); + } + } + + uint64_t get_guid() + { + if (game::environment::is_dedi()) + { + return 0x110000100000000 | (::utils::cryptography::random::get_integer() & ~0x80000000); + } + + return get_key().get_hash(); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Patch steam id bit check + if (game::environment::is_sp()) + { + utils::hook::jump(0x1404267F0, 0x140426846); + utils::hook::jump(0x14042760F, 0x140427650); + utils::hook::jump(0x140427AB4, 0x140427B02); + } + else + { + utils::hook::jump(0x140538920, 0x140538976); + utils::hook::jump(0x140009801, 0x140009B48); + utils::hook::jump(0x140009AEB, 0x140009B48); + utils::hook::jump(0x14053995F, 0x1405399A0); + utils::hook::jump(0x140539E70, 0x140539EB6); + + utils::hook::jump(0x1404421F6, get_direct_connect_stub(), true); + utils::hook::call(0x140208C54, send_connect_data_stub); + } + + command::add("guid", [] + { + console::info("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); + }); + } + }; +} + +REGISTER_COMPONENT(auth::component) diff --git a/src/client/component/auth.hpp b/src/client/component/auth.hpp new file mode 100644 index 0000000..3ee0c53 --- /dev/null +++ b/src/client/component/auth.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace auth +{ + uint64_t get_guid(); +} diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp new file mode 100644 index 0000000..f88a0a6 --- /dev/null +++ b/src/client/component/binding.cpp @@ -0,0 +1,138 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace binding +{ + namespace + { + std::vector custom_binds = {}; + + utils::hook::detour cl_execute_key_hook; + + int get_num_keys() + { + return SELECT_VALUE(102, 103); + } + + int key_write_bindings_to_buffer_stub(int /*localClientNum*/, char* buffer, const int buffer_size) + { + auto bytes_used = 0; + const auto buffer_size_align = static_cast(buffer_size) - 4; + + for (auto key_index = 0; key_index < 256; ++key_index) + { + const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1); + auto value = game::playerKeys->keys[key_index].binding; + + if (value && value < get_num_keys()) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, game::command_whitelist[value]); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + else if (value >= get_num_keys()) + { + value -= get_num_keys(); + if (static_cast(value) < custom_binds.size() && !custom_binds[value].empty()) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, custom_binds[value].data()); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + } + } + + buffer[bytes_used] = 0; + return bytes_used; + } + + int get_binding_for_custom_command(const char* command) + { + auto index = 0; + for (auto& bind : custom_binds) + { + if (bind == command) + { + return index; + } + index++; + } + + custom_binds.emplace_back(command); + index = static_cast(custom_binds.size()) - 1; + + return index; + } + + int key_get_binding_for_cmd_stub(const char* command) + { + // original binds + for (auto i = 0; i <= get_num_keys(); i++) + { + if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) + { + return i; + } + } + + // custom binds + return get_num_keys() + get_binding_for_custom_command(command); + } + + void cl_execute_key_stub(const int local_client_num, int key, const int down, const int time) + { + if (key >= get_num_keys()) + { + key -= get_num_keys(); + + if (static_cast(key) < custom_binds.size() && !custom_binds[key].empty()) + { + game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", custom_binds[key].data())); + } + + return; + } + + cl_execute_key_hook.invoke(local_client_num, key, down, time); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // write all bindings to config file + utils::hook::call(SELECT_VALUE(0x14013F90B, 0x1402081CB), key_write_bindings_to_buffer_stub); + + // links a custom command to an index + utils::hook::jump(SELECT_VALUE(0x1402EE5A0, 0x1403AFB50), key_get_binding_for_cmd_stub); + + // execute custom binds + cl_execute_key_hook.create(SELECT_VALUE(0x14013B110, 0x140202BE0), &cl_execute_key_stub); + } + }; +} + +REGISTER_COMPONENT(binding::component) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp new file mode 100644 index 0000000..6c0a9c3 --- /dev/null +++ b/src/client/component/bots.cpp @@ -0,0 +1,197 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "filesystem.hpp" +#include "network.hpp" +#include "party.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" + +#include +#include + +namespace bots +{ + namespace + { + constexpr std::size_t MAX_NAME_LENGTH = 16; + + bool can_add() + { + if (party::get_client_count() < *game::mp::svs_numclients) + { + return true; + } + + return false; + } + + void bot_team_join(const unsigned int entity_num) + { + scheduler::once([entity_num]() + { + game::Scr_AddInt(2); + game::Scr_AddString("team_select"); + game::Scr_Notify(&game::mp::g_entities[entity_num], static_cast(game::SL_GetString("luinotifyserver", 0)), 2); + + scheduler::once([entity_num]() + { + game::Scr_AddString(utils::string::va("class%d", std::rand() % 5)); + game::Scr_AddString("class_select"); + game::Scr_Notify(&game::mp::g_entities[entity_num], static_cast(game::SL_GetString("luinotifyserver", 0)), 2); + }, scheduler::pipeline::server, 2s); + }, scheduler::pipeline::server, 2s); + } + + void spawn_bot(const int entity_num) + { + game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]); + if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_CORE) + { + bot_team_join(entity_num); + } + } + + void add_bot() + { + if (!can_add()) + { + return; + } + + // SV_BotGetRandomName + const auto* const bot_name = game::SV_BotGetRandomName(); + auto* bot_ent = game::SV_AddBot(bot_name); + if (bot_ent) + { + spawn_bot(bot_ent->s.number); + } + else if (can_add()) // workaround since first bot won't ever spawn + { + add_bot(); + } + } + + utils::hook::detour get_bot_name_hook; + volatile bool bot_names_received = false; + std::vector bot_names; + + const char* get_random_bot_name() + { + if (bot_names.empty()) + { + return get_bot_name_hook.invoke(); + } + + const auto index = std::rand() % bot_names.size(); + const auto& name = bot_names.at(index); + + return utils::string::va("%.*s", static_cast(name.size()), name.data()); + } + + bool should_update_bot_names() + { + return !filesystem::exists("bots.txt"); + } + + void parse_bot_names_from_file() + { + std::string data; + filesystem::read_file("bots.txt", &data); + if (data.empty()) + { + return; + } + + auto name_list = utils::string::split(data, '\n'); + for (auto& entry : name_list) + { + // Take into account CR line endings + entry = utils::string::replace(entry, "\r", ""); + + if (entry.empty()) + { + continue; + } + + entry = entry.substr(0, MAX_NAME_LENGTH - 1); + bot_names.emplace_back(entry); + } + } + + void update_bot_names() + { + bot_names_received = false; + + game::netadr_s master; + if (server_list::get_master_server(master)) + { + console::info("Getting bots...\n"); + network::send(master, "getbots"); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + get_bot_name_hook.create(game::SV_BotGetRandomName, get_random_bot_name); + + command::add("spawnBot", [](const command::params& params) + { + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) return; + + auto num_bots = 1; + if (params.size() == 2) + { + num_bots = std::atoi(params.get(1)); + } + + num_bots = std::min(num_bots, *game::mp::svs_numclients); + + console::info("Spawning %i %s\n", num_bots, (num_bots == 1 ? "bot" : "bots")); + + for (auto i = 0; i < num_bots; ++i) + { + scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i); + } + }); + + if (should_update_bot_names()) + { + scheduler::on_game_initialized([]() -> void + { + update_bot_names(); + scheduler::loop(update_bot_names, scheduler::main, 1h); + }, scheduler::main); + } + else + { + parse_bot_names_from_file(); + } + + network::on("getbotsResponse", [](const game::netadr_s& target, const std::string_view& data) + { + game::netadr_s master{}; + if (server_list::get_master_server(master) && !bot_names_received && target == master) + { + const std::string received_data{ data }; + bot_names = utils::string::split(received_data, '\n'); + bot_names_received = true; + } + }); + } + }; +} + +REGISTER_COMPONENT(bots::component) diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp new file mode 100644 index 0000000..001f2b8 --- /dev/null +++ b/src/client/component/branding.cpp @@ -0,0 +1,69 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "localized_strings.hpp" +#include "scheduler.hpp" +#include "dvars.hpp" + +#include +#include + +#include "version.hpp" + +namespace branding +{ + namespace + { + utils::hook::detour ui_get_formatted_build_number_hook; + + const char* ui_get_formatted_build_number_stub() + { + const auto* const build_num = ui_get_formatted_build_number_hook.invoke(); + + return utils::string::va("%s (%s)", VERSION, build_num); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + if (game::environment::is_mp()) + { + localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "s1-mod: MULTIPLAYER\n"); + } + localized_strings::override("LUA_MENU_LEGAL_COPYRIGHT", "s1-mod: " VERSION); + + dvars::override::set_string("version", utils::string::va("s1-mod %s", VERSION)); + + ui_get_formatted_build_number_hook.create( + SELECT_VALUE(0x14035B3F0, 0x1404A8950), ui_get_formatted_build_number_stub); + + scheduler::loop([]() + { + const auto x = 4; + const auto y = 4; + const auto scale = 1.0f; + float color[4] = {0.666f, 0.666f, 0.666f, 0.666f}; + const auto* text = "s1-mod: " VERSION; + + auto* font = game::R_RegisterFont("fonts/consolefont"); + + if (!font) return; + + game::R_AddCmdDrawText(text, std::numeric_limits::max(), font, static_cast(x), + y + static_cast(font->pixelHeight) * scale, + scale, scale, 0.0f, color, 0); + }, scheduler::pipeline::renderer); + } + }; +} + +REGISTER_COMPONENT(branding::component) diff --git a/src/client/component/bullet.cpp b/src/client/component/bullet.cpp new file mode 100644 index 0000000..6b25a3e --- /dev/null +++ b/src/client/component/bullet.cpp @@ -0,0 +1,44 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace bullet +{ + namespace + { + utils::hook::detour bg_get_surface_penetration_depth_hook; + + float bg_get_surface_penetration_depth_stub(game::Weapon weapon, bool is_alternate, int surfaceType) + { + if (dvars::bg_surfacePenetration->current.value > 0.0f) + { + return dvars::bg_surfacePenetration->current.value; + } + + return bg_get_surface_penetration_depth_hook.invoke(weapon, is_alternate, surfaceType); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + dvars::bg_surfacePenetration = game::Dvar_RegisterFloat("bg_surfacePenetration", 0.0f, + 0.0f, std::numeric_limits::max(), game::DVAR_FLAG_SAVED, + "Set to a value greater than 0 to override the surface penetration depth"); + bg_get_surface_penetration_depth_hook.create(0x1401641A0, &bg_get_surface_penetration_depth_stub); + } + }; +} + +REGISTER_COMPONENT(bullet::component) diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp new file mode 100644 index 0000000..e918a4f --- /dev/null +++ b/src/client/component/colors.cpp @@ -0,0 +1,183 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include +#include + +namespace colors +{ + struct hsv_color + { + unsigned char h; + unsigned char s; + unsigned char v; + }; + + namespace + { + std::vector color_table; + + DWORD hsv_to_rgb(const hsv_color hsv) + { + DWORD rgb; + + if (hsv.s == 0) + { + return RGB(hsv.v, hsv.v, hsv.v); + } + + // converting to 16 bit to prevent overflow + const unsigned int h = hsv.h; + const unsigned int s = hsv.s; + const unsigned int v = hsv.v; + + const auto region = static_cast(h / 43); + const auto remainder = (h - (region * 43)) * 6; + + const auto p = static_cast((v * (255 - s)) >> 8); + const auto q = static_cast( + (v * (255 - ((s * remainder) >> 8))) >> 8); + const auto t = static_cast( + (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8); + + switch (region) + { + case 0: + rgb = RGB(v, t, p); + break; + case 1: + rgb = RGB(q, v, p); + break; + case 2: + rgb = RGB(p, v, t); + break; + case 3: + rgb = RGB(p, q, v); + break; + case 4: + rgb = RGB(t, p, v); + break; + default: + rgb = RGB(v, p, q); + break; + } + + return rgb; + } + + int color_index(const char c) + { + const auto index = c - 48; + return index >= 0xC ? 7 : index; + } + + char add(const uint8_t r, const uint8_t g, const uint8_t b) + { + const char index = '0' + static_cast(color_table.size()); + color_table.push_back(RGB(r, g, b)); + return index; + } + + void com_clean_name_stub(const char* in, char* out, const int out_size) + { + strncpy_s(out, out_size, in, _TRUNCATE); + } + + char* i_clean_str_stub(char* string) + { + utils::string::strip(string, string, std::strlen(string) + 1); + + return string; + } + + size_t get_client_name_stub(const int local_client_num, const int index, char* buf, const int size, + const size_t unk, const size_t unk2) + { + // CL_GetClientName (CL_GetClientNameAndClantag?) + const auto result = reinterpret_cast(0x140213E60)( + local_client_num, index, buf, size, unk, unk2); + + utils::string::strip(buf, buf, static_cast(size)); + + return result; + } + + void rb_lookup_color_stub(const char index, DWORD* color) + { + *color = RGB(255, 255, 255); + + if (index == '8') + { + *color = *reinterpret_cast(SELECT_VALUE(0x14CEDD978, 0x14D8594C4)); + } + else if (index == '9') + { + *color = *reinterpret_cast(SELECT_VALUE(0x14CEDD97C, 0x14D8594C8)); + } + else if (index == ':') + { + *color = hsv_to_rgb({static_cast((game::Sys_Milliseconds() / 100) % 256), 255, 255}); + } + else if (index == ';') + { + *color = *reinterpret_cast(SELECT_VALUE(0x14CEDD984, 0x14D8594D0)); + } + else if (index == '<') + { + *color = 0xFFFCFF80; + } + else + { + *color = color_table[color_index(index)]; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + if (!game::environment::is_sp()) + { + // allows colored name in-game + utils::hook::jump(0x1404C9510, com_clean_name_stub); + + // don't apply colors to overhead names + utils::hook::call(0x1401891B0, get_client_name_stub); + + // patch I_CleanStr + utils::hook::jump(0x1404C99A0, i_clean_str_stub); + } + + // force new colors + utils::hook::jump(SELECT_VALUE(0x1404D3A20, 0x1405F2B90), rb_lookup_color_stub); + + // add colors + add(0, 0, 0); // 0 - Black + add(255, 49, 49); // 1 - Red + add(134, 192, 0); // 2 - Green + add(255, 173, 34); // 3 - Yellow + add(0, 135, 193); // 4 - Blue + add(32, 197, 255); // 5 - Light Blue + add(151, 80, 221); // 6 - Pink + add(255, 255, 255); // 7 - White + + add(0, 0, 0); // 8 - Team color (axis?) + add(0, 0, 0); // 9 - Team color (allies?) + + add(0, 0, 0); // 10 - Rainbow (:) + add(0, 0, 0); + // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! + } + }; +} + +REGISTER_COMPONENT(colors::component) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp new file mode 100644 index 0000000..6408a9a --- /dev/null +++ b/src/client/component/command.cpp @@ -0,0 +1,677 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "game_console.hpp" +#include "scheduler.hpp" +#include "fastfiles.hpp" + +#include +#include +#include +#include + +namespace command +{ + namespace + { + constexpr auto CMD_MAX_NESTING = 8; + + utils::hook::detour client_command_hook; + + std::unordered_map> handlers; + std::unordered_map> handlers_sv; + + void main_handler() + { + params params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (const auto itr = handlers.find(command); itr != handlers.end()) + { + itr->second(params); + } + } + + void client_command(const char client_num) + { + if (game::mp::g_entities[client_num].client == nullptr) + { + // Client is not fully connected + return; + } + + params_sv params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (const auto itr = handlers_sv.find(command); itr != handlers_sv.end()) + { + itr->second(&game::mp::g_entities[client_num], params); + } + + client_command_hook.invoke(client_num); + } + + // Shamelessly stolen from Quake3 + // https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/qcommon/common.c#L364 + void parse_command_line() + { + static auto parsed = false; + if (parsed) + { + return; + } + + static std::string comand_line_buffer = GetCommandLineA(); + auto* command_line = comand_line_buffer.data(); + + auto& com_num_console_lines = *reinterpret_cast(0x147B76504); + auto* com_console_lines = reinterpret_cast(0x147B76510); + + auto inq = false; + com_console_lines[0] = command_line; + com_num_console_lines = 0; + + while (*command_line) + { + if (*command_line == '"') + { + inq = !inq; + } + // look for a + separating character + // if commandLine came from a file, we might have real line seperators + if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r') + { + if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES + { + break; + } + com_console_lines[com_num_console_lines] = command_line + 1; + com_num_console_lines++; + *command_line = '\0'; + } + command_line++; + } + parsed = true; + } + + void parse_commandline_stub() + { + parse_command_line(); + reinterpret_cast(0x1403CEE10)(); + } + } + + void read_startup_variable(const std::string& dvar) + { + // parse the commandline if it's not parsed + parse_command_line(); + + auto& com_num_console_lines = *reinterpret_cast(0x147B76504); + auto* com_console_lines = reinterpret_cast(0x147B76510); + + for (int i = 0; i < com_num_console_lines; i++) + { + game::Cmd_TokenizeString(com_console_lines[i]); + + // only +set dvar value + if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar) + { + game::Dvar_SetCommand(game::Cmd_Argv(1), game::Cmd_Argv(2)); + } + + game::Cmd_EndTokenizeString(); + } + } + + params::params() + : nesting_(game::cmd_args->nesting) + { + assert(this->nesting_ < CMD_MAX_NESTING); + } + + int params::size() const + { + return game::cmd_args->argc[this->nesting_]; + } + + const char* params::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::cmd_args->argv[this->nesting_][index]; + } + + std::string params::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + params_sv::params_sv() + : nesting_(game::sv_cmd_args->nesting) + { + assert(this->nesting_ < CMD_MAX_NESTING); + } + + int params_sv::size() const + { + return game::sv_cmd_args->argc[this->nesting_]; + } + + const char* params_sv::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; + } + + std::string params_sv::join(const int index) const + { + std::string result; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + void add_raw(const char* name, void (*callback)()) + { + game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate()); + } + + void add(const char* name, const std::function& callback) + { + const auto command = utils::string::to_lower(name); + + if (!handlers.contains(command)) + { + add_raw(name, main_handler); + } + + handlers[command] = callback; + } + + void add(const char* name, const std::function& callback) + { + add(name, [callback](const params&) + { + callback(); + }); + } + + void add_sv(const char* name, const std::function& callback) + { + // doing this so the sv command would show up in the console + add_raw(name, nullptr); + + const auto command = utils::string::to_lower(name); + + if (!handlers_sv.contains(command)) + { + handlers_sv[command] = callback; + } + } + + bool cheats_ok(const game::mp::gentity_s* ent) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return false; + } + + if (ent->health < 1) + { + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + "f \"You must be alive to use this command\""); + return false; + } + + return true; + } + + void execute(std::string command, const bool sync) + { + command += "\n"; + + if (sync) + { + game::Cmd_ExecuteSingleCommand(0, 0, command.data()); + } + else + { + game::Cbuf_AddText(0, command.data()); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + add_commands_sp(); + } + else + { + utils::hook::call(0x1403CDF1C, &parse_commandline_stub); + add_commands_mp(); + } + + add_commands_generic(); + } + + private: + static void add_commands_generic() + { + add("quit", game::Com_Quit_f); + add("crash", [] + { + *reinterpret_cast(1) = 0x12345678; + }); + + add("consoleList", [](const params& params) + { + const std::string input = params.get(1); + + std::vector matches; + game_console::find_matches(input, matches, false); + + for(auto& match : matches) + { + auto* dvar = game::Dvar_FindVar(match.c_str()); + if (!dvar) + { + console::info("[CMD]\t %s\n", match.c_str()); + } + else + { + console::info("[DVAR]\t%s \"%s\"\n", match.c_str(), game::Dvar_ValueToString(dvar, dvar->current)); + } + } + + console::info("Total %i matches\n", matches.size()); + }); + + add("dvarDump", [](const params& argument) + { + console::info("================================ DVAR DUMP ========================================\n"); + std::string filename; + if (argument.size() == 2) + { + filename = "s1/"; + filename.append(argument[1]); + if (!filename.ends_with(".txt")) + { + filename.append(".txt"); + } + } + for (auto i = 0; i < *game::dvarCount; i++) + { + const auto dvar = game::sortedDvars[i]; + if (dvar) + { + if (!filename.empty()) + { + const auto line = std::format("{} \"{}\"\r\n", dvar->name, + game::Dvar_ValueToString(dvar, dvar->current)); + utils::io::write_file(filename, line, i != 0); + } + console::info("%s \"%s\"\n", dvar->name, + game::Dvar_ValueToString(dvar, dvar->current)); + } + } + console::info("\n%i dvars\n", *game::dvarCount); + console::info("================================ END DVAR DUMP ====================================\n"); + }); + + add("commandDump", [](const params& argument) + { + console::info("================================ COMMAND DUMP =====================================\n"); + game::cmd_function_s* cmd = (*game::cmd_functions); + std::string filename; + if (argument.size() == 2) + { + filename = "s1/"; + filename.append(argument[1]); + if (!filename.ends_with(".txt")) + { + filename.append(".txt"); + } + } + int i = 0; + while (cmd) + { + if (cmd->name) + { + if (!filename.empty()) + { + const auto line = std::format("{}\r\n", cmd->name); + utils::io::write_file(filename, line, i != 0); + } + console::info("%s\n", cmd->name); + i++; + } + cmd = cmd->next; + } + console::info("\n%i commands\n", i); + console::info("================================ END COMMAND DUMP =================================\n"); + }); + + add("listassetpool", [](const params& params) + { + if (params.size() < 2) + { + console::info("listassetpool [filter]: list all the assets in the specified pool\n"); + + for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++) + { + console::info("%d %s\n", i, game::g_assetNames[i]); + } + } + else + { + const auto type = static_cast(atoi(params.get(1))); + + if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT) + { + console::error("Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1); + return; + } + + console::info("Listing assets in pool %s\n", game::g_assetNames[type]); + + const std::string filter = params.get(2); + fastfiles::enum_assets(type, [type, filter](const game::XAssetHeader header) + { + const auto asset = game::XAsset{ type, header }; + const auto* const asset_name = game::DB_GetXAssetName(&asset); + //const auto entry = game::DB_FindXAssetEntry(type, asset_name); + //TODO: display which zone the asset is from + + if (!filter.empty() && !game_console::match_compare(filter, asset_name, false)) + { + return; + } + + console::info("%s\n", asset_name); + }, true); + } + }); + + add("vstr", [](const params& params) + { + if (params.size() < 2) + { + console::info("vstr : execute a variable command\n"); + return; + } + + const auto* dvarName = params.get(1); + const auto* dvar = game::Dvar_FindVar(dvarName); + + if (dvar == nullptr) + { + console::info("%s doesn't exist\n", dvarName); + return; + } + + if (dvar->type != game::dvar_type::string + && dvar->type != game::dvar_type::enumeration) + { + console::info("%s is not a string-based dvar\n", dvar->name); + return; + } + + execute(dvar->current.string); + }); + } + + static void add_commands_sp() + { + add("god", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 1; + game::CG_GameMessage(0, utils::string::va("godmode %s", + game::sp::g_entities[0].flags & 1 + ? "^2on" + : "^1off")); + }); + + add("demigod", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 2; + game::CG_GameMessage(0, utils::string::va("demigod mode %s", + game::sp::g_entities[0].flags & 2 + ? "^2on" + : "^1off")); + }); + + add("notarget", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 4; + game::CG_GameMessage(0, utils::string::va("notarget %s", + game::sp::g_entities[0].flags & 4 + ? "^2on" + : "^1off")); + }); + + add("noclip", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].client->flags ^= 1; + game::CG_GameMessage(0, utils::string::va("noclip %s", + game::sp::g_entities[0].client->flags & 1 + ? "^2on" + : "^1off")); + }); + + add("ufo", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].client->flags ^= 2; + game::CG_GameMessage(0, utils::string::va("ufo %s", + game::sp::g_entities[0].client->flags & 2 + ? "^2on" + : "^1off")); + }); + + add("give", [](const params& params) + { + if (!game::SV_Loaded()) + { + return; + } + + if (params.size() < 2) + { + game::CG_GameMessage(0, "You did not specify a weapon name"); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(0); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0)) + { + game::G_InitializeAmmo(ps, wp, 0); + game::G_SelectWeapon(0, wp); + } + } + }); + + add("take", [](const params& params) + { + if (!game::SV_Loaded()) + { + return; + } + + if (params.size() < 2) + { + game::CG_GameMessage(0, "You did not specify a weapon name"); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(0); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + game::G_TakePlayerWeapon(ps, wp); + } + }); + } + + static void add_commands_mp() + { + client_command_hook.create(0x1402E98F0, &client_command); + + add_sv("god", [](game::mp::gentity_s* ent, const params_sv&) + { + if (!cheats_ok(ent)) + return; + + ent->flags ^= game::FL_GODMODE; + + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off")); + }); + + add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&) + { + if (!cheats_ok(ent)) + return; + + ent->flags ^= game::FL_DEMI_GODMODE; + + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off")); + }); + + add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&) + { + if (!cheats_ok(ent)) + return; + + ent->flags ^= game::FL_NOTARGET; + + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off")); + }); + + add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&) + { + if (!cheats_ok(ent)) + return; + + ent->client->flags ^= 1; + + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off")); + }); + + add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&) + { + if (!cheats_ok(ent)) + return; + + ent->client->flags ^= 2; + + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off")); + }); + + add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params) + { + if (!cheats_ok(ent)) + return; + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(ent->s.number); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0)) + { + game::G_InitializeAmmo(ps, wp, 0); + game::G_SelectWeapon(ent->s.number, wp); + } + } + }); + + add_sv("take", [](game::mp::gentity_s* ent, const params_sv& params) + { + if (!cheats_ok(ent)) + return; + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, + "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(ent->s.number); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + game::G_TakePlayerWeapon(ps, wp); + } + }); + } + }; +} + +REGISTER_COMPONENT(command::component) diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp new file mode 100644 index 0000000..16563f7 --- /dev/null +++ b/src/client/component/command.hpp @@ -0,0 +1,50 @@ +#pragma once + +namespace command +{ + class params + { + public: + params(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + class params_sv + { + public: + params_sv(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + void read_startup_variable(const std::string& dvar); + + void add_raw(const char* name, void (*callback)()); + void add(const char* name, const std::function& callback); + void add(const char* name, const std::function& callback); + + void add_sv(const char* name, const std::function& callback); + + void execute(std::string command, bool sync = false); +} diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp new file mode 100644 index 0000000..a66101d --- /dev/null +++ b/src/client/component/console.cpp @@ -0,0 +1,260 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "game_console.hpp" +#include "rcon.hpp" +#include "scheduler.hpp" + +#include +#include +#include + +namespace console +{ + namespace + { + using message_queue = std::queue; + utils::concurrency::container message_queue_; + + std::atomic_bool started_{false}; + std::atomic_bool terminate_runner_{false}; + + void print_message(const char* message) + { +#ifdef _DEBUG + OutputDebugStringA(message); +#endif + + if (game::is_headless()) + { + std::fputs(message, stdout); + } + else + { + game::Conbuf_AppendText(message); + } + } + + std::string format(va_list* ap, const char* message) + { + static thread_local char buffer[0x1000]; + + const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap); + + if (count < 0) return {}; + return {buffer, static_cast(count)}; + } + + void dispatch_message(const int type, const std::string& message) + { + if (rcon::message_redirect(message)) + { + return; + } + + game_console::print(type, message); + + if (game::is_headless()) + { + std::fputs(message.data(), stdout); + return; + } + + message_queue_.access([&message](message_queue& queue) + { + queue.emplace(message); + }); + } + + message_queue empty_message_queue() + { + message_queue current_queue{}; + + message_queue_.access([&](message_queue& queue) + { + current_queue = std::move(queue); + queue = {}; + }); + + return current_queue; + } + + void print_stub(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + char buffer[4096]{}; + const auto res = vsnprintf_s(buffer, _TRUNCATE, fmt, ap); + (void)res; + print_message(buffer); + + va_end(ap); + } + + void append_text(const char* text) + { + dispatch_message(con_type_info, text); + } + } + + class component final : public component_interface + { + public: + component() + { + if (game::is_headless()) + { + if (!AttachConsole(ATTACH_PARENT_PROCESS)) + { + AllocConsole(); + AttachConsole(GetCurrentProcessId()); + } + + ShowWindow(GetConsoleWindow(), SW_SHOW); + + FILE* fp; + freopen_s(&fp, "CONIN$", "r", stdin); + freopen_s(&fp, "CONOUT$", "w", stdout); + freopen_s(&fp, "CONOUT$", "w", stderr); + } + } + + void post_unpack() override + { + // Redirect input (]command) + utils::hook::jump(SELECT_VALUE(0x14038F3E0, 0x1404D9200), append_text); + + utils::hook::jump(printf, print_stub); + + if (game::is_headless()) + { + return; + } + + terminate_runner_ = false; + + this->message_runner_ = utils::thread::create_named_thread("Console IO", [] + { + while (!started_) + { + std::this_thread::sleep_for(10ms); + } + + while (!terminate_runner_) + { + std::string message_buffer{}; + auto current_queue = empty_message_queue(); + + while (!current_queue.empty()) + { + const auto& msg = current_queue.front(); + message_buffer.append(msg); + current_queue.pop(); + } + + if (!message_buffer.empty()) + { + print_message(message_buffer.data()); + } + + std::this_thread::sleep_for(5ms); + } + }); + + this->console_runner_ = utils::thread::create_named_thread("Console Window", [this] + { + game::Sys_ShowConsole(); + + MSG msg{}; + while (!terminate_runner_) + { + if (PeekMessageW(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + command::execute("quit", false); + break; + } + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + else + { + std::this_thread::sleep_for(5ms); + } + } + }); + + // Give the console a chance to open or we will lose some early messages + // like the ones printed from the filesystem component + scheduler::once([]() -> void + { + started_ = true; + }, scheduler::pipeline::main); + } + + void pre_destroy() override + { + terminate_runner_ = true; + + if (this->message_runner_.joinable()) + { + this->message_runner_.join(); + } + + if (this->console_runner_.joinable()) + { + this->console_runner_.join(); + } + } + + private: + std::thread console_runner_{}; + std::thread message_runner_{}; + }; + + HWND get_window() + { + return *reinterpret_cast((SELECT_VALUE(0x14A9F6070, 0x14B5B94C0))); + } + + void set_title(std::string title) + { + if (game::is_headless()) + { + SetConsoleTitleA(title.data()); + } + else + { + SetWindowTextA(get_window(), title.data()); + } + } + + void set_size(const int width, const int height) + { + RECT rect; + GetWindowRect(get_window(), &rect); + + SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); + + auto* const logo_window = *reinterpret_cast(SELECT_VALUE(0x14A9F6080, 0x14B5B94D0)); + SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); + } + + void print(const int type, const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + const auto result = format(&ap, fmt); + va_end(ap); + + dispatch_message(type, result); + } +} + +REGISTER_COMPONENT(console::component) diff --git a/src/client/component/console.hpp b/src/client/component/console.hpp new file mode 100644 index 0000000..484266b --- /dev/null +++ b/src/client/component/console.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace console +{ + HWND get_window(); + void set_title(std::string title); + void set_size(int width, int height); + + enum console_type + { + con_type_error = 1, + con_type_warning = 3, + con_type_info = 7 + }; + + void print(int type, const char* fmt, ...); + + template + void error(const char* fmt, Args&&... args) + { + print(con_type_error, fmt, std::forward(args)...); + } + + template + void warn(const char* fmt, Args&&... args) + { + print(con_type_warning, fmt, std::forward(args)...); + } + + template + void info(const char* fmt, Args&&... args) + { + print(con_type_info, fmt, std::forward(args)...); + } +} diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp new file mode 100644 index 0000000..072f3ce --- /dev/null +++ b/src/client/component/dedicated.cpp @@ -0,0 +1,326 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" +#include "network.hpp" +#include "command.hpp" +#include "dvars.hpp" + +#include +#include + +namespace dedicated +{ + namespace + { + utils::hook::detour gscr_set_dynamic_dvar_hook; + utils::hook::detour com_quit_f_hook; + + const game::dvar_t* sv_lanOnly; + + void init_dedicated_server() + { + static bool initialized = false; + if (initialized) return; + initialized = true; + + // R_LoadGraphicsAssets + reinterpret_cast(0x1405A54F0)(); + } + + void send_heartbeat() + { + if (sv_lanOnly->current.enabled) + { + return; + } + + game::netadr_s target{}; + if (server_list::get_master_server(target)) + { + network::send(target, "heartbeat", "S1"); + } + } + + std::vector& get_startup_command_queue() + { + static std::vector startup_command_queue; + return startup_command_queue; + } + + void execute_startup_command(int client, int /*controllerIndex*/, const char* command) + { + if (game::Live_SyncOnlineDataFlags(0) == 0) + { + game::Cbuf_ExecuteBufferInternal(0, 0, command, game::Cmd_ExecuteSingleCommand); + } + else + { + get_startup_command_queue().emplace_back(command); + } + } + + void execute_startup_command_queue() + { + const auto queue = get_startup_command_queue(); + get_startup_command_queue().clear(); + + for (const auto& command : queue) + { + game::Cbuf_ExecuteBufferInternal(0, 0, command.data(), game::Cmd_ExecuteSingleCommand); + } + } + + std::vector& get_console_command_queue() + { + static std::vector console_command_queue; + return console_command_queue; + } + + void execute_console_command([[maybe_unused]] const int local_client_num, const char* command) + { + if (game::Live_SyncOnlineDataFlags(0) == 0) + { + command::execute(command); + } + else + { + get_console_command_queue().emplace_back(command); + } + } + + void execute_console_command_queue() + { + const auto queue = get_console_command_queue(); + get_console_command_queue().clear(); + + for (const auto& command : queue) + { + game::Cbuf_AddText(0, command.data()); + game::Cbuf_AddText(0, "\n"); + } + } + + void sync_gpu_stub() + { + std::this_thread::sleep_for(1ms); + } + + void gscr_set_dynamic_dvar() + { + auto s = game::Scr_GetString(0); + auto* dvar = game::Dvar_FindVar(s); + if (dvar && !std::strncmp("scr_", dvar->name, 4)) + { + return; + } + + gscr_set_dynamic_dvar_hook.invoke(); + } + + void kill_server() + { + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 3) + { + game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, + utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); + } + } + + com_quit_f_hook.invoke(); + } + + void sys_error_stub(const char* msg, ...) + { + char buffer[2048]{}; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + + va_end(ap); + + scheduler::once([] + { + command::execute("map_rotate"); + }, scheduler::main, 3s); + + game::Com_Error(game::ERR_DROP, "%s", buffer); + } + } + + void initialize() + { + command::execute("exec default_xboxlive.cfg", true); + command::execute("onlinegame 1", true); + command::execute("xblive_privatematch 1", true); + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + return nullptr; + } + + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + game::Dvar_RegisterBool("dedicated", true, game::DVAR_FLAG_READ, "Dedicated server"); + + sv_lanOnly = game::Dvar_RegisterBool("sv_lanOnly", false, game::DVAR_FLAG_NONE, "Don't send heartbeat"); + + // Disable VirtualLobby + dvars::override::register_bool("virtualLobbyEnabled", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ); + + // Disable r_preloadShaders + dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ); + + // Don't allow sv_hostname to be changed by the game + dvars::disable::set_string("sv_hostname"); + + // Stop crashing from sys_errors + utils::hook::jump(0x1404D6260, sys_error_stub); + + // Hook R_SyncGpu + utils::hook::jump(0x1405A7630, sync_gpu_stub); + + utils::hook::jump(0x14020C6B0, init_dedicated_server); + + // delay startup commands until the initialization is done + utils::hook::call(0x1403CDF63, execute_startup_command); + + // delay console commands until the initialization is done + utils::hook::call(0x1403CEC35, execute_console_command); + utils::hook::nop(0x1403CEC4B, 5); + + // patch GScr_SetDynamicDvar to behave better + gscr_set_dynamic_dvar_hook.create(0x140312D00, &gscr_set_dynamic_dvar); + + utils::hook::nop(0x1404AE6AE, 5); // don't load config file + utils::hook::nop(0x1403AF719, 5); // ^ + utils::hook::set(0x1403D2490, 0xC3); // don't save config file + utils::hook::set(0x14022AFC0, 0xC3); // disable self-registration + utils::hook::set(0x1404DA780, 0xC3); // init sound system (1) + utils::hook::set(0x14062BC10, 0xC3); // init sound system (2) + utils::hook::set(0x1405F31A0, 0xC3); // render thread + utils::hook::set(0x140213C20, 0xC3); // called from Com_Frame, seems to do renderer stuff + utils::hook::set(0x1402085C0, 0xC3); + // CL_CheckForResend, which tries to connect to the local server constantly + utils::hook::set(0x14059B854, 0); // r_loadForRenderer default to 0 + utils::hook::set(0x1404D6952, 0xC3); // recommended settings check - TODO: Check hook + utils::hook::set(0x1404D9BA0, 0xC3); // some mixer-related function called on shutdown + utils::hook::set(0x1403B2860, 0xC3); // dont load ui gametype stuff + utils::hook::nop(0x14043ABB8, 6); // unknown check in SV_ExecuteClientMessage + utils::hook::nop(0x140439F15, 4); // allow first slot to be occupied + utils::hook::nop(0x14020E01C, 2); // properly shut down dedicated servers + utils::hook::nop(0x14020DFE9, 2); // ^ + utils::hook::nop(0x14020E047, 5); // don't shutdown renderer + + utils::hook::set(0x140057D40, 0xC3); // something to do with blendShapeVertsView + utils::hook::nop(0x14062EA17, 8); // sound thing + + utils::hook::set(0x1404D6960, 0xC3); // cpu detection stuff? + utils::hook::set(0x1405AEC00, 0xC3); // gfx stuff during fastfile loading + utils::hook::set(0x1405AEB10, 0xC3); // ^ + utils::hook::set(0x1405AEBA0, 0xC3); // ^ + utils::hook::set(0x140275640, 0xC3); // ^ + utils::hook::set(0x1405AEB60, 0xC3); // ^ + utils::hook::set(0x140572640, 0xC3); // directx stuff + utils::hook::set(0x1405A1340, 0xC3); // ^ + utils::hook::set(0x140021D60, 0xC3); // ^ - mutex + utils::hook::set(0x1405A17E0, 0xC3); // ^ + + utils::hook::set(0x1400534F0, 0xC3); // rendering stuff + utils::hook::set(0x1405A1AB0, 0xC3); // ^ + utils::hook::set(0x1405A1BB0, 0xC3); // ^ + utils::hook::set(0x1405A21F0, 0xC3); // ^ + utils::hook::set(0x1405A2D60, 0xC3); // ^ + utils::hook::set(0x1405A3400, 0xC3); // ^ + + // shaders + utils::hook::set(0x140057BC0, 0xC3); // ^ + utils::hook::set(0x140057B40, 0xC3); // ^ + + utils::hook::set(0x1405EE040, 0xC3); // ^ - mutex + + utils::hook::set(0x1404DAF30, 0xC3); // idk + utils::hook::set(0x1405736B0, 0xC3); // ^ + + utils::hook::set(0x1405A6E70, 0xC3); // R_Shutdown + utils::hook::set(0x1405732D0, 0xC3); // shutdown stuff + utils::hook::set(0x1405A6F40, 0xC3); // ^ + utils::hook::set(0x1405A61A0, 0xC3); // ^ + + utils::hook::set(0x14062C550, 0xC3); // sound crashes + + utils::hook::set(0x140445070, 0xC3); // disable host migration + + utils::hook::set(0x1403E1A50, 0xC3); // render synchronization lock + utils::hook::set(0x1403E1990, 0xC3); // render synchronization unlock + + utils::hook::set(0x1400E517B, 0xEB); + // LUI: Unable to start the LUI system due to errors in main.lua + + utils::hook::nop(0x1404CC482, 5); // Disable sound pak file loading + utils::hook::nop(0x1404CC471, 2); // ^ + utils::hook::set(0x140279B80, 0xC3); // Disable image pak file loading + + // Reduce min required memory + utils::hook::set(0x1404D140D, 0x80000000); + utils::hook::set(0x1404D14BF, 0x80000000); + + // initialize the game after onlinedataflags is 32 (workaround) + scheduler::schedule([=]() + { + if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2()) + { + scheduler::once([] + { + command::execute("xstartprivateparty", true); + command::execute("disconnect", true); // 32 -> 0 + }, scheduler::pipeline::main, 1s); + return scheduler::cond_end; + } + + return scheduler::cond_continue; + }, scheduler::pipeline::main, 1s); + + scheduler::on_game_initialized([] + { + initialize(); + + console::info("==================================\n"); + console::info("Server started!\n"); + console::info("==================================\n"); + + // remove disconnect command + game::Cmd_RemoveCommand(reinterpret_cast(751)); + + execute_startup_command_queue(); + execute_console_command_queue(); + + // Send heartbeat to dpmaster + scheduler::once(send_heartbeat, scheduler::pipeline::server); + scheduler::loop(send_heartbeat, scheduler::pipeline::server, 10min); + command::add("heartbeat", send_heartbeat); + }, scheduler::pipeline::main, 1s); + + command::add("killserver", kill_server); + com_quit_f_hook.create(0x1403D08C0, &kill_server); + } + }; +} + +REGISTER_COMPONENT(dedicated::component) diff --git a/src/client/component/dedicated.hpp b/src/client/component/dedicated.hpp new file mode 100644 index 0000000..5863323 --- /dev/null +++ b/src/client/component/dedicated.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace dedicated +{ + void initialize(); +} diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp new file mode 100644 index 0000000..ef4b34a --- /dev/null +++ b/src/client/component/dedicated_info.cpp @@ -0,0 +1,64 @@ +#include +#include "console.hpp" +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "scheduler.hpp" +#include + +namespace dedicated_info +{ + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::loop([]() + { + auto* sv_running = game::Dvar_FindVar("sv_running"); + if (!sv_running || !sv_running->current.enabled) + { + console::set_title("s1-mod Dedicated Server"); + return; + } + + auto* const sv_hostname = game::Dvar_FindVar("sv_hostname"); + auto* const sv_maxclients = game::Dvar_FindVar("sv_maxclients"); + auto* const mapname = game::Dvar_FindVar("mapname"); + + auto bot_count = 0; + auto client_count = 0; + + for (auto i = 0; i < sv_maxclients->current.integer; i++) + { + auto* client = &game::mp::svs_clients[i]; + auto* self = &game::mp::g_entities[i]; + + if (client->header.state >= 1 && self && self->client) + { + client_count++; + if (game::SV_BotIsBot(i)) + { + ++bot_count; + } + } + } + + std::string cleaned_hostname = sv_hostname->current.string; + + utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(), + cleaned_hostname.size() + 1); + + console::set_title(utils::string::va("%s on %s [%d/%d] (%d)", cleaned_hostname.data(), + mapname->current.string, client_count, + sv_maxclients->current.integer, bot_count)); + }, scheduler::pipeline::main, 1s); + } + }; +} + +REGISTER_COMPONENT(dedicated_info::component) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp new file mode 100644 index 0000000..c2c5156 --- /dev/null +++ b/src/client/component/demonware.cpp @@ -0,0 +1,448 @@ +#include +#include "loader/component_loader.hpp" + +#include +#include + +#include "game/game.hpp" +#include "game/demonware/servers/lobby_server.hpp" +#include "game/demonware/servers/auth3_server.hpp" +#include "game/demonware/servers/stun_server.hpp" +#include "game/demonware/servers/umbrella_server.hpp" +#include "game/demonware/server_registry.hpp" + +#define TCP_BLOCKING true +#define UDP_BLOCKING false + +namespace demonware +{ + namespace + { + volatile bool exit_server; + std::thread server_thread; + utils::concurrency::container> blocking_sockets; + utils::concurrency::container> socket_map; + server_registry tcp_servers; + server_registry udp_servers; + + tcp_server* find_server(const SOCKET socket) + { + return socket_map.access([&](const std::unordered_map& map) -> tcp_server* + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return nullptr; + } + + return entry->second; + }); + } + + bool socket_link(const SOCKET socket, const uint32_t address) + { + auto* server = tcp_servers.find(address); + if (!server) + { + return false; + } + + socket_map.access([&](std::unordered_map& map) + { + map[socket] = server; + }); + + return true; + } + + void socket_unlink(const SOCKET socket) + { + socket_map.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + bool is_socket_blocking(const SOCKET socket, const bool def) + { + return blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return def; + } + + return entry->second; + }); + } + + void remove_blocking_socket(const SOCKET socket) + { + blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + void add_blocking_socket(const SOCKET socket, const bool block) + { + blocking_sockets.access([&](std::unordered_map& map) + { + map[socket] = block; + }); + } + + void server_main() + { + exit_server = false; + + while (!exit_server) + { + tcp_servers.frame(); + udp_servers.frame(); + std::this_thread::sleep_for(50ms); + } + } + + namespace io + { + hostent* WINAPI gethostbyname_stub(const char* name) + { +#ifdef DEBUG + printf("[ network ]: [gethostbyname]: \"%s\"\n", name); +#endif + + base_server* server = tcp_servers.find(name); + if (!server) + { + server = udp_servers.find(name); + } + + if (!server) + { +#pragma warning(push) +#pragma warning(disable: 4996) + return gethostbyname(name); +#pragma warning(pop) + } + + static thread_local in_addr address{}; + address.s_addr = server->get_address(); + + static thread_local in_addr* addr_list[2]{}; + addr_list[0] = &address; + addr_list[1] = nullptr; + + static thread_local hostent host{}; + host.h_name = const_cast(name); + host.h_aliases = nullptr; + host.h_addrtype = AF_INET; + host.h_length = sizeof(in_addr); + host.h_addr_list = reinterpret_cast(addr_list); + + return &host; + } + + int WINAPI connect_stub(const SOCKET s, const sockaddr* addr, const int len) + { + if (len == sizeof(sockaddr_in)) + { + const auto* in_addr = reinterpret_cast(addr); + if (socket_link(s, in_addr->sin_addr.s_addr)) return 0; + } + + return connect(s, addr, len); + } + + int WINAPI closesocket_stub(const SOCKET s) + { + remove_blocking_socket(s); + socket_unlink(s); + + return closesocket(s); + } + + int WINAPI send_stub(const SOCKET s, const char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + server->handle_input(buf, len); + return len; + } + + return send(s, buf, len, flags); + } + + int WINAPI recv_stub(const SOCKET s, char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + if (server->pending_data()) + { + return static_cast(server->handle_output(buf, len)); + } + else + { + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + } + + return recv(s, buf, len, flags); + } + + int WINAPI sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to, + const int tolen) + { + const auto* in_addr = reinterpret_cast(to); + auto* server = udp_servers.find(in_addr->sin_addr.s_addr); + + if (server) + { + server->handle_input(buf, len, {s, to, tolen}); + return len; + } + + return sendto(s, buf, len, flags, to, tolen); + } + + int WINAPI recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, sockaddr* from, + int* fromlen) + { + // Not supported yet + if (is_socket_blocking(s, UDP_BLOCKING)) + { + return recvfrom(s, buf, len, flags, from, fromlen); + } + + size_t result = 0; + udp_servers.for_each([&](udp_server& server) + { + if (server.pending_data(s)) + { + result = server.handle_output( + s, buf, static_cast(len), from, fromlen); + } + }); + + if (result) + { + return static_cast(result); + } + + return recvfrom(s, buf, len, flags, from, fromlen); + } + + int WINAPI select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + timeval* timeout) + { + if (exit_server) + { + return select(nfds, readfds, writefds, exceptfds, timeout); + } + + auto result = 0; + std::vector read_sockets; + std::vector write_sockets; + + socket_map.access([&](std::unordered_map& sockets) + { + for (auto& s : sockets) + { + if (readfds) + { + if (FD_ISSET(s.first, readfds)) + { + if (s.second->pending_data()) + { + read_sockets.push_back(s.first); + FD_CLR(s.first, readfds); + } + } + } + + if (writefds) + { + if (FD_ISSET(s.first, writefds)) + { + write_sockets.push_back(s.first); + FD_CLR(s.first, writefds); + } + } + + if (exceptfds) + { + if (FD_ISSET(s.first, exceptfds)) + { + FD_CLR(s.first, exceptfds); + } + } + } + }); + + if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0)) + { + timeout->tv_sec = 0; + timeout->tv_usec = 0; + } + + result = select(nfds, readfds, writefds, exceptfds, timeout); + if (result < 0) result = 0; + + for (const auto& socket : read_sockets) + { + if (readfds) + { + FD_SET(socket, readfds); + result++; + } + } + + for (const auto& socket : write_sockets) + { + if (writefds) + { + FD_SET(socket, writefds); + result++; + } + } + + return result; + } + + int WINAPI ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp) + { + if (static_cast(cmd) == (FIONBIO)) + { + add_blocking_socket(s, *argp == 0); + } + + return ioctlsocket(s, cmd, argp); + } + + BOOL internet_get_connected_state_stub(LPDWORD, DWORD) + { + // Allow offline play + return TRUE; + } + } + + void bd_logger_stub(const char* const function, const char* const msg, ...) + { + static const auto* bd_logger_enabled = game::Dvar_RegisterBool("bd_logger_enabled", false, game::DVAR_FLAG_NONE, "Enable bdLogger"); + if (!bd_logger_enabled->current.enabled) + { + return; + } + + char buffer[2048]; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + printf("%s: %s\n", function, buffer); + + va_end(ap); + } + + void startup_dw() + { + udp_servers.create("s1-stun.us.demonware.net"); + udp_servers.create("s1-stun.eu.demonware.net"); + udp_servers.create("s1-stun.jp.demonware.net"); + udp_servers.create("s1-stun.au.demonware.net"); + + udp_servers.create("stun.us.demonware.net"); + udp_servers.create("stun.eu.demonware.net"); + udp_servers.create("stun.jp.demonware.net"); + udp_servers.create("stun.au.demonware.net"); + + tcp_servers.create("aw-pc-auth3.prod.demonware.net"); + tcp_servers.create("aw-pc-lobby.prod.demonware.net"); + tcp_servers.create("prod.umbrella.demonware.net"); + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + startup_dw(); + + server_thread = utils::thread::create_named_thread("Demonware", server_main); + } + + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "WS2_32.dll") + { + if (function == "#3") return io::closesocket_stub; + if (function == "#4") return io::connect_stub; + if (function == "#10") return io::ioctlsocket_stub; + if (function == "#16") return io::recv_stub; + if (function == "#17") return io::recvfrom_stub; + if (function == "#18") return io::select_stub; + if (function == "#19") return io::send_stub; + if (function == "#20") return io::sendto_stub; + if (function == "#52") return io::gethostbyname_stub; + } + + if (function == "InternetGetConnectedState") + { + return io::internet_get_connected_state_stub; + } + + return nullptr; + } + + void post_unpack() override + { + utils::hook::jump(SELECT_VALUE(0x140575880, 0x1406C0080), bd_logger_stub); + + if (game::environment::is_sp()) + { + utils::hook::set(0x1405632E0, 0xC3); // bdAuthSteam + utils::hook::set(0x1402DF2C0, 0xC3); // dwNet + return; + } + + utils::hook::set(0x140698BB2, 0x0); // CURLOPT_SSL_VERIFYPEER + utils::hook::set(0x140698B69, 0xAF); // CURLOPT_SSL_VERIFYHOST + utils::hook::set(0x14088D0E8, 0x0); // HTTPS -> HTTP + + // HTTPS -> HTTP + utils::hook::inject(0x14003852E, "http://prod.umbrella.demonware.net/v1.0/"); + utils::hook::inject(0x14003884F, "http://prod.umbrella.demonware.net/v1.0/"); + utils::hook::inject(0x140038A07, "http://prod.umbrella.demonware.net/v1.0/"); + + utils::hook::set(0x140437CC0, 0xC3); // SV_SendMatchData + utils::hook::set(0x140560D70, 0xC3); // Live_CheckForFullDisconnect + } + + void pre_destroy() override + { + exit_server = true; + if (server_thread.joinable()) + { + server_thread.join(); + } + } + }; +} + +REGISTER_COMPONENT(demonware::component) diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp new file mode 100644 index 0000000..610d09c --- /dev/null +++ b/src/client/component/discord.cpp @@ -0,0 +1,167 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" +#include "network.hpp" +#include "party.hpp" +#include "scheduler.hpp" + +#include +#include + +#include + +namespace discord +{ + namespace + { + DiscordRichPresence discord_presence; + + void join_game(const char* join_secret) + { + game::Cbuf_AddText(0, utils::string::va("connect %s\n", join_secret)); + } + + void join_request(const DiscordUser* request) + { +#ifdef _DEBUG + console::info("Discord: Join request from %s (%s)\n", request->username, request->userId); +#endif + Discord_Respond(request->userId, DISCORD_REPLY_IGNORE); + } + + void update_discord() + { + Discord_RunCallbacks(); + + auto* dvar = game::Dvar_FindVar("virtualLobbyActive"); + if (!game::CL_IsCgameInitialized() || (dvar && dvar->current.enabled == 1)) + { + discord_presence.details = game::environment::is_sp() ? "Singleplayer" : "Multiplayer"; + + dvar = game::Dvar_FindVar("virtualLobbyInFiringRange"); + if (dvar && dvar->current.enabled == 1) + { + discord_presence.state = "Firing Range"; + } + else + { + discord_presence.state = "Main Menu"; + } + + discord_presence.partySize = 0; + discord_presence.partyMax = 0; + discord_presence.startTimestamp = 0; + } + else + { + if (game::environment::is_sp()) return; + + const auto* gametype = game::UI_GetGameTypeDisplayName(game::Dvar_FindVar("ui_gametype")->current.string); + const auto* map = game::UI_GetMapDisplayName(game::Dvar_FindVar("ui_mapname")->current.string); + + discord_presence.details = utils::string::va("%s on %s", gametype, map); + + // get server host name + auto* const host_name = reinterpret_cast(0x141646CC4); + utils::string::strip(host_name, host_name, std::strlen(host_name) + 1); + + // get number of clients in game + auto clients = reinterpret_cast(0x1414CC290); + int clientsNum = *clients; + discord_presence.partySize = clientsNum; + + if (game::Dvar_FindVar("name") && !strcmp(host_name, game::Dvar_FindVar("name")->current.string)) // host_name == name, most likely private match + { + discord_presence.state = "Private Match"; + discord_presence.partyMax = game::Dvar_FindVar("sv_maxclients")->current.integer; + } + else + { + discord_presence.state = host_name; + discord_presence.partyMax = party::server_client_count(); + + std::hash hash_fn; + static const auto nonce = utils::cryptography::random::get_integer(); + + const auto& address = party::get_target(); + discord_presence.partyId = utils::string::va("%zu", hash_fn(address) ^ nonce); + discord_presence.joinSecret = network::net_adr_to_string(address); + } + + if (!discord_presence.startTimestamp) + { + discord_presence.startTimestamp = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + } + } + + Discord_UpdatePresence(&discord_presence); + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + DiscordEventHandlers handlers; + ZeroMemory(&handlers, sizeof(handlers)); + handlers.ready = ready; + handlers.errored = errored; + handlers.disconnected = errored; + handlers.joinGame = join_game; + handlers.spectateGame = nullptr; + handlers.joinRequest = join_request; + + Discord_Initialize("1117777088301240350", &handlers, 1, nullptr); + + scheduler::once([] + { + scheduler::once(update_discord, scheduler::pipeline::main); + scheduler::loop(update_discord, scheduler::pipeline::main, 15s); + }, scheduler::pipeline::main); + + initialized_ = true; + } + + void pre_destroy() override + { + if (!initialized_) + { + return; + } + + Discord_Shutdown(); + } + + private: + bool initialized_ = false; + + static void ready(const DiscordUser* /*request*/) + { + ZeroMemory(&discord_presence, sizeof(discord_presence)); + + discord_presence.instance = 1; + + console::info("Discord: Ready\n"); + + Discord_UpdatePresence(&discord_presence); + } + + static void errored(const int error_code, const char* message) + { + console::error("Discord: Error (%i): %s\n", error_code, message); + } + }; +} + +#ifndef DEV_BUILD +REGISTER_COMPONENT(discord::component) +#endif diff --git a/src/client/component/dvar_cheats.cpp b/src/client/component/dvar_cheats.cpp new file mode 100644 index 0000000..e2284f6 --- /dev/null +++ b/src/client/component/dvar_cheats.cpp @@ -0,0 +1,189 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "console.hpp" + +#include +#include + +namespace dvar_cheats +{ + void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::dvar_value* value) + { + if (dvar && dvar->name == "sv_cheats"s) + { + // if dedi, do not allow internal to change value so servers can allow cheats if they want to + if (game::environment::is_dedi() && source == game::DvarSetSource::DVAR_SOURCE_INTERNAL) + { + value->enabled = dvar->current.enabled; + } + + // if sv_cheats was enabled and it changes to disabled, we need to reset all cheat dvars + else if (dvar->current.enabled && !value->enabled) + { + for (auto i = 0; i < *game::dvarCount; ++i) + { + const auto var = game::sortedDvars[i]; + if (var && (var->flags & game::DvarFlags::DVAR_FLAG_CHEAT)) + { + game::Dvar_Reset(var, game::DvarSetSource::DVAR_SOURCE_INTERNAL); + } + } + } + } + } + + bool dvar_flag_checks(const game::dvar_t* dvar, const game::DvarSetSource source) + { + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_WRITE)) + { + console::error("%s is write protected\n", dvar->name); + return false; + } + + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_READ)) + { + console::error("%s is read only\n", dvar->name); + return false; + } + + // only check cheat/replicated values when the source is external + if (source == game::DvarSetSource::DVAR_SOURCE_EXTERNAL) + { + const auto cl_ingame = game::Dvar_FindVar("cl_ingame"); + const auto sv_running = game::Dvar_FindVar("sv_running"); + + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_REPLICATED) && (cl_ingame && cl_ingame->current.enabled) && ( + sv_running && !sv_running->current.enabled)) + { + console::error("%s can only be changed by the server\n", dvar->name); + return false; + } + + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_CHEAT) && (!dvars::sv_cheats->current.enabled)) + { + console::error("%s is cheat protected\n", dvar->name); + return false; + } + } + + // pass all the flag checks, allow dvar to be changed + return true; + } + + const auto dvar_flag_checks_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto can_set_value = a.newLabel(); + const auto zero_source = a.newLabel(); + + a.pushad64(); + a.mov(r8, rdi); + a.mov(edx, esi); + a.mov(rcx, rbx); + a.call_aligned(apply_sv_cheats); //check if we are setting sv_cheats + a.popad64(); + a.cmp(esi, 0); + a.jz(zero_source); //if the SetSource is 0 (INTERNAL) ignore flag checks + + a.pushad64(); + a.mov(edx, esi); //source + a.mov(rcx, rbx); //dvar + a.call_aligned(dvar_flag_checks); //protect read/write/cheat/replicated dvars + a.cmp(al, 1); + a.jz(can_set_value); + + // if we get here, we are non-zero source and CANNOT set values + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.jmp(0x1404C3D45); + + // if we get here, we are non-zero source and CAN set values + a.bind(can_set_value); + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.jmp(0x1404C3AAE); + + // if we get here, we are zero source and ignore flags + a.bind(zero_source); + a.jmp(0x1404C3AF4); + }); + + void cg_set_client_dvar_from_server(const int local_client_num, void* cg, const char* dvar_id, const char* value) + { + const auto* dvar = game::Dvar_FindVar(dvar_id); + if (dvar) + { + // If we send as string, it can't be set with source SERVERCMD because the game only allows that source on real server cmd dvars. + // Just use external instead as if it was being set by the console + game::Dvar_SetFromStringByNameFromSource(dvar_id, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL); + } + else + { + // Not a dvar name, assume it is an id and the game will handle normally + game::CG_SetClientDvarFromServer(local_client_num, cg, dvar_id, value); + } + } + + void set_client_dvar_by_string(const int entity_num, const char* value) + { + const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack + const auto* command = utils::string::va("q %s \"%s\"", dvar, value); + + game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command); + } + + const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto set_by_string = a.newLabel(); + + a.pushad64(); + + // check if we didn't find a network dvar index + a.mov(ecx, dword_ptr(rsp, 0x8C8)); + a.cmp(ecx, 0); + a.je(set_by_string); + + // we found an index, handle normally + a.popad64(); + a.mov(r8d, ptr(rsp, 0x848)); + a.lea(r9, ptr(rsp, 0x30)); + a.jmp(0x1402E2E57); + + // no index, let's send the dvar as a string + a.bind(set_by_string); + a.movzx(ecx, word_ptr(rsp, 0x8C0)); //entity_num + a.lea(rdx, ptr(rsp, 0xB0)); //value + a.call_aligned(set_client_dvar_by_string); + a.popad64(); + a.jmp(0x1402E2E7D); + }); + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) return; + + utils::hook::nop(0x1404C3A93, 4); // let our stub handle zero-source sets + utils::hook::jump(0x1404C3A9A, dvar_flag_checks_stub, true); // check extra dvar flags when setting values + + utils::hook::nop(0x1402E2E03, 5); // remove error in PlayerCmd_SetClientDvar if setting a non-network dvar + // don't check flags on the dvars, send any existing dvar instead + utils::hook::jump(0x1402E2E4A, player_cmd_set_client_dvar, true); // send non-network dvars as string + utils::hook::call(0x1401BB782, cg_set_client_dvar_from_server); + // check for dvars being sent as string before parsing ids + +#ifdef _DEBUG + constexpr auto value = true; +#else + constexpr auto value = false; +#endif + + dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DVAR_FLAG_REPLICATED, "Allow cheat commands and dvars on this server"); + } + }; +} + +REGISTER_COMPONENT(dvar_cheats::component) diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp new file mode 100644 index 0000000..2dd26b4 --- /dev/null +++ b/src/client/component/dvars.cpp @@ -0,0 +1,387 @@ +#include +#include "loader/component_loader.hpp" +#include "dvars.hpp" + +#include "game/game.hpp" + +#include + +namespace dvars +{ + struct dvar_base + { + unsigned int flags{}; + }; + + struct dvar_bool : dvar_base + { + bool value{}; + }; + + struct dvar_float : dvar_base + { + float value{}; + float min{}; + float max{}; + }; + + struct dvar_vector2 : dvar_base + { + float x{}; + float y{}; + float min{}; + float max{}; + }; + + struct dvar_vector3 : dvar_base + { + + float x{}; + float y{}; + float z{}; + float min{}; + float max{}; + }; + + struct dvar_int : dvar_base + { + int value{}; + int min{}; + int max{}; + }; + + struct dvar_string : dvar_base + { + std::string value{}; + }; + + namespace + { + template + T* find_dvar(std::unordered_map& map, const std::string& name) + { + auto i = map.find(name); + if (i != map.end()) + { + return &i->second; + } + + return nullptr; + } + + bool find_dvar(std::unordered_set& set, const std::string& name) + { + return set.find(name) != set.end(); + } + } + + namespace disable + { + static std::unordered_set set_bool_disables; + static std::unordered_set set_float_disables; + static std::unordered_set set_int_disables; + static std::unordered_set set_string_disables; + + void set_bool(const std::string& name) + { + set_bool_disables.emplace(name); + } + + void set_float(const std::string& name) + { + set_float_disables.emplace(name); + } + + void set_int(const std::string& name) + { + set_int_disables.emplace(name); + } + + void set_string(const std::string& name) + { + set_string_disables.emplace(name); + } + } + + namespace override + { + static std::unordered_map register_bool_overrides; + static std::unordered_map register_float_overrides; + static std::unordered_map register_int_overrides; + static std::unordered_map register_string_overrides; + static std::unordered_map register_vector2_overrides; + static std::unordered_map register_vector3_overrides; + + static std::unordered_map set_bool_overrides; + static std::unordered_map set_float_overrides; + static std::unordered_map set_int_overrides; + static std::unordered_map set_string_overrides; + + void register_bool(const std::string& name, const bool value, const unsigned int flags) + { + dvar_bool values; + values.value = value; + values.flags = flags; + register_bool_overrides[name] = std::move(values); + } + + void register_float(const std::string& name, const float value, const float min, const float max, const unsigned int flags) + { + dvar_float values; + values.value = value; + values.min = min; + values.max = max; + values.flags = flags; + register_float_overrides[name] = std::move(values); + } + + void register_int(const std::string& name, const int value, const int min, const int max, const unsigned int flags) + { + dvar_int values; + values.value = value; + values.min = min; + values.max = max; + values.flags = flags; + register_int_overrides[name] = std::move(values); + } + + void register_string(const std::string& name, const std::string& value, const unsigned int flags) + { + dvar_string values; + values.value = value; + values.flags = flags; + register_string_overrides[name] = std::move(values); + } + + void register_vector2(const std::string& name, float x, float y, float min, float max, const unsigned int flags) + { + dvar_vector2 values; + values.x = x; + values.y = y; + values.min = min; + values.max = max; + values.flags = flags; + register_vector2_overrides[name] = std::move(values); + } + + void register_vector3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags) + { + dvar_vector3 values; + values.x = x; + values.y = y; + values.z = z; + values.min = min; + values.max = max; + values.flags = flags; + register_vector3_overrides[name] = std::move(values); + } + + void set_bool(const std::string& name, const bool value) + { + set_bool_overrides[name] = value; + } + + void set_float(const std::string& name, const float value) + { + set_float_overrides[name] = value; + } + + void set_int(const std::string& name, const int value) + { + set_int_overrides[name] = value; + } + + void set_string(const std::string& name, const std::string& value) + { + set_string_overrides[name] = value; + } + } + + utils::hook::detour dvar_register_bool_hook; + utils::hook::detour dvar_register_float_hook; + utils::hook::detour dvar_register_int_hook; + utils::hook::detour dvar_register_string_hook; + utils::hook::detour dvar_register_vector2_hook; + utils::hook::detour dvar_register_vector3_hook; + + utils::hook::detour dvar_set_bool_hook; + utils::hook::detour dvar_set_float_hook; + utils::hook::detour dvar_set_int_hook; + utils::hook::detour dvar_set_string_hook; + + game::dvar_t* dvar_register_bool_stub(const char* name, bool value, unsigned int flags, const char* description) + { + auto* var = find_dvar(override::register_bool_overrides, name); + if (var) + { + value = var->value; + flags = var->flags; + } + + return dvar_register_bool_hook.invoke(name, value, flags, description); + } + + game::dvar_t* dvar_register_float_stub(const char* name, float value, float min, float max, unsigned int flags, + const char* description) + { + auto* var = find_dvar(override::register_float_overrides, name); + if (var) + { + value = var->value; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_float_hook.invoke(name, value, min, max, flags, description); + } + + game::dvar_t* dvar_register_int_stub(const char* name, int value, int min, int max, unsigned int flags, + const char* description) + { + auto* var = find_dvar(override::register_int_overrides, name); + if (var) + { + value = var->value; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_int_hook.invoke(name, value, min, max, flags, description); + } + + game::dvar_t* dvar_register_string_stub(const char* name, const char* value, unsigned int flags, const char* description) + { + auto* var = find_dvar(override::register_string_overrides, name); + if (var) + { + value = var->value.data(); + flags = var->flags; + } + + return dvar_register_string_hook.invoke(name, value, flags, description); + } + + game::dvar_t* dvar_register_vector2_stub(const char* name, float x, float y, float min, float max, + unsigned int flags, const char* description) + { + auto* var = find_dvar(override::register_vector2_overrides, name); + if (var) + { + x = var->x; + y = var->y; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_vector2_hook.invoke(name, x, y, min, max, flags, description); + } + + game::dvar_t* dvar_register_vector3_stub(const char* name, float x, float y, float z, float min, + float max, unsigned int flags, const char* description) + { + auto* var = find_dvar(override::register_vector3_overrides, name); + if (var) + { + x = var->x; + y = var->y; + z = var->z; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_vector3_hook.invoke(name, x, y, z, min, max, flags, description); + } + + void dvar_set_bool_stub(game::dvar_t* dvar, bool boolean) + { + const auto disabled = find_dvar(disable::set_bool_disables, dvar->name); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_bool_overrides, dvar->name); + if (var) + { + boolean = *var; + } + + return dvar_set_bool_hook.invoke(dvar, boolean); + } + + void dvar_set_float_stub(game::dvar_t* dvar, float fl) + { + const auto disabled = find_dvar(disable::set_float_disables, dvar->name); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_float_overrides, dvar->name); + if (var) + { + fl = *var; + } + + return dvar_set_float_hook.invoke(dvar, fl); + } + + void dvar_set_int_stub(game::dvar_t* dvar, int integer) + { + const auto disabled = find_dvar(disable::set_int_disables, dvar->name); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_int_overrides, dvar->name); + if (var) + { + integer = *var; + } + + return dvar_set_int_hook.invoke(dvar, integer); + } + + void dvar_set_string_stub(game::dvar_t* dvar, const char* string) + { + const auto disabled = find_dvar(disable::set_string_disables, dvar->name); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_string_overrides, dvar->name); + if (var) + { + string = var->data(); + } + + return dvar_set_string_hook.invoke(dvar, string); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + dvar_register_bool_hook.create(SELECT_VALUE(0x140371850, 0x1404C0BE0), &dvar_register_bool_stub); + dvar_register_float_hook.create(SELECT_VALUE(0x140371C20, 0x1404C0FB0), &dvar_register_float_stub); + dvar_register_int_hook.create(SELECT_VALUE(0x140371CF0, 0x1404C1080), &dvar_register_int_stub); + dvar_register_string_hook.create(SELECT_VALUE(0x140372050, 0x1404C1450), &dvar_register_string_stub); + dvar_register_vector2_hook.create(SELECT_VALUE(0x140372120, 0x1404C1520), &dvar_register_vector2_stub); + dvar_register_vector3_hook.create(SELECT_VALUE(0x140372230, 0x1404C1600), &dvar_register_vector3_stub); + + dvar_set_bool_hook.create(SELECT_VALUE(0x140372B70, 0x1404C1F30), &dvar_set_bool_stub); + dvar_set_float_hook.create(SELECT_VALUE(0x140373420, 0x1404C2A10), &dvar_set_float_stub); + dvar_set_int_hook.create(SELECT_VALUE(0x1403738D0, 0x1404C2F40), &dvar_set_int_stub); + dvar_set_string_hook.create(SELECT_VALUE(0x140373DE0, 0x1404C3610), &dvar_set_string_stub); + } + }; +} + +REGISTER_COMPONENT(dvars::component) diff --git a/src/client/component/dvars.hpp b/src/client/component/dvars.hpp new file mode 100644 index 0000000..a0e5c52 --- /dev/null +++ b/src/client/component/dvars.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace dvars +{ + namespace disable + { + void set_bool(const std::string& name); + void set_float(const std::string& name); + void set_int(const std::string& name); + void set_string(const std::string& name); + } + + namespace override + { + void register_bool(const std::string& name, bool value, unsigned int flags); + void register_float(const std::string& name, float value, float min, float max, unsigned int flags); + void register_int(const std::string& name, int value, int min, int max, unsigned int flags); + void register_string(const std::string& name, const std::string& value, unsigned int flags); + void register_vector2(const std::string& name, float x, float y, float min, float max, unsigned int flags); + void register_vector3(const std::string& name, float x, float y, float z, float min, float max, unsigned int flags); + + void set_bool(const std::string& name, bool boolean); + void set_float(const std::string& name, float fl); + void set_int(const std::string& name, int integer); + void set_string(const std::string& name, const std::string& string); + } +} diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp new file mode 100644 index 0000000..7bb1262 --- /dev/null +++ b/src/client/component/fastfiles.cpp @@ -0,0 +1,178 @@ +#include +#include "loader/component_loader.hpp" +#include "game/dvars.hpp" + +#include "fastfiles.hpp" +#include "command.hpp" +#include "console.hpp" + +#include +#include +#include + +namespace fastfiles +{ + static utils::concurrency::container current_fastfile; + + namespace + { + utils::hook::detour db_try_load_x_file_internal_hook; + utils::hook::detour db_find_x_asset_header_hook; + + void db_try_load_x_file_internal(const char* zone_name, const int flags) + { + console::info("Loading fastfile %s\n", zone_name); + current_fastfile.access([&](std::string& fastfile) + { + fastfile = zone_name; + }); + return db_try_load_x_file_internal_hook.invoke(zone_name, flags); + } + + void dump_gsc_script(const std::string& name, game::XAssetHeader header) + { + if (!dvars::g_dump_scripts->current.enabled) + { + return; + } + + std::string buffer; + buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1); + buffer.append(reinterpret_cast(&header.scriptfile->compressedLen), sizeof(int)); + buffer.append(reinterpret_cast(&header.scriptfile->len), sizeof(int)); + buffer.append(reinterpret_cast(&header.scriptfile->bytecodeLen), sizeof(int)); + buffer.append(header.scriptfile->buffer, header.scriptfile->compressedLen); + buffer.append(reinterpret_cast(header.scriptfile->bytecode), header.scriptfile->bytecodeLen); + + const auto out_name = std::format("gsc_dump/{}.gscbin", name); + utils::io::write_file(out_name, buffer); + + console::info("Dumped %s\n", out_name.data()); + } + + game::XAssetHeader db_find_x_asset_header_stub(game::XAssetType type, const char* name, int allow_create_default) + { + const auto start = game::Sys_Milliseconds(); + const auto result = db_find_x_asset_header_hook.invoke(type, name, allow_create_default); + const auto diff = game::Sys_Milliseconds() - start; + + if (type == game::ASSET_TYPE_SCRIPTFILE) + { + dump_gsc_script(name, result); + } + + if (diff > 100) + { + console::print( + result.data == nullptr ? console::con_type_error : console::con_type_warning, "Waited %i msec for asset '%s' of type '%s'.\n", + diff, + name, + game::g_assetNames[type] + ); + } + + return result; + } + } + + std::string get_current_fastfile() + { + auto fastfile_copy = current_fastfile.access([&](std::string& fastfile) + { + return fastfile; + }); + + return fastfile_copy; + } + + constexpr int get_asset_type_size(const game::XAssetType type) + { + constexpr int asset_type_sizes[] = + { + 96, 88, 128, 56, 40, 216, 56, 680, + 480, 32, 32, 32, 32, 32, 352, 1456, + 104, 32, 24, 152, 152, 152, 16, 64, + 640, 40, 16, 408, 24, 288, 176, 2800, + 48, -1, 40, 24, 200, 88, 16, 120, + 3560, 32, 64, 16, 16, -1, -1, -1, + -1, 24, 40, 24, 40, 24, 128, 2256, + 136, 32, 72, 24, 64, 88, 48, 32, + 96, 152, 64, 32, + }; + + return asset_type_sizes[type]; + } + + template + char* reallocate_asset_pool() + { + constexpr auto element_size = get_asset_type_size(Type); + static char new_pool[element_size * Size] = {0}; + assert(get_asset_type_size(Type) == game::DB_GetXAssetTypeSize(Type)); + + std::memmove(new_pool, game::DB_XAssetPool[Type], game::g_poolSize[Type] * element_size); + + game::DB_XAssetPool[Type] = new_pool; + game::g_poolSize[Type] = Size; + + return new_pool; + } + + void enum_assets(const game::XAssetType type, const std::function& callback, const bool include_override) + { + game::DB_EnumXAssets_Internal(type, static_cast([](game::XAssetHeader header, void* data) + { + const auto& cb = *static_cast*>(data); + cb(header); + }), &callback, include_override); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + db_try_load_x_file_internal_hook.create(SELECT_VALUE(0x1401816F0, 0x1402741C0), &db_try_load_x_file_internal); + + db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); + dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE, "Dump GSC scripts to binary format"); + + command::add("loadzone", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: loadzone \n"); + return; + } + + game::XZoneInfo info{}; + info.name = params.get(1); + info.allocFlags = 1; + info.freeFlags = 0; + game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_SYNC); + }); + + command::add("g_poolSizes", []() + { + for (auto i = 0; i < game::ASSET_TYPE_COUNT; i++) + { + console::info("g_poolSize[%i]: %i // %s\n", i, game::g_poolSize[i], game::g_assetNames[i]); + } + }); + + reallocate_asset_pool(); + + if (!game::environment::is_sp()) + { + const auto* xmodel_pool = reallocate_asset_pool(); + utils::hook::inject(0x14026FD63, xmodel_pool + 8); + utils::hook::inject(0x14026FDB3, xmodel_pool + 8); + utils::hook::inject(0x14026FFAC, xmodel_pool + 8); + utils::hook::inject(0x14027463C, xmodel_pool + 8); + utils::hook::inject(0x140274689, xmodel_pool + 8); + } + } + }; +} + +REGISTER_COMPONENT(fastfiles::component) diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp new file mode 100644 index 0000000..8eb7bdd --- /dev/null +++ b/src/client/component/fastfiles.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "game/game.hpp" + +namespace fastfiles +{ + std::string get_current_fastfile(); + + void enum_assets(game::XAssetType type, const std::function& callback, bool include_override); +} diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp new file mode 100644 index 0000000..367f6c0 --- /dev/null +++ b/src/client/component/filesystem.cpp @@ -0,0 +1,272 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "dvars.hpp" + +#include "filesystem.hpp" +#include "game_module.hpp" +#include "console.hpp" + +#include +#include +#include + +namespace filesystem +{ + namespace + { + bool initialized = false; + + bool custom_path_registered = false; + + std::deque& get_search_paths_internal() + { + static std::deque search_paths{}; + return search_paths; + } + + std::string get_binary_directory() + { + const auto dir = game_module::get_host_module().get_folder(); + return utils::string::replace(dir, "/", "\\"); + } + + void register_custom_path_stub(const char* path, const char* dir) + { + if (!custom_path_registered) + { + custom_path_registered = true; + + const auto launcher_dir = get_binary_directory(); + game::FS_AddLocalizedGameDirectory(launcher_dir.data(), "data"); + } + + game::FS_AddLocalizedGameDirectory(path, dir); + } + + void fs_startup_stub(const char* gamename) + { + console::info("[FS] Startup\n"); + + custom_path_registered = false; + + game::FS_Startup(gamename); + } + + bool can_insert_path(const std::filesystem::path& path) + { + const auto& paths = get_search_paths_internal(); + return std::ranges::none_of(paths.cbegin(), paths.cend(), [path](const auto& elem) + { + return elem == path; + }); + } + + void startup() + { + register_path("s1"); + register_path(get_binary_directory() + "\\data"); + + // game's search paths + register_path("devraw"); + register_path("devraw_shared"); + register_path("raw_shared"); + register_path("raw"); + register_path("main"); + } + + void check_for_startup() + { + if (!initialized) + { + initialized = true; + startup(); + } + } + } + + file::file(std::string name) + : name_(std::move(name)) + { + char* buffer{}; + const auto size = game::FS_ReadFile(this->name_.data(), &buffer); + + if (size >= 0 && buffer) + { + this->valid_ = true; + this->buffer_.append(buffer, size); + game::FS_FreeFile(buffer); + } + } + + bool file::exists() const + { + return this->valid_; + } + + const std::string& file::get_buffer() const + { + return this->buffer_; + } + + const std::string& file::get_name() const + { + return this->name_; + } + + std::string read_file(const std::string& path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + return utils::io::read_file(path_.generic_string()); + } + } + + return {}; + } + + bool read_file(const std::string& path, std::string* data, std::string* real_path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::read_file(path_.generic_string(), data)) + { + if (real_path != nullptr) + { + *real_path = path_.generic_string(); + } + + return true; + } + } + + return false; + } + + bool find_file(const std::string& path, std::string* real_path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + *real_path = path_.generic_string(); + return true; + } + } + + return false; + } + + bool exists(const std::string& path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + return true; + } + } + + return false; + } + + void register_path(const std::filesystem::path& path) + { + if (can_insert_path(path)) + { + console::info("[FS] Registering path '%s'\n", path.generic_string().data()); + get_search_paths_internal().push_front(path); + } + } + + void unregister_path(const std::filesystem::path& path) + { + if (!initialized) + { + return; + } + + auto& search_paths = get_search_paths_internal(); + for (auto i = search_paths.begin(); i != search_paths.end();) + { + if (*i == path) + { + console::info("[FS] Unregistering path '%s'\n", path.generic_string().data()); + i = search_paths.erase(i); + } + else + { + ++i; + } + } + } + + std::vector get_search_paths() + { + std::vector paths{}; + + for (const auto& path : get_search_paths_internal()) + { + paths.push_back(path.generic_string()); + } + + return paths; + } + + std::vector get_search_paths_rev() + { + std::vector paths{}; + const auto& search_paths = get_search_paths_internal(); + + for (auto i = search_paths.rbegin(); i != search_paths.rend(); ++i) + { + paths.push_back(i->generic_string()); + } + + return paths; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Set fs_basegame + dvars::override::register_string("fs_basegame", "s1", game::DVAR_FLAG_WRITE); + + if (game::environment::is_sp()) + { + utils::hook::call(0x140360A74, fs_startup_stub); + + utils::hook::call(0x140361FE0, register_custom_path_stub); + utils::hook::call(0x140362000, register_custom_path_stub); + utils::hook::call(0x14036203F, register_custom_path_stub); + } + else + { + utils::hook::call(0x1404AE192, fs_startup_stub); + utils::hook::call(0x1404AE5C3, fs_startup_stub); + + utils::hook::call(0x1404AEFD0, register_custom_path_stub); + utils::hook::call(0x1404AEFF0, register_custom_path_stub); + utils::hook::call(0x1404AF02F, register_custom_path_stub); + } + } + }; +} + +REGISTER_COMPONENT(filesystem::component) diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp new file mode 100644 index 0000000..f085210 --- /dev/null +++ b/src/client/component/filesystem.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace filesystem +{ + class file + { + public: + file(std::string name); + + [[nodiscard]] bool exists() const; + [[nodiscard]] const std::string& get_buffer() const; + [[nodiscard]] const std::string& get_name() const; + + private: + bool valid_ = false; + std::string name_; + std::string buffer_; + }; + + std::string read_file(const std::string& path); + bool read_file(const std::string& path, std::string* data, std::string* real_path = nullptr); + bool find_file(const std::string& path, std::string* real_path); + bool exists(const std::string& path); + + void register_path(const std::filesystem::path& path); + void unregister_path(const std::filesystem::path& path); + + std::vector get_search_paths(); + std::vector get_search_paths_rev(); +} diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp new file mode 100644 index 0000000..8edd2ed --- /dev/null +++ b/src/client/component/fps.cpp @@ -0,0 +1,186 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" +#include "fps.hpp" +#include "localized_strings.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +namespace fps +{ + namespace + { + const game::dvar_t* cg_drawFPS; + const game::dvar_t* cg_drawPing; + + float fps_color_good[4] = {0.6f, 1.0f, 0.0f, 1.0f}; + float fps_color_ok[4] = {1.0f, 0.7f, 0.3f, 1.0f}; + float fps_color_bad[4] = {1.0f, 0.3f, 0.3f, 1.0f}; + + //float origin_color[4] = { 1.0f, 0.67f, 0.13f, 1.0f }; + float ping_color[4] = {1.0f, 1.0f, 1.0f, 0.65f}; + + struct cg_perf_data + { + std::chrono::time_point perf_start; + std::int32_t current_ms{}; + std::int32_t previous_ms{}; + std::int32_t frame_ms{}; + std::int32_t history[32]{}; + std::int32_t count{}; + std::int32_t index{}; + std::int32_t instant{}; + std::int32_t total{}; + float average{}; + float variance{}; + std::int32_t min{}; + std::int32_t max{}; + }; + + cg_perf_data cg_perf = cg_perf_data(); + + void perf_calc_fps(cg_perf_data* data, const std::int32_t value) + { + data->history[data->index % 32] = value; + data->instant = value; + data->min = std::numeric_limits::max(); + data->max = 0; + data->average = 0.0f; + data->variance = 0.0f; + data->total = 0; + + for (auto i = 0; i < data->count; ++i) + { + const std::int32_t idx = (data->index - i) % 32; + + if (idx < 0) + { + break; + } + + data->total += data->history[idx]; + + if (data->min > data->history[idx]) + { + data->min = data->history[idx]; + } + + if (data->max < data->history[idx]) + { + data->max = data->history[idx]; + } + } + + data->average = static_cast(data->total) / static_cast(data->count); + ++data->index; + } + + void perf_update() + { + cg_perf.count = 32; + + cg_perf.current_ms = static_cast(std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - cg_perf.perf_start).count()); + cg_perf.frame_ms = cg_perf.current_ms - cg_perf.previous_ms; + cg_perf.previous_ms = cg_perf.current_ms; + + perf_calc_fps(&cg_perf, cg_perf.frame_ms); + + utils::hook::invoke(SELECT_VALUE(0x1404F6A90, 0x14062C540)); + } + + void cg_draw_fps() + { + if (cg_drawFPS && cg_drawFPS->current.integer > 0) + { + const auto fps = get_fps(); + + auto* font = game::R_RegisterFont("fonts/consolefont"); + if (!font) return; + + const auto* const fps_string = utils::string::va("%i", fps); + + const auto scale = 1.0f; + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 10.0f) - game::R_TextWidth( + fps_string, std::numeric_limits::max(), font) * scale; + + const auto y = font->pixelHeight * 1.2f; + + const auto fps_color = fps >= 60 ? fps_color_good : (fps >= 30 ? fps_color_ok : fps_color_bad); + game::R_AddCmdDrawText(fps_string, std::numeric_limits::max(), font, x, y, scale, scale, 0.0f, fps_color, 6); + } + } + + void cg_draw_ping() + { + if (cg_drawPing->current.integer > 0 && game::CL_IsCgameInitialized()) + { + auto* font = game::R_RegisterFont("fonts/consolefont"); + if (!font) return; + + auto* const ping_string = utils::string::va("Ping: %i", *game::mp::ping); + + const auto scale = 1.0f; + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 375.0f) - game::R_TextWidth( + ping_string, std::numeric_limits::max(), font) * scale; + + const auto y = font->pixelHeight * 1.2f; + + game::R_AddCmdDrawText(ping_string, std::numeric_limits::max(), font, x, y, scale, scale, 0.0f, ping_color, 6); + } + } + + const game::dvar_t* cg_draw_fps_register_stub(const char* dvar_name, const char** value_list, const int default_index, unsigned int /*flags*/, const char* description) + { + cg_drawFPS = game::Dvar_RegisterEnum(dvar_name, value_list, default_index, game::DVAR_FLAG_SAVED, description); + return cg_drawFPS; + } + } + + int get_fps() + { + return static_cast(static_cast(1000.0f / + static_cast(cg_perf.average)) + 9.313225746154785e-10); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // fps setup + cg_perf.perf_start = std::chrono::high_resolution_clock::now(); + utils::hook::call(SELECT_VALUE(0x140144D41, 0x140213B27), &perf_update); + + // change cg_drawfps flags to saved + utils::hook::call(SELECT_VALUE(0x1400EF951, 0x1401A4B8E), &cg_draw_fps_register_stub); + + // fix ping value + utils::hook::nop(0x140213031, 2); + + scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer); + if (game::environment::is_mp()) + { + cg_drawPing = game::Dvar_RegisterInt("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Draw ping"); + scheduler::loop(cg_draw_ping, scheduler::pipeline::renderer); + } + + game::Dvar_RegisterBool("cg_infobar_ping", false, game::DVAR_FLAG_SAVED, "Show server latency"); + game::Dvar_RegisterBool("cg_infobar_fps", false, game::DVAR_FLAG_SAVED, "Show FPS counter"); + } + }; +} + +REGISTER_COMPONENT(fps::component) diff --git a/src/client/component/fps.hpp b/src/client/component/fps.hpp new file mode 100644 index 0000000..74f937d --- /dev/null +++ b/src/client/component/fps.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace fps +{ + int get_fps(); +} \ No newline at end of file diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp new file mode 100644 index 0000000..61c2bde --- /dev/null +++ b/src/client/component/game_console.cpp @@ -0,0 +1,780 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "scheduler.hpp" +#include "game_console.hpp" + +#include +#include +#include + +#include "version.hpp" + +#define console_font game::R_RegisterFont("fonts/consolefont") +#define material_white game::Material_RegisterHandle("white") + +namespace game_console +{ + namespace + { + struct console_globals + { + float x{}; + float y{}; + float left_x{}; + float font_height{}; + bool may_auto_complete{}; + char auto_complete_choice[64]{}; + int info_line_count{}; + }; + + using output_queue = std::deque; + + struct ingame_console + { + char buffer[256]{}; + int cursor{}; + int font_height{}; + int visible_line_count{}; + int visible_pixel_width{}; + float screen_min[2]{}; //left & top + float screen_max[2]{}; //right & bottom + console_globals globals{}; + bool output_visible{}; + int display_line_offset{}; + int line_count{}; + utils::concurrency::container output{}; + }; + + ingame_console con{}; + + std::int32_t history_index = -1; + std::deque history{}; + + std::string fixed_input{}; + std::vector matches{}; + + float color_white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float color_s1[4] = {1.0f, 0.90f, 0.0f, 1.0f}; + + void clear() + { + strncpy_s(con.buffer, "", sizeof(con.buffer)); + con.cursor = 0; + + fixed_input = ""; + matches.clear(); + } + + void print_internal(const std::string& data) + { + con.output.access([&](output_queue& output) + { + if (con.visible_line_count > 0 + && con.display_line_offset == (output.size() - con.visible_line_count)) + { + con.display_line_offset++; + } + output.push_back(data); + if (output.size() > 512) + { + output.pop_front(); + } + }); + } + + void toggle_console() + { + clear(); + + con.output_visible = false; + *game::keyCatchers ^= 1; + } + + void toggle_console_output() + { + con.output_visible = con.output_visible == 0; + } + + void check_resize() + { + con.screen_min[0] = 6.0f; + con.screen_min[1] = 6.0f; + con.screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 6.0f; + con.screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1] - 6.0f; + + if (console_font) + { + con.font_height = console_font->pixelHeight; + con.visible_line_count = static_cast((con.screen_max[1] - con.screen_min[1] - (con.font_height * 2) + ) - + 24.0f) / con.font_height; + con.visible_pixel_width = static_cast(((con.screen_max[0] - con.screen_min[0]) - 10.0f) - 18.0f); + } + else + { + con.font_height = 0; + con.visible_line_count = 0; + con.visible_pixel_width = 0; + } + } + + void draw_box(const float x, const float y, const float w, const float h, float* color) + { + game::vec4_t dark_color; + + dark_color[0] = color[0] * 0.5f; + dark_color[1] = color[1] * 0.5f; + dark_color[2] = color[2] * 0.5f; + dark_color[3] = color[3]; + + game::R_AddCmdDrawStretchPic(x, y, w, h, 0.0f, 0.0f, 0.0f, 0.0f, color, material_white); + game::R_AddCmdDrawStretchPic(x, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic((x + w) - 2.0f, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + game::R_AddCmdDrawStretchPic(x, y, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic(x, (y + h) - 2.0f, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + } + + void draw_input_box(const int lines, float* color) + { + draw_box( + con.globals.x - 6.0f, + con.globals.y - 6.0f, + (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]), + (lines * con.globals.font_height) + 12.0f, + color); + } + + void draw_input_text_and_over(const char* str, float* color) + { + game::R_AddCmdDrawText(str, 0x7FFFFFFF, console_font, con.globals.x, + con.globals.y + con.globals.font_height, 1, + 1, 0, color, 0); + con.globals.x = game::R_TextWidth(str, 0, console_font) + con.globals.x + 6.0f; + } + + void draw_hint_box(const int lines, float* color, [[maybe_unused]] float offset_x = 0.0f, + [[maybe_unused]] float offset_y = 0.0f) + { + const auto _h = lines * con.globals.font_height + 12.0f; + const auto _y = con.globals.y - 3.0f + con.globals.font_height + 12.0f; + const auto _w = (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]); + + draw_box(con.globals.x - 6.0f, _y, _w, _h, color); + } + + void draw_hint_text(const int line, const char* text, float* color, const float offset = 0.0f) + { + const auto _y = con.globals.font_height + con.globals.y + (con.globals.font_height * (line + 1)) + 15.0f; + + game::R_AddCmdDrawText(text, 0x7FFFFFFF, console_font, con.globals.x + offset, _y, 1.0f, 1.0f, 0.0f, color, + 0); + } + + void draw_input() + { + con.globals.font_height = static_cast(console_font->pixelHeight); + con.globals.x = con.screen_min[0] + 6.0f; + con.globals.y = con.screen_min[1] + 6.0f; + con.globals.left_x = con.screen_min[0] + 6.0f; + + draw_input_box(1, dvars::con_inputBoxColor->current.vector); + draw_input_text_and_over("s1-mod: " VERSION ">", color_s1); + + con.globals.left_x = con.globals.x; + con.globals.auto_complete_choice[0] = 0; + + game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0, + con.cursor, '|'); + + // check if using a prefixed '/' or not + const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\') + ? std::string(con.buffer).substr(1) + : std::string(con.buffer); + + if (!input.length()) + { + return; + } + + if (input != fixed_input) + { + matches.clear(); + + if (input.find(" ") != std::string::npos) + { + find_matches(input.substr(0, input.find(" ")), matches, true); + } + else + { + find_matches(input, matches, false); + } + + fixed_input = input; + } + + con.globals.may_auto_complete = false; + if (matches.size() > 24) + { + draw_hint_box(1, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()), + dvars::con_inputDvarMatchColor->current.vector); + } + else if (matches.size() == 1) + { + auto* const dvar = game::Dvar_FindVar(matches[0].data()); + const auto line_count = dvar ? 2 : 1; + + draw_hint_box(line_count, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, matches[0].data(), + dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + draw_hint_text(0, game::Dvar_ValueToString(dvar, dvar->current), + dvars::con_inputDvarValueColor->current.vector, offset); + draw_hint_text(1, " default", dvars::con_inputDvarInactiveValueColor->current.vector); + draw_hint_text(1, game::Dvar_ValueToString(dvar, dvar->reset), + dvars::con_inputDvarInactiveValueColor->current.vector, offset); + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64); + con.globals.may_auto_complete = true; + } + else if (matches.size() > 1) + { + draw_hint_box(static_cast(matches.size()), dvars::con_inputHintBoxColor->current.vector); + + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + for (size_t i = 0; i < matches.size(); i++) + { + auto* const dvar = game::Dvar_FindVar(matches[i].data()); + + draw_hint_text(static_cast(i), matches[i].data(), + dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + draw_hint_text(static_cast(i), game::Dvar_ValueToString(dvar, dvar->current), + dvars::con_inputDvarValueColor->current.vector, offset); + } + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64); + con.globals.may_auto_complete = true; + } + } + + void draw_output_scrollbar(const float x, float y, const float width, const float height, output_queue& output) + { + const auto _x = (x + width) - 10.0f; + draw_box(_x, y, 10.0f, height, dvars::con_outputBarColor->current.vector); + + auto _height = height; + if (output.size() > con.visible_line_count) + { + const auto percentage = static_cast(con.visible_line_count) / output.size(); + _height *= percentage; + + const auto remainingSpace = height - _height; + const auto percentageAbove = static_cast(con.display_line_offset) / (output.size() - con. + visible_line_count); + + y = y + (remainingSpace * percentageAbove); + } + + draw_box(_x, y, 10.0f, _height, dvars::con_outputSliderColor->current.vector); + } + + void draw_output_text(const float x, float y, output_queue& output) + { + const auto offset = output.size() >= con.visible_line_count + ? 0.0f + : (con.font_height * (con.visible_line_count - output.size())); + + for (auto i = 0; i < con.visible_line_count; i++) + { + y = console_font->pixelHeight + y; + + const auto index = i + con.display_line_offset; + if (index >= output.size()) + { + break; + } + + game::R_AddCmdDrawText(output.at(index).data(), 0x7FFF, console_font, x, y + offset, 1.0f, 1.0f, + 0.0f, color_white, 0); + } + } + + void draw_output_window() + { + con.output.access([](output_queue& output) + { + draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0], + (con.screen_max[1] - con.screen_min[1]) - 32.0f, dvars::con_outputWindowColor->current.vector); + + const auto x = con.screen_min[0] + 6.0f; + const auto y = (con.screen_min[1] + 32.0f) + 6.0f; + const auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f; + const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f; + + game::R_AddCmdDrawText(game::Dvar_FindVar("version")->current.string, 0x7FFFFFFF, console_font, x, + ((height - 12.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_s1, + 0); + + draw_output_scrollbar(x, y, width, height, output); + draw_output_text(x, y, output); + }); + } + + void draw_console() + { + check_resize(); + + if (*game::keyCatchers & 1) + { + if (!(*game::keyCatchers & 1)) + { + con.output_visible = false; + } + + if (con.output_visible) + { + draw_output_window(); + } + + draw_input(); + } + } + } + + void print_internal(const char* fmt, ...) + { + char va_buffer[0x200]{}; + + va_list ap; + va_start(ap, fmt); + vsprintf_s(va_buffer, fmt, ap); + va_end(ap); + + const auto formatted = std::string(va_buffer); + const auto lines = utils::string::split(formatted, '\n'); + + for (const auto& line : lines) + { + print_internal(line); + } + } + + void print(const int type, const std::string& data) + { + try + { + if (game::environment::is_dedi()) + { + return; + } + } + catch (std::exception&) + { + return; + } + + const auto lines = utils::string::split(data, '\n'); + for (const auto& line : lines) + { + print_internal(type == console::con_type_info ? line : "^"s.append(std::to_string(type)).append(line)); + } + } + + bool console_char_event(const int local_client_num, const int key) + { + if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) + { + return false; + } + + if (*game::keyCatchers & 1) + { + if (key == game::keyNum_t::K_TAB) // tab (auto complete) + { + if (con.globals.may_auto_complete) + { + const auto first_char = con.buffer[0]; + + clear(); + + if (first_char == '\\' || first_char == '/') + { + con.buffer[0] = first_char; + con.buffer[1] = '\0'; + } + + strncat_s(con.buffer, con.globals.auto_complete_choice, 64); + con.cursor = static_cast(std::string(con.buffer).length()); + + if (con.cursor != 254) + { + con.buffer[con.cursor++] = ' '; + con.buffer[con.cursor] = '\0'; + } + } + } + + if (key == 'v' - 'a' + 1) // paste + { + const auto clipboard = utils::string::get_clipboard_data(); + if (clipboard.empty()) + { + return false; + } + + for (size_t i = 0; i < clipboard.length(); i++) + { + console_char_event(local_client_num, clipboard[i]); + } + + return false; + } + + if (key == 'c' - 'a' + 1) // clear + { + clear(); + con.line_count = 0; + con.display_line_offset = 0; + con.output.access([](output_queue& output) + { + output.clear(); + }); + history_index = -1; + history.clear(); + + return false; + } + + if (key == 'h' - 'a' + 1) // backspace + { + if (con.cursor > 0) + { + memmove(con.buffer + con.cursor - 1, con.buffer + con.cursor, + strlen(con.buffer) + 1 - con.cursor); + con.cursor--; + } + + return false; + } + + if (key < 32) + { + return false; + } + + if (con.cursor == 256 - 1) + { + return false; + } + + memmove(con.buffer + con.cursor + 1, con.buffer + con.cursor, strlen(con.buffer) + 1 - con.cursor); + con.buffer[con.cursor] = static_cast(key); + con.cursor++; + + if (con.cursor == strlen(con.buffer) + 1) + { + con.buffer[con.cursor] = 0; + } + } + + return true; + } + + bool console_key_event(const int local_client_num, const int key, const int down) + { + if (key == game::keyNum_t::K_F10) + { + if (game::mp::svs_clients[local_client_num].header.state >= 1) + { + return false; + } + + game::Cmd_ExecuteSingleCommand(local_client_num, 0, "lui_open menu_systemlink_join\n"); + } + + if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) + { + if (!down) + { + return false; + } + + if (game::playerKeys[local_client_num].keys[game::keyNum_t::K_SHIFT].down) + { + if (!(*game::keyCatchers & 1)) + toggle_console(); + + toggle_console_output(); + return false; + } + + toggle_console(); + + return false; + } + + if (*game::keyCatchers & 1) + { + if (down) + { + if (key == game::keyNum_t::K_UPARROW) + { + if (++history_index >= history.size()) + { + history_index = static_cast(history.size()) - 1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + con.cursor = static_cast(strlen(con.buffer)); + } + } + else if (key == game::keyNum_t::K_DOWNARROW) + { + if (--history_index < -1) + { + history_index = -1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + con.cursor = static_cast(strlen(con.buffer)); + } + } + + if (key == game::keyNum_t::K_RIGHTARROW) + { + if (con.cursor < strlen(con.buffer)) + { + con.cursor++; + } + + return false; + } + + if (key == game::keyNum_t::K_LEFTARROW) + { + if (con.cursor > 0) + { + con.cursor--; + } + + return false; + } + + //scroll through output + if (key == game::keyNum_t::K_MWHEELUP || key == game::keyNum_t::K_PGUP) + { + con.output.access([](output_queue& output) + { + if (output.size() > con.visible_line_count && con.display_line_offset > 0) + { + con.display_line_offset--; + } + }); + } + else if (key == game::keyNum_t::K_MWHEELDOWN || key == game::keyNum_t::K_PGDN) + { + con.output.access([](output_queue& output) + { + if (output.size() > con.visible_line_count + && con.display_line_offset < (output.size() - con.visible_line_count)) + { + con.display_line_offset++; + } + }); + } + + if (key == game::keyNum_t::K_ENTER) + { + game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data())); + + if (history_index != -1) + { + const auto itr = history.begin() + history_index; + + if (*itr == con.buffer) + { + history.erase(history.begin() + history_index); + } + } + + history.push_front(con.buffer); + + console::info("]%s\n", con.buffer); + + if (history.size() > 10) + { + history.erase(history.begin() + 10); + } + + history_index = -1; + + clear(); + } + } + } + + return true; + } + + bool match_compare(const std::string& input, const std::string& text, const bool exact) + { + if (exact && text == input) return true; + if (!exact && text.find(input) != std::string::npos) return true; + return false; + } + + void find_matches(std::string input, std::vector& suggestions, const bool exact) + { + input = utils::string::to_lower(input); + + for (auto i = 0; i < *game::dvarCount; i++) + { + if (game::sortedDvars[i] && game::sortedDvars[i]->name) + { + auto name = utils::string::to_lower(game::sortedDvars[i]->name); + if (game_console::match_compare(input, name, exact)) + { + suggestions.emplace_back(game::sortedDvars[i]->name); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + } + + auto* cmd = *game::cmd_functions; + while (cmd) + { + if (cmd->name) + { + auto name = utils::string::to_lower(cmd->name); + if (game_console::match_compare(input, name, exact)) + { + suggestions.emplace_back(cmd->name); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + cmd = cmd->next; + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + scheduler::loop(draw_console, scheduler::pipeline::renderer); + } + + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // initialize our structs + con.cursor = 0; + con.visible_line_count = 0; + con.output_visible = false; + con.display_line_offset = 0; + con.line_count = 0; + strncpy_s(con.buffer, "", sizeof(con.buffer)); + + con.globals.x = 0.0f; + con.globals.y = 0.0f; + con.globals.left_x = 0.0f; + con.globals.font_height = 0.0f; + con.globals.may_auto_complete = false; + con.globals.info_line_count = 0; + strncpy_s(con.globals.auto_complete_choice, "", 64); + + // add clear command + command::add("clear", [&]() + { + clear(); + con.line_count = 0; + con.display_line_offset = 0; + con.output.access([](output_queue& output) + { + output.clear(); + }); + history_index = -1; + history.clear(); + }); + + // add our dvars + dvars::con_inputBoxColor = game::Dvar_RegisterVec4("con_inputBoxColor", 0.2f, 0.2f, 0.2f, 0.9f, 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, + "color of console input box"); + dvars::con_inputHintBoxColor = game::Dvar_RegisterVec4("con_inputHintBoxColor", 0.3f, 0.3f, 0.3f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, "color of console input hint box"); + dvars::con_outputBarColor = game::Dvar_RegisterVec4("con_outputBarColor", 0.5f, 0.5f, 0.5f, 0.6f, 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, + "color of console output bar"); + dvars::con_outputSliderColor = game::Dvar_RegisterVec4("con_outputSliderColor", 1.0f, 0.8f, 0.0f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, "color of console output slider"); + dvars::con_outputWindowColor = game::Dvar_RegisterVec4("con_outputWindowColor", 0.25f, 0.25f, 0.25f, 0.85f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console output window"); + dvars::con_inputDvarMatchColor = game::Dvar_RegisterVec4("con_inputDvarMatchColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar"); + dvars::con_inputDvarValueColor = game::Dvar_RegisterVec4("con_inputDvarValueColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar value"); + dvars::con_inputDvarInactiveValueColor = game::Dvar_RegisterVec4( + "con_inputDvarInactiveValueColor", 0.8f, 0.8f, + 0.8f, 1.0f, 0.0f, 1.0f, game::DVAR_FLAG_SAVED, + "color of console inactive dvar value"); + dvars::con_inputCmdMatchColor = game::Dvar_RegisterVec4("con_inputCmdMatchColor", 0.80f, 0.80f, 1.0f, 1.0f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console matched command"); + } + }; +} + +REGISTER_COMPONENT(game_console::component) diff --git a/src/client/component/game_console.hpp b/src/client/component/game_console.hpp new file mode 100644 index 0000000..e941917 --- /dev/null +++ b/src/client/component/game_console.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace game_console +{ + void print(int type, const std::string& data); + + bool console_char_event(int local_client_num, int key); + bool console_key_event(int local_client_num, int key, int down); + + bool match_compare(const std::string& input, const std::string& text, const bool exact); + void find_matches(std::string input, std::vector& suggestions, const bool exact); +} diff --git a/src/client/component/game_log.cpp b/src/client/component/game_log.cpp new file mode 100644 index 0000000..b205183 --- /dev/null +++ b/src/client/component/game_log.cpp @@ -0,0 +1,116 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" +#include "scripting.hpp" +#include "console.hpp" +#include "game_log.hpp" + +#include "gsc/script_extension.hpp" + +#include +#include +#include + +namespace game_log +{ + namespace + { + void gscr_log_print() + { + char buf[1024]{}; + std::size_t out_chars = 0; + + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + const auto* value = game::Scr_GetString(i); + const auto len = std::strlen(value); + + out_chars += len; + if (out_chars >= sizeof(buf)) + { + break; + } + + strncat_s(buf, value, _TRUNCATE); + } + + g_log_printf("%s", buf); + } + } + + void g_log_printf(const char* fmt, ...) + { + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + return; + } + + char buffer[0x400]{}; + + va_list ap; + va_start(ap, fmt); + + vsnprintf_s(buffer, _TRUNCATE, fmt, ap); + + va_end(ap); + + const auto time = *game::level_time / 1000; + utils::io::write_file(log, utils::string::va("%3i:%i%i %s", + time / 60, + time % 60 / 10, + time % 60 % 10, + buffer + ), true); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + gsc::override_function("logprint", &gscr_log_print); + + scheduler::once([] + { + dvars::g_log = game::Dvar_RegisterString("g_log", "logs/games_mp.log", game::DVAR_FLAG_NONE, "Log file name"); + }, scheduler::pipeline::main); + + scripting::on_init([] + { + console::info("------- Game Initialization -------\n"); + console::info("gamename: S1\n"); + console::info("gamedate: " __DATE__ "\n"); + + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + console::info("Not logging to disk.\n"); + return; + } + + console::info("Logging to disk: '%s'.\n", log); + g_log_printf("------------------------------------------------------------\n"); + g_log_printf("InitGame\n"); + }); + + scripting::on_shutdown([](int free_scripts) + { + console::info("==== ShutdownGame (%d) ====\n", free_scripts); + + g_log_printf("ShutdownGame:\n"); + g_log_printf("------------------------------------------------------------\n"); + }); + } + }; +} + +REGISTER_COMPONENT(game_log::component) diff --git a/src/client/component/game_log.hpp b/src/client/component/game_log.hpp new file mode 100644 index 0000000..4135e71 --- /dev/null +++ b/src/client/component/game_log.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace game_log +{ + void g_log_printf(const char* fmt, ...); +} diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp new file mode 100644 index 0000000..bd98462 --- /dev/null +++ b/src/client/component/game_module.cpp @@ -0,0 +1,118 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" + +#include + +namespace game_module +{ + namespace + { + utils::hook::detour handle_a_hook; + utils::hook::detour handle_w_hook; + utils::hook::detour handle_ex_a_hook; + utils::hook::detour handle_ex_w_hook; + utils::hook::detour file_name_a_hook; + utils::hook::detour file_name_w_hook; + + HMODULE __stdcall get_module_handle_a(const LPCSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_a_hook.invoke(module_name); + } + + HMODULE __stdcall get_module_handle_w(const LPWSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_w_hook.invoke(module_name); + } + + BOOL __stdcall get_module_handle_ex_a(const DWORD flags, const LPCSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_a_hook.invoke(flags, module_name, hmodule); + } + + BOOL __stdcall get_module_handle_ex_w(const DWORD flags, const LPCWSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_w_hook.invoke(flags, module_name, hmodule); + } + + DWORD __stdcall get_module_file_name_a(HMODULE hmodule, const LPSTR filename, const DWORD size) + { + if (!hmodule) + { + hmodule = get_game_module(); + } + + return file_name_a_hook.invoke(hmodule, filename, size); + } + + DWORD __stdcall get_module_file_name_w(HMODULE hmodule, const LPWSTR filename, const DWORD size) + { + if (!hmodule) + { + hmodule = get_game_module(); + } + + return file_name_w_hook.invoke(hmodule, filename, size); + } + + void hook_module_resolving() + { + handle_a_hook.create(&GetModuleHandleA, &get_module_handle_a); + handle_w_hook.create(&GetModuleHandleW, &get_module_handle_w); + handle_ex_w_hook.create(&GetModuleHandleExA, &get_module_handle_ex_a); + handle_ex_w_hook.create(&GetModuleHandleExW, &get_module_handle_ex_w); + file_name_a_hook.create(&GetModuleFileNameA, &get_module_file_name_a); + file_name_w_hook.create(&GetModuleFileNameW, &get_module_file_name_w); + } + } + + utils::nt::library get_game_module() + { + static utils::nt::library game{HMODULE(0x140000000)}; + return game; + } + + utils::nt::library get_host_module() + { + static utils::nt::library host{}; + return host; + } + + class component final : public component_interface + { + public: + void post_start() override + { + get_host_module(); + } + + void post_load() override + { + hook_module_resolving(); + } + }; +} + +REGISTER_COMPONENT(game_module::component) diff --git a/src/client/component/game_module.hpp b/src/client/component/game_module.hpp new file mode 100644 index 0000000..35a39f7 --- /dev/null +++ b/src/client/component/game_module.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace game_module +{ + utils::nt::library get_game_module(); + utils::nt::library get_host_module(); +} diff --git a/src/client/component/gameplay.cpp b/src/client/component/gameplay.cpp new file mode 100644 index 0000000..1ac5649 --- /dev/null +++ b/src/client/component/gameplay.cpp @@ -0,0 +1,206 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace gameplay +{ + namespace + { + utils::hook::detour pm_weapon_use_ammo_hook; + + int stuck_in_client_stub(game::mp::gentity_s* entity) + { + if (dvars::g_playerEjection->current.enabled) + { + return utils::hook::invoke(0x1402DA310, entity); // StuckInClient + } + + return 0; + } + + void cm_transformed_capsule_trace_stub(game::trace_t* results, const float* start, const float* end, + game::Bounds* bounds, game::Bounds* capsule, int contents, const float* origin, const float* angles) + { + if (dvars::g_playerCollision->current.enabled) + { + utils::hook::invoke(0x1403AB1C0, + results, start, end, bounds, capsule, contents, origin, angles); // CM_TransformedCapsuleTrace + } + } + + const auto pm_bouncing_stub_mp = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto no_bounce = a.newLabel(); + const auto loc_14014DF48 = a.newLabel(); + + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::pm_bouncing))); + a.mov(al, byte_ptr(rax, 0x10)); + a.cmp(byte_ptr(rbp, -0x2D), al); + + a.pop(rax); + a.jz(no_bounce); + a.jmp(0x14014DFB0); + + a.bind(no_bounce); + a.cmp(dword_ptr(rsp, 0x70), 0); + a.jnz(loc_14014DF48); + a.jmp(0x14014DFA2); + + a.bind(loc_14014DF48); + a.jmp(0x14014DF48); + }); + + void pm_weapon_use_ammo_stub(game::playerState_s* ps, game::Weapon weapon, + bool is_alternate, int amount, game::PlayerHandIndex hand) + { + if (!dvars::player_sustainAmmo->current.enabled) + { + pm_weapon_use_ammo_hook.invoke(ps, weapon, is_alternate, amount, hand); + } + } + + const auto client_end_frame_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::g_gravity))); + a.mov(eax, dword_ptr(rax, 0x10)); + a.mov(word_ptr(rbx, 0x36), ax); + + a.pop(rax); + + // Game code hook skipped + a.mov(eax, dword_ptr(rbx, 0x5084)); + a.mov(rdi, rcx); + + a.jmp(0x1402D5A6A); + }); + + const auto client_think_real_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::g_speed))); + a.mov(eax, dword_ptr(rax, 0x10)); + a.mov(word_ptr(rbx, 0x38), ax); + + a.pop(rax); + + // Game code hook skipped + a.movzx(eax, word_ptr(rbx, 0x3C)); + a.add(eax, dword_ptr(rbx, 0x48)); + + a.jmp(0x1402D6A9C); + }); + + const auto jump_push_off_ladder = utils::hook::assemble([](utils::hook::assembler& a) + { + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::jump_ladderPushVel))); + a.mulss(xmm7, dword_ptr(rax, 0x10)); + a.mulss(xmm6, dword_ptr(rax, 0x10)); + + a.pop(rax); + + a.jmp(0x1401358C3); + }); + + void jump_start_stub(game::pmove_t* pm, game::pml_t* pml, float /*height*/) + { + utils::hook::invoke(0x140135A90, pm, pml, dvars::jump_height->current.value); + } + + void pm_player_trace_stub(game::pmove_t* pm, game::trace_t* results, const float* start, + const float* end, const game::Bounds* bounds, int pass_entity_num, int content_mask) + { + utils::hook::invoke(0x14014A420, pm, results, start, end, bounds, pass_entity_num, content_mask); + + if (dvars::g_elevators->current.enabled) + { + results->startsolid = false; + } + } + + void pm_trace_stub(const game::pmove_t* pm, game::trace_t* results, const float* start, + const float* end, const game::Bounds* bounds, int pass_entity_num, int content_mask) + { + utils::hook::invoke(0x14014A610, pm, results, start, end, bounds, pass_entity_num, content_mask); + + if (dvars::g_elevators->current.enabled) + { + results->allsolid = false; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + dvars::player_sustainAmmo = game::Dvar_RegisterBool("player_sustainAmmo", false, + game::DVAR_FLAG_REPLICATED, "Firing weapon will not decrease clip ammo"); + pm_weapon_use_ammo_hook.create(SELECT_VALUE(0x1403DD050, 0x140162B20), &pm_weapon_use_ammo_stub); + + if (game::environment::is_sp()) return; + + // Implement player ejection dvar + dvars::g_playerEjection = game::Dvar_RegisterBool("g_playerEjection", true, game::DVAR_FLAG_REPLICATED, + "Flag whether player ejection is on or off"); + utils::hook::call(0x1402D5E4A, stuck_in_client_stub); + + // Implement player collision dvar + dvars::g_playerCollision = game::Dvar_RegisterBool("g_playerCollision", true, game::DVAR_FLAG_REPLICATED, + "Flag whether player collision is on or off"); + utils::hook::call(0x1404563DA, cm_transformed_capsule_trace_stub); // SV_ClipMoveToEntity + utils::hook::call(0x1401F7F8F, cm_transformed_capsule_trace_stub); // CG_ClipMoveToEntity + + // Implement bouncing dvar + utils::hook::jump(0x14014DF91, pm_bouncing_stub_mp, true); + dvars::pm_bouncing = game::Dvar_RegisterBool("pm_bouncing", false, + game::DVAR_FLAG_REPLICATED, "Enable bouncing"); + + // Change jump_slowdownEnable dvar flags to just "replicated" + utils::hook::set(0x140135992, game::DVAR_FLAG_REPLICATED); + + // Choosing the following min/max because the game would truncate larger values + dvars::g_gravity = game::Dvar_RegisterInt("g_gravity", 800, std::numeric_limits::min(), + std::numeric_limits::max(), game::DVAR_FLAG_REPLICATED, "Gravity in inches per second per second"); + utils::hook::jump(0x1402D5A5D, client_end_frame_stub, true); + utils::hook::nop(0x1402D5A69, 1); // Nop skipped opcode + + // Choosing the following min/max because the game would truncate larger values + dvars::g_speed = game::Dvar_RegisterInt("g_speed", 190, + std::numeric_limits::min(), std::numeric_limits::max(), game::DVAR_FLAG_REPLICATED, "Player speed"); + utils::hook::jump(0x1402D6A8C, client_think_real_stub, true); + utils::hook::nop(0x1402D6A98, 4); // Nop skipped opcodes + + dvars::jump_height = game::Dvar_RegisterFloat("jump_height", 39.0f, + 0.0f, 1000.0f, game::DVAR_FLAG_REPLICATED, "The maximum height of a player's jump"); + utils::hook::call(0x1401352FF, jump_start_stub); + + dvars::jump_ladderPushVel = game::Dvar_RegisterFloat("jump_ladderPushVel", 128.0f, + 0.0f, 1024.0f, game::DVAR_FLAG_REPLICATED, "The velocity of a jump off of a ladder"); + utils::hook::jump(0x1401358B3, jump_push_off_ladder, true); + utils::hook::nop(0x1401358BF, 4); // Nop skipped opcodes + + dvars::g_elevators = game::Dvar_RegisterBool("g_elevators", false, + game::DVAR_FLAG_REPLICATED, "Enable elevators"); + utils::hook::call(0x140146134, pm_player_trace_stub); + utils::hook::call(0x14014619B, pm_player_trace_stub); + + // Allow player to stand from prone/ducked + utils::hook::call(0x140142AF6, pm_trace_stub); + utils::hook::call(0x140142A1B, pm_trace_stub); + utils::hook::call(0x14014298D, pm_trace_stub); + } + }; +} + +REGISTER_COMPONENT(gameplay::component) diff --git a/src/client/component/gsc/script_error.cpp b/src/client/component/gsc/script_error.cpp new file mode 100644 index 0000000..867c003 --- /dev/null +++ b/src/client/component/gsc/script_error.cpp @@ -0,0 +1,339 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "script_extension.hpp" +#include "script_error.hpp" + +#include "component/scripting.hpp" + +#include +#include + +using namespace utils::string; + +namespace gsc +{ + namespace + { + utils::hook::detour scr_emit_function_hook; + + unsigned int current_filename = 0; + + std::string unknown_function_error; + + // Array count confirmed at 0x1409BE0D0 + std::array var_typename = + { + "undefined", + "object", + "string", + "localized string", + "vector", + "float", + "int", + "codepos", + "precodepos", + "function", + "builtin function", + "builtin method", + "stack", + "animation", + "pre animation", + "thread", + "thread", + "thread", + "thread", + "struct", + "removed entity", + "entity", + "array", + "removed thread", + "", + "thread list", + "endon list", + }; + + void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos) + { + current_filename = filename; + scr_emit_function_hook.invoke(filename, thread_name, code_pos); + } + + std::string get_filename_name() + { + const auto filename_str = game::SL_ConvertToString(static_cast(current_filename)); + const auto id = std::atoi(filename_str); + if (!id) + { + return filename_str; + } + + return scripting::get_token(id); + } + + void get_unknown_function_error(const char* code_pos) + { + const auto function = find_function(code_pos); + if (function.has_value()) + { + const auto& pos = function.value(); + unknown_function_error = std::format( + "while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file + ); + } + else + { + unknown_function_error = std::format("unknown script '{}'", scripting::current_file); + } + } + + void get_unknown_function_error(unsigned int thread_name) + { + const auto filename = get_filename_name(); + const auto name = scripting::get_token(thread_name); + + unknown_function_error = std::format( + "while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name + ); + } + + void compile_error_stub(const char* code_pos, [[maybe_unused]] const char* msg) + { + get_unknown_function_error(code_pos); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + unsigned int find_variable_stub(unsigned int parent_id, unsigned int thread_name) + { + const auto res = game::FindVariable(parent_id, thread_name); + if (!res) + { + get_unknown_function_error(thread_name); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + return res; + } + + unsigned int scr_get_object(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_POINTER) + { + return value->u.pointerValue; + } + + scr_error(va("Type %s is not an object", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_string(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (game::Scr_CastString(value)) + { + assert(value->type == game::VAR_STRING); + return value->u.stringValue; + } + + game::Scr_ErrorInternal(); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_istring(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_ISTRING) + { + return value->u.stringValue; + } + + scr_error(va("Type %s is not a localized string", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + void scr_validate_localized_string_ref(int parm_index, const char* token, int token_len) + { + assert(token); + assert(token_len >= 0); + + if (token_len < 2) + { + return; + } + + for (auto char_iter = 0; char_iter < token_len; ++char_iter) + { + if (!std::isalnum(static_cast(token[char_iter])) && token[char_iter] != '_') + { + scr_error(va("Illegal localized string reference: %s must contain only alpha-numeric characters and underscores", token)); + } + } + } + + void scr_get_vector(unsigned int index, float* vector_value) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_VECTOR) + { + std::memcpy(vector_value, value->u.vectorValue, sizeof(std::float_t[3])); + return; + } + + scr_error(va("Type %s is not a vector", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + } + + int scr_get_int(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_INTEGER) + { + return value->u.intValue; + } + + scr_error(va("Type %s is not an int", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + float scr_get_float(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_FLOAT) + { + return value->u.floatValue; + } + + if (value->type == game::VAR_INTEGER) + { + return static_cast(value->u.intValue); + } + + scr_error(va("Type %s is not a float", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0.0f; + } + + int scr_get_pointer_type(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + if ((game::scr_VmPub->top - index)->type == game::VAR_POINTER) + { + return static_cast(game::GetObjectType((game::scr_VmPub->top - index)->u.uintValue)); + } + + scr_error(va("Type %s is not an object", var_typename[(game::scr_VmPub->top - index)->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + int scr_get_type(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + return (game::scr_VmPub->top - index)->type; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + const char* scr_get_type_name(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + return var_typename[(game::scr_VmPub->top - index)->type]; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return nullptr; + } + } + + std::optional> find_function(const char* pos) + { + for (const auto& file : scripting::script_function_table_sort) + { + for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i) + { + const auto next = std::next(i); + if (pos >= i->second && pos < next->second) + { + return {std::make_pair(i->first, file.first)}; + } + } + } + + return {}; + } + + class error final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + scr_emit_function_hook.create(0x1403ED900, &scr_emit_function_stub); + + utils::hook::call(0x1403ED894, compile_error_stub); // LinkFile + utils::hook::call(0x1403ED8E8, compile_error_stub); // LinkFile + utils::hook::call(0x1403ED9DB, find_variable_stub); // Scr_EmitFunction + + // Restore basic error messages for commonly used scr functions + utils::hook::jump(0x1403F8990, scr_get_object); + utils::hook::jump(0x1403F8510, scr_get_const_string); + utils::hook::jump(0x1403F82F0, scr_get_const_istring); + utils::hook::jump(0x140327870, scr_validate_localized_string_ref); + utils::hook::jump(0x1403F8EC0, scr_get_vector); + utils::hook::jump(0x1403F88D0, scr_get_int); + utils::hook::jump(0x1403F8820, scr_get_float); + + utils::hook::jump(0x1403F8BA0, scr_get_pointer_type); + utils::hook::jump(0x1403F8D70, scr_get_type); + utils::hook::jump(0x1403F8DE0, scr_get_type_name); + } + + void pre_destroy() override + { + scr_emit_function_hook.clear(); + } + }; +} + +REGISTER_COMPONENT(gsc::error) diff --git a/src/client/component/gsc/script_error.hpp b/src/client/component/gsc/script_error.hpp new file mode 100644 index 0000000..284af43 --- /dev/null +++ b/src/client/component/gsc/script_error.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace gsc +{ + std::optional> find_function(const char* pos); +} diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp new file mode 100644 index 0000000..5b0e3a2 --- /dev/null +++ b/src/client/component/gsc/script_extension.cpp @@ -0,0 +1,288 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/scripting/functions.hpp" + +#include + +#include "component/console.hpp" +#include "component/command.hpp" + +#include "script_error.hpp" +#include "script_extension.hpp" +#include "script_loading.hpp" + +#include + +namespace gsc +{ + std::uint16_t function_id_start = 0x2DF; + void* func_table[0x1000]; + + const game::dvar_t* developer_script = nullptr; + + namespace + { + #define RVA(ptr) static_cast(reinterpret_cast(ptr) - 0x140000000) + + struct gsc_error : public std::runtime_error + { + using std::runtime_error::runtime_error; + }; + + std::unordered_map functions; + + bool force_error_print = false; + std::optional gsc_error_msg; + + std::unordered_map builtin_funcs_overrides; + + utils::hook::detour scr_register_function_hook; + + unsigned int scr_get_function_stub(const char** p_name, int* type) + { + const auto result = utils::hook::invoke(0x1403318B0, p_name, type); + + for (const auto& [name, func] : functions) + { + game::Scr_RegisterFunction(func, 0, name); + } + + return result; + } + + void execute_custom_function(game::BuiltinFunction function) + { + auto error = false; + + try + { + function(); + } + catch (const std::exception& ex) + { + error = true; + force_error_print = true; + gsc_error_msg = ex.what(); + } + + if (error) + { + game::Scr_ErrorInternal(); + } + } + + void vm_call_builtin_function(const std::uint32_t index) + { + const auto func = reinterpret_cast(scripting::get_function_by_index(index)); + + const auto custom = functions.contains(static_cast(index)); + if (!custom) + { + func(); + } + else + { + execute_custom_function(func); + } + } + + void builtin_call_error(const std::string& error) + { + const auto pos = game::scr_function_stack->pos; + const auto function_id = *reinterpret_cast(reinterpret_cast(pos - 2)); + + if (function_id > 0x1000) + { + console::warn("in call to builtin method \"%s\"%s", gsc_ctx->meth_name(function_id).data(), error.data()); + } + else + { + console::warn("in call to builtin function \"%s\"%s", gsc_ctx->func_name(function_id).data(), error.data()); + } + } + + std::optional get_opcode_name(const std::uint8_t opcode) + { + try + { + const auto index = gsc_ctx->opcode_enum(opcode); + return {gsc_ctx->opcode_name(index)}; + } + catch (...) + { + return {}; + } + } + + void print_callstack() + { + for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame) + { + const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos; + const auto function = find_function(frame->fs.pos); + + if (function.has_value()) + { + console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data()); + } + else + { + console::warn("\tat unknown location %p\n", pos); + } + } + } + + void vm_error_stub(int mark_pos) + { + if (!developer_script->current.enabled && !force_error_print) + { + utils::hook::invoke(0x1404B6790, mark_pos); + return; + } + + console::warn("******* script runtime error ********\n"); + const auto opcode_id = *reinterpret_cast(0x148806768); + + const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string(); + + if ((opcode_id >= 0x1A && opcode_id <= 0x20) || (opcode_id >= 0xA9 && opcode_id <= 0xAF)) + { + builtin_call_error(error); + } + else + { + const auto opcode = get_opcode_name(opcode_id); + if (opcode.has_value()) + { + console::warn("while processing instruction %s%s\n", opcode.value().data(), error.data()); + } + else + { + console::warn("while processing instruction 0x%X%s\n", opcode_id, error.data()); + } + } + + force_error_print = false; + gsc_error_msg = {}; + + print_callstack(); + console::warn("************************************\n"); + utils::hook::invoke(0x1404B6790, mark_pos); + } + + void scr_register_function_stub(void* func, int type, unsigned int name) + { + if (const auto itr = builtin_funcs_overrides.find(name); itr != builtin_funcs_overrides.end()) + { + func = itr->second; + } + + scr_register_function_hook.invoke(func, type, name); + } + + void scr_print() + { + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + console::info("%s", game::Scr_GetString(i)); + } + } + + void scr_print_ln() + { + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + console::info("%s", game::Scr_GetString(i)); + } + + console::info("\n"); + } + + void assert_cmd() + { + if (!game::Scr_GetInt(0)) + { + scr_error("Assert fail"); + } + } + + void assert_ex_cmd() + { + if (!game::Scr_GetInt(0)) + { + scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(1))); + } + } + + void assert_msg_cmd() + { + scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(0))); + } + } + + void scr_error(const char* error) + { + force_error_print = true; + gsc_error_msg = error; + + game::Scr_ErrorInternal(); + } + + void override_function(const std::string& name, game::BuiltinFunction func) + { + const auto id = gsc_ctx->func_id(name); + builtin_funcs_overrides.emplace(id, func); + } + + void add_function(const std::string& name, game::BuiltinFunction function) + { + ++function_id_start; + functions[function_id_start] = function; + gsc_ctx->func_add(name, function_id_start); + } + + class extension final : public component_interface + { + public: + void post_unpack() override + { + scr_register_function_hook.create(game::Scr_RegisterFunction, &scr_register_function_stub); + + override_function("print", &scr_print); + override_function("println", &scr_print_ln); + + utils::hook::set(SELECT_VALUE(0x1403115BC, 0x1403EDAEC), 0x1000); // Scr_RegisterFunction + + utils::hook::set(SELECT_VALUE(0x1403115C2 + 4, 0x1403EDAF2 + 4), RVA(&func_table)); // Scr_RegisterFunction + utils::hook::set(SELECT_VALUE(0x14031F097 + 3, 0x1403FB7F7 + 3), RVA(&func_table)); // VM_Execute_0 + utils::hook::inject(SELECT_VALUE(0x140311964 + 3, 0x1403EDEE4 + 3), &func_table); // Scr_BeginLoadScripts + + if (game::environment::is_sp()) + { + return; + } + + developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + + utils::hook::nop(0x1403FB7F7 + 5, 2); + utils::hook::call(0x1403FB7F7, vm_call_builtin_function); + + utils::hook::call(0x1403FCAB0, vm_error_stub); // LargeLocalResetToMark + + utils::hook::call(0x1403EDF1F, scr_get_function_stub); + + override_function("assert", &assert_cmd); + override_function("assertex", &assert_ex_cmd); + override_function("assertmsg", &assert_msg_cmd); + + add_function("executecommand", [] + { + const auto* cmd = game::Scr_GetString(0); + command::execute(cmd); + }); + } + }; +} + +REGISTER_COMPONENT(gsc::extension) diff --git a/src/client/component/gsc/script_extension.hpp b/src/client/component/gsc/script_extension.hpp new file mode 100644 index 0000000..bdd44ff --- /dev/null +++ b/src/client/component/gsc/script_extension.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace gsc +{ + extern void* func_table[0x1000]; + + extern const game::dvar_t* developer_script; + + void scr_error(const char* error); + void override_function(const std::string& name, game::BuiltinFunction func); + void add_function(const std::string& name, game::BuiltinFunction function); +} diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp new file mode 100644 index 0000000..5f3bd65 --- /dev/null +++ b/src/client/component/gsc/script_loading.cpp @@ -0,0 +1,396 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include +#include +#include + +#include "component/filesystem.hpp" +#include "component/console.hpp" +#include "component/scripting.hpp" +#include "component/fastfiles.hpp" + +#include "script_loading.hpp" + +namespace gsc +{ + std::unique_ptr gsc_ctx; + + namespace + { + std::unordered_map main_handles; + std::unordered_map init_handles; + + std::unordered_map loaded_scripts; + utils::memory::allocator script_allocator; + + const game::dvar_t* developer_script; + + void clear() + { + main_handles.clear(); + init_handles.clear(); + loaded_scripts.clear(); + script_allocator.clear(); + } + + bool read_raw_script_file(const std::string& name, std::string* data) + { + if (filesystem::read_file(name, data)) + { + return true; + } + + // This will prevent 'fake' GSC raw files from being compiled. + // They are parsed by the game's own parser later as they are special files. + if (name.starts_with("maps/createfx") || name.starts_with("maps/createart") || + (name.starts_with("maps/mp") && name.ends_with("_fx.gsc"))) + { +#ifdef _DEBUG + console::info("Refusing to compile rawfile '%s\n", name.data()); +#endif + return false; + } + + const auto* name_str = name.data(); + if (game::DB_XAssetExists(game::ASSET_TYPE_RAWFILE, name_str) && + !game::DB_IsXAssetDefault(game::ASSET_TYPE_RAWFILE, name_str)) + { + const auto asset = game::DB_FindXAssetHeader(game::ASSET_TYPE_RAWFILE, name.data(), false); + const auto len = game::DB_GetRawFileLen(asset.rawfile); + data->resize(len); + game::DB_GetRawBuffer(asset.rawfile, data->data(), len); + if (len > 0) + { + data->pop_back(); + } + + return true; + } + + return false; + } + + game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name) + { + if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end()) + { + return itr->second; + } + + try + { + auto& compiler = gsc_ctx->compiler(); + auto& assembler = gsc_ctx->assembler(); + + std::string source_buffer{}; + if (!read_raw_script_file(real_name + ".gsc", &source_buffer)) + { + return nullptr; + } + + std::vector data; + data.assign(source_buffer.begin(), source_buffer.end()); + + const auto assembly_ptr = compiler.compile(real_name, data); + // Pair of two buffers. First is the byte code and second is the stack + const auto output_script = assembler.assemble(*assembly_ptr); + + const auto script_file_ptr = static_cast(script_allocator.allocate(sizeof(game::ScriptFile))); + script_file_ptr->name = file_name; + + script_file_ptr->bytecodeLen = static_cast(std::get<0>(output_script).size); + script_file_ptr->len = static_cast(std::get<1>(output_script).size); + + const auto byte_code_size = static_cast(std::get<0>(output_script).size + 1); + const auto stack_size = static_cast(std::get<1>(output_script).size + 1); + + script_file_ptr->buffer = static_cast(script_allocator.allocate(stack_size)); + std::memcpy(const_cast(script_file_ptr->buffer), std::get<1>(output_script).data, std::get<1>(output_script).size); + + script_file_ptr->bytecode = static_cast(game::PMem_AllocFromSource_NoDebug(byte_code_size, 4, 1, 5)); + std::memcpy(script_file_ptr->bytecode, std::get<0>(output_script).data, std::get<0>(output_script).size); + + script_file_ptr->compressedLen = 0; + + loaded_scripts[real_name] = script_file_ptr; + + return script_file_ptr; + } + catch (const std::exception& ex) + { + console::error("*********** script compile error *************\n"); + console::error("failed to compile '%s':\n%s", real_name.data(), ex.what()); + console::error("**********************************************\n"); + return nullptr; + } + } + + std::string get_script_file_name(const std::string& name) + { + const auto id = gsc_ctx->token_id(name); + if (!id) + { + return name; + } + + return std::to_string(id); + } + + std::pair> read_compiled_script_file(const std::string& name, const std::string& real_name) + { + const auto* script_file = game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name.data(), false).scriptfile; + if (!script_file) + { + throw std::runtime_error(std::format("Could not load scriptfile '{}'", real_name)); + } + + console::info("Decompiling scriptfile '%s'\n", real_name.data()); + + const auto len = script_file->compressedLen; + const std::string stack{script_file->buffer, static_cast(len)}; + + const auto decompressed_stack = utils::compression::zlib::decompress(stack); + + std::vector stack_data; + stack_data.assign(decompressed_stack.begin(), decompressed_stack.end()); + + return {{script_file->bytecode, static_cast(script_file->bytecodeLen)}, stack_data}; + } + + void load_script(const std::string& name) + { + if (!game::Scr_LoadScript(name.data())) + { + return; + } + + const auto main_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("main")); + const auto init_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("init")); + + if (main_handle) + { + console::info("Loaded '%s::main'\n", name.data()); + main_handles[name] = main_handle; + } + + if (init_handle) + { + console::info("Loaded '%s::init'\n", name.data()); + init_handles[name] = init_handle; + } + } + + void load_scripts(const std::filesystem::path& root_dir) + { + const std::filesystem::path script_dir = root_dir / "scripts"; + if (!utils::io::directory_exists(script_dir.generic_string())) + { + return; + } + + const auto scripts = utils::io::list_files(script_dir.generic_string()); + for (const auto& script : scripts) + { + if (!script.ends_with(".gsc")) + { + continue; + } + + std::filesystem::path path(script); + const auto relative = path.lexically_relative(root_dir).generic_string(); + const auto base_name = relative.substr(0, relative.size() - 4); + + load_script(base_name); + } + } + + int db_is_x_asset_default(game::XAssetType type, const char* name) + { + if (loaded_scripts.contains(name)) + { + return 0; + } + + return game::DB_IsXAssetDefault(type, name); + } + + void gscr_post_load_scripts_stub() + { + utils::hook::invoke(0x140323F20); + + if (game::VirtualLobby_Loaded()) + { + return; + } + + clear(); + + fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](const game::XAssetHeader header) + { + const std::string name = header.rawfile->name; + + if (name.ends_with(".gsc") && name.starts_with("scripts/")) + { + // Remove .gsc from the file name as it will be re-added by the game later + const auto base_name = name.substr(0, name.size() - 4); + load_script(base_name); + } + }, true); + + for (const auto& path : filesystem::get_search_paths()) + { + load_scripts(path); + } + } + + void db_get_raw_buffer_stub(const game::RawFile* rawfile, char* buf, const int size) + { + if (rawfile->len > 0 && rawfile->compressedLen == 0) + { + std::memset(buf, 0, size); + std::memcpy(buf, rawfile->buffer, std::min(rawfile->len, size)); + return; + } + + game::DB_GetRawBuffer(rawfile, buf, size); + } + + void g_load_structs_stub() + { + if (!game::VirtualLobby_Loaded()) + { + for (auto& function_handle : main_handles) + { + console::info("Executing '%s::main'\n", function_handle.first.data()); + const auto thread = game::Scr_ExecThread(static_cast(function_handle.second), 0); + game::RemoveRefToObject(thread); + } + } + + utils::hook::invoke(0x1403380D0); + } + + void scr_load_level_stub() + { + utils::hook::invoke(0x140325B90); + + if (game::VirtualLobby_Loaded()) + { + return; + } + + for (auto& function_handle : init_handles) + { + console::info("Executing '%s::init'\n", function_handle.first.data()); + const auto thread = game::Scr_ExecThread(static_cast(function_handle.second), 0); + game::RemoveRefToObject(thread); + } + } + + void scr_begin_load_scripts_stub() + { + const auto comp_mode = developer_script->current.enabled ? + xsk::gsc::build::dev : + xsk::gsc::build::prod; + + gsc_ctx->init(comp_mode, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair> + { + const auto script_name = std::filesystem::path(included_path).replace_extension().string(); + + std::string file_buffer; + if (!read_raw_script_file(included_path, &file_buffer) || file_buffer.empty()) + { + const auto name = get_script_file_name(script_name); + if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, name.data())) + { + return read_compiled_script_file(name, script_name); + } + + throw std::runtime_error(std::format("Could not load gsc file '{}'", script_name)); + } + + std::vector script_data; + script_data.assign(file_buffer.begin(), file_buffer.end()); + + return {{}, script_data}; + }); + + utils::hook::invoke(SELECT_VALUE(0x1403118E0, 0x1403EDE60)); + } + + void scr_end_load_scripts_stub() + { + // Cleanup the compiler + gsc_ctx->cleanup(); + + utils::hook::invoke(SELECT_VALUE(0x140243780, 0x1403EDF90)); + } + } + + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default) + { + std::string real_name = name; + const auto id = static_cast(std::strtol(name, nullptr, 10)); + if (id) + { + real_name = gsc_ctx->token_name(id); + } + + auto* script = load_custom_script(name, real_name); + if (script) + { + return script; + } + + return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile; + } + + class loading final : public component_interface + { + public: + void post_load() override + { + gsc_ctx = std::make_unique(); + } + + void post_unpack() override + { + // Load our scripts with an uncompressed stack + utils::hook::call(SELECT_VALUE(0x14031ABB0, 0x1403F7380), db_get_raw_buffer_stub); + + utils::hook::call(SELECT_VALUE(0x1403309E9, 0x1403309E9), scr_begin_load_scripts_stub); // GScr_LoadScripts + utils::hook::call(SELECT_VALUE(0x14023DA84, 0x140330B9C), scr_end_load_scripts_stub); // GScr_LoadScripts + + developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + + if (game::environment::is_sp()) + { + return; + } + + // ProcessScript + utils::hook::call(0x1403F7317, find_script); + utils::hook::call(0x1403F7327, db_is_x_asset_default); + + // GScr_LoadScripts + utils::hook::call(0x140330B97, gscr_post_load_scripts_stub); + + // Exec script handles + utils::hook::call(0x1402F71AE, g_load_structs_stub); + utils::hook::call(0x1402F71C7, scr_load_level_stub); + + scripting::on_shutdown([](int free_scripts) + { + if (free_scripts) + { + clear(); + } + }); + } + }; +} + +REGISTER_COMPONENT(gsc::loading) diff --git a/src/client/component/gsc/script_loading.hpp b/src/client/component/gsc/script_loading.hpp new file mode 100644 index 0000000..da9c4cd --- /dev/null +++ b/src/client/component/gsc/script_loading.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace gsc +{ + extern std::unique_ptr gsc_ctx; + + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default); +} diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp new file mode 100644 index 0000000..632686c --- /dev/null +++ b/src/client/component/input.cpp @@ -0,0 +1,59 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "game_console.hpp" +#include "server_list.hpp" + +#include + +namespace input +{ + namespace + { + utils::hook::detour cl_char_event_hook; + utils::hook::detour cl_key_event_hook; + + void cl_char_event_stub(const int local_client_num, const int key) + { + if (!game_console::console_char_event(local_client_num, key)) + { + return; + } + + cl_char_event_hook.invoke(local_client_num, key); + } + + void cl_key_event_stub(const int local_client_num, const int key, const signed int down, const int arg4) + { + if (!game_console::console_key_event(local_client_num, key, down)) + { + return; + } + + if (game::environment::is_mp() && !server_list::sl_key_event(key, down)) + { + return; + } + + cl_key_event_hook.invoke(local_client_num, key, down, arg4); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + cl_char_event_hook.create(SELECT_VALUE(0x14013E7B0, 0x140206690), cl_char_event_stub); + cl_key_event_hook.create(SELECT_VALUE(0x14013EB20, 0x140206900), cl_key_event_stub); + } + }; +} + +REGISTER_COMPONENT(input::component) diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp new file mode 100644 index 0000000..98475eb --- /dev/null +++ b/src/client/component/localized_strings.cpp @@ -0,0 +1,52 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include +#include +#include +#include "game/game.hpp" + +namespace localized_strings +{ + namespace + { + utils::hook::detour seh_string_ed_get_string_hook; + + using localized_map = std::unordered_map; + utils::concurrency::container localized_overrides; + + const char* seh_string_ed_get_string(const char* reference) + { + return localized_overrides.access([&](const localized_map& map) + { + const auto entry = map.find(reference); + if (entry != map.end()) + { + return utils::string::va("%s", entry->second.data()); + } + + return seh_string_ed_get_string_hook.invoke(reference); + }); + } + } + + void override(const std::string& key, const std::string& value) + { + localized_overrides.access([&](localized_map& map) + { + map[key] = value; + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Change some localized strings + seh_string_ed_get_string_hook.create(SELECT_VALUE(0x140339CF0, 0x140474FC0), &seh_string_ed_get_string); + } + }; +} + +REGISTER_COMPONENT(localized_strings::component) diff --git a/src/client/component/localized_strings.hpp b/src/client/component/localized_strings.hpp new file mode 100644 index 0000000..47c4389 --- /dev/null +++ b/src/client/component/localized_strings.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace localized_strings +{ + void override(const std::string& key, const std::string& value); +} diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp new file mode 100644 index 0000000..68306e8 --- /dev/null +++ b/src/client/component/logger.cpp @@ -0,0 +1,172 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "party.hpp" +#include "console.hpp" + +#include + +namespace logger +{ + namespace + { + utils::hook::detour com_error_hook; + + game::dvar_t* logger_dev = nullptr; + + void print_error(const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::error("%s", buffer); + } + + void print_com_error(int, const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::error("%s", buffer); + } + + void com_error_stub(const int error, const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::error("Error: %s\n", buffer); + + party::clear_sv_motd(); // clear sv_motd on error if it exists + + com_error_hook.invoke(error, "%s", buffer); + } + + void print_warning(const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::warn("%s", buffer); + } + + void print(const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::info("%s", buffer); + } + + void print_dev(const char* msg, ...) + { + if (!logger_dev->current.enabled) + { + return; + } + + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::info("%s", buffer); + } + + // nullsub_56 + void nullsub_56() + { + utils::hook::call(0x1400D2572, print_warning); + utils::hook::call(0x1400D257E, print_warning); + utils::hook::call(0x1400D2586, print_warning); + utils::hook::call(0x1400D2592, print_warning); + + utils::hook::call(0x1400D2B7D, print_warning); + utils::hook::call(0x1400D2B89, print_warning); + utils::hook::call(0x1400D2B91, print_warning); + utils::hook::call(0x1400D2B9D, print_warning); + + utils::hook::call(0x1400D78ED, print_warning); + utils::hook::call(0x1400D78F9, print_warning); + utils::hook::call(0x1400D7901, print_warning); + utils::hook::call(0x1400D790D, print_warning); + + utils::hook::call(0x1400D84F8, print_warning); + utils::hook::call(0x1400D850C, print_warning); + + utils::hook::call(0x1400D8C08, print_warning); + utils::hook::call(0x1400D8C28, print_warning); + utils::hook::call(0x1400D8C34, print_warning); + + utils::hook::call(0x1400D8CD8, print_warning); + utils::hook::call(0x1400D8CF8, print_warning); + utils::hook::call(0x1400D8D04, print_warning); + utils::hook::call(0x1400D8D1D, print_warning); + + utils::hook::call(0x1400DAE67, print_warning); + utils::hook::call(0x1400DB019, print_warning); + } + + // sub_1400E7420 + void sub_1400E7420() + { + utils::hook::call(0x1400CEC1C, print_warning); + utils::hook::call(0x1400D218E, print_warning); + utils::hook::call(0x1400D2319, print_warning); + utils::hook::call(0x1400D65BC, print_dev); + utils::hook::call(0x1400D7C94, print_dev); + utils::hook::call(0x1400DAB6A, print_dev); + utils::hook::call(0x1400DB9BC, print_dev); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_mp()) + { + nullsub_56(); + sub_1400E7420(); + + // Make havok script's print function actually print + utils::hook::jump(0x140701A1C, print); + } + + if (!game::environment::is_sp()) + { + utils::hook::call(0x1404D8543, print_com_error); + } + + com_error_hook.create(game::Com_Error, com_error_stub); + + logger_dev = game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_SAVED, "Print dev stuff"); + } + }; +} + +REGISTER_COMPONENT(logger::component) diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp new file mode 100644 index 0000000..7aa9a9e --- /dev/null +++ b/src/client/component/lui.cpp @@ -0,0 +1,60 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" + +#include + +namespace lui +{ + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) return; + + // Don't show create cod account popup + utils::hook::set(0x1400EAD12, 0); + +#ifdef _DEBUG + // Enable development menus (causes issues in sp) + utils::hook::set(SELECT_VALUE(0x1400B4ABC, 0x140109FAC), 1); +#endif + + command::add("lui_open", [](const command::params& params) + { + if (params.size() <= 1) + { + console::info("usage: lui_open \n"); + return; + } + + game::LUI_OpenMenu(0, params[1], 0, 0, 0); + }); + + command::add("lui_open_popup", [](const command::params& params) + { + if (params.size() <= 1) + { + console::info("usage: lui_open_popup \n"); + return; + } + + game::LUI_OpenMenu(0, params[1], 1, 0, 0); + }); + + command::add("runMenuScript", [](const command::params& params) + { + const auto args_str = params.join(1); + const auto* args = args_str.data(); + game::UI_RunMenuScript(0, &args); + }); + } + }; +} + +REGISTER_COMPONENT(lui::component) diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp new file mode 100644 index 0000000..832985d --- /dev/null +++ b/src/client/component/map_rotation.cpp @@ -0,0 +1,306 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "scheduler.hpp" +#include "map_rotation.hpp" + +#include +#include + +namespace map_rotation +{ + namespace + { + rotation_data dedicated_rotation; + + const game::dvar_t* sv_map_rotation; + const game::dvar_t* sv_map_rotation_current; + const game::dvar_t* sv_random_map_rotation; + + void set_gametype(const std::string& gametype) + { + assert(!gametype.empty()); + + auto* g_gametype = game::Dvar_FindVar("g_gametype"); + game::Dvar_SetString(g_gametype, gametype.data()); + } + + void launch_map(const std::string& mapname) + { + assert(!mapname.empty()); + + command::execute(utils::string::va("map %s", mapname.data()), false); + } + + void launch_default_map() + { + auto* mapname = game::Dvar_FindVar("mapname"); + if (mapname && std::strcmp(mapname->current.string, "mp_vlobby_room") != 0) + { + launch_map(mapname->current.string); + } + else + { + if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_ZOMBIES) + { + launch_map("mp_zombie_lab"); + } + else + { + launch_map("mp_venus"); + } + } + } + + void apply_rotation(rotation_data& rotation) + { + assert(!rotation.empty()); + + std::size_t i = 0; + while (i < rotation.get_entries_size()) + { + const auto& entry = rotation.get_next_entry(); + if (entry.first == "map"s) + { + console::info("Loading new map: '%s'\n", entry.second.data()); + if (!game::SV_MapExists(entry.second.data())) + { + console::info("map_rotation: '%s' map doesn't exist!\n", entry.second.data()); + launch_default_map(); + return; + } + + launch_map(entry.second); + + // Map was found so we exit the loop + break; + } + + if (entry.first == "gametype"s) + { + console::info("Applying new gametype: '%s'\n", entry.second.data()); + set_gametype(entry.second); + } + + ++i; + } + + if (i == rotation.get_entries_size()) + { + console::error("Map rotation does not contain any map. Restarting\n"); + launch_default_map(); + } + } + + void load_rotation(const std::string& data) + { + static auto loaded = false; + if (loaded) + { + return; + } + + loaded = true; + try + { + dedicated_rotation.parse(data); + } + catch (const std::exception& ex) + { + console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation->name); + } +#ifdef _DEBUG + console::info("dedicated_rotation size after parsing is '%zu'", dedicated_rotation.get_entries_size()); +#endif + } + + void load_map_rotation() + { + const std::string map_rotation = sv_map_rotation->current.string; + if (!map_rotation.empty()) + { +#ifdef _DEBUG + console::info("%s is not empty. Parsing...\n", sv_map_rotation->name); +#endif + load_rotation(map_rotation); + } + } + + void apply_map_rotation_current(const std::string& data) + { + assert(!data.empty()); + + rotation_data rotation_current; + + try + { + rotation_current.parse(data); + } + catch (const std::exception& ex) + { + console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation_current->name); + } + + game::Dvar_SetString(sv_map_rotation_current, ""); + + if (rotation_current.empty()) + { + console::warn("%s is empty or contains invalid data\n", sv_map_rotation_current->name); + launch_default_map(); + return; + } + + apply_rotation(rotation_current); + } + + void randomize_map_rotation() + { + if (sv_random_map_rotation->current.enabled) + { + console::info("Randomizing the map rotation\n"); + dedicated_rotation.randomize(); + } + } + + void perform_map_rotation() + { + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s); + return; + } + + console::info("Rotating map...\n"); + + // This takes priority because of backwards compatibility + const std::string map_rotation_current = sv_map_rotation_current->current.string; + if (!map_rotation_current.empty()) + { +#ifdef _DEBUG + console::info("Applying %s\n", sv_map_rotation_current->name); +#endif + apply_map_rotation_current(map_rotation_current); + return; + } + + load_map_rotation(); + if (dedicated_rotation.empty()) + { + console::warn("%s is empty or contains invalid data. Restarting map\n", sv_map_rotation->name); + launch_default_map(); + return; + } + + randomize_map_rotation(); + + apply_rotation(dedicated_rotation); + } + + void trigger_map_rotation() + { + scheduler::schedule([] + { + if (game::CL_IsCgameInitialized()) + { + return scheduler::cond_continue; + } + + command::execute("map_rotate", false); + return scheduler::cond_end; + }, scheduler::pipeline::main, 1s); + } + + } + + rotation_data::rotation_data() + : index_(0) + { + } + + void rotation_data::randomize() + { + std::random_device rd; + std::mt19937 gen(rd()); + + std::ranges::shuffle(this->rotation_entries_, gen); + } + + void rotation_data::add_entry(const std::string& key, const std::string& value) + { + this->rotation_entries_.emplace_back(std::make_pair(key, value)); + } + + bool rotation_data::contains(const std::string& key, const std::string& value) const + { + return std::ranges::any_of(this->rotation_entries_, [&](const auto& entry) + { + return entry.first == key && entry.second == value; + }); + } + + bool rotation_data::empty() const noexcept + { + return this->rotation_entries_.empty(); + } + + std::size_t rotation_data::get_entries_size() const noexcept + { + return this->rotation_entries_.size(); + } + + rotation_data::rotation_entry& rotation_data::get_next_entry() + { + const auto index = this->index_; + ++this->index_ %= this->rotation_entries_.size(); + return this->rotation_entries_.at(index); + } + + void rotation_data::parse(const std::string& data) + { + const auto tokens = utils::string::split(data, ' '); + for (std::size_t i = 0; !tokens.empty() && i < (tokens.size() - 1); i += 2) + { + const auto& key = tokens[i]; + const auto& value = tokens[i + 1]; + + if (key == "map"s || key == "gametype"s) + { + this->add_entry(key, value); + } + else + { + throw map_rotation_parse_error(); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::once([] + { + sv_map_rotation = game::Dvar_RegisterString("sv_mapRotation", "", game::DVAR_FLAG_NONE, ""); + sv_map_rotation_current = game::Dvar_RegisterString("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, ""); + }, scheduler::pipeline::main); + + sv_random_map_rotation = game::Dvar_RegisterBool("sv_randomMapRotation", false, game::DVAR_FLAG_NONE, "Randomize map rotation"); + + command::add("map_rotate", &perform_map_rotation); + + // Hook GScr_ExitLevel + utils::hook::jump(0x14032E490, &trigger_map_rotation); + } + }; +} + +REGISTER_COMPONENT(map_rotation::component) diff --git a/src/client/component/map_rotation.hpp b/src/client/component/map_rotation.hpp new file mode 100644 index 0000000..c1620c8 --- /dev/null +++ b/src/client/component/map_rotation.hpp @@ -0,0 +1,34 @@ +#pragma once + +namespace map_rotation +{ + struct map_rotation_parse_error : public std::exception + { + [[nodiscard]] const char* what() const noexcept override { return "Map Rotation Parse Erro"; } + }; + + class rotation_data + { + public: + using rotation_entry = std::pair; + + rotation_data(); + + void randomize(); + + // In case a new way to enrich the map rotation is added (other than sv_mapRotation) + // this method should be called to add a new entry (gamemode/map & value) + void add_entry(const std::string& key, const std::string& value); + + [[nodiscard]] bool contains(const std::string& key, const std::string& value) const; + [[nodiscard]] bool empty() const noexcept; + [[nodiscard]] std::size_t get_entries_size() const noexcept; + [[nodiscard]] rotation_entry& get_next_entry(); + + void parse(const std::string& data); + + private: + std::vector rotation_entries_; + std::size_t index_; + }; +} diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp new file mode 100644 index 0000000..e813a1d --- /dev/null +++ b/src/client/component/network.cpp @@ -0,0 +1,287 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "network.hpp" +#include "console.hpp" +#include "dvars.hpp" + +#include +#include + +namespace network +{ + namespace + { + std::unordered_map& get_callbacks() + { + static std::unordered_map callbacks{}; + return callbacks; + } + + bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) + { + const auto cmd_string = utils::string::to_lower(command); + auto& callbacks = get_callbacks(); + const auto handler = callbacks.find(cmd_string); + const auto offset = cmd_string.size() + 5; + if (message->cursize < offset || handler == callbacks.end()) + { + return false; + } + + const std::string data(message->data + offset, message->cursize - offset); + + handler->second(*address, data); + return true; + } + + void handle_command_stub(utils::hook::assembler& a) + { + const auto return_unhandled = a.newLabel(); + + a.pushad64(); + + a.mov(r8, rsi); // message + a.mov(rdx, rdi); // command + a.mov(rcx, r14); // netaddr + + a.call_aligned(handle_command); + + a.test(al, al); + a.jz(return_unhandled); + + // Command handled + a.popad64(); + a.mov(al, 1); + a.jmp(0x14020AA10); + + a.bind(return_unhandled); + a.popad64(); + a.jmp(0x14020A19A); + } + + int net_compare_base_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + if (a1->type == a2->type) + { + switch (a1->type) + { + case game::netadrtype_t::NA_BOT: + case game::netadrtype_t::NA_LOOPBACK: + return a1->port == a2->port; + + case game::netadrtype_t::NA_IP: + return !memcmp(a1->ip, a2->ip, 4); + case game::netadrtype_t::NA_BROADCAST: + return true; + default: + break; + } + } + + return false; + } + + int net_compare_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + return net_compare_base_address(a1, a2) && a1->port == a2->port; + } + + void reconnect_migratated_client(void*, game::netadr_s* from, const int, const int, const char*, + const char*, bool) + { + // This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid + // We don't want this to do anything. It decides to crash seemingly randomly + // Rather than try and let the player in, just tell them they are a duplicate player and reject connection + game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server."); + } + } + + void on(const std::string& command, const callback& callback) + { + get_callbacks()[utils::string::to_lower(command)] = callback; + } + + int dw_send_to_stub(const int size, const char* src, game::netadr_s* a3) + { + sockaddr s = {}; + game::NetadrToSockadr(a3, &s); + return sendto(*game::query_socket, src, size, 0, &s, 16) >= 0; + } + + void send(const game::netadr_s& address, const std::string& command, const std::string& data, const char separator) + { + std::string packet = "\xFF\xFF\xFF\xFF"; + packet.append(command); + packet.push_back(separator); + packet.append(data); + + send_data(address, packet); + } + + void send_data(const game::netadr_s& address, const std::string& data) + { + auto size = static_cast(data.size()); + if (address.type == game::NA_LOOPBACK) + { + // TODO: Fix this for loopback + if (size > 1280) + { + console::error("Packet was too long. Truncated!\n"); + size = 1280; + } + + game::NET_SendLoopPacket(game::NS_CLIENT1, size, data.data(), &address); + } + else + { + game::Sys_SendPacket(size, data.data(), &address); + } + } + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b) + { + return net_compare_address(&a, &b); + } + + const char* net_adr_to_string(const game::netadr_s& a) + { + if (a.type == game::netadrtype_t::NA_LOOPBACK) + { + return "loopback"; + } + + if (a.type == game::netadrtype_t::NA_BOT) + { + return "bot"; + } + + if (a.type == game::netadrtype_t::NA_IP || a.type == game::netadrtype_t::NA_BROADCAST) + { + if (a.port) + { + return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port)); + } + + return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + } + + return "bad"; + } + + game::dvar_t* register_netport_stub(const char* dvarName, int value, int min, int max, unsigned int flags, + const char* description) + { + auto dvar = game::Dvar_RegisterInt("net_port", 27016, 0, 0xFFFFu, game::DVAR_FLAG_LATCHED, "Network port"); + + // read net_port from command line + command::read_startup_variable("net_port"); + + return dvar; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + { + if (game::environment::is_sp()) + { + return; + } + + // redirect dw_sendto to raw socket + //utils::hook::jump(0x1404D850A, reinterpret_cast(0x1404D849A)); + utils::hook::call(0x1404D851F, dw_send_to_stub); + utils::hook::jump(game::Sys_SendPacket, dw_send_to_stub); + + // intercept command handling + utils::hook::jump(0x14020A175, utils::hook::assemble(handle_command_stub), true); + + // handle xuid without secure connection + utils::hook::nop(0x14043FFF8, 6); + + utils::hook::jump(0x1403DA700, net_compare_address); + utils::hook::jump(0x1403DA750, net_compare_base_address); + + // don't establish secure conenction + utils::hook::set(0x140232BBD, 0xEB); + utils::hook::set(0x140232C9A, 0xEB); + utils::hook::set(0x140232F8D, 0xEB); + utils::hook::set(0x14020862F, 0xEB); + + // ignore unregistered connection + utils::hook::jump(0x140439EA9, reinterpret_cast(0x140439E28)); + utils::hook::set(0x140439E9E, 0xEB); + + // disable xuid verification + utils::hook::set(0x140022319, 0xEB); + utils::hook::set(0x140022334, 0xEB); + + // disable xuid verification + utils::hook::nop(0x14043CC4C, 2); + utils::hook::set(0x14043CCA8, 0xEB); + + // ignore configstring mismatch + utils::hook::set(0x140211610, 0xEB); + + // ignore dw handle in SV_PacketEvent + utils::hook::set(0x140442F6D, 0xEB); + utils::hook::call(0x140442F61, &net_compare_address); + + // ignore dw handle in SV_FindClientByAddress + utils::hook::set(0x14044256D, 0xEB); + utils::hook::call(0x140442561, &net_compare_address); + + // ignore dw handle in SV_DirectConnect + utils::hook::set(0x140439BA8, 0xEB); + utils::hook::set(0x140439DA5, 0xEB); + utils::hook::call(0x140439B9B, &net_compare_address); + utils::hook::call(0x140439D98, &net_compare_address); + + // increase cl_maxpackets + dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED); + + // increase snaps + dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE); + + // ignore impure client + utils::hook::jump(0x14043AC0D, reinterpret_cast(0x14043ACA3)); + + // don't send checksum + utils::hook::set(0x1404D84C0, 0); + utils::hook::set(0x1404D8519, 0); + + // don't read checksum + utils::hook::jump(0x1404D842B, 0x1404D8453); + + // don't try to reconnect client + utils::hook::call(0x140439D4D, reconnect_migratated_client); + utils::hook::nop(0x140439D28, 4); // this crashes when reconnecting for some reason + + // allow server owner to modify net_port before the socket bind + utils::hook::call(0x1404D7A3D, register_netport_stub); + utils::hook::call(0x1404D7E28, register_netport_stub); + + // increase allowed packet size + const auto max_packet_size = 0x20000; + utils::hook::set(0x1403DADE6, max_packet_size); + utils::hook::set(0x1403DAE20, max_packet_size); + utils::hook::set(0x1403DAD14, max_packet_size); + utils::hook::set(0x1403DAD35, max_packet_size); + + // ignore built in "print" oob command and add in our own + utils::hook::set(0x14020A723, 0xEB); + on("print", [](const game::netadr_s&, const std::string& data) + { + console::info("%s", data.data()); + }); + } + } + }; +} + +REGISTER_COMPONENT(network::component) diff --git a/src/client/component/network.hpp b/src/client/component/network.hpp new file mode 100644 index 0000000..4e6ae49 --- /dev/null +++ b/src/client/component/network.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace network +{ + using callback = std::function; + + void on(const std::string& command, const callback& callback); + void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' '); + void send_data(const game::netadr_s& address, const std::string& data); + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b); + + const char* net_adr_to_string(const game::netadr_s& a); +} + +inline bool operator==(const game::netadr_s& a, const game::netadr_s& b) +{ + return network::are_addresses_equal(a, b); // +} + +inline bool operator!=(const game::netadr_s& a, const game::netadr_s& b) +{ + return !(a == b); // +} + +namespace std +{ + template <> + struct equal_to + { + using result_type = bool; + + bool operator()(const game::netadr_s& lhs, const game::netadr_s& rhs) const + { + return network::are_addresses_equal(lhs, rhs); + } + }; + + template <> + struct hash + { + size_t operator()(const game::netadr_s& x) const noexcept + { + return hash()(*reinterpret_cast(&x.ip[0])) ^ hash()(x.port); + } + }; +} diff --git a/src/client/component/notifies.cpp b/src/client/component/notifies.cpp new file mode 100644 index 0000000..6a449d9 --- /dev/null +++ b/src/client/component/notifies.cpp @@ -0,0 +1,208 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "scheduler.hpp" +#include "notifies.hpp" +#include "scripting.hpp" +#include "game_log.hpp" + +#include + +namespace notifies +{ + bool hook_enabled = true; + + namespace + { + struct gsc_hook + { + const char* target_pos{}; + }; + + std::unordered_map vm_execute_hooks; + utils::hook::detour scr_player_killed_hook; + utils::hook::detour scr_player_damage_hook; + + char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END + const char* target_function = nullptr; + + + + void client_command_stub(const int client_num) + { + if (game::mp::g_entities[client_num].client == nullptr) + { + return; + } + + command::params_sv params; + + if (params[0] == "say"s || params[0] == "say_team"s) + { + std::string message(params.join(1)); + + auto msg_index = 0; + if (message[msg_index] == '\x1F') + { + msg_index = 1; + } + + auto hidden = false; + if (message[msg_index] == '/') + { + hidden = true; + + if (msg_index == 1) + { + // Overwrite / with \x1F only if present + message[msg_index] = message[msg_index - 1]; + } + // Skip over the first character + message.erase(message.begin()); + } + + scheduler::once([params, message, msg_index, client_num] + { + const auto* guid = game::SV_GetGuid(client_num); + const auto* name = game::mp::svs_clients[client_num].name; + + game_log::g_log_printf("%s;%s;%i;%s;%s\n", + params[0], + guid, + client_num, + name, + message.data() + ); + + }, scheduler::pipeline::server); + + if (hidden) + { + return; + } + } + + // ClientCommand + utils::hook::invoke(0x1402E98F0, client_num); + } + + unsigned int local_id_to_entity(unsigned int local_id) + { + const auto variable = game::scr_VarGlob->objectVariableValue[local_id]; + return variable.u.f.next; + } + + bool execute_vm_hook(const char* pos) + { + if (!vm_execute_hooks.contains(pos)) + { + hook_enabled = true; + return false; + } + + if (!hook_enabled && pos > reinterpret_cast(vm_execute_hooks.size())) + { + hook_enabled = true; + return false; + } + + const auto hook = vm_execute_hooks[pos]; + target_function = hook.target_pos; + + return true; + } + + void vm_execute_stub(utils::hook::assembler& a) + { + const auto replace = a.newLabel(); + const auto end = a.newLabel(); + + a.pushad64(); + + a.mov(rcx, r14); + a.call_aligned(execute_vm_hook); + + a.cmp(al, 0); + a.jne(replace); + + a.popad64(); + a.jmp(end); + + a.bind(end); + + a.movzx(r15d, byte_ptr(r14)); + a.inc(r14); + a.lea(eax, dword_ptr(r15, -0x17)); + a.mov(dword_ptr(rbp, 0x68), r15d); + + a.jmp(0x1403FA143); + + a.bind(replace); + + a.popad64(); + a.mov(rax, qword_ptr(reinterpret_cast(&target_function))); + a.mov(r14, rax); + a.jmp(end); + } + } + + void clear_callbacks() + { + vm_execute_hooks.clear(); + } + + void enable_vm_execute_hook() + { + hook_enabled = true; + } + + void disable_vm_execute_hook() + { + hook_enabled = false; + } + + void set_gsc_hook(const char* source, const char* target) + { + gsc_hook hook; + hook.target_pos = target; + vm_execute_hooks[source] = hook; + } + + void clear_hook(const char* pos) + { + vm_execute_hooks.erase(pos); + } + + std::size_t get_hook_count() + { + return vm_execute_hooks.size(); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + utils::hook::call(0x14043A9AD, client_command_stub); + + utils::hook::jump(0x1403FA134, utils::hook::assemble(vm_execute_stub), true); + + scripting::on_shutdown([](bool free_scripts) + { + if (free_scripts) + { + vm_execute_hooks.clear(); + } + }); + } + }; +} + +REGISTER_COMPONENT(notifies::component) diff --git a/src/client/component/notifies.hpp b/src/client/component/notifies.hpp new file mode 100644 index 0000000..0016693 --- /dev/null +++ b/src/client/component/notifies.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace notifies +{ + extern bool hook_enabled; + + void set_gsc_hook(const char* source, const char* target); + void clear_hook(const char* pos); + std::size_t get_hook_count(); + + void clear_callbacks(); + + void enable_vm_execute_hook(); + void disable_vm_execute_hook(); +} diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp new file mode 100644 index 0000000..5e06767 --- /dev/null +++ b/src/client/component/party.cpp @@ -0,0 +1,638 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "party.hpp" +#include "console.hpp" +#include "command.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" + +#include "steam/steam.hpp" + +#include +#include +#include +#include + +#include + +namespace party +{ + namespace + { + struct + { + game::netadr_s host{}; + std::string challenge{}; + bool hostDefined{false}; + } connect_state; + + std::string sv_motd; + + int sv_maxclients; + + void perform_game_initialization() + { + command::execute("onlinegame 1", true); + command::execute("xstartprivateparty", true); + command::execute("xblive_privatematch 1", true); + command::execute("startentitlements", true); + } + + void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype) + { + if (game::environment::is_sp()) + { + return; + } + + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + // initialize the game after onlinedataflags is 32 (workaround) + if (game::Live_SyncOnlineDataFlags(0) == 32) + { + scheduler::once([=]() + { + command::execute("xstartprivateparty", true); + command::execute("disconnect", true); // 32 -> 0 + + connect_to_party(target, mapname, gametype); + }, scheduler::pipeline::main, 1s); + return; + } + else + { + scheduler::once([=]() + { + connect_to_party(target, mapname, gametype); + }, scheduler::pipeline::main, 1s); + return; + } + } + + perform_game_initialization(); + + // exit from virtuallobby + reinterpret_cast(0x14020EB90)(); + + // CL_ConnectFromParty + char session_info[0x100] = {}; + reinterpret_cast(0x140209360)( + 0, session_info, &target, mapname.data(), gametype.data()); + } + + std::string get_dvar_string(const std::string& dvar) + { + const auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value && dvar_value->current.string) + { + return {dvar_value->current.string}; + } + + return {}; + } + + bool get_dvar_bool(const std::string& dvar) + { + const auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value && dvar_value->current.enabled) + { + return dvar_value->current.enabled; + } + + return false; + } + + void didyouknow_stub(const char* dvar_name, const char* string) + { + if (!party::sv_motd.empty()) + { + string = party::sv_motd.data(); + } + + // This function either does Dvar_SetString or Dvar_RegisterString for the given dvar + reinterpret_cast(0x1404C39B0)(dvar_name, string); + } + + void disconnect_stub() + { + if (!game::VirtualLobby_Loaded()) + { + if (game::CL_IsCgameInitialized()) + { + game::CL_ForwardCommandToServer(0, "disconnect"); + game::CL_WritePacket(0); + } + + game::CL_Disconnect(0); + } + } + + utils::hook::detour cl_disconnect_hook; + + void cl_disconnect_stub(int a1) + { + clear_sv_motd(); + cl_disconnect_hook.invoke(a1); + } + + const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.mov(rdx, rdi); + a.mov(ecx, 2); + a.jmp(0x140209DD9); + }); + } + + void clear_sv_motd() + { + sv_motd.clear(); + } + + int get_client_num_by_name(const std::string& name) + { + for (auto i = 0; !name.empty() && i < *game::mp::svs_numclients; ++i) + { + if (game::mp::g_entities[i].client) + { + char client_name[16] = {0}; + strncpy_s(client_name, game::mp::g_entities[i].client->name, sizeof(client_name)); + game::I_CleanStr(client_name); + + if (client_name == name) + { + return i; + } + } + } + return -1; + } + + void reset_connect_state() + { + connect_state = {}; + } + + int get_client_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 1) + { + ++count; + } + } + + return count; + } + + int get_bot_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 1 && + game::SV_BotIsBot(i)) + { + ++count; + } + } + + return count; + } + + game::netadr_s& get_target() + { + return connect_state.host; + } + + void connect(const game::netadr_s& target) + { + if (game::environment::is_sp()) + { + return; + } + + command::execute("lui_open_popup popup_acceptinginvite", false); + + connect_state.host = target; + connect_state.challenge = utils::cryptography::random::get_challenge(); + connect_state.hostDefined = true; + + network::send(target, "getInfo", connect_state.challenge); + } + + void start_map(const std::string& mapname) + { + if (game::Live_SyncOnlineDataFlags(0) > 32) + { + scheduler::once([=]() + { + command::execute("map " + mapname, false); + }, scheduler::pipeline::main, 1s); + } + else + { + if (!game::SV_MapExists(mapname.data())) + { + console::info("Map '%s' doesn't exist.\n", mapname.data()); + return; + } + + auto* current_mapname = game::Dvar_FindVar("mapname"); + if (current_mapname && utils::string::to_lower(current_mapname->current.string) == + utils::string::to_lower(mapname) && (game::SV_Loaded() && !game::VirtualLobby_Loaded())) + { + console::info("Restarting map: %s\n", mapname.data()); + command::execute("map_restart", false); + return; + } + + if (!game::environment::is_dedi()) + { + if (game::SV_Loaded()) + { + const auto* args = "Leave"; + game::UI_RunMenuScript(0, &args); + } + + perform_game_initialization(); + } + + console::info("Starting map: %s\n", mapname.data()); + + auto* gametype = game::Dvar_FindVar("g_gametype"); + if (gametype && gametype->current.string) + { + command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true); + } + command::execute(utils::string::va("ui_mapname %s", mapname.data()), true); + + /*auto* maxclients = game::Dvar_FindVar("sv_maxclients"); + if (maxclients) + { + command::execute(utils::string::va("ui_maxclients %i", maxclients->current.integer), true); + command::execute(utils::string::va("party_maxplayers %i", maxclients->current.integer), true); + }*/ + + const auto* args = "StartServer"; + game::UI_RunMenuScript(0, &args); + } + } + + int server_client_count() + { + return sv_maxclients; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + // hook disconnect command function + utils::hook::jump(0x14020A010, disconnect_stub); + + // detour CL_Disconnect to clear motd + cl_disconnect_hook.create(0x140209EC0, cl_disconnect_stub); + + if (game::environment::is_mp()) + { + // show custom drop reason + utils::hook::nop(0x140209D5C, 13); + utils::hook::jump(0x140209D5C, drop_reason_stub, true); + } + // enable custom kick reason in GScr_KickPlayer + utils::hook::set(0x14032ED80, 0xEB); + + command::add("map", [](const command::params& argument) + { + if (argument.size() != 2) + { + return; + } + + start_map(argument[1]); + }); + + command::add("map_restart", []() + { + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) + { + return; + } + *reinterpret_cast(0x1488692B0) = 1; // sv_map_restart + *reinterpret_cast(0x1488692B4) = 1; // sv_loadScripts + *reinterpret_cast(0x1488692B8) = 0; // sv_migrate + reinterpret_cast(0x140437460)(0); // SV_CheckLoadGame + }); + + command::add("fast_restart", []() + { + if (game::SV_Loaded() && !game::VirtualLobby_Loaded()) + { + game::SV_FastRestart(0); + } + }); + + command::add("reconnect", [](const command::params& argument) + { + if (!connect_state.hostDefined) + { + console::info("Cannot connect to server.\n"); + return; + } + + if (game::CL_IsCgameInitialized()) + { + command::execute("disconnect"); + command::execute("reconnect"); + } + else + { + connect(connect_state.host); + } + }); + + command::add("connect", [](const command::params& argument) + { + if (argument.size() != 2) + { + return; + } + + game::netadr_s target{}; + if (game::NET_StringToAdr(argument[1], &target)) + { + connect(target); + } + }); + + command::add("kickClient", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: kickClient , (optional)\n"); + return; + } + + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) + { + return; + } + + std::string reason; + if (params.size() > 2) + { + reason = params.join(2); + } + if (reason.empty()) + { + reason = "EXE_PLAYERKICKED"; + } + + const auto client_num = atoi(params.get(1)); + if (client_num < 0 || client_num >= *game::mp::svs_numclients) + { + return; + } + + scheduler::once([client_num, reason]() + { + game::SV_KickClientNum(client_num, reason.data()); + }, scheduler::pipeline::server); + }); + + command::add("kick", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: kick , (optional)\n"); + return; + } + + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) + { + return; + } + + std::string reason; + if (params.size() > 2) + { + reason = params.join(2); + } + if (reason.empty()) + { + reason = "EXE_PLAYERKICKED"; + } + + const std::string name = params.get(1); + if (name == "all"s) + { + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + scheduler::once([i, reason] + { + game::SV_KickClientNum(i, reason.data()); + }, scheduler::pipeline::server); + } + return; + } + + const auto client_num = get_client_num_by_name(name); + if (client_num < 0 || client_num >= *game::mp::svs_numclients) + { + return; + } + + scheduler::once([client_num, reason]() + { + game::SV_KickClientNum(client_num, reason.data()); + }, scheduler::pipeline::server); + }); + + scheduler::once([]() + { + game::Dvar_RegisterString("sv_sayName", "console", game::DvarFlags::DVAR_FLAG_NONE, + "The name to pose as for 'say' commands"); + }, scheduler::pipeline::main); + + command::add("tell", [](const command::params& params) + { + if (params.size() < 3) + { + return; + } + + const auto client_num = atoi(params.get(1)); + const auto message = params.join(2); + const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; + + game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + printf("%s -> %i: %s\n", name, client_num, message.data()); + }); + + command::add("tellraw", [](const command::params& params) + { + if (params.size() < 3) + { + return; + } + + const auto client_num = atoi(params.get(1)); + const auto message = params.join(2); + + game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s\"", 84, message.data())); + printf("%i: %s\n", client_num, message.data()); + }); + + command::add("say", [](const command::params& params) + { + if (params.size() < 2) + { + return; + } + + const auto message = params.join(1); + const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; + + game::SV_GameSendServerCommand( + -1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + printf("%s: %s\n", name, message.data()); + }); + + command::add("sayraw", [](const command::params& params) + { + if (params.size() < 2) + { + return; + } + + const auto message = params.join(1); + + game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s\"", 84, message.data())); + printf("%s\n", message.data()); + }); + + utils::hook::call(0x14048811C, didyouknow_stub); // allow custom didyouknow based on sv_motd + + network::on("getInfo", [](const game::netadr_s& target, const std::string& data) + { + utils::info_string info{}; + info.set("challenge", data); + info.set("gamename", "S1"); + info.set("hostname", get_dvar_string("sv_hostname")); + info.set("gametype", get_dvar_string("g_gametype")); + info.set("sv_motd", get_dvar_string("sv_motd")); + info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); + info.set("mapname", get_dvar_string("mapname")); + info.set("isPrivate", get_dvar_string("g_password").empty() ? "0" : "1"); + info.set("clients", std::to_string(get_client_count())); + info.set("bots", std::to_string(get_bot_count())); + info.set("sv_maxclients", std::to_string(*game::mp::svs_numclients)); + info.set("protocol", std::to_string(PROTOCOL)); + info.set("playmode", utils::string::va("%i", game::Com_GetCurrentCoDPlayMode())); + info.set("sv_running", std::to_string(get_dvar_bool("sv_running"))); + info.set("dedicated", std::to_string(get_dvar_bool("dedicated"))); + info.set("shortversion", SHORTVERSION); + + network::send(target, "infoResponse", info.build(), '\n'); + }); + + if (game::environment::is_dedi()) + { + return; + } + + network::on("infoResponse", [](const game::netadr_s& target, const std::string& data) + { + const utils::info_string info(data); + server_list::handle_info_response(target, info); + + if (connect_state.host != target) + { + return; + } + + if (info.get("challenge") != connect_state.challenge) + { + const auto* error_msg = "Invalid challenge."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + const auto gamename = info.get("gamename"); + if (gamename != "S1"s) + { + const auto* error_msg = "Invalid gamename."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + const auto playmode = info.get("playmode"); + if (std::atoi(playmode.data()) != game::Com_GetCurrentCoDPlayMode()) + { + const auto* error_msg = "Invalid playmode."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + const auto sv_running = info.get("sv_running"); + if (sv_running != "1"s) + { + const auto* error_msg = "Server not running."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + const auto mapname = info.get("mapname"); + if (mapname.empty()) + { + const auto* error_msg = "Invalid map."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + const auto gametype = info.get("gametype"); + if (gametype.empty()) + { + const auto* error_msg = "Invalid gametype."; + console::error("%s\n", error_msg); + game::Com_Error(game::ERR_DROP, "%s", error_msg); + return; + } + + sv_motd = info.get("sv_motd"); + + try + { + sv_maxclients = std::stoi(info.get("sv_maxclients")); + } + catch([[maybe_unused]] const std::exception& ex) + { + sv_maxclients = 1; + } + + connect_to_party(target, mapname, gametype); + }); + } + }; +} + +REGISTER_COMPONENT(party::component) diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp new file mode 100644 index 0000000..4c45014 --- /dev/null +++ b/src/client/component/party.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace party +{ + void reset_connect_state(); + + void connect(const game::netadr_s& target); + void start_map(const std::string& mapname); + + void clear_sv_motd(); + int server_client_count(); + + [[nodiscard]] int get_client_num_by_name(const std::string& name); + + [[nodiscard]] int get_client_count(); + [[nodiscard]] int get_bot_count(); + + [[nodiscard]] game::netadr_s& get_target(); +} diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp new file mode 100644 index 0000000..6408da2 --- /dev/null +++ b/src/client/component/patches.cpp @@ -0,0 +1,322 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "dvars.hpp" +#include "fastfiles.hpp" +#include "filesystem.hpp" +#include "scheduler.hpp" + +#include +#include + +#include + +namespace patches +{ + namespace + { + utils::hook::detour live_get_local_client_name_hook; + + const char* live_get_local_client_name() + { + return game::Dvar_FindVar("name")->current.string; + } + + utils::hook::detour sv_kick_client_num_hook; + + void sv_kick_client_num(const int client_num, const char* reason) + { + // Don't kick bot to equalize team balance. + if (reason == "EXE_PLAYERKICKED_BOT_BALANCE"s) + { + return; + } + return sv_kick_client_num_hook.invoke(client_num, reason); + } + + std::string get_login_username() + { + char username[UNLEN + 1]; + DWORD username_len = UNLEN + 1; + if (!GetUserNameA(username, &username_len)) + { + return "Unknown Soldier"; + } + + return std::string{username, username_len - 1}; + } + + utils::hook::detour com_register_dvars_hook; + + void com_register_dvars_stub() + { + if (game::environment::is_mp()) + { + // Make name save + game::Dvar_RegisterString("name", get_login_username().data(), game::DVAR_FLAG_SAVED, "Player name."); + + // Disable data validation error popup + game::Dvar_RegisterInt("data_validation_allow_drop", 0, 0, 0, game::DVAR_FLAG_NONE, ""); + } + + return com_register_dvars_hook.invoke(); + } + + game::dvar_t* register_com_maxfps_stub(const char* name, int /*value*/, int /*min*/, int /*max*/, const unsigned int /*flags*/, const char* description) + { + return game::Dvar_RegisterInt(name, 0, 0, 1000, game::DVAR_FLAG_SAVED, description); + } + + game::dvar_t* register_cg_fov_stub(const char* name, float value, float min, float /*max*/, const unsigned int /*flags*/, const char* description) + { + return game::Dvar_RegisterFloat(name, value, min, 160, game::DVAR_FLAG_SAVED, description); + } + + game::dvar_t* register_fovscale_stub(const char* name, float /*value*/, float /*min*/, float /*max*/, unsigned int /*flags*/, const char* desc) + { + return game::Dvar_RegisterFloat(name, 1.0f, 0.2f, 5.0f, game::DVAR_FLAG_SAVED, desc); + } + + int dvar_command_patch() // game makes this return an int and compares with eax instead of al -_- + { + const command::params args{}; + + if (args.size() <= 0) + return 0; + + auto* dvar = game::Dvar_FindVar(args.get(0)); + if (dvar) + { + if (args.size() == 1) + { + const auto* const current = game::Dvar_ValueToString(dvar, dvar->current); + const auto* const reset = game::Dvar_ValueToString(dvar, dvar->reset); + console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current, reset); + console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data()); + } + else + { + char command[0x1000] = {0}; + game::Dvar_GetCombinedString(command, 1); + game::Dvar_SetCommand(args.get(0), command); + } + + return 1; + } + + return 0; + } + + char* db_read_raw_file_stub(const char* filename, char* buf, const int size) + { + std::string file_name = filename; + if (file_name.find(".cfg") == std::string::npos) + { + file_name.append(".cfg"); + } + + const auto file = filesystem::file(file_name); + if (file.exists()) + { + snprintf(buf, size, "%s\n", file.get_buffer().data()); + return buf; + } + + return game::DB_ReadRawFile(filename, buf, size); + } + + void aim_assist_add_to_target_list(void* a1, void* a2) + { + if (!dvars::aimassist_enabled->current.enabled) + return; + + game::AimAssist_AddToTargetList(a1, a2); + } + + void missing_content_error_stub(int /*mode*/, const char* /*message*/) + { + game::Com_Error(game::ERR_DROP, utils::string::va("MISSING FILE\n%s.ff", fastfiles::get_current_fastfile().data())); + } + + void bsp_sys_error_stub(const char* error, const char* arg1) + { + if (game::environment::is_dedi()) + { + game::Sys_Error(error, arg1); + } + else + { + scheduler::once([]() + { + command::execute("reconnect"); + }, scheduler::pipeline::main, 1s); + game::Com_Error(game::ERR_DROP, error, arg1); + } + } + + void set_client_dvar_from_server_stub(void* a1, void* a2, const char* dvar, const char* value) + { + if (utils::string::to_lower(dvar) == "cg_fov") + { + return; + } + + // CG_SetClientDvarFromServer + reinterpret_cast(0x1401BF0A0)(a1, a2, dvar, value); + } + + utils::hook::detour cmd_lui_notify_server_hook; + void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) + { + command::params_sv params{}; + const auto menu_id = atoi(params.get(1)); + const auto client = &game::mp::svs_clients[ent->s.number]; + + // 22 => "end_game" + if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) + { + return; + } + + cmd_lui_notify_server_hook.invoke(ent); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Increment ref-count on these + LoadLibraryA("PhysXDevice64.dll"); + LoadLibraryA("PhysXUpdateLoader64.dll"); + + // Register dvars + com_register_dvars_hook.create(SELECT_VALUE(0x1402F86F0, 0x1403CF7F0), &com_register_dvars_stub); + + // Unlock fps in main menu + utils::hook::set(SELECT_VALUE(0x140144F5B, 0x140213C3B), 0xEB); + + // Unlock com_maxfps + utils::hook::call(SELECT_VALUE(0x1402F8726, 0x1403CF8CA), register_com_maxfps_stub); + + // Unlock cg_fov + utils::hook::call(SELECT_VALUE(0x1400EF830, 0x140014F66), register_cg_fov_stub); + + // Unlock cg_fovscale + utils::hook::call(SELECT_VALUE(0x140227599, 0x140014F9B), register_fovscale_stub); + + // Patch Dvar_Command to print out values how CoD4 does it + utils::hook::jump(SELECT_VALUE(0x1402FB4C0, 0x1403D31C0), dvar_command_patch); + + // Show missing fastfiles + utils::hook::call(SELECT_VALUE(0x1401817AF, 0x1402742A8), missing_content_error_stub); + + // Allow executing custom cfg files with the "exec" command + utils::hook::call(SELECT_VALUE(0x1402EE225, 0x1403AF7CD), db_read_raw_file_stub); + + // Fix mouse lag + utils::hook::nop(SELECT_VALUE(0x14038FAFF, 0x1404DB1AF), 6); + scheduler::loop([]() + { + SetThreadExecutionState(ES_DISPLAY_REQUIRED); + }, scheduler::pipeline::main); + + // Allow kbam input when gamepad is enabled + utils::hook::nop(SELECT_VALUE(0x14013EF83, 0x140206DB3), 2); + utils::hook::nop(SELECT_VALUE(0x14013CBAC, 0x140204710), 6); + + if (game::environment::is_sp()) + { + patch_sp(); + } + else + { + patch_mp(); + } + } + + static void patch_mp() + { + // Use name dvar + live_get_local_client_name_hook.create(0x1404D47F0, &live_get_local_client_name); + + // Patch SV_KickClientNum + sv_kick_client_num_hook.create(0x1404377A0, &sv_kick_client_num); + + // block changing name in-game + utils::hook::set(0x140438850, 0xC3); + + // patch "Couldn't find the bsp for this map." error to not be fatal in mp + utils::hook::call(0x14026E63B, bsp_sys_error_stub); + + // client side aim assist dvar + dvars::aimassist_enabled = game::Dvar_RegisterBool("aimassist_enabled", true, game::DVAR_FLAG_SAVED, "Enables aim assist for controllers"); + utils::hook::call(0x140003609, aim_assist_add_to_target_list); + + // isProfanity + utils::hook::set(0x14023BDC0, 0xC3C033); + + // disable emblems + dvars::override::register_int("emblems_active", 0, 0, 0, game::DVAR_FLAG_NONE); + utils::hook::set(0x140479590, 0xC3); // don't register commands + + // disable elite_clan + dvars::override::register_int("elite_clan_active", 0, 0, 0, game::DVAR_FLAG_NONE); + utils::hook::set(0x14054AB20, 0xC3); // don't register commands + + // disable codPointStore + dvars::override::register_int("codPointStore_enabled", 0, 0, 0, game::DVAR_FLAG_NONE); + + // don't register every replicated dvar as a network dvar + utils::hook::nop(0x1403534BE, 5); // dvar_foreach + + // Patch "Server is on a different version" + utils::hook::inject(0x1404398B2, VERSION); + + // prevent servers overriding our fov + utils::hook::call(0x1401BB782, set_client_dvar_from_server_stub); + utils::hook::nop(0x1403D1195, 5); + utils::hook::nop(0x1400FAE36, 5); + utils::hook::set(0x14019B9B9, 0xEB); + + // some anti tamper thing that kills performance + dvars::override::register_int("dvl", 0, 0, 0, game::DVAR_FLAG_READ); + + // unlock safeArea_* + utils::hook::jump(0x140219F5E, 0x140219F67); + utils::hook::jump(0x140219F80, 0x140219F8E); + dvars::override::register_float("safeArea_adjusted_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_float("safeArea_adjusted_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_float("safeArea_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_float("safeArea_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); + + // move chat position on the screen above menu splashes + dvars::override::register_vector2("cg_hudChatPosition", 5, 170, 0, 640, game::DVAR_FLAG_SAVED); + + // allow servers to check for new packages more often + dvars::override::register_int("sv_network_fps", 1000, 20, 1000, game::DVAR_FLAG_SAVED); + + // Massively increate timeouts + dvars::override::register_int("cl_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // Seems unused + dvars::override::register_int("sv_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // 30 - 0 - 1800 + dvars::override::register_int("cl_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // Seems unused + dvars::override::register_int("sv_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // 60 - 0 - 1800 + + game::Dvar_RegisterInt("scr_game_spectatetype", 1, 0, 99, game::DVAR_FLAG_REPLICATED, ""); + + // Prevent clients from ending the game as non host by sending 'end_game' lui notification + cmd_lui_notify_server_hook.create(0x1402E9390, cmd_lui_notify_server_stub); + } + + static void patch_sp() + { + } + }; +} + +REGISTER_COMPONENT(patches::component) diff --git a/src/client/component/ranked.cpp b/src/client/component/ranked.cpp new file mode 100644 index 0000000..238215b --- /dev/null +++ b/src/client/component/ranked.cpp @@ -0,0 +1,46 @@ +#include +#include "loader/component_loader.hpp" + +#include "dvars.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +namespace ranked +{ + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + if (game::environment::is_mp()) + { + dvars::override::register_bool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED); + } + + if (game::environment::is_dedi() && !utils::flags::has_flag("unranked")) + { + dvars::override::register_bool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED | game::DVAR_FLAG_WRITE); + + // Some dvar used in gsc + game::Dvar_RegisterBool("force_ranking", true, game::DVAR_FLAG_WRITE, "Force ranking"); + } + + // Always run bots, even if xblive_privatematch is 0 + utils::hook::set(0x14013A0C0, 0xC301B0); // BG_BotSystemEnabled + utils::hook::set(0x140139A60, 0xC301B0); // BG_AISystemEnabled + utils::hook::set(0x14013A080, 0xC301B0); // BG_BotFastFileEnabled + utils::hook::set(0x14013A200, 0xC301B0); // BG_BotsUsingTeamDifficulty + } + }; +} + +REGISTER_COMPONENT(ranked::component) diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp new file mode 100644 index 0000000..12ca20d --- /dev/null +++ b/src/client/component/rcon.cpp @@ -0,0 +1,213 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "network.hpp" +#include "scheduler.hpp" + +#include +#include + +namespace rcon +{ + namespace + { + bool is_redirecting_ = false; + game::netadr_s redirect_target_ = {}; + std::recursive_mutex redirect_lock; + + void setup_redirect(const game::netadr_s& target) + { + std::lock_guard $(redirect_lock); + + is_redirecting_ = true; + redirect_target_ = target; + } + + void clear_redirect() + { + std::lock_guard $(redirect_lock); + + is_redirecting_ = false; + redirect_target_ = {}; + } + + void send_rcon_command(const std::string& password, const std::string& data) + { + // If you are the server, don't bother with rcon and just execute the command + if (game::Dvar_FindVar("sv_running")->current.enabled) + { + game::Cbuf_AddText(0, data.data()); + return; + } + + if (password.empty()) + { + console::info("You must login first to use RCON\n"); + return; + } + + if (*reinterpret_cast(0x1417E1690) >= 5) //clientUIActive.connectionState >= CA_CONNECTED + { + const auto target = *reinterpret_cast(0x141C7A8FC); + const auto buffer = password + " " + data; + network::send(target, "rcon", buffer); + } + else + { + console::warn("You need to be connected to a server!\n"); + } + } + + std::string build_status_buffer() + { + const auto sv_maxclients = game::Dvar_FindVar("sv_maxclients"); + const auto mapname = game::Dvar_FindVar("mapname"); + + std::string buffer{}; + buffer.append(utils::string::va("map: %s\n", mapname->current.string)); + buffer.append( + "num score bot ping guid name address qport\n"); + buffer.append( + "--- ----- --- ---- -------------------------------- ---------------- --------------------- -----\n"); + + for (int i = 0; i < sv_maxclients->current.integer; i++) + { + const auto client = &game::mp::svs_clients[i]; + + char clean_name[32] = { 0 }; + strncpy_s(clean_name, client->name, sizeof(clean_name)); + game::I_CleanStr(clean_name); + + if (client->header.state >= 1) + { + buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", + i, + game::G_GetClientScore(i), + game::SV_BotIsBot(i) ? "Yes" : "No", + (client->header.state == 2) + ? "CNCT" + : (client->header.state == 1) + ? "ZMBI" + : utils::string::va("%4i", game::SV_GetClientPing(i)), + game::SV_GetGuid(i), + clean_name, + network::net_adr_to_string(client->header.remoteAddress), + client->header.remoteAddress.port) + ); + } + } + + return buffer; + } + } + + bool message_redirect(const std::string& message) + { + std::lock_guard $(redirect_lock); + + if (is_redirecting_) + { + network::send(redirect_target_, "print", message); + return true; + } + + return false; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + scheduler::once([]() + { + game::Dvar_RegisterString("rcon_password", "", game::DvarFlags::DVAR_FLAG_NONE, + "The password for remote console"); + }, scheduler::pipeline::main); + + command::add("status", []() + { + const auto sv_running = game::Dvar_FindVar("sv_running"); + if (game::VirtualLobby_Loaded() || !sv_running || !sv_running->current.enabled) + { + console::error("Server is not running\n"); + return; + } + + auto status_buffer = build_status_buffer(); + console::info(status_buffer.data()); + }); + + if (!game::environment::is_dedi()) + { + command::add("rcon", [&](const command::params& params) + { + static std::string rcon_password{}; + + if (params.size() < 2) return; + + const auto operation = params.get(1); + if (operation == "login"s) + { + if (params.size() < 3) return; + + rcon_password = params.get(2); + } + else if (operation == "logout"s) + { + rcon_password.clear(); + } + else + { + send_rcon_command(rcon_password, params.join(1)); + } + }); + } + else + { + network::on("rcon", [](const game::netadr_s& addr, const std::string_view& data) + { + const auto message = std::string{data}; + const auto pos = message.find_first_of(" "); + if (pos == std::string::npos) + { + console::info("Invalid RCon request from %s\n", network::net_adr_to_string(addr)); + return; + } + + const auto password = message.substr(0, pos); + const auto command = message.substr(pos + 1); + const auto rcon_password = game::Dvar_FindVar("rcon_password"); + if (command.empty() || !rcon_password || !rcon_password->current.string || !strlen( + rcon_password->current.string)) + { + return; + } + + setup_redirect(addr); + + if (password != rcon_password->current.string) + { + console::error("Invalid rcon password\n"); + } + else + { + command::execute(command, true); + } + + clear_redirect(); + }); + } + } + }; +} + +REGISTER_COMPONENT(rcon::component) diff --git a/src/client/component/rcon.hpp b/src/client/component/rcon.hpp new file mode 100644 index 0000000..2a6c23c --- /dev/null +++ b/src/client/component/rcon.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace rcon +{ + bool message_redirect(const std::string& message); +} diff --git a/src/client/component/redirect.cpp b/src/client/component/redirect.cpp new file mode 100644 index 0000000..2b4abd9 --- /dev/null +++ b/src/client/component/redirect.cpp @@ -0,0 +1,83 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" +#include +#include + +namespace redirect +{ + namespace + { + void launch_complementary_game(const bool singleplayer, const std::string& mode = "") + { + const auto self = game_module::get_host_module(); + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + auto* arguments = const_cast(utils::string::va("%s%s%s", self.get_path().data(), + (singleplayer ? " -singleplayer" : " -multiplayer"), + (mode.empty() ? "" : (" +"s + mode).data()))); + CreateProcessA(self.get_path().data(), arguments, nullptr, nullptr, false, NULL, nullptr, nullptr, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hThread); + } + + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hProcess); + } + } + + HINSTANCE shell_execute_a(const HWND hwnd, const LPCSTR operation, const LPCSTR file, const LPCSTR parameters, + const LPCSTR directory, const INT show_cmd) + { + if (utils::string::starts_with(file, "steam://run/209650/")) + { + launch_complementary_game(true); + return HINSTANCE(33); + } + else if (utils::string::starts_with(file, "steam://run/209660/")) + { + std::string mode(file); + mode.erase(0, 20); + if (!mode.empty()) + { + mode = utils::string::replace(mode, "%2b", ""); // '+' + mode = utils::string::replace(mode, "%2", " "); // ' ' + } + + launch_complementary_game(false, mode); + return HINSTANCE(33); + } + + return ShellExecuteA(hwnd, operation, file, parameters, directory, show_cmd); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "SHELL32.dll") + { + if (function == "ShellExecuteA") + { + return shell_execute_a; + } + } + + return nullptr; + } + }; +} + +REGISTER_COMPONENT(redirect::component) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp new file mode 100644 index 0000000..709095a --- /dev/null +++ b/src/client/component/renderer.cpp @@ -0,0 +1,82 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace renderer +{ + namespace + { + utils::hook::detour r_init_draw_method_hook; + utils::hook::detour r_update_front_end_dvar_options_hook; + + int get_fullbright_technique() + { + switch (dvars::r_fullbright->current.integer) + { + case 3: + return 13; + case 2: + return 25; + default: + return game::TECHNIQUE_UNLIT; + } + } + + void gfxdrawmethod() + { + game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; + game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_LIT; + game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE; + game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : 182; + } + + void r_init_draw_method_stub() + { + gfxdrawmethod(); + } + + bool r_update_front_end_dvar_options_stub() + { + if (dvars::r_fullbright->modified) + { + game::Dvar_ClearModified(dvars::r_fullbright); + game::R_SyncRenderThread(); + + gfxdrawmethod(); + } + + return r_update_front_end_dvar_options_hook.invoke(); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + dvars::r_fullbright = game::Dvar_RegisterInt("r_fullbright", 0, 0, 3, game::DVAR_FLAG_SAVED, "Toggles rendering without lighting"); + + r_init_draw_method_hook.create(SELECT_VALUE(0x14046C150, 0x140588B00), &r_init_draw_method_stub); + r_update_front_end_dvar_options_hook.create(SELECT_VALUE(0x1404A5330, 0x1405C3AE0), &r_update_front_end_dvar_options_stub); + + // use "saved" flags for "r_normalMap" + utils::hook::set(SELECT_VALUE(0x14047E0B8, 0x14059AD71), game::DVAR_FLAG_SAVED); + + // use "saved" flags for "r_specularMap" + utils::hook::set(SELECT_VALUE(0x14047E0DA, 0x14059AD99), game::DVAR_FLAG_SAVED); + + // use "saved" flags for "r_specOccMap" + utils::hook::set(SELECT_VALUE(0x14047E0FC, 0x14059ADC1), game::DVAR_FLAG_SAVED); + } + }; +} + +REGISTER_COMPONENT(renderer::component) diff --git a/src/client/component/resources.cpp b/src/client/component/resources.cpp new file mode 100644 index 0000000..7f9b5a2 --- /dev/null +++ b/src/client/component/resources.cpp @@ -0,0 +1,70 @@ +#include +#include "loader/component_loader.hpp" +#include + +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) diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp new file mode 100644 index 0000000..6ae75ba --- /dev/null +++ b/src/client/component/scheduler.cpp @@ -0,0 +1,197 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "scheduler.hpp" + +#include +#include +#include + +namespace scheduler +{ + namespace + { + struct task + { + std::function handler{}; + std::chrono::milliseconds interval{}; + std::chrono::high_resolution_clock::time_point last_call{}; + }; + + using task_list = std::vector; + + class task_pipeline + { + public: + void add(task&& task) + { + new_callbacks_.access([&task](task_list& tasks) + { + tasks.emplace_back(std::move(task)); + }); + } + + void execute() + { + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + + for (auto i = tasks.begin(); i != tasks.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - i->last_call; + + if (diff < i->interval) + { + ++i; + continue; + } + + i->last_call = now; + + const auto res = i->handler(); + if (res == cond_end) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + private: + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + + void merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } + }; + + volatile bool kill = false; + std::thread thread; + task_pipeline pipelines[pipeline::count]; + utils::hook::detour r_end_frame_hook; + + void execute(const pipeline type) + { + assert(type >= 0 && type < pipeline::count); + pipelines[type].execute(); + } + + void r_end_frame_stub() + { + execute(pipeline::renderer); + r_end_frame_hook.invoke(); + } + + void server_frame_stub() + { + game::G_Glass_Update(); + execute(pipeline::server); + } + + void main_frame_stub() + { + execute(pipeline::main); + game::Com_Frame_Try_Block_Function(); + } + } + + void schedule(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + assert(type >= 0 && type < pipeline::count); + + task task; + task.handler = callback; + task.interval = delay; + task.last_call = std::chrono::high_resolution_clock::now(); + + pipelines[type].add(std::move(task)); + } + + void loop(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_continue; + }, type, delay); + } + + void once(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_end; + }, type, delay); + } + + void on_game_initialized(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([=]() + { + const auto dw_init = game::environment::is_sp() ? true : game::Live_SyncOnlineDataFlags(0) == 0; + if (dw_init && game::Sys_IsDatabaseReady2()) + { + once(callback, type, delay); + return cond_end; + } + + return cond_continue; + }, pipeline::main); + } + + class component final : public component_interface + { + public: + void post_start() override + { + thread = utils::thread::create_named_thread("Async Scheduler", []() + { + while (!kill) + { + execute(pipeline::async); + std::this_thread::sleep_for(10ms); + } + }); + } + + void post_unpack() override + { + r_end_frame_hook.create(SELECT_VALUE(0x1404A3E20, 0x1405C25B0), r_end_frame_stub); + + utils::hook::call(SELECT_VALUE(0x1402F7DC2, 0x1403CEEE2), main_frame_stub); + utils::hook::call(SELECT_VALUE(0x140228647, 0x1402F8879), server_frame_stub); + } + + void pre_destroy() override + { + kill = true; + if (thread.joinable()) + { + thread.join(); + } + } + }; +} + +REGISTER_COMPONENT(scheduler::component) diff --git a/src/client/component/scheduler.hpp b/src/client/component/scheduler.hpp new file mode 100644 index 0000000..1e0de7a --- /dev/null +++ b/src/client/component/scheduler.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace scheduler +{ + enum pipeline + { + // Asynchronuous pipeline, disconnected from the game + async = 0, + + // The game's rendering pipeline + renderer, + + // The game's server thread + server, + + // The game's main thread + main, + + count, + }; + + static const bool cond_continue = false; + static const bool cond_end = true; + + void schedule(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void loop(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void once(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void on_game_initialized(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); +} diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp new file mode 100644 index 0000000..d4579c0 --- /dev/null +++ b/src/client/component/scripting.cpp @@ -0,0 +1,193 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "game/scripting/functions.hpp" + +#include "scheduler.hpp" +#include "scripting.hpp" + +#include "gsc/script_loading.hpp" + +#include + +namespace scripting +{ + std::unordered_map> script_function_table; + std::unordered_map>> script_function_table_sort; + std::unordered_map> script_function_table_rev; + + std::string current_file; + + namespace + { + utils::hook::detour vm_notify_hook; + utils::hook::detour scr_load_level_hook; + utils::hook::detour g_shutdown_game_hook; + + utils::hook::detour scr_set_thread_position_hook; + utils::hook::detour process_script_hook; + utils::hook::detour sl_get_canonical_string_hook; + + std::string current_script_file; + std::uint32_t current_file_id = 0; + + std::unordered_map canonical_string_table; + + std::vector> shutdown_callbacks; + std::vector> init_callbacks; + + void scr_load_level_stub() + { + scr_load_level_hook.invoke(); + if (!game::VirtualLobby_Loaded()) + { + for (const auto& callback : init_callbacks) + { + callback(); + } + } + } + + void g_shutdown_game_stub(const int free_scripts) + { + if (free_scripts) + { + script_function_table_sort.clear(); + script_function_table.clear(); + script_function_table_rev.clear(); + canonical_string_table.clear(); + } + + for (const auto& callback : shutdown_callbacks) + { + callback(free_scripts); + } + + return g_shutdown_game_hook.invoke(free_scripts); + } + + void process_script_stub(const char* filename) + { + current_script_file = filename; + + const auto file_id = atoi(filename); + if (file_id) + { + current_file_id = static_cast(file_id); + } + else + { + current_file_id = 0; + current_file = filename; + } + + process_script_hook.invoke(filename); + } + + void add_function_sort(unsigned int id, const char* pos) + { + std::string filename = current_file; + if (current_file_id) + { + filename = get_token(current_file_id); + } + + if (!script_function_table_sort.contains(filename)) + { + const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false); + if (script) + { + const auto* end = &script->bytecode[script->bytecodeLen]; + script_function_table_sort[filename].emplace_back("__end__", reinterpret_cast(end)); + } + } + + const auto name = scripting::get_token(id); + auto& itr = script_function_table_sort[filename]; + itr.insert(itr.end() - 1, {name, pos}); + } + + void add_function(const std::string& file, unsigned int id, const char* pos) + { + const auto name = get_token(id); + script_function_table[file][name] = pos; + script_function_table_rev[pos] = {file, name}; + } + + void scr_set_thread_position_stub(unsigned int thread_name, const char* code_pos) + { + add_function_sort(thread_name, code_pos); + + if (current_file_id) + { + const auto name = get_token(current_file_id); + add_function(name, thread_name, code_pos); + } + else + { + add_function(current_file, thread_name, code_pos); + } + + scr_set_thread_position_hook.invoke(thread_name, code_pos); + } + + unsigned int sl_get_canonical_string_stub(const char* str) + { + const auto result = sl_get_canonical_string_hook.invoke(str); + canonical_string_table[result] = str; + return result; + } + } + + std::string get_token(unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return itr->second; + } + + return find_token(id); + } + + void on_shutdown(const std::function& callback) + { + shutdown_callbacks.push_back(callback); + } + + void on_init(const std::function& callback) + { + init_callbacks.push_back(callback); + } + + std::optional get_canonical_string(const unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return {itr->second}; + } + + return {}; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // SP address is wrong, but should be ok + scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x140325B90), &scr_load_level_stub); + g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x1402F8C10), &g_shutdown_game_stub); + + scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x1403EDB10), &scr_set_thread_position_stub); + process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1403F7300), &process_script_stub); + sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, &sl_get_canonical_string_stub); + + scheduler::loop([] + { + }, scheduler::pipeline::server); + } + }; +} + +REGISTER_COMPONENT(scripting::component) diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp new file mode 100644 index 0000000..c841903 --- /dev/null +++ b/src/client/component/scripting.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace scripting +{ + extern std::unordered_map> script_function_table; + extern std::unordered_map>> script_function_table_sort; + extern std::unordered_map> script_function_table_rev; + + extern std::string current_file; + + void on_shutdown(const std::function& callback); + void on_init(const std::function& callback); + + std::optional get_canonical_string(unsigned int id); + std::string get_token(unsigned int id); +} diff --git a/src/client/component/security.cpp b/src/client/component/security.cpp new file mode 100644 index 0000000..b0bb0e9 --- /dev/null +++ b/src/client/component/security.cpp @@ -0,0 +1,77 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" + +#include + +namespace security +{ + namespace + { + void set_cached_playerdata_stub(const int localclient, const int index1, const int index2) + { + if (index1 >= 0 && index1 < 18 && index2 >= 0 && index2 < 42) + { + reinterpret_cast(0x140536A60)(localclient, index1, index2); + } + } + + void remap_cached_entities(game::mp::cachedSnapshot_t& snapshot) + { + static bool printed = false; + if(snapshot.num_clients > 1200 && !printed) + { + printed = true; + console::info("Too many entities (%d)... remapping!\n", snapshot.num_clients); + } + + snapshot.num_clients = std::min(snapshot.num_clients, 1200); + } + + void remap_cached_entities_stub(utils::hook::assembler& a) + { + a.pushad64(); + + a.mov(rcx, rbx); + a.call_aligned(remap_cached_entities); + + a.popad64(); + a.jmp(0x14044DE51); + } + + void sv_execute_client_message_stub(game::mp::client_t* client, game::msg_t* msg) + { + if ((client->reliableSequence - client->reliableAcknowledge) < 0) + { + client->reliableAcknowledge = client->reliableSequence; + console::info("Negative reliableAcknowledge from %s - cl->reliableSequence is %i, reliableAcknowledge is %i\n", + client->name, client->reliableSequence, client->reliableAcknowledge); + return; + } + + utils::hook::invoke(0x14043AA90, client, msg); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) return; + + // Patch vulnerability in PlayerCards_SetCachedPlayerData + utils::hook::call(0x1401BB909, set_cached_playerdata_stub); + + // Patch entity overflow + utils::hook::jump(0x14044DE3A, assemble(remap_cached_entities_stub), true); + + // It is possible to make the server hang if left unchecked + utils::hook::call(0x140443051, sv_execute_client_message_stub); + } + }; +} + +REGISTER_COMPONENT(security::component) diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp new file mode 100644 index 0000000..587f5b4 --- /dev/null +++ b/src/client/component/server_list.cpp @@ -0,0 +1,433 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "server_list.hpp" +#include "localized_strings.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "party.hpp" + +#include +#include +#include + +namespace server_list +{ + namespace + { + const int server_limit = 14; + + struct server_info + { + // gotta add more to this + int clients; + int max_clients; + int bots; + int ping; + std::string host_name; + std::string map_name; + std::string game_type; + game::CodPlayMode play_mode; + char in_game; + game::netadr_s address; + }; + + struct + { + game::netadr_s address{}; + volatile bool requesting = false; + std::unordered_map queued_servers{}; + } master_state; + + std::mutex mutex; + std::vector servers; + + size_t server_list_page = 0; + volatile bool update_server_list = false; + std::chrono::high_resolution_clock::time_point last_scroll{}; + + size_t get_page_count() + { + const auto count = servers.size() / server_limit; + return count + (servers.size() % server_limit > 0); + } + + size_t get_page_base_index() + { + return server_list_page * server_limit; + } + + void refresh_server_list() + { + { + std::lock_guard _(mutex); + servers.clear(); + master_state.queued_servers.clear(); + server_list_page = 0; + } + + party::reset_connect_state(); + + if (get_master_server(master_state.address)) + { + master_state.requesting = true; + network::send(master_state.address, "getservers", utils::string::va("S1 %i full empty", PROTOCOL)); + } + } + + void join_server(int, int, const int index) + { + std::lock_guard _(mutex); + + const auto i = static_cast(index) + get_page_base_index(); + if (i < servers.size()) + { + static auto last_index = ~0ull; + if (last_index != i) + { + last_index = i; + } + else + { + printf("Connecting to (%d - %zu): %s\n", index, i, servers[i].host_name.data()); + party::connect(servers[i].address); + } + } + } + + void trigger_refresh() + { + update_server_list = true; + } + + int ui_feeder_count() + { + std::lock_guard _(mutex); + if (update_server_list) + { + update_server_list = false; + return 0; + } + const auto count = static_cast(servers.size()); + const auto index = get_page_base_index(); + const auto diff = count - index; + return diff > server_limit ? server_limit : static_cast(diff); + } + + const char* ui_feeder_item_text(int /*localClientNum*/, void* /*a2*/, void* /*a3*/, const int index, + const int column) + { + std::lock_guard _(mutex); + + const auto i = get_page_base_index() + index; + + if (i >= servers.size()) + { + return ""; + } + + if (column == 0) + { + return servers[i].host_name.empty() ? "" : utils::string::va("%s", servers[i].host_name.data()); + } + + if (column == 1) + { + return servers[i].map_name.empty() ? "" : utils::string::va("%s", servers[i].map_name.data()); + } + + if (column == 2) + { + return servers[i].game_type.empty() ? "" : utils::string::va("%s", servers[i].game_type.data()); + } + + if (column == 3) + { + return utils::string::va("%d/%d [%d]", servers[i].clients, servers[i].max_clients, + servers[i].bots); + } + + if (column == 4) + { + return servers[i].ping ? utils::string::va("%d", servers[i].ping) : ""; + } + + return ""; + } + + void sort_serverlist() + { + std::ranges::stable_sort(servers, [](const server_info& a, const server_info& b) + { + if (a.clients == b.clients) + { + return a.ping < b.ping; + } + + return a.clients > b.clients; + }); + } + + void insert_server(server_info&& server) + { + std::lock_guard _(mutex); + servers.emplace_back(std::move(server)); + sort_serverlist(); + trigger_refresh(); + } + + void do_frame_work() + { + auto& queue = master_state.queued_servers; + if (queue.empty()) + { + return; + } + + std::lock_guard _(mutex); + + size_t queried_servers = 0; + const size_t query_limit = 3; + + for (auto i = queue.begin(); i != queue.end();) + { + if (i->second) + { + const auto now = game::Sys_Milliseconds(); + if (now - i->second > 10'000) + { + i = queue.erase(i); + continue; + } + } + else if (queried_servers++ < query_limit) + { + i->second = game::Sys_Milliseconds(); + network::send(i->first, "getInfo", utils::cryptography::random::get_challenge()); + } + + ++i; + } + } + + bool is_server_list_open() + { + return game::Menu_IsMenuOpenAndVisible(0, "menu_systemlink_join"); + } + + bool is_scrolling_disabled() + { + return update_server_list || (std::chrono::high_resolution_clock::now() - last_scroll) < 500ms; + } + + bool scroll_down() + { + if (!is_server_list_open()) + { + return false; + } + + if (!is_scrolling_disabled() && server_list_page + 1 < get_page_count()) + { + last_scroll = std::chrono::high_resolution_clock::now(); + ++server_list_page; + trigger_refresh(); + } + + return true; + } + + bool scroll_up() + { + if (!is_server_list_open()) + { + return false; + } + + if (!is_scrolling_disabled() && server_list_page > 0) + { + last_scroll = std::chrono::high_resolution_clock::now(); + --server_list_page; + trigger_refresh(); + } + + return true; + } + + void resize_host_name(std::string& name) + { + name = utils::string::split(name, '\n').front(); + + game::Font_s* font; + if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_ZOMBIES) + { + font = game::R_RegisterFont("fonts/zmBodyFont"); + } + else + { + font = game::R_RegisterFont("fonts/bodyFont"); + } + auto text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); + + while (text_size > 450) + { + text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); + name.pop_back(); + } + } + + void lui_open_menu_stub(int /*controllerIndex*/, const char* /*menu*/, int /*a3*/, int /*a4*/, + unsigned int /*a5*/) + { + refresh_server_list(); + game::Cmd_ExecuteSingleCommand(0, 0, "lui_open menu_systemlink_join\n"); + } + } + + bool sl_key_event(const int key, const int down) + { + if (down) + { + if (key == game::keyNum_t::K_MWHEELUP) + { + return !scroll_up(); + } + + if (key == game::keyNum_t::K_MWHEELDOWN) + { + return !scroll_down(); + } + } + + return true; + } + + bool get_master_server(game::netadr_s& address) + { + return game::NET_StringToAdr("server.alterware.dev:20810", &address); + } + + void handle_info_response(const game::netadr_s& address, const utils::info_string& info) + { + // Don't show servers that aren't dedicated! + const auto dedicated = info.get("dedicated"); + if (dedicated != "1"s) + { + return; + } + + // Don't show servers that aren't running! + const auto sv_running = info.get("sv_running"); + if (sv_running != "1"s) + { + return; + } + + // Only handle servers of the same playmode! + const auto playmode = static_cast(std::atoi(info.get("playmode").data())); + if (game::Com_GetCurrentCoDPlayMode() != playmode) + { + return; + } + + int start_time{}; + const auto now = game::Sys_Milliseconds(); + + { + std::lock_guard _(mutex); + const auto entry = master_state.queued_servers.find(address); + + if (entry == master_state.queued_servers.end() || !entry->second) + { + return; + } + + start_time = entry->second; + master_state.queued_servers.erase(entry); + } + + server_info server{}; + server.address = address; + server.host_name = info.get("hostname"); + server.map_name = game::UI_GetMapDisplayName(info.get("mapname").data()); + server.game_type = game::UI_GetGameTypeDisplayName(info.get("gametype").data()); + server.play_mode = playmode; + server.clients = std::atoi(info.get("clients").data()); + server.max_clients = std::atoi(info.get("sv_maxclients").data()); + server.bots = std::atoi(info.get("bots").data()); + server.ping = std::min(now - start_time, 999); + + server.in_game = 1; + + resize_host_name(server.host_name); + + insert_server(std::move(server)); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) return; + + // replace UI_RunMenuScript call in LUI_CoD_LuaCall_RefreshServerList to our refresh_servers + utils::hook::call(0x1400F5AA1, &refresh_server_list); + utils::hook::call(0x1400F5F26, &join_server); + utils::hook::nop(0x1400F5F45, 5); + + // do feeder stuff + utils::hook::call(0x1400F5B55, &ui_feeder_count); + utils::hook::call(0x1400F5D35, &ui_feeder_item_text); + + scheduler::loop(do_frame_work, scheduler::pipeline::main); + + network::on("getServersResponse", [](const game::netadr_s& target, const std::string_view& data) + { + { + std::lock_guard _(mutex); + if (!master_state.requesting || master_state.address != target) + { + return; + } + + master_state.requesting = false; + + std::optional start{}; + for (size_t i = 0; i + 6 < data.size(); ++i) + { + if (data[i + 6] == '\\') + { + start.emplace(i); + break; + } + } + + if (!start.has_value()) + { + return; + } + + for (auto i = start.value(); i + 6 < data.size(); i += 7) + { + if (data[i + 6] != '\\') + { + break; + } + + game::netadr_s address{}; + address.type = game::NA_IP; + address.localNetID = game::NS_CLIENT1; + memcpy(&address.ip[0], data.data() + i + 0, 4); + memcpy(&address.port, data.data() + i + 4, 2); + + master_state.queued_servers[address] = 0; + } + } + }); + } + }; +} + +REGISTER_COMPONENT(server_list::component) diff --git a/src/client/component/server_list.hpp b/src/client/component/server_list.hpp new file mode 100644 index 0000000..09f62b2 --- /dev/null +++ b/src/client/component/server_list.hpp @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace server_list +{ + bool get_master_server(game::netadr_s& address); + void handle_info_response(const game::netadr_s& address, const utils::info_string& info); + + bool sl_key_event(int key, int down); +} diff --git a/src/client/component/slowmotion.cpp b/src/client/component/slowmotion.cpp new file mode 100644 index 0000000..6af2946 --- /dev/null +++ b/src/client/component/slowmotion.cpp @@ -0,0 +1,53 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace slowmotion +{ + namespace + { + void scr_cmd_set_slow_motion() + { + if (game::Scr_GetNumParam() < 1) + { + return; + } + + int duration = 1000; + float end = 1.0f; + const float start = game::Scr_GetFloat(0); + + if (game::Scr_GetNumParam() >= 2) + { + end = game::Scr_GetFloat(1u); + } + + if (game::Scr_GetNumParam() >= 3) + { + duration = static_cast(game::Scr_GetFloat(2u) * 1000.0f); + } + + game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end)); + game::Com_SetSlowMotion(start, end, duration); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + utils::hook::jump(0x14030EF90, scr_cmd_set_slow_motion); + } + }; +} + +REGISTER_COMPONENT(slowmotion::component) diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp new file mode 100644 index 0000000..becd17b --- /dev/null +++ b/src/client/component/splash.cpp @@ -0,0 +1,141 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game_module.hpp" + +#include +#include + +namespace splash +{ + class component final : public component_interface + { + public: + void post_start() override + { + const utils::nt::library self; + image_ = LoadImageA(self, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + } + + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + this->show(); + } + + void post_unpack() override + { + // Disable native splash screen + utils::hook::nop(SELECT_VALUE(0x14038D88C, 0x1404D74E3), 5); + utils::hook::jump(SELECT_VALUE(0x14038ECD0, 0x1404D8A70), destroy_stub); + utils::hook::jump(SELECT_VALUE(0x14038ED10, 0x1404D8AB0), destroy_stub); + } + + void pre_destroy() override + { + this->destroy(); + + MSG msg; + while (this->window_ && IsWindow(this->window_)) + { + if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + std::this_thread::sleep_for(1ms); + } + } + + this->window_ = nullptr; + } + + private: + HWND window_{}; + HANDLE image_{}; + + static void destroy_stub() + { + component_loader::get()->destroy(); + } + + void destroy() const + { + if (this->window_ && IsWindow(this->window_)) + { + ShowWindow(this->window_, SW_HIDE); + DestroyWindow(this->window_); + UnregisterClassA("s1-mod Splash Screen", utils::nt::library{}); + } + } + + void show() + { + WNDCLASSA wnd_class; + + const auto self = game_module::get_host_module(); + + wnd_class.style = CS_DROPSHADOW; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.lpszMenuName = nullptr; + wnd_class.lpfnWndProc = DefWindowProcA; + wnd_class.hInstance = self; + wnd_class.hIcon = LoadIconA(self, reinterpret_cast(102)); + wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING); + wnd_class.hbrBackground = reinterpret_cast(6); + wnd_class.lpszClassName = "s1-mod Splash Screen"; + + if (RegisterClassA(&wnd_class)) + { + const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); + const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); + + if (image_) + { + this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "s1-mod Splash Screen", "s1-mod", + WS_POPUP | WS_SYSMENU, + (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, + nullptr, + self, nullptr); + + if (this->window_) + { + auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, + 0, 0, + 320, 100, this->window_, nullptr, self, nullptr); + if (image_window) + { + RECT rect; + SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image_)); + GetWindowRect(image_window, &rect); + + const int width = rect.right - rect.left; + rect.left = (x_pixels - width) / 2; + + const int height = rect.bottom - rect.top; + rect.top = (y_pixels - height) / 2; + + rect.right = rect.left + width; + rect.bottom = rect.top + height; + AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); + SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER); + + ShowWindow(this->window_, SW_SHOW); + UpdateWindow(this->window_); + } + } + } + } + } + }; +} + +REGISTER_COMPONENT(splash::component) diff --git a/src/client/component/stats.cpp b/src/client/component/stats.cpp new file mode 100644 index 0000000..bccac67 --- /dev/null +++ b/src/client/component/stats.cpp @@ -0,0 +1,128 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" + +#include + +namespace stats +{ + namespace + { + game::dvar_t* cg_unlock_all_items; + + utils::hook::detour is_item_unlocked_hook; + utils::hook::detour is_item_unlocked_hook2; + utils::hook::detour is_item_unlocked_hook3; + + int is_item_unlocked_stub(void* a1, void* a2, void* a3) + { + if (cg_unlock_all_items->current.enabled) + { + return 0; + } + + return is_item_unlocked_hook.invoke(a1, a2, a3); + } + + int is_item_unlocked_stub2(void* a1, void* a2, void* a3, void* a4, void* a5) + { + if (cg_unlock_all_items->current.enabled) + { + return 0; + } + + return is_item_unlocked_hook2.invoke(a1, a2, a3, a4, a5); + } + + int is_item_unlocked_stub3(void* a1) + { + if (cg_unlock_all_items->current.enabled) + { + return 0; + } + + return is_item_unlocked_hook3.invoke(a1); + } + + int is_item_unlocked() + { + return 0; // 0 == yes + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + if (game::environment::is_dedi()) + { + // unlock all items + utils::hook::jump(0x1403BD790, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable_LocalClient + utils::hook::jump(0x1403BD290, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable + utils::hook::jump(0x1403BAF60, is_item_unlocked); // idk ( unlocks loot etc ) + } + else + { + // unlock all items + cg_unlock_all_items = game::Dvar_RegisterBool("cg_unlockall_items", false, game::DVAR_FLAG_SAVED, "Whether items should be locked based on the player's stats or always unlocked."); + game::Dvar_RegisterBool("cg_unlockall_classes", false, game::DVAR_FLAG_SAVED, "Whether classes should be locked based on the player's stats or always unlocked."); + + is_item_unlocked_hook.create(0x1403BD790, is_item_unlocked_stub); // LiveStorage_IsItemUnlockedFromTable_LocalClient + is_item_unlocked_hook2.create(0x1403BD290, is_item_unlocked_stub2); // LiveStorage_IsItemUnlockedFromTable + is_item_unlocked_hook3.create(0x1403BAF60, is_item_unlocked_stub3); // idk (unlocks loot etc) + } + + command::add("setPlayerDataInt", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: setPlayerDataInt , \n"); + return; + } + + // SL_FindString + const auto lookup_string = game::SL_FindString(params.get(1)); + const auto value = atoi(params.get(2)); + + // SetPlayerDataInt + reinterpret_cast(0x1403BF550)( + 0, lookup_string, value, 0); + }); + + command::add("getPlayerDataInt", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: getPlayerDataInt \n"); + return; + } + + // SL_FindString + const auto lookup_string = game::SL_FindString(params.get(1)); + + // GetPlayerDataInt + const auto result = reinterpret_cast(0x1403BE860)( + 0, lookup_string, 0); + console::info("%d\n", result); + }); + + command::add("unlockstats", []() + { + command::execute("setPlayerDataInt prestige 30"); + command::execute("setPlayerDataInt experience 1002100"); + }); + } + }; +} + +REGISTER_COMPONENT(stats::component) diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp new file mode 100644 index 0000000..00115d9 --- /dev/null +++ b/src/client/component/steam_proxy.cpp @@ -0,0 +1,208 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" + +#include +#include +#include + +#include "game/game.hpp" + +#include "steam/interface.hpp" +#include "steam/steam.hpp" + +namespace steam_proxy +{ + namespace + { + enum class ownership_state + { + success, + unowned, + nosteam, + error, + }; + + ownership_state state_; + + utils::binary_resource runner_file(RUNNER, "s1-mod-runner.exe"); + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + this->load_client(); + this->clean_up_on_error(); + +#ifndef DEV_BUILD + try + { + const std::string mod_name = "\xF0\x9F\x92\x8E" " s1-mod: "; + state_ = this->start_mod(mod_name + game::environment::get_string(), game::environment::is_sp() ? 209650 : 209660); + } + catch (const std::exception& ex) + { + state_ = ownership_state::error; + printf("Steam: %s\n", ex.what()); + } +#endif + } + + void pre_destroy() override + { + if (this->steam_client_module_) + { + if (this->steam_pipe_) + { + if (this->global_user_) + { + this->steam_client_module_.invoke("Steam_ReleaseUser", this->steam_pipe_, this->global_user_); + } + + this->steam_client_module_.invoke("Steam_BReleaseSteamPipe", this->steam_pipe_); + } + } + } + + const utils::nt::library& get_overlay_module() const + { + return steam_overlay_module_; + } + + private: + utils::nt::library steam_client_module_{}; + utils::nt::library steam_overlay_module_{}; + + steam::interface client_engine_{}; + steam::interface client_user_{}; + steam::interface client_utils_{}; + + void* steam_pipe_ = nullptr; + void* global_user_ = nullptr; + + void* load_client_engine() const + { + if (!this->steam_client_module_) return nullptr; + + for (auto i = 1; i < 1000; ++i) + { + const auto* name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); + auto* const client_engine = this->steam_client_module_.invoke("CreateInterface", name, nullptr); + if (client_engine) return client_engine; + } + + return nullptr; + } + + void load_client() + { + const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); + if (steam_path.empty()) return; + + utils::nt::library::load(steam_path / "tier0_s64.dll"); + utils::nt::library::load(steam_path / "vstdlib_s64.dll"); + this->steam_overlay_module_ = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); + this->steam_client_module_ = utils::nt::library::load(steam_path / "steamclient64.dll"); + if (!this->steam_client_module_) return; + + this->client_engine_ = load_client_engine(); + if (!this->client_engine_) return; + + this->steam_pipe_ = this->steam_client_module_.invoke("Steam_CreateSteamPipe"); + this->global_user_ = this->steam_client_module_.invoke("Steam_ConnectToGlobalUser", this->steam_pipe_); + this->client_user_ = this->client_engine_.invoke(8, this->steam_pipe_, this->global_user_); + // GetIClientUser + this->client_utils_ = this->client_engine_.invoke(14, this->steam_pipe_); // GetIClientUtils + } + + ownership_state start_mod(const std::string& title, const size_t app_id) + { + __try + { + return this->start_mod_unsafe(title, app_id); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + this->do_cleanup(); + return ownership_state::error; + } + } + + ownership_state start_mod_unsafe(const std::string& title, size_t app_id) + { + if (!this->client_utils_ || !this->client_user_) + { + return ownership_state::nosteam; + } + + if (!this->client_user_.invoke("BIsSubscribedApp", app_id)) + { +#ifdef _DEBUG + app_id = 480; // Spacewar +#else + return ownership_state::unowned; +#endif + } + + this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); + + char our_directory[MAX_PATH]{}; + GetCurrentDirectoryA(sizeof(our_directory), our_directory); + + const auto path = runner_file.get_extracted_file(); + const auto* cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); + + steam::game_id game_id; + game_id.raw.type = 1; // k_EGameIDTypeGameMod + game_id.raw.app_id = app_id & 0xFFFFFF; + + const auto* mod_id = "s1-mod"; + game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; + + this->client_user_.invoke("SpawnProcess", path.data(), cmdline, our_directory, + &game_id.bits, title.data(), 0, 0, 0); + + return ownership_state::success; + } + + void do_cleanup() + { + this->client_engine_ = nullptr; + this->client_user_ = nullptr; + this->client_utils_ = nullptr; + + this->steam_pipe_ = nullptr; + this->global_user_ = nullptr; + + this->steam_client_module_ = utils::nt::library{nullptr}; + } + + void clean_up_on_error() + { + scheduler::schedule([this]() + { + if (this->steam_client_module_ + && this->steam_pipe_ + && this->global_user_ + && this->steam_client_module_.invoke("Steam_BConnected", this->global_user_, this->steam_pipe_) + && this->steam_client_module_.invoke("Steam_BLoggedOn", this->global_user_, this->steam_pipe_) + ) + { + return scheduler::cond_continue; + } + + this->do_cleanup(); + return scheduler::cond_end; + }); + } + }; +} + +REGISTER_COMPONENT(steam_proxy::component) diff --git a/src/client/component/survival.cpp b/src/client/component/survival.cpp new file mode 100644 index 0000000..01aa763 --- /dev/null +++ b/src/client/component/survival.cpp @@ -0,0 +1,46 @@ +#include +#include "loader/component_loader.hpp" +#include + +namespace survival +{ + namespace + { + const char* get_commandline_stub() + { + static std::string commandline{}; + if (commandline.empty()) + { + commandline = GetCommandLineA(); + + const auto real_mode = game::environment::get_real_mode(); + if (real_mode == launcher::mode::survival) + { + commandline += " +survival 01"; + } + else if (real_mode == launcher::mode::zombies) + { + commandline += " +zombiesMode 01"; + } + } + + return commandline.data(); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (function == "GetCommandLineA") + { + return get_commandline_stub; + } + + return nullptr; + } + }; +} + +REGISTER_COMPONENT(survival::component) diff --git a/src/client/component/system_check.cpp b/src/client/component/system_check.cpp new file mode 100644 index 0000000..e428a8c --- /dev/null +++ b/src/client/component/system_check.cpp @@ -0,0 +1,100 @@ +#include +#include "loader/component_loader.hpp" +#include "system_check.hpp" + +#include "game/game.hpp" + +#include +#include + +namespace system_check +{ + namespace + { + std::string read_zone(const std::string& name) + { + std::string data{}; + if (utils::io::read_file(name, &data)) + { + return data; + } + + if (utils::io::read_file("zone/" + name, &data)) + { + return data; + } + + return {}; + } + + std::string hash_zone(const std::string& name) + { + const auto data = read_zone(name); + return utils::cryptography::sha256::compute(data, true); + } + + bool verify_hashes(const std::unordered_map& zone_hashes) + { + for (const auto& zone_hash : zone_hashes) + { + const auto hash = hash_zone(zone_hash.first); + if (hash != zone_hash.second) + { + return false; + } + } + + return true; + } + + bool is_system_valid() + { + static std::unordered_map mp_zone_hashes = + { + {"patch_common_mp.ff", "23B15B4EF0AC9B52B3C6F9F681290B25B6B24B49F17238076A3D7F3CCEF9A0E1"}, + }; + + static std::unordered_map sp_zone_hashes = + { + // Steam doesn't necessarily deliver this file :( + //{"patch_common.ff", "4624A974C6C7F8BECD9C343E7951722D8378889AC08ED4F2B22459B171EC553C"}, + {"patch_common_zm_mp.ff", "DA16B546B7233BBC4F48E1E9084B49218CB9271904EA7120A0EB4CB8723C19CF"}, + }; + + return verify_hashes(mp_zone_hashes) && (game::environment::is_dedi() || verify_hashes(sp_zone_hashes)); + } + + void verify_binary_version() + { + const auto value = *reinterpret_cast(0x140001337); + if (value != 0x24AFEB05 && value != 0x1D860F04) + { + throw std::runtime_error("Unsupported Call of Duty: Advanced Warfare version"); + } + } + } + + bool is_valid() + { + static auto valid = is_system_valid(); + return valid; + } + + class component final : public component_interface + { + public: + void post_load() override + { + verify_binary_version(); + + if (!is_valid()) + { + game::show_error("Your game files are outdated or unsupported.\n" + "Please get the latest officially supported Call of Duty: Advanced Warfare files, or you will get random crashes and issues.", + "Invalid game files!"); + } + } + }; +} + +REGISTER_COMPONENT(system_check::component) diff --git a/src/client/component/system_check.hpp b/src/client/component/system_check.hpp new file mode 100644 index 0000000..4813846 --- /dev/null +++ b/src/client/component/system_check.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace system_check +{ + bool is_valid(); +} diff --git a/src/client/component/thread_names.cpp b/src/client/component/thread_names.cpp new file mode 100644 index 0000000..84b5fa7 --- /dev/null +++ b/src/client/component/thread_names.cpp @@ -0,0 +1,60 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" + +#include "game/game.hpp" + +#include + +namespace thread_names +{ + namespace + { + void set_thread_names() + { + static std::unordered_map thread_names = + { + {game::THREAD_CONTEXT_MAIN, "Main"}, + {game::THREAD_CONTEXT_BACKEND, "Backend"}, // Renderer + {game::THREAD_CONTEXT_WORKER0, "Worker0"}, + {game::THREAD_CONTEXT_WORKER1, "Worker1"}, + {game::THREAD_CONTEXT_WORKER2, "Worker2"}, + {game::THREAD_CONTEXT_WORKER3, "Worker3"}, + {game::THREAD_CONTEXT_WORKER4, "Worker4"}, + {game::THREAD_CONTEXT_WORKER5, "Worker5"}, + {game::THREAD_CONTEXT_WORKER6, "Worker6"}, + {game::THREAD_CONTEXT_WORKER7, "Worker7"}, + {game::THREAD_CONTEXT_SERVER, "Server"}, + {game::THREAD_CONTEXT_CINEMATIC, "Cinematic"}, + {game::THREAD_CONTEXT_DATABASE, "Database"}, + {game::THREAD_CONTEXT_STREAM, "Stream"}, + {game::THREAD_CONTEXT_SNDSTREAMPACKETCALLBACK, "Snd stream packet callback"}, + {game::THREAD_CONTEXT_STATS_WRITE, "Stats write"}, + }; + + for (const auto& thread_name : thread_names) + { + const auto id = game::threadIds[thread_name.first]; + if (id) + { + utils::thread::set_name(id, thread_name.second); + } + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + set_thread_names(); + scheduler::once(set_thread_names, scheduler::pipeline::main); + scheduler::once(set_thread_names, scheduler::pipeline::renderer); + scheduler::once(set_thread_names, scheduler::pipeline::server); + } + }; +} + +REGISTER_COMPONENT(thread_names::component) diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp new file mode 100644 index 0000000..c2e9393 --- /dev/null +++ b/src/client/component/ui_scripting.cpp @@ -0,0 +1,363 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" + +#include "localized_strings.hpp" +#include "console.hpp" +#include "game_module.hpp" +#include "fps.hpp" + +#include "game/ui_scripting/execution.hpp" + +#include "ui_scripting.hpp" + +#include +#include + +namespace ui_scripting +{ + namespace + { + std::unordered_map> converted_functions; + + utils::hook::detour hks_start_hook; + utils::hook::detour hks_shutdown_hook; + utils::hook::detour hks_package_require_hook; + + struct script + { + std::string name; + std::string root; + }; + + struct globals + { + std::string in_require_script; + std::vector + + + diff --git a/src/client/resources/splash.bmp b/src/client/resources/splash.bmp new file mode 100644 index 0000000..522db95 Binary files /dev/null and b/src/client/resources/splash.bmp differ diff --git a/src/client/std_include.cpp b/src/client/std_include.cpp new file mode 100644 index 0000000..efe6cd6 --- /dev/null +++ b/src/client/std_include.cpp @@ -0,0 +1,32 @@ +#include + +#pragma comment(linker, "/base:0x160000000") + +extern "C" +{ + __declspec(dllexport) DWORD NvOptimusEnablement = 1; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +}; + +extern "C" +{ + int s_read_arc4random(void*, size_t) + { + return -1; + } + + int s_read_getrandom(void*, size_t) + { + return -1; + } + + int s_read_urandom(void*, size_t) + { + return -1; + } + + int s_read_ltm_rng(void*, size_t) + { + return -1; + } +} diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp new file mode 100644 index 0000000..4ba2eb3 --- /dev/null +++ b/src/client/std_include.hpp @@ -0,0 +1,99 @@ +#pragma once + +#define BINARY_PAYLOAD_SIZE 0x12000000 + +#pragma warning(push) +#pragma warning(disable: 4100) +#pragma warning(disable: 4127) +#pragma warning(disable: 4244) +#pragma warning(disable: 4458) +#pragma warning(disable: 4702) +#pragma warning(disable: 4996) +#pragma warning(disable: 5054) + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#pragma warning(pop) +#pragma warning(disable: 4100) + +#pragma comment(lib, "Crypt32.lib") +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "dbghelp.lib") +#pragma comment(lib, "ntdll.lib") +#pragma comment(lib, "urlmon.lib" ) +#pragma comment(lib, "ws2_32.lib") + +#include "resource.hpp" + +using namespace std::literals; diff --git a/src/client/steam/interface.cpp b/src/client/steam/interface.cpp new file mode 100644 index 0000000..75ca922 --- /dev/null +++ b/src/client/steam/interface.cpp @@ -0,0 +1,98 @@ +#include +#include "interface.hpp" + +#include +#include + +namespace steam +{ + interface::interface() : interface(nullptr) + { + } + + interface::interface(void* interface_ptr) : interface_ptr_(static_cast(interface_ptr)) + { + } + + interface::operator bool() const + { + return this->interface_ptr_ != nullptr; + } + + void* interface::find_method(const std::string& name) + { + const auto method_entry = this->methods_.find(name); + if (method_entry != this->methods_.end()) + { + return method_entry->second; + } + + return this->search_method(name); + } + + void* interface::search_method(const std::string& name) + { + if (!utils::memory::is_bad_read_ptr(this->interface_ptr_)) + { + auto vftbl = *this->interface_ptr_; + + while (!utils::memory::is_bad_read_ptr(vftbl) && !utils::memory::is_bad_code_ptr(*vftbl)) + { + const auto ptr = *vftbl; + const auto result = this->analyze_method(ptr); + if (!result.empty()) + { + this->methods_[result] = ptr; + + if (result == name) + { + return ptr; + } + } + + ++vftbl; + } + } + + return {}; + } + + std::string interface::analyze_method(const void* method_ptr) + { + if (utils::memory::is_bad_code_ptr(method_ptr)) return {}; + + ud_t ud; + ud_init(&ud); + ud_set_mode(&ud, 64); + ud_set_pc(&ud, uint64_t(method_ptr)); + ud_set_input_buffer(&ud, static_cast(method_ptr), INT32_MAX); + + while (true) + { + ud_disassemble(&ud); + + if (ud_insn_mnemonic(&ud) == UD_Iret) + { + break; + } + + if (ud_insn_mnemonic(&ud) == UD_Ilea) + { + const auto* operand = ud_insn_opr(&ud, 1); + if (operand && operand->type == UD_OP_MEM && operand->base == UD_R_RIP) + { + auto* operand_ptr = reinterpret_cast(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->lval. + sdword); + if (!utils::memory::is_bad_read_ptr(operand_ptr) && utils::memory::is_rdata_ptr(operand_ptr)) + { + return operand_ptr; + } + } + } + + if (*reinterpret_cast(ud.pc) == 0xCC) break; // int 3 + } + + return {}; + } +} diff --git a/src/client/steam/interface.hpp b/src/client/steam/interface.hpp new file mode 100644 index 0000000..c118c80 --- /dev/null +++ b/src/client/steam/interface.hpp @@ -0,0 +1,85 @@ +#pragma once + +#ifdef interface +#undef interface +#endif + +namespace steam +{ + struct raw_steam_id final + { + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; + }; + + typedef union + { + raw_steam_id raw; + unsigned long long bits; + } steam_id; + +#pragma pack( push, 1 ) + struct raw_game_id final + { + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; + }; + + typedef union + { + raw_game_id raw; + unsigned long long bits; + } game_id; +#pragma pack( pop ) + + class interface final + { + public: + + interface(); + interface(void* interface_ptr); + + operator bool() const; + + template + T invoke(const std::string& method_name, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + const auto method = this->find_method(method_name); + if (!method) + { + throw std::runtime_error("Unable to find method: " + method_name); + } + + return static_cast(method)(this->interface_ptr_, args...); + } + + template + T invoke(const size_t table_entry, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + return static_cast((*this->interface_ptr_)[table_entry])( + this->interface_ptr_, args...); + } + + private: + void*** interface_ptr_; + std::unordered_map methods_; + + void* find_method(const std::string& name); + void* search_method(const std::string& name); + + std::string analyze_method(const void* method_ptr); + }; +} diff --git a/src/client/steam/interfaces/apps.cpp b/src/client/steam/interfaces/apps.cpp new file mode 100644 index 0000000..44350e5 --- /dev/null +++ b/src/client/steam/interfaces/apps.cpp @@ -0,0 +1,104 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool apps::BIsSubscribed() + { + return true; + } + + bool apps::BIsLowViolence() + { + return false; + } + + bool apps::BIsCybercafe() + { + return false; + } + + bool apps::BIsVACBanned() + { + return false; + } + + const char* apps::GetCurrentGameLanguage() + { + return "english"; + } + + const char* apps::GetAvailableGameLanguages() + { + return "english"; + } + + bool apps::BIsSubscribedApp(unsigned int appID) + { + return true; + } + + bool apps::BIsDlcInstalled(unsigned int appID) + { + return true; + } + + unsigned int apps::GetEarliestPurchaseUnixTime(unsigned int nAppID) + { + return 0; + } + + bool apps::BIsSubscribedFromFreeWeekend() + { + return false; + } + + int apps::GetDLCCount() + { + return 0; + } + + bool apps::BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize) + { + return false; + } + + void apps::InstallDLC(unsigned int nAppID) + { + } + + void apps::UninstallDLC(unsigned int nAppID) + { + } + + void apps::RequestAppProofOfPurchaseKey(unsigned int nAppID) + { + } + + bool apps::GetCurrentBetaName(char* pchName, int cchNameBufferSize) + { + strncpy_s(pchName, cchNameBufferSize, "public", cchNameBufferSize); + return true; + } + + bool apps::MarkContentCorrupt(bool bMissingFilesOnly) + { + return false; + } + + unsigned int apps::GetInstalledDepots(int* pvecDepots, unsigned int cMaxDepots) + { + return 0; + } + + unsigned int apps::GetAppInstallDir(unsigned int appID, char* pchFolder, unsigned int cchFolderBufferSize) + { + return 0; + } + + bool apps::BIsAppInstalled(unsigned int appID) + { + return false; + } +} \ No newline at end of file diff --git a/src/client/steam/interfaces/apps.hpp b/src/client/steam/interfaces/apps.hpp new file mode 100644 index 0000000..0729808 --- /dev/null +++ b/src/client/steam/interfaces/apps.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace steam +{ + class apps + { + public: + ~apps() = default; + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char* GetCurrentGameLanguage(); + virtual const char* GetAvailableGameLanguages(); + virtual bool BIsSubscribedApp(unsigned int appID); + virtual bool BIsDlcInstalled(unsigned int appID); + virtual unsigned int GetEarliestPurchaseUnixTime(unsigned int nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize); + virtual void InstallDLC(unsigned int nAppID); + virtual void UninstallDLC(unsigned int nAppID); + virtual void RequestAppProofOfPurchaseKey(unsigned int nAppID); + virtual bool GetCurrentBetaName(char* pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual unsigned int GetInstalledDepots(int* pvecDepots, unsigned int cMaxDepots); + virtual unsigned int GetAppInstallDir(unsigned int appID, char* pchFolder, unsigned int cchFolderBufferSize); + virtual bool BIsAppInstalled(unsigned int appID); + }; +} diff --git a/src/client/steam/interfaces/friends.cpp b/src/client/steam/interfaces/friends.cpp new file mode 100644 index 0000000..5f3d5ab --- /dev/null +++ b/src/client/steam/interfaces/friends.cpp @@ -0,0 +1,313 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + const char* friends::GetPersonaName() + { + return "1337"; + } + + unsigned long long friends::SetPersonaName(const char* pchPersonaName) + { + return 0; + } + + int friends::GetPersonaState() + { + return 1; + } + + int friends::GetFriendCount(int eFriendFlags) + { + return 0; + } + + steam_id friends::GetFriendByIndex(int iFriend, int iFriendFlags) + { + return steam_id(); + } + + int friends::GetFriendRelationship(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetFriendPersonaState(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendPersonaName(steam_id steamIDFriend) + { + return ""; + } + + bool friends::GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo) + { + return false; + } + + const char* friends::GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName) + { + return ""; + } + + bool friends::HasFriend(steam_id steamIDFriend, int eFriendFlags) + { + return false; + } + + int friends::GetClanCount() + { + return 0; + } + + steam_id friends::GetClanByIndex(int iClan) + { + return steam_id(); + } + + const char* friends::GetClanName(steam_id steamIDClan) + { + return "3arc"; + } + + const char* friends::GetClanTag(steam_id steamIDClan) + { + return this->GetClanName(steamIDClan); + } + + bool friends::GetClanActivityCounts(steam_id steamID, int* pnOnline, int* pnInGame, int* pnChatting) + { + return false; + } + + unsigned long long friends::DownloadClanActivityCounts(steam_id groupIDs[], int nIds) + { + return 0; + } + + int friends::GetFriendCountFromSource(steam_id steamIDSource) + { + return 0; + } + + steam_id friends::GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend) + { + return steam_id(); + } + + bool friends::IsUserInSource(steam_id steamIDUser, steam_id steamIDSource) + { + return false; + } + + void friends::SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking) + { + } + + void friends::ActivateGameOverlay(const char* pchDialog) + { + } + + void friends::ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID) + { + } + + void friends::ActivateGameOverlayToWebPage(const char* pchURL) + { + } + + void friends::ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag) + { + } + + void friends::SetPlayedWith(steam_id steamIDUserPlayedWith) + { + } + + void friends::ActivateGameOverlayInviteDialog(steam_id steamIDLobby) + { + } + + int friends::GetSmallFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetMediumFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetLargeFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + bool friends::RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly) + { + return false; + } + + unsigned long long friends::RequestClanOfficerList(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOwner(steam_id steamIDClan) + { + return steam_id(); + } + + int friends::GetClanOfficerCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer) + { + return steam_id(); + } + + int friends::GetUserRestrictions() + { + return 0; + } + + bool friends::SetRichPresence(const char* pchKey, const char* pchValue) + { + return true; + } + + void friends::ClearRichPresence() + { + } + + const char* friends::GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey) + { + return ""; + } + + int friends::GetFriendRichPresenceKeyCount(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey) + { + return "a"; + } + + void friends::RequestFriendRichPresence(steam_id steamIDFriend) + { + } + + bool friends::InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString) + { + return false; + } + + int friends::GetCoplayFriendCount() + { + return 0; + } + + steam_id friends::GetCoplayFriend(int iCoplayFriend) + { + return steam_id(); + } + + int friends::GetFriendCoplayTime(steam_id steamIDFriend) + { + return 0; + } + + unsigned int friends::GetFriendCoplayGame(steam_id steamIDFriend) + { + return 0; + } + + unsigned long long friends::JoinClanChatRoom(steam_id steamIDClan) + { + return 0; + } + + bool friends::LeaveClanChatRoom(steam_id steamIDClan) + { + return false; + } + + int friends::GetClanChatMemberCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetChatMemberByIndex(steam_id steamIDClan, int iUser) + { + return steam_id(); + } + + bool friends::SendClanChatMessage(steam_id steamIDClanChat, const char* pchText) + { + return false; + } + + int friends::GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void* prgchText, int cchTextMax, + unsigned int* peChatEntryType, steam_id* pSteamIDChatter) + { + return 0; + } + + bool friends::IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser) + { + return false; + } + + bool friends::IsClanChatWindowOpenInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::OpenClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::CloseClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::SetListenForFriendsMessages(bool bInterceptEnabled) + { + return false; + } + + bool friends::ReplyToFriendMessage(steam_id steamIDFriend, const char* pchMsgToSend) + { + return false; + } + + int friends::GetFriendMessage(steam_id steamIDFriend, int iMessageID, void* pvData, int cubData, + unsigned int* peChatEntryType) + { + return 0; + } + + unsigned long long friends::GetFollowerCount(steam_id steamID) + { + return 0; + } + + unsigned long long friends::IsFollowing(steam_id steamID) + { + return 0; + } + + unsigned long long friends::EnumerateFollowingList(unsigned int unStartIndex) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/friends.hpp b/src/client/steam/interfaces/friends.hpp new file mode 100644 index 0000000..f7cb2a2 --- /dev/null +++ b/src/client/steam/interfaces/friends.hpp @@ -0,0 +1,76 @@ +#pragma once + +namespace steam +{ + class friends + { + public: + ~friends() = default; + + virtual const char* GetPersonaName(); + virtual unsigned long long SetPersonaName(const char* pchPersonaName); + virtual int GetPersonaState(); + virtual int GetFriendCount(int eFriendFlags); + virtual steam_id GetFriendByIndex(int iFriend, int iFriendFlags); + virtual int GetFriendRelationship(steam_id steamIDFriend); + virtual int GetFriendPersonaState(steam_id steamIDFriend); + virtual const char* GetFriendPersonaName(steam_id steamIDFriend); + virtual bool GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo); + virtual const char* GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName); + virtual bool HasFriend(steam_id steamIDFriend, int eFriendFlags); + virtual int GetClanCount(); + virtual steam_id GetClanByIndex(int iClan); + virtual const char* GetClanName(steam_id steamIDClan); + virtual const char* GetClanTag(steam_id steamIDClan); + virtual bool GetClanActivityCounts(steam_id steamID, int* pnOnline, int* pnInGame, int* pnChatting); + virtual unsigned long long DownloadClanActivityCounts(steam_id groupIDs[], int nIds); + virtual int GetFriendCountFromSource(steam_id steamIDSource); + virtual steam_id GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend); + virtual bool IsUserInSource(steam_id steamIDUser, steam_id steamIDSource); + virtual void SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking); + virtual void ActivateGameOverlay(const char* pchDialog); + virtual void ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID); + virtual void ActivateGameOverlayToWebPage(const char* pchURL); + virtual void ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag); + virtual void SetPlayedWith(steam_id steamIDUserPlayedWith); + virtual void ActivateGameOverlayInviteDialog(steam_id steamIDLobby); + virtual int GetSmallFriendAvatar(steam_id steamIDFriend); + virtual int GetMediumFriendAvatar(steam_id steamIDFriend); + virtual int GetLargeFriendAvatar(steam_id steamIDFriend); + virtual bool RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly); + virtual unsigned long long RequestClanOfficerList(steam_id steamIDClan); + virtual steam_id GetClanOwner(steam_id steamIDClan); + virtual int GetClanOfficerCount(steam_id steamIDClan); + virtual steam_id GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer); + virtual int GetUserRestrictions(); + virtual bool SetRichPresence(const char* pchKey, const char* pchValue); + virtual void ClearRichPresence(); + virtual const char* GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey); + virtual int GetFriendRichPresenceKeyCount(steam_id steamIDFriend); + virtual const char* GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey); + virtual void RequestFriendRichPresence(steam_id steamIDFriend); + virtual bool InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString); + virtual int GetCoplayFriendCount(); + virtual steam_id GetCoplayFriend(int iCoplayFriend); + virtual int GetFriendCoplayTime(steam_id steamIDFriend); + virtual unsigned int GetFriendCoplayGame(steam_id steamIDFriend); + virtual unsigned long long JoinClanChatRoom(steam_id steamIDClan); + virtual bool LeaveClanChatRoom(steam_id steamIDClan); + virtual int GetClanChatMemberCount(steam_id steamIDClan); + virtual steam_id GetChatMemberByIndex(steam_id steamIDClan, int iUser); + virtual bool SendClanChatMessage(steam_id steamIDClanChat, const char* pchText); + virtual int GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void* prgchText, int cchTextMax, + unsigned int* peChatEntryType, steam_id* pSteamIDChatter); + virtual bool IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser); + virtual bool IsClanChatWindowOpenInSteam(steam_id steamIDClanChat); + virtual bool OpenClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool CloseClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool SetListenForFriendsMessages(bool bInterceptEnabled); + virtual bool ReplyToFriendMessage(steam_id steamIDFriend, const char* pchMsgToSend); + virtual int GetFriendMessage(steam_id steamIDFriend, int iMessageID, void* pvData, int cubData, + unsigned int* peChatEntryType); + virtual unsigned long long GetFollowerCount(steam_id steamID); + virtual unsigned long long IsFollowing(steam_id steamID); + virtual unsigned long long EnumerateFollowingList(unsigned int unStartIndex); + }; +} diff --git a/src/client/steam/interfaces/game_server.cpp b/src/client/steam/interfaces/game_server.cpp new file mode 100644 index 0000000..11e7a79 --- /dev/null +++ b/src/client/steam/interfaces/game_server.cpp @@ -0,0 +1,204 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool game_server::InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, + unsigned int unServerFlags, unsigned int nAppID, const char* pchVersion) + { + return true; + } + + void game_server::SetProduct(const char* pchProductName) + { + } + + void game_server::SetGameDescription(const char* pchGameDescription) + { + } + + void game_server::SetModDir(const char* pchModDir) + { + } + + void game_server::SetDedicatedServer(bool bDedicatedServer) + { + } + + void game_server::LogOn(const char* pszAccountName, const char* pszPassword) + { + } + + void game_server::LogOnAnonymous() + { + auto* const retvals = calloc(1, 1); + const auto result = callbacks::register_call(); + callbacks::return_call(retvals, 0, 101, result); + } + + void game_server::LogOff() + { + } + + bool game_server::BLoggedOn() + { + return true; + } + + bool game_server::BSecure() + { + return false; + } + + steam_id game_server::GetSteamID() + { + return SteamUser()->GetSteamID(); + } + + bool game_server::WasRestartRequested() + { + return false; + } + + void game_server::SetMaxPlayerCount(int cPlayersMax) + { + } + + void game_server::SetBotPlayerCount(int cBotPlayers) + { + } + + void game_server::SetServerName(const char* pszServerName) + { + } + + void game_server::SetMapName(const char* pszMapName) + { + } + + void game_server::SetPasswordProtected(bool bPasswordProtected) + { + } + + void game_server::SetSpectatorPort(unsigned short unSpectatorPort) + { + } + + void game_server::SetSpectatorServerName(const char* pszSpectatorServerName) + { + } + + void game_server::ClearAllKeyValues() + { + } + + void game_server::SetKeyValue(const char* pKey, const char* pValue) + { + } + + void game_server::SetGameTags(const char* pchGameTags) + { + } + + void game_server::SetGameData(const char* pchGameData) + { + } + + void game_server::SetRegion(const char* pchRegionName) + { + } + + int game_server::SendUserConnectAndAuthenticate(unsigned int unIPClient, const void* pvAuthBlob, + unsigned int cubAuthBlobSize, steam_id* pSteamIDUser) + { + return 0; + } + + steam_id game_server::CreateUnauthenticatedUserConnection() + { + return SteamUser()->GetSteamID(); + } + + void game_server::SendUserDisconnect(steam_id steamIDUser) + { + } + + bool game_server::BUpdateUserData(steam_id steamIDUser, const char* pchPlayerName, unsigned int uScore) + { + return false; + } + + int game_server::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + return 0; + } + + int game_server::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void game_server::EndAuthSession(steam_id steamID) + { + } + + void game_server::CancelAuthTicket(int hAuthTicket) + { + } + + int game_server::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool game_server::RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup) + { + return false; + } + + void game_server::GetGameplayStats() + { + } + + unsigned long long game_server::GetServerReputation() + { + return 0; + } + + unsigned int game_server::GetPublicIP() + { + return 0; + } + + bool game_server::HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort) + { + return false; + } + + int game_server::GetNextOutgoingPacket(void* pOut, int cbMaxOut, unsigned int* pNetAdr, unsigned short* pPort) + { + return 0; + } + + void game_server::EnableHeartbeats(bool bActive) + { + } + + void game_server::SetHeartbeatInterval(int iHeartbeatInterval) + { + } + + void game_server::ForceHeartbeat() + { + } + + unsigned long long game_server::AssociateWithClan(steam_id clanID) + { + return 0; + } + + unsigned long long game_server::ComputeNewPlayerCompatibility(steam_id steamID) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/game_server.hpp b/src/client/steam/interfaces/game_server.hpp new file mode 100644 index 0000000..3f7f7c7 --- /dev/null +++ b/src/client/steam/interfaces/game_server.hpp @@ -0,0 +1,57 @@ +#pragma once + +namespace steam +{ + class game_server + { + public: + ~game_server() = default; + + virtual bool InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, + unsigned int unServerFlags, unsigned int nAppID, const char* pchVersion); + virtual void SetProduct(const char* pchProductName); + virtual void SetGameDescription(const char* pchGameDescription); + virtual void SetModDir(const char* pchModDir); + virtual void SetDedicatedServer(bool bDedicatedServer); + virtual void LogOn(const char* pszAccountName, const char* pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual steam_id GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotPlayers); + virtual void SetServerName(const char* pszServerName); + virtual void SetMapName(const char* pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(unsigned short unSpectatorPort); + virtual void SetSpectatorServerName(const char* pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char* pKey, const char* pValue); + virtual void SetGameTags(const char* pchGameTags); + virtual void SetGameData(const char* pchGameData); + virtual void SetRegion(const char* pchRegionName); + virtual int SendUserConnectAndAuthenticate(unsigned int unIPClient, const void* pvAuthBlob, + unsigned int cubAuthBlobSize, steam_id* pSteamIDUser); + virtual steam_id CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(steam_id steamIDUser); + virtual bool BUpdateUserData(steam_id steamIDUser, const char* pchPlayerName, unsigned int uScore); + virtual int GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + virtual int BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(int hAuthTicket); + virtual int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup); + virtual void GetGameplayStats(); + virtual unsigned long long GetServerReputation(); + virtual unsigned int GetPublicIP(); + virtual bool HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort); + virtual int GetNextOutgoingPacket(void* pOut, int cbMaxOut, unsigned int* pNetAdr, unsigned short* pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual unsigned long long AssociateWithClan(steam_id clanID); + virtual unsigned long long ComputeNewPlayerCompatibility(steam_id steamID); + }; +} diff --git a/src/client/steam/interfaces/matchmaking.cpp b/src/client/steam/interfaces/matchmaking.cpp new file mode 100644 index 0000000..8b8dec7 --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.cpp @@ -0,0 +1,230 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + int matchmaking::GetFavoriteGameCount() + { + return 0; + } + + bool matchmaking::GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer) + { + return false; + } + + int matchmaking::AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer) + { + return 0; + } + + bool matchmaking::RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags) + { + return false; + } + + unsigned long long matchmaking::RequestLobbyList() + { + return 0; + } + + void matchmaking::AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo) + { + } + + void matchmaking::AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable) + { + } + + void matchmaking::AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter) + { + } + + void matchmaking::AddRequestLobbyListResultCountFilter(int cMaxResults) + { + } + + void matchmaking::AddRequestLobbyListCompatibleMembersFilter(steam_id steamID) + { + } + + steam_id matchmaking::GetLobbyByIndex(int iLobby) + { + steam_id id; + + id.raw.account_id = SteamUser()->GetSteamID().raw.account_id; + id.raw.universe = 1; + id.raw.account_type = 8; + id.raw.account_instance = 0x40000; + + return id; + } + + unsigned long long matchmaking::CreateLobby(int eLobbyType, int cMaxMembers) + { + const auto result = callbacks::register_call(); + auto retvals = static_cast(calloc(1, sizeof(lobby_created))); + //::Utils::Memory::AllocateArray(); + steam_id id; + + id.raw.account_id = SteamUser()->GetSteamID().raw.account_id; + id.raw.universe = 1; + id.raw.account_type = 8; + id.raw.account_instance = 0x40000; + + retvals->m_e_result = 1; + retvals->m_ul_steam_id_lobby = id; + + callbacks::return_call(retvals, sizeof(lobby_created), lobby_created::callback_id, result); + + matchmaking::JoinLobby(id); + + return result; + } + + unsigned long long matchmaking::JoinLobby(steam_id steamIDLobby) + { + const auto result = callbacks::register_call(); + auto* retvals = static_cast(calloc(1, sizeof(lobby_enter))); + //::Utils::Memory::AllocateArray(); + retvals->m_b_locked = false; + retvals->m_e_chat_room_enter_response = 1; + retvals->m_rgf_chat_permissions = 0xFFFFFFFF; + retvals->m_ul_steam_id_lobby = steamIDLobby; + + callbacks::return_call(retvals, sizeof(lobby_enter), lobby_enter::callback_id, result); + + return result; + } + + void matchmaking::LeaveLobby(steam_id steamIDLobby) + { + } + + bool matchmaking::InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee) + { + return true; + } + + int matchmaking::GetNumLobbyMembers(steam_id steamIDLobby) + { + return 1; + } + + steam_id matchmaking::GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember) + { + return SteamUser()->GetSteamID(); + } + + const char* matchmaking::GetLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return ""; + } + + bool matchmaking::SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + return true; + } + + int matchmaking::GetLobbyDataCount(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize) + { + return true; + } + + bool matchmaking::DeleteLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return true; + } + + const char* matchmaking::GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey) + { + return ""; + } + + void matchmaking::SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + } + + bool matchmaking::SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody) + { + return true; + } + + int matchmaking::GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType) + { + return 0; + } + + bool matchmaking::RequestLobbyData(steam_id steamIDLobby) + { + return true; + } + + void matchmaking::SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer) + { + } + + bool matchmaking::GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer) + { + return true; + } + + bool matchmaking::SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers) + { + return true; + } + + int matchmaking::GetLobbyMemberLimit(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::SetLobbyType(steam_id steamIDLobby, int eLobbyType) + { + return true; + } + + bool matchmaking::SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable) + { + return true; + } + + steam_id matchmaking::GetLobbyOwner(steam_id steamIDLobby) + { + return SteamUser()->GetSteamID(); + } + + bool matchmaking::SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner) + { + return true; + } + + bool matchmaking::SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2) + { + return true; + } +} diff --git a/src/client/steam/interfaces/matchmaking.hpp b/src/client/steam/interfaces/matchmaking.hpp new file mode 100644 index 0000000..8892321 --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace steam +{ + struct lobby_created final + { + enum { callback_id = 513 }; + + int m_e_result; + int m_pad; + steam_id m_ul_steam_id_lobby; + }; + + struct lobby_enter final + { + enum { callback_id = 504 }; + + steam_id m_ul_steam_id_lobby; + int m_rgf_chat_permissions; + bool m_b_locked; + int m_e_chat_room_enter_response; + }; + + class matchmaking + { + public: + ~matchmaking() = default; + + virtual int GetFavoriteGameCount(); + virtual bool GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer); + virtual int AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer); + virtual bool RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags); + virtual unsigned long long RequestLobbyList(); + virtual void AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo); + virtual void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable); + virtual void AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter); + virtual void AddRequestLobbyListResultCountFilter(int cMaxResults); + virtual void AddRequestLobbyListCompatibleMembersFilter(steam_id steamID); + virtual steam_id GetLobbyByIndex(int iLobby); + virtual unsigned long long CreateLobby(int eLobbyType, int cMaxMembers); + virtual unsigned long long JoinLobby(steam_id steamIDLobby); + virtual void LeaveLobby(steam_id steamIDLobby); + virtual bool InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee); + virtual int GetNumLobbyMembers(steam_id steamIDLobby); + virtual steam_id GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember); + virtual const char* GetLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual bool SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual int GetLobbyDataCount(steam_id steamIDLobby); + virtual bool GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize); + virtual bool DeleteLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual const char* GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey); + virtual void SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual bool SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody); + virtual int GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType); + virtual bool RequestLobbyData(steam_id steamIDLobby); + virtual void SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer); + virtual bool GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer); + virtual bool SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers); + virtual int GetLobbyMemberLimit(steam_id steamIDLobby); + virtual bool SetLobbyType(steam_id steamIDLobby, int eLobbyType); + virtual bool SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable); + virtual steam_id GetLobbyOwner(steam_id steamIDLobby); + virtual bool SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner); + virtual bool SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2); + }; +} diff --git a/src/client/steam/interfaces/networking.cpp b/src/client/steam/interfaces/networking.cpp new file mode 100644 index 0000000..d0ee6e0 --- /dev/null +++ b/src/client/steam/interfaces/networking.cpp @@ -0,0 +1,121 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool networking::SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType) + { + return false; + } + + bool networking::IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk) + { + return false; + } + + bool networking::ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote) + { + return false; + } + + bool networking::AcceptP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort) + { + return false; + } + + bool networking::GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState) + { + return false; + } + + bool networking::AllowP2PPacketRelay(bool bAllow) + { + return false; + } + + unsigned int networking::CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec) + { + return NULL; + } + + bool networking::DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable) + { + return false; + } + + bool networking::IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote) + { + return false; + } + + bool networking::GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort) + { + return false; + } + + int networking::GetSocketConnectionType(unsigned int hSocket) + { + return 0; + } + + int networking::GetMaxPacketSize(unsigned int hSocket) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/networking.hpp b/src/client/steam/interfaces/networking.hpp new file mode 100644 index 0000000..bb1b29d --- /dev/null +++ b/src/client/steam/interfaces/networking.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace steam +{ + class networking + { + public: + ~networking() = default; + + virtual bool SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType); + virtual bool IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk); + virtual bool ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote); + virtual bool AcceptP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort); + virtual bool GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState); + virtual bool AllowP2PPacketRelay(bool bAllow); + virtual unsigned int CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec); + virtual bool DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable); + virtual bool IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize); + virtual bool RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize); + virtual bool IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote); + virtual bool GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort); + virtual int GetSocketConnectionType(unsigned int hSocket); + virtual int GetMaxPacketSize(unsigned int hSocket); + }; +} diff --git a/src/client/steam/interfaces/remote_storage.cpp b/src/client/steam/interfaces/remote_storage.cpp new file mode 100644 index 0000000..02bc968 --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.cpp @@ -0,0 +1,283 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool remote_storage::FileWrite(const char* pchFile, const void* pvData, int cubData) + { + return true; + } + + int remote_storage::FileRead(const char* pchFile, void* pvData, int cubDataToRead) + { + return 0; + } + + bool remote_storage::FileForget(const char* pchFile) + { + return true; + } + + bool remote_storage::FileDelete(const char* pchFile) + { + return true; + } + + unsigned long long remote_storage::FileShare(const char* pchFile) + { + return 0; + } + + bool remote_storage::SetSyncPlatforms(const char* pchFile, unsigned int eRemoteStoragePlatform) + { + return true; + } + + unsigned long long remote_storage::FileWriteStreamOpen(const char* pchFile) + { + return 0; + } + + int remote_storage::FileWriteStreamWriteChunk(unsigned long long hStream, const void* pvData, int cubData) + { + return 1; + } + + int remote_storage::FileWriteStreamClose(unsigned long long hStream) + { + return 1; + } + + int remote_storage::FileWriteStreamCancel(unsigned long long hStream) + { + return 1; + } + + bool remote_storage::FileExists(const char* pchFile) + { + return true; + } + + bool remote_storage::FilePersisted(const char* pchFile) + { + return true; + } + + int remote_storage::GetFileSize(const char* pchFile) + { + return 0; + } + + long long remote_storage::GetFileTimestamp(const char* pchFile) + { + return 0; + } + + unsigned remote_storage::GetSyncPlatforms(const char* pchFile) + { + return 0; + } + + int remote_storage::GetFileCount() + { + return 0; + } + + const char* remote_storage::GetFileNameAndSize(int iFile, int* pnFileSizeInBytes) + { + *pnFileSizeInBytes = 0; + return ""; + } + + bool remote_storage::GetQuota(int* pnTotalBytes, int* puAvailableBytes) + { + *pnTotalBytes = 0x10000000; + *puAvailableBytes = 0x10000000; + return false; + } + + bool remote_storage::IsCloudEnabledForAccount() + { + return false; + } + + bool remote_storage::IsCloudEnabledForApp() + { + return false; + } + + void remote_storage::SetCloudEnabledForApp(bool bEnabled) + { + } + + unsigned long long remote_storage::UGCDownload(unsigned long long hContent, unsigned int uUnk) + { + return 0; + } + + bool remote_storage::GetUGCDownloadProgress(unsigned long long hContent, unsigned int* puDownloadedBytes, + unsigned int* puTotalBytes) + { + return false; + } + + bool remote_storage::GetUGCDetails(unsigned long long hContent, unsigned int* pnAppID, char** ppchName, + int* pnFileSizeInBytes, steam_id* pSteamIDOwner) + { + return false; + } + + int remote_storage::UGCRead(unsigned long long hContent, void* pvData, int cubDataToRead, unsigned int uOffset) + { + return 0; + } + + int remote_storage::GetCachedUGCCount() + { + return 0; + } + + unsigned long long remote_storage::GetCachedUGCHandle(int iCachedContent) + { + return 0; + } + + unsigned long long remote_storage::PublishWorkshopFile(const char* pchFile, const char* pchPreviewFile, + unsigned int nConsumerAppId, const char* pchTitle, + const char* pchDescription, unsigned int eVisibility, + int* pTags, unsigned int eWorkshopFileType) + { + return 0; + } + + unsigned long long remote_storage::CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char* pchFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char* pchPreviewFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char* pchTitle) + { + return false; + } + + bool remote_storage::UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char* pchDescription) + { + return false; + } + + bool remote_storage::UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTags(unsigned long long hUpdateRequest, int* pTags) + { + return false; + } + + unsigned long long remote_storage::CommitPublishedFileUpdate(unsigned long long hUpdateRequest) + { + return 0; + } + + unsigned long long remote_storage::GetPublishedFileDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::DeletePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserPublishedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::SubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSubscribedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::UnsubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, + const char* cszDescription) + { + return false; + } + + unsigned long long remote_storage::GetPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp) + { + return 0; + } + + unsigned long long remote_storage::GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, + unsigned int uStartIndex, int* pRequiredTags, + int* pExcludedTags) + { + return 0; + } + + unsigned long long remote_storage::PublishVideo(unsigned int eVideoProvider, const char* cszVideoAccountName, + const char* cszVideoIdentifier, const char* cszFileName, + unsigned int nConsumerAppId, const char* cszTitle, + const char* cszDescription, unsigned int eVisibility, int* pTags) + { + return 0; + } + + unsigned long long remote_storage::SetUserPublishedFileAction(unsigned long long unPublishedFileId, + unsigned int eAction) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedFilesByUserAction( + unsigned int eAction, unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, + unsigned int cDays, unsigned int cCount, + int* pTags, int* pUserTags) + { + return 0; + } + + unsigned long long remote_storage::UGCDownloadToLocation(unsigned long long hContent, const char* cszLocation, + unsigned int uUnk) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/remote_storage.hpp b/src/client/steam/interfaces/remote_storage.hpp new file mode 100644 index 0000000..ec0d64e --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.hpp @@ -0,0 +1,78 @@ +#pragma once + +namespace steam +{ + class remote_storage + { + public: + ~remote_storage() = default; + + virtual bool FileWrite(const char* pchFile, const void* pvData, int cubData); + virtual int FileRead(const char* pchFile, void* pvData, int cubDataToRead); + virtual bool FileForget(const char* pchFile); + virtual bool FileDelete(const char* pchFile); + virtual unsigned long long FileShare(const char* pchFile); + virtual bool SetSyncPlatforms(const char* pchFile, unsigned int eRemoteStoragePlatform); + virtual unsigned long long FileWriteStreamOpen(const char* pchFile); + virtual int FileWriteStreamWriteChunk(unsigned long long hStream, const void* pvData, int cubData); + virtual int FileWriteStreamClose(unsigned long long hStream); + virtual int FileWriteStreamCancel(unsigned long long hStream); + virtual bool FileExists(const char* pchFile); + virtual bool FilePersisted(const char* pchFile); + virtual int GetFileSize(const char* pchFile); + virtual long long GetFileTimestamp(const char* pchFile); + virtual unsigned int GetSyncPlatforms(const char* pchFile); + virtual int GetFileCount(); + virtual const char* GetFileNameAndSize(int iFile, int* pnFileSizeInBytes); + virtual bool GetQuota(int* pnTotalBytes, int* puAvailableBytes); + virtual bool IsCloudEnabledForAccount(); + virtual bool IsCloudEnabledForApp(); + virtual void SetCloudEnabledForApp(bool bEnabled); + virtual unsigned long long UGCDownload(unsigned long long hContent, unsigned int uUnk); + virtual bool GetUGCDownloadProgress(unsigned long long hContent, unsigned int* puDownloadedBytes, + unsigned int* puTotalBytes); + virtual bool GetUGCDetails(unsigned long long hContent, unsigned int* pnAppID, char** ppchName, + int* pnFileSizeInBytes, steam_id* pSteamIDOwner); + virtual int UGCRead(unsigned long long hContent, void* pvData, int cubDataToRead, unsigned int uOffset); + virtual int GetCachedUGCCount(); + virtual unsigned long long GetCachedUGCHandle(int iCachedContent); + virtual unsigned long long PublishWorkshopFile(const char* pchFile, const char* pchPreviewFile, + unsigned int nConsumerAppId, const char* pchTitle, + const char* pchDescription, unsigned int eVisibility, int* pTags, + unsigned int eWorkshopFileType); + virtual unsigned long long CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char* pchFile); + virtual bool UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char* pchPreviewFile); + virtual bool UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char* pchTitle); + virtual bool UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char* pchDescription); + virtual bool UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility); + virtual bool UpdatePublishedFileTags(unsigned long long hUpdateRequest, int* pTags); + virtual unsigned long long CommitPublishedFileUpdate(unsigned long long hUpdateRequest); + virtual unsigned long long GetPublishedFileDetails(unsigned long long unPublishedFileId); + virtual unsigned long long DeletePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserPublishedFiles(unsigned int uStartIndex); + virtual unsigned long long SubscribePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSubscribedFiles(unsigned int uStartIndex); + virtual unsigned long long UnsubscribePublishedFile(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, + const char* cszDescription); + virtual unsigned long long GetPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp); + virtual unsigned long long GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, + unsigned int uStartIndex, int* pRequiredTags, + int* pExcludedTags); + virtual unsigned long long PublishVideo(unsigned int eVideoProvider, const char* cszVideoAccountName, + const char* cszVideoIdentifier, const char* cszFileName, + unsigned int nConsumerAppId, const char* cszTitle, + const char* cszDescription, unsigned int eVisibility, int* pTags); + virtual unsigned long long SetUserPublishedFileAction(unsigned long long unPublishedFileId, + unsigned int eAction); + virtual unsigned long long EnumeratePublishedFilesByUserAction(unsigned int eAction, unsigned int uStartIndex); + virtual unsigned long long EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, + unsigned int cDays, unsigned int cCount, int* pTags, + int* pUserTags); + virtual unsigned long long UGCDownloadToLocation(unsigned long long hContent, const char* cszLocation, + unsigned int uUnk); + }; +} diff --git a/src/client/steam/interfaces/user.cpp b/src/client/steam/interfaces/user.cpp new file mode 100644 index 0000000..752007b --- /dev/null +++ b/src/client/steam/interfaces/user.cpp @@ -0,0 +1,164 @@ +#include +#include "../steam.hpp" + +#include "component/auth.hpp" + +namespace steam +{ + namespace + { + std::string auth_ticket; + + steam_id generate_steam_id() + { + steam_id id{}; + id.bits = auth::get_guid(); + return id; + } + } + + int user::GetHSteamUser() + { + return NULL; + } + + bool user::LoggedOn() + { + return true; + } + + steam_id user::GetSteamID() + { + static auto id = generate_steam_id(); + return id; + } + + int user::InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure) + { + return 0; + } + + void user::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer) + { + } + + void user::TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo) + { + } + + bool user::GetUserDataFolder(char* pchBuffer, int cubBuffer) + { + return false; + } + + void user::StartVoiceRecording() + { + } + + void user::StopVoiceRecording() + { + } + + int user::GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten) + { + return 0; + } + + unsigned int user::GetVoiceOptimalSampleRate() + { + return 0; + } + + unsigned int user::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + static uint32_t ticket = 0; + *pcbTicket = 1; + + const auto result = callbacks::register_call(); + auto* response = static_cast(calloc( + 1, sizeof(get_auth_session_ticket_response))); + response->m_h_auth_ticket = ++ticket; + response->m_e_result = 1; // k_EResultOK; + + callbacks::return_call(response, sizeof(get_auth_session_ticket_response), + get_auth_session_ticket_response::callback_id, result); + return response->m_h_auth_ticket; + } + + int user::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void user::EndAuthSession(steam_id steamID) + { + } + + void user::CancelAuthTicket(unsigned int hAuthTicket) + { + } + + unsigned int user::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool user::BIsBehindNAT() + { + return false; + } + + void user::AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer) + { + } + + unsigned long long user::RequestEncryptedAppTicket(void* pUserData, int cbUserData) + { + const auto id = this->GetSteamID(); + + auth_ticket = "S1"; + auth_ticket.resize(32); + auth_ticket.append(static_cast(pUserData), 24); // key + auth_ticket.append(reinterpret_cast(&id.bits), sizeof(id.bits)); // user id + auth_ticket.append(&static_cast(pUserData)[24], 64); // user name + + // Create the call response + const auto result = callbacks::register_call(); + const auto retvals = static_cast(calloc(1, sizeof(encrypted_app_ticket_response))); + //::Utils::Memory::AllocateArray(); + retvals->m_e_result = 1; + + // Return the call response + callbacks::return_call(retvals, sizeof(encrypted_app_ticket_response), + encrypted_app_ticket_response::callback_id, result); + + return result; + } + + bool user::GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + if (cbMaxTicket < 0 || auth_ticket.empty()) return false; + + const auto size = std::min(size_t(cbMaxTicket), auth_ticket.size()); + std::memcpy(pTicket, auth_ticket.data(), size); + *pcbTicket = static_cast(size); + + return true; + } +} diff --git a/src/client/steam/interfaces/user.hpp b/src/client/steam/interfaces/user.hpp new file mode 100644 index 0000000..07cd801 --- /dev/null +++ b/src/client/steam/interfaces/user.hpp @@ -0,0 +1,55 @@ +#pragma once + +namespace steam +{ + struct encrypted_app_ticket_response final + { + enum { callback_id = 154 }; + + int m_e_result; + }; + + struct get_auth_session_ticket_response + { + enum { callback_id = 163 }; + + unsigned int m_h_auth_ticket; + int m_e_result; + }; + + class user + { + public: + ~user() = default; + + virtual int GetHSteamUser(); + virtual bool LoggedOn(); + virtual steam_id GetSteamID(); + + virtual int InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure); + virtual void TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer); + virtual void TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo = ""); + virtual bool GetUserDataFolder(char* pchBuffer, int cubBuffer); + virtual void StartVoiceRecording(); + virtual void StopVoiceRecording(); + virtual int GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten); + virtual unsigned int GetVoiceOptimalSampleRate(); + virtual unsigned int GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + virtual int BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(unsigned int hAuthTicket); + virtual unsigned int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool BIsBehindNAT(); + virtual void AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer); + virtual unsigned long long RequestEncryptedAppTicket(void* pUserData, int cbUserData); + virtual bool GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + }; +} diff --git a/src/client/steam/interfaces/user_stats.cpp b/src/client/steam/interfaces/user_stats.cpp new file mode 100644 index 0000000..13d4ccc --- /dev/null +++ b/src/client/steam/interfaces/user_stats.cpp @@ -0,0 +1,231 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + bool user_stats::RequestCurrentStats() + { + return true; + } + + bool user_stats::GetStat(const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetStat(const char* pchName, float* pData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, int nData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, float fData) + { + return false; + } + + bool user_stats::UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength) + { + return false; + } + + bool user_stats::GetAchievement(const char* pchName, bool* pbAchieved) + { + return true; + } + + bool user_stats::SetAchievement(const char* pchName) + { + return true; + } + + bool user_stats::ClearAchievement(const char* pchName) + { + return true; + } + + bool user_stats::GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime) + { + return true; + } + + bool user_stats::StoreStats() + { + return true; + } + + int user_stats::GetAchievementIcon(const char* pchName) + { + return 0; + } + + const char* user_stats::GetAchievementDisplayAttribute(const char* pchName, const char* pchKey) + { + return ""; + } + + bool user_stats::IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress) + { + return true; + } + + unsigned int user_stats::GetNumAchievements() + { + return 0; + } + + const char* user_stats::GetAchievementName(unsigned int iAchievement) + { + return ""; + } + + unsigned long long user_stats::RequestUserStats(steam_id steamIDUser) + { + return 0; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, float* pData) + { + return false; + } + + bool user_stats::GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved) + { + return true; + } + + bool user_stats::GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime) + { + return true; + } + + bool user_stats::ResetAllStats(bool bAchievementsToo) + { + return false; + } + + unsigned long long user_stats::FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType) + { + return 0; + } + + unsigned long long user_stats::FindLeaderboard(const char* pchLeaderboardName) + { + return 0; + } + + const char* user_stats::GetLeaderboardName(unsigned long long hSteamLeaderboard) + { + return ""; + } + + int user_stats::GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, + int nRangeEnd) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers) + { + return 0; + } + + bool user_stats::GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax) + { + return false; + } + + unsigned long long user_stats::UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount) + { + return 0; + } + + unsigned long long user_stats::AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC) + { + return 0; + } + + unsigned long long user_stats::GetNumberOfCurrentPlayers() + { + return 0; + } + + unsigned long long user_stats::RequestGlobalAchievementPercentages() + { + return 0; + } + + int user_stats::GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved) + { + return 0; + } + + int user_stats::GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved) + { + return 0; + } + + bool user_stats::GetAchievementAchievedPercent(const char* pchName, float* pflPercent) + { + return true; + } + + unsigned long long user_stats::RequestGlobalStats(int nHistoryDays) + { + return 0; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, long long* pData) + { + return false; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, double* pData) + { + return false; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData) + { + return 0; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/user_stats.hpp b/src/client/steam/interfaces/user_stats.hpp new file mode 100644 index 0000000..c49c79d --- /dev/null +++ b/src/client/steam/interfaces/user_stats.hpp @@ -0,0 +1,65 @@ +#pragma once + +namespace steam +{ + class user_stats + { + public: + ~user_stats() = default; + + virtual bool RequestCurrentStats(); + virtual bool GetStat(const char* pchName, int* pData); + virtual bool GetStat(const char* pchName, float* pData); + virtual bool SetStat(const char* pchName, int nData); + virtual bool SetStat(const char* pchName, float fData); + virtual bool UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength); + virtual bool GetAchievement(const char* pchName, bool* pbAchieved); + virtual bool SetAchievement(const char* pchName); + virtual bool ClearAchievement(const char* pchName); + virtual bool GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime); + virtual bool StoreStats(); + virtual int GetAchievementIcon(const char* pchName); + virtual const char* GetAchievementDisplayAttribute(const char* pchName, const char* pchKey); + virtual bool IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress); + virtual unsigned int GetNumAchievements(); + virtual const char* GetAchievementName(unsigned int iAchievement); + virtual unsigned long long RequestUserStats(steam_id steamIDUser); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, int* pData); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, float* pData); + virtual bool GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved); + virtual bool GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime); + virtual bool ResetAllStats(bool bAchievementsToo); + virtual unsigned long long FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType); + virtual unsigned long long FindLeaderboard(const char* pchLeaderboardName); + virtual const char* GetLeaderboardName(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard); + virtual unsigned long long DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, + int nRangeEnd); + virtual unsigned long long DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers); + virtual bool GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax); + virtual unsigned long long UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount); + virtual unsigned long long AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC); + virtual unsigned long long GetNumberOfCurrentPlayers(); + virtual unsigned long long RequestGlobalAchievementPercentages(); + virtual int GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved); + virtual int GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved); + virtual bool GetAchievementAchievedPercent(const char* pchName, float* pflPercent); + virtual unsigned long long RequestGlobalStats(int nHistoryDays); + virtual bool GetGlobalStat(const char* pchStatName, long long* pData); + virtual bool GetGlobalStat(const char* pchStatName, double* pData); + virtual int GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData); + virtual int GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData); + }; +} diff --git a/src/client/steam/interfaces/utils.cpp b/src/client/steam/interfaces/utils.cpp new file mode 100644 index 0000000..60339f9 --- /dev/null +++ b/src/client/steam/interfaces/utils.cpp @@ -0,0 +1,118 @@ +#include +#include "../steam.hpp" + +namespace steam +{ + unsigned int utils::GetSecondsSinceAppActive() + { + return 0; + } + + unsigned int utils::GetSecondsSinceComputerActive() + { + return (uint32_t)GetTickCount64() / 1000; + } + + int utils::GetConnectedUniverse() + { + return 1; + } + + unsigned int utils::GetServerRealTime() + { + return (uint32_t)time(NULL); + } + + const char* utils::GetIPCountry() + { + return "US"; + } + + bool utils::GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight) + { + return false; + } + + bool utils::GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize) + { + return false; + } + + bool utils::GetCSERIPPort(unsigned int* unIP, unsigned short* usPort) + { + return false; + } + + unsigned char utils::GetCurrentBatteryPower() + { + return 255; + } + + unsigned int utils::GetAppID() + { + return 209660; + } + + void utils::SetOverlayNotificationPosition(int eNotificationPosition) + { + } + + bool utils::IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed) + { + return false; + } + + int utils::GetAPICallFailureReason(unsigned long long hSteamAPICall) + { + return -1; + } + + bool utils::GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed) + { + return false; + } + + void utils::RunFrame() + { + } + + unsigned int utils::GetIPCCallCount() + { + return 0; + } + + void utils::SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)) + { + } + + bool utils::IsOverlayEnabled() + { + return false; + } + + bool utils::BOverlayNeedsPresent() + { + return false; + } + + unsigned long long utils::CheckFileSignature(const char* szFileName) + { + return 0; + } + + bool utils::ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char* szText, unsigned int uMaxLength) + { + return false; + } + + unsigned int utils::GetEnteredGamepadTextLength() + { + return 0; + } + + bool utils::GetEnteredGamepadTextInput(char* pchValue, unsigned int cchValueMax) + { + return false; + } +} diff --git a/src/client/steam/interfaces/utils.hpp b/src/client/steam/interfaces/utils.hpp new file mode 100644 index 0000000..d42a27f --- /dev/null +++ b/src/client/steam/interfaces/utils.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace steam +{ + class utils + { + public: + ~utils() = default; + + virtual unsigned int GetSecondsSinceAppActive(); + virtual unsigned int GetSecondsSinceComputerActive(); + virtual int GetConnectedUniverse(); + virtual unsigned int GetServerRealTime(); + virtual const char* GetIPCountry(); + virtual bool GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight); + virtual bool GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize); + virtual bool GetCSERIPPort(unsigned int* unIP, unsigned short* usPort); + virtual unsigned char GetCurrentBatteryPower(); + virtual unsigned int GetAppID(); + virtual void SetOverlayNotificationPosition(int eNotificationPosition); + virtual bool IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed); + virtual int GetAPICallFailureReason(unsigned long long hSteamAPICall); + virtual bool GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed); + virtual void RunFrame(); + virtual unsigned int GetIPCCallCount(); + virtual void SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)); + virtual bool IsOverlayEnabled(); + virtual bool BOverlayNeedsPresent(); + virtual unsigned long long CheckFileSignature(const char* szFileName); + + virtual bool ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char* szText, + unsigned int uMaxLength); + virtual unsigned int GetEnteredGamepadTextLength(); + virtual bool GetEnteredGamepadTextInput(char* pchValue, unsigned int cchValueMax); + }; +} diff --git a/src/client/steam/steam.cpp b/src/client/steam/steam.cpp new file mode 100644 index 0000000..b6fb0db --- /dev/null +++ b/src/client/steam/steam.cpp @@ -0,0 +1,238 @@ +#include +#include "steam.hpp" + +namespace steam +{ + uint64_t callbacks::call_id_ = 0; + std::recursive_mutex callbacks::mutex_; + std::map callbacks::calls_; + std::map callbacks::result_handlers_; + std::vector callbacks::results_; + std::vector callbacks::callback_list_; + + uint64_t callbacks::register_call() + { + std::lock_guard _(mutex_); + calls_[++call_id_] = false; + return call_id_; + } + + void callbacks::register_callback(base* handler, const int callback) + { + std::lock_guard _(mutex_); + handler->set_i_callback(callback); + callback_list_.push_back(handler); + } + + void callbacks::unregister_callback(base* handler) + { + std::lock_guard _(mutex_); + for (auto i = callback_list_.begin(); i != callback_list_.end();) + { + if (*i == handler) + { + i = callback_list_.erase(i); + } + else + { + ++i; + } + } + } + + void callbacks::register_call_result(const uint64_t call, base* result) + { + std::lock_guard _(mutex_); + result_handlers_[call] = result; + } + + void callbacks::unregister_call_result(const uint64_t call, base* /*result*/) + { + std::lock_guard _(mutex_); + const auto i = result_handlers_.find(call); + if (i != result_handlers_.end()) + { + result_handlers_.erase(i); + } + } + + void callbacks::return_call(void* data, const int size, const int type, const uint64_t call) + { + std::lock_guard _(mutex_); + + result result{}; + result.call = call; + result.data = data; + result.size = size; + result.type = type; + + calls_[call] = true; + + results_.emplace_back(result); + } + + void callbacks::run_callbacks() + { + std::lock_guard _(mutex_); + + for (const auto& result : results_) + { + if (result_handlers_.find(result.call) != result_handlers_.end()) + { + result_handlers_[result.call]->run(result.data, false, result.call); + } + + for (const auto& callback : callback_list_) + { + if (callback && callback->get_i_callback() == result.type) + { + callback->run(result.data, false, 0); + } + } + + if (result.data) + { + free(result.data); + } + } + + results_.clear(); + } + + extern "C" { + + bool SteamAPI_RestartAppIfNecessary() + { + return false; + } + + bool SteamAPI_Init() + { + return true; + } + + void SteamAPI_RegisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::register_call_result(call, result); + } + + void SteamAPI_RegisterCallback(callbacks::base* handler, const int callback) + { + callbacks::register_callback(handler, callback); + } + + void SteamAPI_RunCallbacks() + { + callbacks::run_callbacks(); + } + + void SteamAPI_Shutdown() + { + } + + void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::unregister_call_result(call, result); + } + + void SteamAPI_UnregisterCallback(callbacks::base* handler) + { + callbacks::unregister_callback(handler); + } + + const char* SteamAPI_GetSteamInstallPath() + { + static std::string install_path{}; + if (!install_path.empty()) + { + return install_path.data(); + } + + HKEY reg_key; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\WOW6432Node\\Valve\\Steam", 0, KEY_QUERY_VALUE, + ®_key) == + ERROR_SUCCESS) + { + char path[MAX_PATH] = {0}; + DWORD length = sizeof(path); + RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), + &length); + RegCloseKey(reg_key); + + install_path = path; + } + + return install_path.data(); + } + + + bool SteamGameServer_Init() + { + return true; + } + + void SteamGameServer_RunCallbacks() + { + } + + void SteamGameServer_Shutdown() + { + } + + + friends* SteamFriends() + { + static friends friends; + return &friends; + } + + matchmaking* SteamMatchmaking() + { + static matchmaking matchmaking; + return &matchmaking; + } + + game_server* SteamGameServer() + { + static game_server game_server; + return &game_server; + } + + networking* SteamNetworking() + { + static networking networking; + return &networking; + } + + remote_storage* SteamRemoteStorage() + { + static remote_storage remote_storage; + return &remote_storage; + } + + user* SteamUser() + { + static user user; + return &user; + } + + utils* SteamUtils() + { + static utils utils; + return &utils; + } + + apps* SteamApps() + { + static apps apps; + return &apps; + } + + user_stats* SteamUserStats() + { + static user_stats user_stats; + return &user_stats; + } + + } +} diff --git a/src/client/steam/steam.hpp b/src/client/steam/steam.hpp new file mode 100644 index 0000000..3018921 --- /dev/null +++ b/src/client/steam/steam.hpp @@ -0,0 +1,121 @@ +#pragma once + +#define STEAM_EXPORT extern "C" __declspec(dllexport) + +struct raw_steam_id final +{ + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; +}; + +typedef union +{ + raw_steam_id raw; + unsigned long long bits; +} steam_id; + +#pragma pack( push, 1 ) +struct raw_game_id final +{ + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; +}; + +typedef union +{ + raw_game_id raw; + unsigned long long bits; +} game_id; +#pragma pack( pop ) + +#include "interfaces/apps.hpp" +#include "interfaces/user.hpp" +#include "interfaces/utils.hpp" +#include "interfaces/friends.hpp" +#include "interfaces/user_stats.hpp" +#include "interfaces/game_server.hpp" +#include "interfaces/networking.hpp" +#include "interfaces/matchmaking.hpp" +#include "interfaces/remote_storage.hpp" + +namespace steam +{ + class callbacks + { + public: + class base + { + public: + base() : flags_(0), callback_(0) + { + } + + virtual void run(void* pv_param) = 0; + virtual void run(void* pv_param, bool failure, uint64_t handle) = 0; + virtual int get_callback_size_bytes() = 0; + + int get_i_callback() const { return callback_; } + void set_i_callback(const int i_callback) { callback_ = i_callback; } + + protected: + ~base() = default; + + unsigned char flags_; + int callback_; + }; + + struct result final + { + void* data{}; + int size{}; + int type{}; + uint64_t call{}; + }; + + static uint64_t register_call(); + + static void register_callback(base* handler, int callback); + static void unregister_callback(base* handler); + + static void register_call_result(uint64_t call, base* result); + static void unregister_call_result(uint64_t call, base* result); + + static void return_call(void* data, int size, int type, uint64_t call); + static void run_callbacks(); + + private: + static uint64_t call_id_; + static std::recursive_mutex mutex_; + static std::map calls_; + static std::map result_handlers_; + static std::vector results_; + static std::vector callback_list_; + }; + + STEAM_EXPORT bool SteamAPI_RestartAppIfNecessary(); + STEAM_EXPORT bool SteamAPI_Init(); + STEAM_EXPORT void SteamAPI_RegisterCallResult(callbacks::base* result, uint64_t call); + STEAM_EXPORT void SteamAPI_RegisterCallback(callbacks::base* handler, int callback); + STEAM_EXPORT void SteamAPI_RunCallbacks(); + STEAM_EXPORT void SteamAPI_Shutdown(); + STEAM_EXPORT void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call); + STEAM_EXPORT void SteamAPI_UnregisterCallback(callbacks::base* handler); + STEAM_EXPORT const char* SteamAPI_GetSteamInstallPath(); + + STEAM_EXPORT bool SteamGameServer_Init(); + STEAM_EXPORT void SteamGameServer_RunCallbacks(); + STEAM_EXPORT void SteamGameServer_Shutdown(); + + STEAM_EXPORT friends* SteamFriends(); + STEAM_EXPORT matchmaking* SteamMatchmaking(); + STEAM_EXPORT game_server* SteamGameServer(); + STEAM_EXPORT networking* SteamNetworking(); + STEAM_EXPORT remote_storage* SteamRemoteStorage(); + STEAM_EXPORT user* SteamUser(); + STEAM_EXPORT utils* SteamUtils(); + STEAM_EXPORT apps* SteamApps(); + STEAM_EXPORT user_stats* SteamUserStats(); +} diff --git a/src/common/utils/binary_resource.cpp b/src/common/utils/binary_resource.cpp new file mode 100644 index 0000000..eed83b0 --- /dev/null +++ b/src/common/utils/binary_resource.cpp @@ -0,0 +1,75 @@ +#include "binary_resource.hpp" + +#include +#include "nt.hpp" +#include "io.hpp" + +namespace utils +{ + namespace + { + std::string get_temp_folder() + { + char path[MAX_PATH] = {0}; + if (!GetTempPathA(sizeof(path), path)) + { + throw std::runtime_error("Unable to get temp path"); + } + + return path; + } + + std::string write_existing_temp_file(const std::string& file, const std::string& data, + const bool fatal_if_overwrite_fails) + { + const auto temp = get_temp_folder(); + auto file_path = temp + file; + + std::string current_data; + if (!io::read_file(file_path, ¤t_data)) + { + if (!io::write_file(file_path, data)) + { + throw std::runtime_error("Failed to write file: " + file_path); + } + + return file_path; + } + + if (current_data == data || io::write_file(file_path, data) || !fatal_if_overwrite_fails) + { + return file_path; + } + + throw std::runtime_error( + "Temporary file was already written, but differs. It can't be overwritten as it's still in use: " + + file_path); + } + } + + binary_resource::binary_resource(const int id, std::string file) + : filename_(std::move(file)) + { + this->resource_ = nt::load_resource(id); + + if (this->resource_.empty()) + { + throw std::runtime_error("Unable to load resource: " + std::to_string(id)); + } + } + + std::string binary_resource::get_extracted_file(const bool fatal_if_overwrite_fails) + { + if (this->path_.empty()) + { + this->path_ = write_existing_temp_file(this->filename_, this->resource_, fatal_if_overwrite_fails); + } + + return this->path_; + } + + const std::string& binary_resource::get_data() const + { + return this->resource_; + } +} diff --git a/src/common/utils/binary_resource.hpp b/src/common/utils/binary_resource.hpp new file mode 100644 index 0000000..da19af1 --- /dev/null +++ b/src/common/utils/binary_resource.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace utils +{ + class binary_resource + { + public: + binary_resource(int id, std::string file); + + std::string get_extracted_file(bool fatal_if_overwrite_fails = false); + const std::string& get_data() const; + + private: + std::string resource_; + std::string filename_; + std::string path_; + }; +} diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp new file mode 100644 index 0000000..1688cee --- /dev/null +++ b/src/common/utils/compression.cpp @@ -0,0 +1,169 @@ +#include "memory.hpp" +#include "compression.hpp" + +#include +#include + +#include + +#include "io.hpp" + +namespace utils::compression +{ + namespace zlib + { + namespace + { + class zlib_stream + { + public: + zlib_stream() + { + memset(&stream_, 0, sizeof(stream_)); + valid_ = inflateInit(&stream_) == Z_OK; + } + + zlib_stream(zlib_stream&&) = delete; + zlib_stream(const zlib_stream&) = delete; + zlib_stream& operator=(zlib_stream&&) = delete; + zlib_stream& operator=(const zlib_stream&) = delete; + + ~zlib_stream() + { + if (valid_) + { + inflateEnd(&stream_); + } + } + + z_stream& get() + { + return stream_; // + } + + bool is_valid() const + { + return valid_; + } + + private: + bool valid_{false}; + z_stream stream_{}; + }; + } + + std::string decompress(const std::string& data) + { + std::string buffer{}; + zlib_stream stream_container{}; + if (!stream_container.is_valid()) + { + return {}; + } + + int ret{}; + size_t offset = 0; + static thread_local uint8_t dest[CHUNK] = {0}; + auto& stream = stream_container.get(); + + do + { + const auto input_size = std::min(sizeof(dest), data.size() - offset); + stream.avail_in = static_cast(input_size); + stream.next_in = reinterpret_cast(data.data()) + offset; + offset += stream.avail_in; + + do + { + stream.avail_out = sizeof(dest); + stream.next_out = dest; + + ret = inflate(&stream, Z_NO_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + return {}; + } + + buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out); + } + while (stream.avail_out == 0); + } + while (ret != Z_STREAM_END); + + return buffer; + } + + std::string compress(const std::string& data) + { + std::string result{}; + auto length = compressBound(static_cast(data.size())); + result.resize(length); + + if (compress2(reinterpret_cast(result.data()), &length, + reinterpret_cast(data.data()), static_cast(data.size()), + Z_BEST_COMPRESSION) != Z_OK) + { + return {}; + } + + result.resize(length); + return result; + } + } + + namespace zip + { + namespace + { + bool add_file(zipFile& zip_file, const std::string& filename, const std::string& data) + { + const auto zip_64 = data.size() > 0xffffffff ? 1 : 0; + if (ZIP_OK != zipOpenNewFileInZip64(zip_file, filename.data(), nullptr, nullptr, 0, nullptr, 0, nullptr, + Z_DEFLATED, Z_BEST_COMPRESSION, zip_64)) + { + return false; + } + + const auto _ = gsl::finally([&zip_file]() + { + zipCloseFileInZip(zip_file); + }); + + return ZIP_OK == zipWriteInFileInZip(zip_file, data.data(), static_cast(data.size())); + } + } + + void archive::add(std::string filename, std::string data) + { + this->files_[std::move(filename)] = std::move(data); + } + + bool archive::write(const std::string& filename, const std::string& comment) + { + // Hack to create the directory :3 + io::write_file(filename, {}); + io::remove_file(filename); + + auto* zip_file = zipOpen64(filename.data(), 0); + if (!zip_file) + { + return false; + } + + const auto _ = gsl::finally([&zip_file, &comment]() + { + zipClose(zip_file, comment.empty() ? nullptr : comment.data()); + }); + + for (const auto& file : this->files_) + { + if (!add_file(zip_file, file.first, file.second)) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp new file mode 100644 index 0000000..dfe36ad --- /dev/null +++ b/src/common/utils/compression.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#define CHUNK 16384u + +namespace utils::compression +{ + namespace zlib + { + std::string compress(const std::string& data); + std::string decompress(const std::string& data); + } + + namespace zip + { + class archive + { + public: + void add(std::string filename, std::string data); + bool write(const std::string& filename, const std::string& comment = {}); + + private: + std::unordered_map files_; + }; + } +}; diff --git a/src/common/utils/concurrency.hpp b/src/common/utils/concurrency.hpp new file mode 100644 index 0000000..05c5d3a --- /dev/null +++ b/src/common/utils/concurrency.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace utils::concurrency +{ + template + class container + { + public: + template + R access(F&& accessor) const + { + std::lock_guard _{mutex_}; + return accessor(object_); + } + + template + R access(F&& accessor) + { + std::lock_guard _{mutex_}; + return accessor(object_); + } + + template + R access_with_lock(F&& accessor) const + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } + + template + R access_with_lock(F&& accessor) + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } + + T& get_raw() { return object_; } + const T& get_raw() const { return object_; } + + private: + mutable MutexType mutex_{}; + T object_{}; + }; +} diff --git a/src/common/utils/cryptography.cpp b/src/common/utils/cryptography.cpp new file mode 100644 index 0000000..2e2065a --- /dev/null +++ b/src/common/utils/cryptography.cpp @@ -0,0 +1,640 @@ +#include "string.hpp" +#include "cryptography.hpp" +#include "nt.hpp" +#include + +#undef max +using namespace std::string_literals; + +/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf + +namespace utils::cryptography +{ + namespace + { + struct __ + { + __() + { + ltc_mp = ltm_desc; + + register_cipher(&aes_desc); + register_cipher(&des3_desc); + + register_prng(&sprng_desc); + register_prng(&fortuna_desc); + register_prng(&yarrow_desc); + + register_hash(&sha1_desc); + register_hash(&sha256_desc); + register_hash(&sha512_desc); + } + } ___; + + [[maybe_unused]] const char* cs(const uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] char* cs(uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] const uint8_t* cs(const char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] uint8_t* cs(char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] unsigned long ul(const size_t value) + { + return static_cast(value); + } + + class prng + { + public: + prng(const ltc_prng_descriptor& descriptor, const bool autoseed = true) + : state_(std::make_unique()) + , descriptor_(descriptor) + { + this->id_ = register_prng(&descriptor); + if (this->id_ == -1) + { + throw std::runtime_error("PRNG "s + this->descriptor_.name + " could not be registered!"); + } + + if (autoseed) + { + this->auto_seed(); + } + else + { + this->descriptor_.start(this->state_.get()); + } + } + + ~prng() + { + this->descriptor_.done(this->state_.get()); + } + + prng_state* get_state() const + { + this->descriptor_.ready(this->state_.get()); + return this->state_.get(); + } + + int get_id() const + { + return this->id_; + } + + void add_entropy(const void* data, const size_t length) const + { + this->descriptor_.add_entropy(static_cast(data), ul(length), this->state_.get()); + } + + void read(void* data, const size_t length) const + { + this->descriptor_.read(static_cast(data), ul(length), this->get_state()); + } + + private: + int id_; + std::unique_ptr state_; + const ltc_prng_descriptor& descriptor_; + + void auto_seed() const + { + rng_make_prng(128, this->id_, this->state_.get(), nullptr); + + int i[4]; // uninitialized data + auto* i_ptr = &i; + this->add_entropy(reinterpret_cast(&i), sizeof(i)); + this->add_entropy(reinterpret_cast(&i_ptr), sizeof(i_ptr)); + + auto t = time(nullptr); + this->add_entropy(reinterpret_cast(&t), sizeof(t)); + } + }; + + const prng prng_(fortuna_desc); + } + + ecc::key::key() + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + ecc::key::~key() + { + this->free(); + } + + ecc::key::key(key&& obj) noexcept + : key() + { + this->operator=(std::move(obj)); + } + + ecc::key::key(const key& obj) + : key() + { + this->operator=(obj); + } + + ecc::key& ecc::key::operator=(key&& obj) noexcept + { + if (this != &obj) + { + std::memmove(&this->key_storage_, &obj.key_storage_, sizeof(this->key_storage_)); + ZeroMemory(&obj.key_storage_, sizeof(obj.key_storage_)); + } + + return *this; + } + + ecc::key& ecc::key::operator=(const key& obj) + { + if (this != &obj && obj.is_valid()) + { + this->deserialize(obj.serialize(obj.key_storage_.type)); + } + + return *this; + } + + bool ecc::key::is_valid() const + { + return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); + } + + ecc_key& ecc::key::get() + { + return this->key_storage_; + } + + const ecc_key& ecc::key::get() const + { + return this->key_storage_; + } + + std::string ecc::key::get_public_key() const + { + uint8_t buffer[512] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return {}; + } + + void ecc::key::set(const std::string& pub_key_buffer) + { + this->free(); + + if (ecc_ansi_x963_import(cs(pub_key_buffer.data()), + ul(pub_key_buffer.size()), + &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + void ecc::key::deserialize(const std::string& key) + { + this->free(); + + if (ecc_import(cs(key.data()), ul(key.size()), + &this->key_storage_) != CRYPT_OK + ) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + std::string ecc::key::serialize(const int type) const + { + uint8_t buffer[4096] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return ""; + } + + void ecc::key::free() + { + if (this->is_valid()) + { + ecc_free(&this->key_storage_); + } + + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + bool ecc::key::operator==(key& key) const + { + return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); + } + + uint64_t ecc::key::get_hash() const + { + const auto hash = sha1::compute(this->get_public_key()); + if (hash.size() >= 8) + { + return *reinterpret_cast(hash.data()); + } + + return 0; + } + + ecc::key ecc::generate_key(const int bits) + { + key key; + ecc_make_key(prng_.get_state(), prng_.get_id(), bits / 8, &key.get()); + + return key; + } + + ecc::key ecc::generate_key(const int bits, const std::string& entropy) + { + key key{}; + const prng yarrow(yarrow_desc, false); + yarrow.add_entropy(entropy.data(), entropy.size()); + + ecc_make_key(yarrow.get_state(), yarrow.get_id(), bits / 8, &key.get()); + + return key; + } + + std::string ecc::sign_message(const key& key, const std::string& message) + { + if (!key.is_valid()) return ""; + + uint8_t buffer[512]; + unsigned long length = sizeof(buffer); + + ecc_sign_hash(cs(message.data()), ul(message.size()), buffer, &length, prng_.get_state(), prng_.get_id(), + &key.get()); + + return std::string(cs(buffer), length); + } + + bool ecc::verify_message(const key& key, const std::string& message, const std::string& signature) + { + if (!key.is_valid()) return false; + + auto result = 0; + return (ecc_verify_hash(cs(signature.data()), + ul(signature.size()), + cs(message.data()), + ul(message.size()), &result, + &key.get()) == CRYPT_OK && result != 0); + } + + bool ecc::encrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, + prng_.get_state(), prng_.get_id(), find_hash("sha512"), &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + bool ecc::decrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_decrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) + { + rsa_key new_key; + rsa_import(cs(key.data()), ul(key.size()), &new_key); + const auto _ = gsl::finally([&]() + { + rsa_free(&new_key); + }); + + + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return rsa_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, cs(hash.data()), + ul(hash.size()), prng_.get_state(), prng_.get_id(), find_hash("sha512"), &new_key); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res == CRYPT_OK) + { + out_data.resize(out_len); + return out_data; + } + + return {}; + } + + std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), cs(enc_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), cs(dec_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string tiger::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[24] = {0}; + + hash_state state; + tiger_init(&state); + tiger_process(&state, data, ul(length)); + tiger_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string aes::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), + cs(enc_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string aes::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), + cs(dec_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string hmac_sha1::compute(const std::string& data, const std::string& key) + { + std::string buffer; + buffer.resize(20); + + hmac_state state; + hmac_init(&state, find_hash("sha1"), cs(key.data()), ul(key.size())); + hmac_process(&state, cs(data.data()), static_cast(data.size())); + + auto out_len = ul(buffer.size()); + hmac_done(&state, cs(buffer.data()), &out_len); + + buffer.resize(out_len); + return buffer; + } + + std::string sha1::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[20] = {0}; + + hash_state state; + sha1_init(&state); + sha1_process(&state, data, ul(length)); + sha1_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha256::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[32] = {0}; + + hash_state state; + sha256_init(&state); + sha256_process(&state, data, ul(length)); + sha256_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha512::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[64] = {0}; + + hash_state state; + sha512_init(&state); + sha512_process(&state, data, ul(length)); + sha512_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string base64::encode(const uint8_t* data, const size_t len) + { + std::string result; + result.resize((len + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_encode(data, ul(len), result.data(), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + std::string base64::encode(const std::string& data) + { + return base64::encode(cs(data.data()), static_cast(data.size())); + } + + std::string base64::decode(const std::string& data) + { + std::string result; + result.resize((data.size() + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_decode(data.data(), ul(data.size()), cs(result.data()), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + unsigned int jenkins_one_at_a_time::compute(const std::string& data) + { + return compute(data.data(), data.size()); + } + + unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) + { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } + + uint32_t random::get_integer() + { + uint32_t result; + random::get_data(&result, sizeof(result)); + return result; + } + + std::string random::get_challenge() + { + std::string result; + result.resize(sizeof(uint32_t)); + random::get_data(result.data(), result.size()); + return string::dump_hex(result, ""); + } + + void random::get_data(void* data, const size_t size) + { + prng_.read(data, size); + } +} diff --git a/src/common/utils/cryptography.hpp b/src/common/utils/cryptography.hpp new file mode 100644 index 0000000..9538c5e --- /dev/null +++ b/src/common/utils/cryptography.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include + +namespace utils::cryptography +{ + namespace ecc + { + class key final + { + public: + key(); + ~key(); + + key(key&& obj) noexcept; + key(const key& obj); + key& operator=(key&& obj) noexcept; + key& operator=(const key& obj); + + bool is_valid() const; + + ecc_key& get(); + const ecc_key& get() const; + + std::string get_public_key() const; + + void set(const std::string& pub_key_buffer); + + void deserialize(const std::string& key); + + std::string serialize(int type = PK_PRIVATE) const; + + void free(); + + bool operator==(key& key) const; + + uint64_t get_hash() const; + + private: + ecc_key key_storage_{}; + }; + + key generate_key(int bits); + key generate_key(int bits, const std::string& entropy); + std::string sign_message(const key& key, const std::string& message); + bool verify_message(const key& key, const std::string& message, const std::string& signature); + + bool encrypt(const key& key, std::string& data); + bool decrypt(const key& key, std::string& data); + } + + namespace rsa + { + std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); + } + + namespace des3 + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace tiger + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace aes + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace hmac_sha1 + { + std::string compute(const std::string& data, const std::string& key); + } + + namespace sha1 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha256 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha512 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace base64 + { + std::string encode(const uint8_t* data, size_t len); + std::string encode(const std::string& data); + std::string decode(const std::string& data); + } + + namespace jenkins_one_at_a_time + { + unsigned int compute(const std::string& data); + unsigned int compute(const char* key, size_t len); + }; + + namespace random + { + uint32_t get_integer(); + std::string get_challenge(); + void get_data(void* data, size_t size); + } +} diff --git a/src/common/utils/flags.cpp b/src/common/utils/flags.cpp new file mode 100644 index 0000000..a90247a --- /dev/null +++ b/src/common/utils/flags.cpp @@ -0,0 +1,47 @@ +#include "flags.hpp" +#include "string.hpp" +#include "nt.hpp" + +#include + +namespace utils::flags +{ + void parse_flags(std::vector& flags) + { + int num_args; + auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args); + + flags.clear(); + + if (argv) + { + for (auto i = 0; i < num_args; ++i) + { + std::wstring wide_flag(argv[i]); + if (wide_flag[0] == L'-') + { + wide_flag.erase(wide_flag.begin()); + const auto flag = string::convert(wide_flag); + flags.emplace_back(string::to_lower(flag)); + } + } + + LocalFree(argv); + } + } + + bool has_flag(const std::string& flag) + { + static auto parsed = false; + static std::vector enabled_flags; + + if (!parsed) + { + parse_flags(enabled_flags); + parsed = true; + } + + return std::ranges::any_of(enabled_flags.cbegin(), enabled_flags.cend(), + [flag](const auto& elem) { return elem == string::to_lower(flag); }); + } +} diff --git a/src/common/utils/flags.hpp b/src/common/utils/flags.hpp new file mode 100644 index 0000000..cf304b2 --- /dev/null +++ b/src/common/utils/flags.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::flags +{ + bool has_flag(const std::string& flag); +} diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp new file mode 100644 index 0000000..be05cb9 --- /dev/null +++ b/src/common/utils/hook.cpp @@ -0,0 +1,310 @@ +#include "hook.hpp" +#include "string.hpp" + +#include + +namespace utils::hook +{ + namespace + { + [[maybe_unused]] class _ + { + public: + _() + { + if (MH_Initialize() != MH_OK) + { + throw std::runtime_error("Failed to initialize MinHook"); + } + } + + ~_() + { + MH_Uninitialize(); + } + } __; + } + + void assembler::pushad64() + { + this->push(rax); + this->push(rcx); + this->push(rdx); + this->push(rbx); + this->push(rsp); + this->push(rbp); + this->push(rsi); + this->push(rdi); + + this->sub(rsp, 0x40); + } + + void assembler::popad64() + { + this->add(rsp, 0x40); + + this->pop(rdi); + this->pop(rsi); + this->pop(rbp); + this->pop(rsp); + this->pop(rbx); + this->pop(rdx); + this->pop(rcx); + this->pop(rax); + } + + void assembler::prepare_stack_for_call() + { + const auto reserve_callee_space = this->newLabel(); + const auto stack_unaligned = this->newLabel(); + + this->test(rsp, 0xF); + this->jnz(stack_unaligned); + + this->sub(rsp, 0x8); + this->push(rsp); + + this->push(rax); + this->mov(rax, ptr(rsp, 8, 8)); + this->add(rax, 0x8); + this->mov(ptr(rsp, 8, 8), rax); + this->pop(rax); + + this->jmp(reserve_callee_space); + + this->bind(stack_unaligned); + this->push(rsp); + + this->bind(reserve_callee_space); + this->sub(rsp, 0x40); + } + + void assembler::restore_stack_after_call() + { + this->lea(rsp, ptr(rsp, 0x40)); + this->pop(rsp); + } + + asmjit::Error assembler::call(void* target) + { + return Assembler::call(size_t(target)); + } + + asmjit::Error assembler::jmp(void* target) + { + return Assembler::jmp(size_t(target)); + } + + detour::detour(const size_t place, void* target) : detour(reinterpret_cast(place), target) + { + } + + detour::detour(void* place, void* target) + { + this->create(place, target); + } + + detour::~detour() + { + this->clear(); + } + + void detour::enable() const + { + MH_EnableHook(this->place_); + } + + void detour::disable() const + { + MH_DisableHook(this->place_); + } + + void detour::create(void* place, void* target) + { + this->clear(); + this->place_ = place; + + if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) + { + throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_)); + } + + this->enable(); + } + + void detour::create(const size_t place, void* target) + { + this->create(reinterpret_cast(place), target); + } + + void detour::clear() + { + if (this->place_) + { + MH_RemoveHook(this->place_); + } + + this->place_ = nullptr; + this->original_ = nullptr; + } + + void* detour::get_original() const + { + return this->original_; + } + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub) + { + if (!library.is_valid()) return false; + + auto* const ptr = library.get_iat_entry(target_library, process); + if (!ptr) return false; + + DWORD protect; + VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); + + *ptr = stub; + + VirtualProtect(ptr, sizeof(*ptr), protect, &protect); + return true; + } + + void nop(void* place, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memset(place, 0x90, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void nop(const size_t place, const size_t length) + { + nop(reinterpret_cast(place), length); + } + + void copy(void* place, const void* data, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memmove(place, data, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void copy(const size_t place, const void* data, const size_t length) + { + copy(reinterpret_cast(place), data, length); + } + + bool is_relatively_far(const void* pointer, const void* data, const int offset) + { + const int64_t diff = size_t(data) - (size_t(pointer) + offset); + const auto small_diff = int32_t(diff); + return diff != int64_t(small_diff); + } + + void call(void* pointer, void* data) + { + if (is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + set(patch_pointer, 0xE8); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + + void call(const size_t pointer, void* data) + { + return call(reinterpret_cast(pointer), data); + } + + void call(const size_t pointer, const size_t data) + { + return call(pointer, reinterpret_cast(data)); + } + + void jump(void* pointer, void* data, const bool use_far) + { + static const unsigned char jump_data[] = { + 0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0 + }; + + if (!use_far && is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + + if (use_far) + { + copy(patch_pointer, jump_data, sizeof(jump_data)); + copy(patch_pointer + 2, &data, sizeof(data)); + } + else + { + set(patch_pointer, 0xE9); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + } + + void jump(const size_t pointer, void* data, const bool use_far) + { + return jump(reinterpret_cast(pointer), data, use_far); + } + + void jump(const size_t pointer, const size_t data, const bool use_far) + { + return jump(pointer, reinterpret_cast(data), use_far); + } + + void* assemble(const std::function& asm_function) + { + static asmjit::JitRuntime runtime; + + asmjit::CodeHolder code; + code.init(runtime.environment()); + + assembler a(&code); + + asm_function(a); + + void* result = nullptr; + runtime.add(&result, &code); + + return result; + } + + void inject(void* pointer, const void* data) + { + if (is_relatively_far(pointer, data, 4)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + set(pointer, int32_t(size_t(data) - (size_t(pointer) + 4))); + } + + void inject(const size_t pointer, const void* data) + { + return inject(reinterpret_cast(pointer), data); + } + + void* follow_branch(void* address) + { + auto* const data = static_cast(address); + if (*data != 0xE8 && *data != 0xE9) + { + throw std::runtime_error("No branch instruction found"); + } + + return extract(data + 1); + } +} diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp new file mode 100644 index 0000000..bb24f8c --- /dev/null +++ b/src/common/utils/hook.hpp @@ -0,0 +1,205 @@ +#pragma once +#include "signature.hpp" + +#include +#include + +using namespace asmjit::x86; + +namespace utils::hook +{ + namespace detail + { + template + std::vector get_iota_functions() + { + if constexpr (entries == 0) + { + std::vector functions; + return functions; + } + else + { + auto functions = get_iota_functions(); + functions.emplace_back([]() + { + return entries - 1; + }); + return functions; + } + } + } + + // Gets the pointer to the entry in the v-table. + // It seems otherwise impossible to get this. + // This is ugly as fuck and only safely works on x64 + // Example: + // ID3D11Device* device = ... + // auto entry = get_vtable_entry(device, &ID3D11Device::CreateTexture2D); + template + void** get_vtable_entry(Class* obj, T (Class::* entry)(Args ...)) + { + union + { + decltype(entry) func; + void* pointer; + }; + + func = entry; + + auto iota_functions = detail::get_iota_functions(); + auto* object = iota_functions.data(); + + using FakeFunc = size_t(__thiscall*)(void* self); + auto index = static_cast(pointer)(&object); + + void** obj_v_table = *reinterpret_cast(obj); + return &obj_v_table[index]; + } + + class assembler : public Assembler + { + public: + using Assembler::Assembler; + using Assembler::call; + using Assembler::jmp; + + void pushad64(); + void popad64(); + + void prepare_stack_for_call(); + void restore_stack_after_call(); + + template + void call_aligned(T&& target) + { + this->prepare_stack_for_call(); + this->call(std::forward(target)); + this->restore_stack_after_call(); + } + + asmjit::Error call(void* target); + asmjit::Error jmp(void* target); + }; + + class detour + { + public: + detour() = default; + detour(void* place, void* target); + detour(size_t place, void* target); + ~detour(); + + detour(detour&& other) noexcept + { + this->operator=(std::move(other)); + } + + detour& operator=(detour&& other) noexcept + { + if (this != &other) + { + this->~detour(); + + this->place_ = other.place_; + this->original_ = other.original_; + + other.place_ = nullptr; + other.original_ = nullptr; + } + + return *this; + } + + detour(const detour&) = delete; + detour& operator=(const detour&) = delete; + + void enable() const; + void disable() const; + + void create(void* place, void* target); + void create(size_t place, void* target); + void clear(); + + template + T* get() const + { + return static_cast(this->get_original()); + } + + template + T invoke(Args ... args) + { + return static_cast(this->get_original())(args...); + } + + [[nodiscard]] void* get_original() const; + + private: + void* place_{}; + void* original_{}; + }; + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub); + + void nop(void* place, size_t length); + void nop(size_t place, size_t length); + + void copy(void* place, const void* data, size_t length); + void copy(size_t place, const void* data, size_t length); + + bool is_relatively_far(const void* pointer, const void* data, int offset = 5); + + void call(void* pointer, void* data); + void call(size_t pointer, void* data); + void call(size_t pointer, size_t data); + + void jump(void* pointer, void* data, bool use_far = false); + void jump(size_t pointer, void* data, bool use_far = false); + void jump(size_t pointer, size_t data, bool use_far = false); + + void* assemble(const std::function& asm_function); + + void inject(void* pointer, const void* data); + void inject(size_t pointer, const void* data); + + template + T extract(void* address) + { + auto* const data = static_cast(address); + const auto offset = *reinterpret_cast(data); + return reinterpret_cast(data + offset + 4); + } + + void* follow_branch(void* address); + + template + static void set(void* place, T value) + { + DWORD old_protect; + VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); + + *static_cast(place) = value; + + VirtualProtect(place, sizeof(T), old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); + } + + template + static void set(const size_t place, T value) + { + return set(reinterpret_cast(place), value); + } + + template + static T invoke(size_t func, Args ... args) + { + return reinterpret_cast(func)(args...); + } + + template + static T invoke(void* func, Args ... args) + { + return static_cast(func)(args...); + } +} diff --git a/src/common/utils/http.cpp b/src/common/utils/http.cpp new file mode 100644 index 0000000..3cb5999 --- /dev/null +++ b/src/common/utils/http.cpp @@ -0,0 +1,48 @@ +#include "http.hpp" +#include "nt.hpp" +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url) + { + CComPtr stream; + + if (FAILED(URLOpenBlockingStreamA(nullptr, url.data(), &stream, 0, nullptr))) + { + return {}; + } + + char buffer[0x1000]; + std::string result; + + HRESULT status{}; + + do + { + DWORD bytes_read = 0; + status = stream->Read(buffer, sizeof(buffer), &bytes_read); + + if (bytes_read > 0) + { + result.append(buffer, bytes_read); + } + } + while (SUCCEEDED(status) && status != S_FALSE); + + if (FAILED(status)) + { + return {}; + } + + return {result}; + } + + std::future> get_data_async(const std::string& url) + { + return std::async(std::launch::async, [url]() + { + return get_data(url); + }); + } +} diff --git a/src/common/utils/http.hpp b/src/common/utils/http.hpp new file mode 100644 index 0000000..65628a9 --- /dev/null +++ b/src/common/utils/http.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url); + std::future> get_data_async(const std::string& url); +} diff --git a/src/common/utils/info_string.cpp b/src/common/utils/info_string.cpp new file mode 100644 index 0000000..229d0ef --- /dev/null +++ b/src/common/utils/info_string.cpp @@ -0,0 +1,65 @@ +#include "info_string.hpp" +#include "string.hpp" + +namespace utils +{ + info_string::info_string(const std::string& buffer) + { + this->parse(buffer); + } + + info_string::info_string(const std::string_view& buffer) + : info_string(std::string{buffer}) + { + } + + void info_string::set(const std::string& key, const std::string& value) + { + this->key_value_pairs_[key] = value; + } + + std::string info_string::get(const std::string& key) const + { + const auto value = this->key_value_pairs_.find(key); + if (value != this->key_value_pairs_.end()) + { + return value->second; + } + + return {}; + } + + void info_string::parse(std::string buffer) + { + if (buffer[0] == '\\') + { + buffer = buffer.substr(1); + } + + const auto key_values = string::split(buffer, '\\'); + for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2) + { + const auto& key = key_values[i]; + const auto& value = key_values[i + 1]; + + if (!this->key_value_pairs_.contains(key)) + { + this->key_value_pairs_[key] = value; + } + } + } + + std::string info_string::build() const + { + std::string info_string; + for (const auto& [key, val] : this->key_value_pairs_) + { + info_string.append("\\"); + info_string.append(key); + info_string.append("\\"); + info_string.append(val); + } + + return info_string; + } +} diff --git a/src/common/utils/info_string.hpp b/src/common/utils/info_string.hpp new file mode 100644 index 0000000..369038f --- /dev/null +++ b/src/common/utils/info_string.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace utils +{ + class info_string + { + public: + info_string() = default; + explicit info_string(const std::string& buffer); + explicit info_string(const std::string_view& buffer); + + void set(const std::string& key, const std::string& value); + std::string get(const std::string& key) const; + std::string build() const; + + private: + std::unordered_map key_value_pairs_{}; + + void parse(std::string buffer); + }; +} diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp new file mode 100644 index 0000000..24624de --- /dev/null +++ b/src/common/utils/io.cpp @@ -0,0 +1,125 @@ +#include "io.hpp" +#include "nt.hpp" +#include + +namespace utils::io +{ + bool remove_file(const std::string& file) + { + return DeleteFileA(file.data()) == TRUE; + } + + bool move_file(const std::string& src, const std::string& target) + { + return MoveFileA(src.data(), target.data()) == TRUE; + } + + bool file_exists(const std::string& file) + { + return std::ifstream(file).good(); + } + + bool write_file(const std::string& file, const std::string& data, const bool append) + { + const auto pos = file.find_last_of("/\\"); + if (pos != std::string::npos) + { + create_directory(file.substr(0, pos)); + } + + std::ofstream stream( + file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0)); + + if (stream.is_open()) + { + stream.write(data.data(), static_cast(data.size())); + stream.close(); + return true; + } + + return false; + } + + std::string read_file(const std::string& file) + { + std::string data; + read_file(file, &data); + return data; + } + + bool read_file(const std::string& file, std::string* data) + { + if (!data) return false; + data->clear(); + + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + if (!stream.is_open()) return false; + + stream.seekg(0, std::ios::end); + const std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + if (size > -1) + { + data->resize(static_cast(size)); + stream.read(data->data(), size); + stream.close(); + return true; + } + } + + return false; + } + + size_t file_size(const std::string& file) + { + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + + if (stream.good()) + { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } + } + + return 0; + } + + bool create_directory(const std::string& directory) + { + return std::filesystem::create_directories(directory); + } + + bool directory_exists(const std::string& directory) + { + return std::filesystem::is_directory(directory); + } + + bool directory_is_empty(const std::string& directory) + { + return std::filesystem::is_empty(directory); + } + + std::vector list_files(const std::string& directory) + { + std::vector files; + + for (auto& file : std::filesystem::directory_iterator(directory)) + { + files.push_back(file.path().generic_string()); + } + + return files; + } + + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) + { + std::filesystem::copy(src, target, + std::filesystem::copy_options::overwrite_existing | + std::filesystem::copy_options::recursive); + } +} diff --git a/src/common/utils/io.hpp b/src/common/utils/io.hpp new file mode 100644 index 0000000..ab4ebaa --- /dev/null +++ b/src/common/utils/io.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +namespace utils::io +{ + bool remove_file(const std::string& file); + bool move_file(const std::string& src, const std::string& target); + bool file_exists(const std::string& file); + bool write_file(const std::string& file, const std::string& data, bool append = false); + bool read_file(const std::string& file, std::string* data); + std::string read_file(const std::string& file); + size_t file_size(const std::string& file); + bool create_directory(const std::string& directory); + bool directory_exists(const std::string& directory); + bool directory_is_empty(const std::string& directory); + std::vector list_files(const std::string& directory); + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); +} diff --git a/src/common/utils/memory.cpp b/src/common/utils/memory.cpp new file mode 100644 index 0000000..e71ca10 --- /dev/null +++ b/src/common/utils/memory.cpp @@ -0,0 +1,162 @@ +#include "memory.hpp" +#include "nt.hpp" + +namespace utils +{ + memory::allocator memory::mem_allocator_; + + memory::allocator::~allocator() + { + this->clear(); + } + + void memory::allocator::clear() + { + std::lock_guard _(this->mutex_); + + for (const auto& data : this->pool_) + { + memory::free(data); + } + + this->pool_.clear(); + } + + void memory::allocator::free(void* data) + { + std::lock_guard _(this->mutex_); + + const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); + if (j != this->pool_.end()) + { + memory::free(data); + this->pool_.erase(j); + } + } + + void memory::allocator::free(const void* data) + { + this->free(const_cast(data)); + } + + void* memory::allocator::allocate(const size_t length) + { + std::lock_guard _(this->mutex_); + + auto* data = memory::allocate(length); + this->pool_.push_back(data); + return data; + } + + bool memory::allocator::empty() const + { + return this->pool_.empty(); + } + + char* memory::allocator::duplicate_string(const std::string& string) + { + std::lock_guard _(this->mutex_); + + auto* data = memory::duplicate_string(string); + this->pool_.push_back(data); + return data; + } + + void* memory::allocate(const size_t length) + { + return std::calloc(length, 1); + } + + char* memory::duplicate_string(const std::string& string) + { + auto* new_string = allocate_array(string.size() + 1); + std::memcpy(new_string, string.data(), string.size()); + return new_string; + } + + void memory::free(void* data) + { + std::free(data); + } + + void memory::free(const void* data) + { + free(const_cast(data)); + } + + bool memory::is_set(const void* mem, const char chr, const size_t length) + { + const auto mem_arr = static_cast(mem); + + for (size_t i = 0; i < length; ++i) + { + if (mem_arr[i] != chr) + { + return false; + } + } + + return true; + } + + bool memory::is_bad_read_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + return true; + } + + bool memory::is_bad_code_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + return true; + } + + bool memory::is_rdata_ptr(void* pointer) + { + const std::string rdata = ".rdata"; + const auto pointer_lib = utils::nt::library::get_by_address(pointer); + + for (const auto& section : pointer_lib.get_section_headers()) + { + const auto size = sizeof(section->Name); + char name[size + 1]; + name[size] = 0; + std::memcpy(name, section->Name, size); + + if (name == rdata) + { + const auto target = size_t(pointer); + const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData; + const size_t source_end = source_start + section->SizeOfRawData; + + return target >= source_start && target <= source_end; + } + } + + return false; + } + + memory::allocator* memory::get_allocator() + { + return &memory::mem_allocator_; + } +} diff --git a/src/common/utils/memory.hpp b/src/common/utils/memory.hpp new file mode 100644 index 0000000..0448894 --- /dev/null +++ b/src/common/utils/memory.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +namespace utils +{ + class memory final + { + public: + class allocator final + { + public: + ~allocator(); + + void clear(); + + void free(void* data); + + void free(const void* data); + + void* allocate(size_t length); + + template + T* allocate() + { + return this->allocate_array(1); + } + + template + T* allocate_array(const size_t count = 1) + { + return static_cast(this->allocate(count * sizeof(T))); + } + + bool empty() const; + + char* duplicate_string(const std::string& string); + + private: + std::mutex mutex_; + std::vector pool_; + }; + + static void* allocate(size_t length); + + template + static T* allocate() + { + return allocate_array(1); + } + + template + static T* allocate_array(const size_t count = 1) + { + return static_cast(allocate(count * sizeof(T))); + } + + static char* duplicate_string(const std::string& string); + + static void free(void* data); + static void free(const void* data); + + static bool is_set(const void* mem, char chr, size_t length); + + static bool is_bad_read_ptr(const void* ptr); + static bool is_bad_code_ptr(const void* ptr); + static bool is_rdata_ptr(void* ptr); + + static allocator* get_allocator(); + + private: + static allocator mem_allocator_; + }; +} diff --git a/src/common/utils/nt.cpp b/src/common/utils/nt.cpp new file mode 100644 index 0000000..13ae0c1 --- /dev/null +++ b/src/common/utils/nt.cpp @@ -0,0 +1,276 @@ +#include "nt.hpp" + +namespace utils::nt +{ + library library::load(const std::string& name) + { + return library(LoadLibraryA(name.data())); + } + + library library::load(const std::filesystem::path& path) + { + return library::load(path.generic_string()); + } + + library library::get_by_address(void* address) + { + HMODULE handle = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + static_cast(address), &handle); + return library(handle); + } + + library::library() + { + this->module_ = GetModuleHandleA(nullptr); + } + + library::library(const std::string& name) + { + this->module_ = GetModuleHandleA(name.data()); + } + + library::library(const HMODULE handle) + { + this->module_ = handle; + } + + bool library::operator==(const library& obj) const + { + return this->module_ == obj.module_; + } + + library::operator bool() const + { + return this->is_valid(); + } + + library::operator HMODULE() const + { + return this->get_handle(); + } + + PIMAGE_NT_HEADERS library::get_nt_headers() const + { + if (!this->is_valid()) return nullptr; + return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); + } + + PIMAGE_DOS_HEADER library::get_dos_header() const + { + return reinterpret_cast(this->get_ptr()); + } + + PIMAGE_OPTIONAL_HEADER library::get_optional_header() const + { + if (!this->is_valid()) return nullptr; + return &this->get_nt_headers()->OptionalHeader; + } + + std::vector library::get_section_headers() const + { + std::vector headers; + + auto nt_headers = this->get_nt_headers(); + auto section = IMAGE_FIRST_SECTION(nt_headers); + + for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) + { + if (section) headers.push_back(section); + } + + return headers; + } + + std::uint8_t* library::get_ptr() const + { + return reinterpret_cast(this->module_); + } + + void library::unprotect() const + { + if (!this->is_valid()) return; + + DWORD protection; + VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, + &protection); + } + + size_t library::get_relative_entry_point() const + { + if (!this->is_valid()) return 0; + return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; + } + + void* library::get_entry_point() const + { + if (!this->is_valid()) return nullptr; + return this->get_ptr() + this->get_relative_entry_point(); + } + + bool library::is_valid() const + { + return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; + } + + std::string library::get_name() const + { + if (!this->is_valid()) return {}; + + auto path = this->get_path(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) return path; + + return path.substr(pos + 1); + } + + std::string library::get_path() const + { + if (!this->is_valid()) return {}; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof name); + + return name; + } + + std::string library::get_folder() const + { + if (!this->is_valid()) return {}; + + const auto path = std::filesystem::path(this->get_path()); + return path.parent_path().generic_string(); + } + + void library::free() + { + if (this->is_valid()) + { + FreeLibrary(this->module_); + this->module_ = nullptr; + } + } + + HMODULE library::get_handle() const + { + return this->module_; + } + + void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const + { + return this->get_iat_entry(module_name, proc_name.data()); + } + + void** library::get_iat_entry(const std::string& module_name, const char* proc_name) const + { + if (!this->is_valid()) return nullptr; + + const library other_module(module_name); + if (!other_module.is_valid()) return nullptr; + + auto* const target_function = other_module.get_proc(proc_name); + if (!target_function) return nullptr; + + const auto* header = this->get_optional_header(); + if (!header) return nullptr; + + auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory + [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + while (import_descriptor->Name) + { + if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) + { + auto* original_thunk_data = reinterpret_cast(import_descriptor-> + OriginalFirstThunk + this->get_ptr()); + auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> + get_ptr()); + + while (original_thunk_data->u1.AddressOfData) + { + if (thunk_data->u1.Function == reinterpret_cast(target_function)) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + + const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; + + if (ordinal_number <= 0xFFFF) + { + auto* proc = GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)); + if (reinterpret_cast(proc) == target_function) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + } + + ++original_thunk_data; + ++thunk_data; + } + + //break; + } + + ++import_descriptor; + } + + return nullptr; + } + + bool is_wine() + { + static const auto has_wine_export = []() -> bool + { + const library ntdll("ntdll.dll"); + return ntdll.get_proc("wine_get_version"); + }(); + + return has_wine_export; + } + + void raise_hard_exception() + { + int data = false; + const library ntdll("ntdll.dll"); + ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); + ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); + } + + std::string load_resource(const int id) + { + auto* const res = FindResourceA(library(), MAKEINTRESOURCE(id), RT_RCDATA); + if (!res) return {}; + + auto* const handle = LoadResource(nullptr, res); + if (!handle) return {}; + + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); + } + + void relaunch_self() + { + const library self; + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + char current_dir[MAX_PATH]; + GetCurrentDirectoryA(sizeof(current_dir), current_dir); + auto* const command_line = GetCommandLineA(); + + CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); + } + + void terminate(const uint32_t code) + { + TerminateProcess(GetCurrentProcess(), code); + } +} diff --git a/src/common/utils/nt.hpp b/src/common/utils/nt.hpp new file mode 100644 index 0000000..c0e903d --- /dev/null +++ b/src/common/utils/nt.hpp @@ -0,0 +1,120 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include +#include + +namespace utils::nt +{ + class library final + { + public: + static library load(const std::string& name); + static library load(const std::filesystem::path& path); + static library get_by_address(void* address); + + library(); + explicit library(const std::string& name); + explicit library(HMODULE handle); + + library(const library& a) : module_(a.module_) + { + } + + bool operator!=(const library& obj) const { return !(*this == obj); }; + bool operator==(const library& obj) const; + + operator bool() const; + operator HMODULE() const; + + void unprotect() const; + void* get_entry_point() const; + size_t get_relative_entry_point() const; + + bool is_valid() const; + std::string get_name() const; + std::string get_path() const; + std::string get_folder() const; + std::uint8_t* get_ptr() const; + void free(); + + HMODULE get_handle() const; + + template + T get_proc(const std::string& process) const + { + if (!this->is_valid()) T{}; + return reinterpret_cast(GetProcAddress(this->module_, process.data())); + } + + template + T get_proc(const char* name) const + { + if (!this->is_valid()) T{}; + return reinterpret_cast(GetProcAddress(this->module_, name)); + } + + template + std::function get(const std::string& process) const + { + if (!this->is_valid()) return std::function(); + return static_cast(this->get_proc(process)); + } + + template + T invoke(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_pascal(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_this(const std::string& process, void* this_ptr, Args ... args) const + { + auto method = this->get(this_ptr, process); + if (method) return method(args...); + return T(); + } + + std::vector get_section_headers() const; + + PIMAGE_NT_HEADERS get_nt_headers() const; + PIMAGE_DOS_HEADER get_dos_header() const; + PIMAGE_OPTIONAL_HEADER get_optional_header() const; + + void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const; + void** get_iat_entry(const std::string& module_name, const char* name) const; + + private: + HMODULE module_; + }; + + bool is_wine(); + + __declspec(noreturn) void raise_hard_exception(); + std::string load_resource(int id); + + void relaunch_self(); + __declspec(noreturn) void terminate(uint32_t code = 0); +} diff --git a/src/common/utils/signature.cpp b/src/common/utils/signature.cpp new file mode 100644 index 0000000..9bb8c62 --- /dev/null +++ b/src/common/utils/signature.cpp @@ -0,0 +1,212 @@ +#include "signature.hpp" +#include +#include + +#include + +namespace utils::hook +{ + void signature::load_pattern(const std::string& pattern) + { + this->mask_.clear(); + this->pattern_.clear(); + + uint8_t nibble = 0; + auto has_nibble = false; + + for (auto val : pattern) + { + if (val == ' ') continue; + if (val == '?') + { + this->mask_.push_back(val); + this->pattern_.push_back(0); + } + else + { + if ((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val > 'f')) + { + throw std::runtime_error("Invalid pattern"); + } + + char str[] = {val, 0}; + const auto current_nibble = static_cast(strtol(str, nullptr, 16)); + + if (!has_nibble) + { + has_nibble = true; + nibble = current_nibble; + } + else + { + has_nibble = false; + const uint8_t byte = current_nibble | (nibble << 4); + + this->mask_.push_back('x'); + this->pattern_.push_back(byte); + } + } + } + + while (!this->mask_.empty() && this->mask_.back() == '?') + { + this->mask_.pop_back(); + this->pattern_.pop_back(); + } + + if (this->has_sse_support()) + { + while (this->pattern_.size() < 16) + { + this->pattern_.push_back(0); + } + } + + if (has_nibble) + { + throw std::runtime_error("Invalid pattern"); + } + } + + std::vector signature::process_range(uint8_t* start, const size_t length) const + { + if (this->has_sse_support()) return this->process_range_vectorized(start, length); + return this->process_range_linear(start, length); + } + + std::vector signature::process_range_linear(uint8_t* start, const size_t length) const + { + std::vector result; + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + + size_t j = 0; + for (; j < this->mask_.size(); ++j) + { + if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) + { + break; + } + } + + if (j == this->mask_.size()) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + std::vector signature::process_range_vectorized(uint8_t* start, const size_t length) const + { + std::vector result; + __declspec(align(16)) char desired_mask[16] = {0}; + + for (size_t i = 0; i < this->mask_.size(); i++) + { + desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; + } + + const auto mask = _mm_load_si128(reinterpret_cast(desired_mask)); + const auto comparand = _mm_loadu_si128(reinterpret_cast(this->pattern_.data())); + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + const auto value = _mm_loadu_si128(reinterpret_cast(address)); + const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast(this->mask_.size()), + _SIDD_CMP_EQUAL_EACH); + + const auto matches = _mm_and_si128(mask, comparison); + const auto equivalence = _mm_xor_si128(mask, matches); + + if (_mm_test_all_zeros(equivalence, equivalence)) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + signature::signature_result signature::process() const + { + const auto range = this->length_ - this->mask_.size(); + const auto cores = std::max(1u, std::thread::hardware_concurrency()); + + if (range <= cores * 10ull) return this->process_serial(); + return this->process_parallel(); + } + + signature::signature_result signature::process_serial() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + return {this->process_range(this->start_, this->length_ - sub)}; + } + + signature::signature_result signature::process_parallel() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + const auto range = this->length_ - sub; + const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); + // Only use half of the available cores + const auto grid = range / cores; + + std::mutex mutex; + std::vector result; + std::vector threads; + + for (auto i = 0u; i < cores; ++i) + { + const auto start = this->start_ + (grid * i); + const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; + threads.emplace_back([&, start, length]() + { + auto local_result = this->process_range(start, length); + if (local_result.empty()) return; + + std::lock_guard _(mutex); + for (const auto& address : local_result) + { + result.push_back(address); + } + }); + } + + for (auto& t : threads) + { + if (t.joinable()) + { + t.join(); + } + } + + std::sort(result.begin(), result.end()); + return {std::move(result)}; + } + + bool signature::has_sse_support() const + { + if (this->mask_.size() <= 16) + { + int cpu_id[4]; + __cpuid(cpu_id, 0); + + if (cpu_id[0] >= 1) + { + __cpuidex(cpu_id, 1, 0); + return (cpu_id[2] & (1 << 20)) != 0; + } + } + + return false; + } +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len) +{ + return utils::hook::signature(std::string(str, len)).process(); +} diff --git a/src/common/utils/signature.hpp b/src/common/utils/signature.hpp new file mode 100644 index 0000000..a372832 --- /dev/null +++ b/src/common/utils/signature.hpp @@ -0,0 +1,73 @@ +#pragma once +#include "nt.hpp" +#include + +namespace utils::hook +{ + class signature final + { + public: + class signature_result + { + public: + signature_result(std::vector&& matches) : matches_(std::move(matches)) + { + } + + [[nodiscard]] uint8_t* get(const size_t index) const + { + if (index >= this->count()) + { + throw std::runtime_error("Invalid index"); + } + + return reinterpret_cast(this->matches_[index]); + } + + [[nodiscard]] size_t count() const + { + return this->matches_.size(); + } + + private: + std::vector matches_; + }; + + explicit signature(const std::string& pattern, const nt::library library = {}) + : signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) + { + } + + signature(const std::string& pattern, void* start, void* end) + : signature(pattern, start, size_t(end) - size_t(start)) + { + } + + signature(const std::string& pattern, void* start, const size_t length) + : start_(static_cast(start)), length_(length) + { + this->load_pattern(pattern); + } + + signature_result process() const; + + private: + std::string mask_; + std::basic_string pattern_; + + uint8_t* start_; + size_t length_; + + void load_pattern(const std::string& pattern); + + signature_result process_parallel() const; + signature_result process_serial() const; + std::vector process_range(uint8_t* start, size_t length) const; + std::vector process_range_linear(uint8_t* start, size_t length) const; + std::vector process_range_vectorized(uint8_t* start, size_t length) const; + + bool has_sse_support() const; + }; +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, size_t len); diff --git a/src/common/utils/smbios.cpp b/src/common/utils/smbios.cpp new file mode 100644 index 0000000..a3282c2 --- /dev/null +++ b/src/common/utils/smbios.cpp @@ -0,0 +1,94 @@ +#include "smbios.hpp" +#include "memory.hpp" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +namespace utils::smbios +{ + namespace + { +#pragma warning(push) +#pragma warning(disable: 4200) + struct RawSMBIOSData + { + BYTE Used20CallingMethod; + BYTE SMBIOSMajorVersion; + BYTE SMBIOSMinorVersion; + BYTE DmiRevision; + DWORD Length; + BYTE SMBIOSTableData[]; + }; + + typedef struct + { + BYTE type; + BYTE length; + WORD handle; + } dmi_header; +#pragma warning(pop) + + std::vector get_smbios_data() + { + DWORD size = 0; + std::vector data{}; + + size = GetSystemFirmwareTable('RSMB', 0, nullptr, size); + data.resize(size); + GetSystemFirmwareTable('RSMB', 0, data.data(), size); + + return data; + } + + std::string parse_uuid(const uint8_t* data) + { + if (utils::memory::is_set(data, 0, 16) || utils::memory::is_set(data, -1, 16)) + { + return {}; + } + + char uuid[16] = {0}; + *reinterpret_cast(uuid + 0) = + _byteswap_ulong(*reinterpret_cast(data + 0)); + *reinterpret_cast(uuid + 4) = + _byteswap_ushort(*reinterpret_cast(data + 4)); + *reinterpret_cast(uuid + 6) = + _byteswap_ushort(*reinterpret_cast(data + 6)); + memcpy(uuid + 8, data + 8, 8); + + return std::string(uuid, sizeof(uuid)); + } + } + + std::string get_uuid() + { + auto smbios_data = get_smbios_data(); + auto* raw_data = reinterpret_cast(smbios_data.data()); + + auto* data = raw_data->SMBIOSTableData; + for (DWORD i = 0; i + sizeof(dmi_header) < raw_data->Length;) + { + auto* header = reinterpret_cast(data + i); + if (header->length < 4) + { + return {}; + } + + if (header->type == 0x01 && header->length >= 0x19) + { + return parse_uuid(data + i + 0x8); + } + + i += header->length; + while ((i + 1) < raw_data->Length && *reinterpret_cast(data + i) != 0) + { + ++i; + } + + i += 2; + } + + return {}; + } +} diff --git a/src/common/utils/smbios.hpp b/src/common/utils/smbios.hpp new file mode 100644 index 0000000..bbd1939 --- /dev/null +++ b/src/common/utils/smbios.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::smbios +{ + std::string get_uuid(); +} diff --git a/src/common/utils/string.cpp b/src/common/utils/string.cpp new file mode 100644 index 0000000..f8129d3 --- /dev/null +++ b/src/common/utils/string.cpp @@ -0,0 +1,179 @@ +#include "string.hpp" +#include +#include +#include + +#include "nt.hpp" + +namespace utils::string +{ + const char* va(const char* fmt, ...) + { + static thread_local va_provider<8, 256> provider; + + va_list ap; + va_start(ap, fmt); + + const char* result = provider.get(fmt, ap); + + va_end(ap); + return result; + } + + std::vector split(const std::string& s, const char delim) + { + std::stringstream ss(s); + std::string item; + std::vector elems; + + while (std::getline(ss, item, delim)) + { + elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) + } + + return elems; + } + + std::string to_lower(const std::string& text) + { + std::string result; + std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input) + { + return static_cast(std::tolower(input)); + }); + + return result; + } + + std::string to_upper(const std::string& text) + { + std::string result; + std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input) + { + return static_cast(std::toupper(input)); + }); + + return result; + } + + bool starts_with(const std::string& text, const std::string& substring) + { + return text.find(substring) == 0; + } + + bool ends_with(const std::string& text, const std::string& substring) + { + if (substring.size() > text.size()) return false; + return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); + } + + std::string dump_hex(const std::string& data, const std::string& separator) + { + std::string result; + + for (unsigned int i = 0; i < data.size(); ++i) + { + if (i > 0) + { + result.append(separator); + } + + result.append(va("%02X", data[i] & 0xFF)); + } + + return result; + } + + std::string get_clipboard_data() + { + if (OpenClipboard(nullptr)) + { + std::string data; + + auto* const clipboard_data = GetClipboardData(1u); + if (clipboard_data) + { + auto* const cliptext = static_cast(GlobalLock(clipboard_data)); + if (cliptext) + { + data.append(cliptext); + GlobalUnlock(clipboard_data); + } + } + CloseClipboard(); + + return data; + } + return {}; + } + + void strip(const char* in, char* out, size_t max) + { + if (!in || !out) return; + + max--; + auto current = 0u; + while (*in != 0 && current < max) + { + const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48); + + if (*in == '^' && (color_index != 7 || *(in + 1) == '7')) + { + ++in; + } + else + { + *out = *in; + ++out; + ++current; + } + + ++in; + } + + *out = '\0'; + } + + std::string convert(const std::wstring& wstr) + { + std::string result; + result.reserve(wstr.size()); + + for (const auto& chr : wstr) + { + result.push_back(static_cast(chr)); + } + + return result; + } + + std::wstring convert(const std::string& str) + { + std::wstring result; + result.reserve(str.size()); + + for (const auto& chr : str) + { + result.push_back(static_cast(chr)); + } + + return result; + } + + std::string replace(std::string str, const std::string& from, const std::string& to) + { + if (from.empty()) + { + return str; + } + + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + return str; + } +} diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp new file mode 100644 index 0000000..2757d2e --- /dev/null +++ b/src/common/utils/string.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "memory.hpp" +#include + +template +constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; } + +namespace utils::string +{ + template + class va_provider final + { + public: + static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); + + va_provider() : current_buffer_(0) + { + } + + char* get(const char* format, const va_list ap) + { + ++this->current_buffer_ %= ARRAY_COUNT(this->string_pool_); + auto entry = &this->string_pool_[this->current_buffer_]; + + if (!entry->size || !entry->buffer) + { + throw std::runtime_error("String pool not initialized"); + } + + while (true) + { + const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + if (res > 0) break; // Success + if (res == 0) return nullptr; // Error + + entry->double_size(); + } + + return entry->buffer; + } + + private: + class entry final + { + public: + explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr) + { + if (this->size < MinBufferSize) this->size = MinBufferSize; + this->allocate(); + } + + ~entry() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->size = 0; + this->buffer = nullptr; + } + + void allocate() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->buffer = memory::get_allocator()->allocate_array(this->size + 1); + } + + void double_size() + { + this->size *= 2; + this->allocate(); + } + + size_t size; + char* buffer; + }; + + size_t current_buffer_; + entry string_pool_[Buffers]; + }; + + const char* va(const char* fmt, ...); + + std::vector split(const std::string& s, char delim); + + std::string to_lower(const std::string& text); + std::string to_upper(const std::string& text); + bool starts_with(const std::string& text, const std::string& substring); + bool ends_with(const std::string& text, const std::string& substring); + + std::string dump_hex(const std::string& data, const std::string& separator = " "); + + std::string get_clipboard_data(); + + void strip(const char* in, char* out, size_t max); + + std::string convert(const std::wstring& wstr); + std::wstring convert(const std::string& str); + + std::string replace(std::string str, const std::string& from, const std::string& to); +} diff --git a/src/common/utils/thread.cpp b/src/common/utils/thread.cpp new file mode 100644 index 0000000..7239b53 --- /dev/null +++ b/src/common/utils/thread.cpp @@ -0,0 +1,128 @@ +#include "thread.hpp" +#include "string.hpp" + +#include + +#include + +namespace utils::thread +{ + bool set_name(const HANDLE t, const std::string& name) + { + const nt::library kernel32("kernel32.dll"); + if (!kernel32) + { + return false; + } + + const auto set_description = kernel32.get_proc("SetThreadDescription"); + if (!set_description) + { + return false; + } + + return SUCCEEDED(set_description(t, string::convert(name).data())); + } + + bool set_name(const DWORD id, const std::string& name) + { + auto* const t = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, id); + if (!t) return false; + + const auto _ = gsl::finally([t]() + { + CloseHandle(t); + }); + + return set_name(t, name); + } + + bool set_name(std::thread& t, const std::string& name) + { + return set_name(t.native_handle(), name); + } + + bool set_name(const std::string& name) + { + return set_name(GetCurrentThread(), name); + } + + std::vector get_thread_ids() + { + auto* const h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId()); + if (h == INVALID_HANDLE_VALUE) + { + return {}; + } + + const auto _ = gsl::finally([h]() + { + CloseHandle(h); + }); + + THREADENTRY32 entry{}; + entry.dwSize = sizeof(entry); + if (!Thread32First(h, &entry)) + { + return {}; + } + + std::vector ids{}; + + do + { + const auto check_size = entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + + sizeof(entry.th32OwnerProcessID); + entry.dwSize = sizeof(entry); + + if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId()) + { + ids.emplace_back(entry.th32ThreadID); + } + } + while (Thread32Next(h, &entry)); + + return ids; + } + + void for_each_thread(const std::function& callback) + { + const auto ids = get_thread_ids(); + + for (const auto& id : ids) + { + auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id); + if (thread != nullptr) + { + const auto _ = gsl::finally([thread]() + { + CloseHandle(thread); + }); + + callback(thread); + } + } + } + + void suspend_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + SuspendThread(thread); + } + }); + } + + void resume_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + ResumeThread(thread); + } + }); + } +} diff --git a/src/common/utils/thread.hpp b/src/common/utils/thread.hpp new file mode 100644 index 0000000..4ea3598 --- /dev/null +++ b/src/common/utils/thread.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include "nt.hpp" + +namespace utils::thread +{ + bool set_name(HANDLE t, const std::string& name); + bool set_name(DWORD id, const std::string& name); + bool set_name(std::thread& t, const std::string& name); + bool set_name(const std::string& name); + + template + std::thread create_named_thread(const std::string& name, Args&&... args) + { + auto t = std::thread(std::forward(args)...); + set_name(t, name); + return t; + } + + std::vector get_thread_ids(); + void for_each_thread(const std::function& callback); + + void suspend_other_threads(); + void resume_other_threads(); +} diff --git a/src/common/utils/toast.cpp b/src/common/utils/toast.cpp new file mode 100644 index 0000000..9ffd44d --- /dev/null +++ b/src/common/utils/toast.cpp @@ -0,0 +1,109 @@ +#include "toast.hpp" +#include "string.hpp" + +#pragma warning(push) +#pragma warning(disable: 6387) +#include +#pragma warning(pop) + +namespace utils +{ + namespace + { + bool initialize() + { + static bool initialized = false; + static bool success = false; + if (initialized) + { + return success; + } + + initialized = true; + auto* instance = WinToastLib::WinToast::instance(); + if (!instance) + { + success = false; + return success; + } + + instance->setAppName(L"s1-mod"); + instance->setAppUserModelId( + WinToastLib::WinToast::configureAUMI(L"AlterWare", L"s1-mod", L"", L"20201212")); + + WinToastLib::WinToast::WinToastError error; + success = instance->initialize(&error); + + return success; + } + + class toast_handler : public WinToastLib::IWinToastHandler + { + public: + void toastActivated() const override + { + } + + void toastActivated(const int /*actionIndex*/) const override + { + } + + void toastFailed() const override + { + } + + void toastDismissed(WinToastDismissalReason /*state*/) const override + { + } + }; + } + + toast::toast(const int64_t id) + : id_(id) + { + } + + toast::operator bool() const + { + return this->id_ >= 0; + } + + void toast::hide() const + { + if (this->operator bool()) + { + WinToastLib::WinToast::instance()->hideToast(this->id_); + } + } + + toast toast::show(const std::string& title, const std::string& text) + { + if (!initialize()) + { + return toast{-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::Text02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + + return toast{WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } + + toast toast::show(const std::string& title, const std::string& text, const std::string& image) + { + if (!initialize()) + { + return {-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::ImageAndText02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + toast_template.setImagePath(string::convert(image)); + + return {WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } +} diff --git a/src/common/utils/toast.hpp b/src/common/utils/toast.hpp new file mode 100644 index 0000000..739c5c8 --- /dev/null +++ b/src/common/utils/toast.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace utils +{ + class toast + { + public: + static toast show(const std::string& title, const std::string& text); + static toast show(const std::string& title, const std::string& text, const std::string& image); + + operator bool() const; + void hide() const; + + private: + toast(int64_t id); + int64_t id_; + }; +} diff --git a/src/runner/debugger.cpp b/src/runner/debugger.cpp new file mode 100644 index 0000000..d58149b --- /dev/null +++ b/src/runner/debugger.cpp @@ -0,0 +1,95 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include "debugger.hpp" + +namespace +{ + bool acquire_debug_privilege() + { + TOKEN_PRIVILEGES token_privileges; + ZeroMemory(&token_privileges, sizeof(token_privileges)); + token_privileges.PrivilegeCount = 1; + + HANDLE token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) + { + return false; + } + + if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid)) + { + CloseHandle(token); + return false; + } + + token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + DWORD size; + if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, nullptr, &size)) + { + CloseHandle(token); + return false; + } + + return CloseHandle(token) != FALSE; + } +} + +debugger::debugger(const unsigned long process_id, const bool start) +{ + if (!start) + { + return; + } + + this->runner_ = std::thread([this, process_id]() + { + this->terminate_ = false; + this->run(process_id); + }); +} + +debugger::~debugger() +{ + this->terminate_ = true; + if (this->runner_.joinable()) + { + this->runner_.join(); + } +} + +void debugger::run(const unsigned long process_id) const +{ + acquire_debug_privilege(); + if (!DebugActiveProcess(process_id)) + { + return; + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + + DEBUG_EVENT event; + while (!this->terminate_ && WaitForDebugEvent(&event,INFINITE)) + { + if (event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + continue; + } + + if (event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + break; + } + +#ifdef DEV_BUILD + if (event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + OutputDebugStringA("Debugger attached!\n"); + } +#endif + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + } +} diff --git a/src/runner/debugger.hpp b/src/runner/debugger.hpp new file mode 100644 index 0000000..99d1073 --- /dev/null +++ b/src/runner/debugger.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +class debugger +{ +public: + debugger(unsigned long process_id, bool start); + ~debugger(); + +private: + volatile bool terminate_ = false; + std::thread runner_; + + void run(unsigned long process_id) const; +}; diff --git a/src/runner/resource.rc b/src/runner/resource.rc new file mode 100644 index 0000000..e9db75c --- /dev/null +++ b/src/runner/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "AlterWare" + VALUE "FileDescription", "Steam mod runner" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "Runner" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "runner.exe" + VALUE "ProductName", "runner" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +102 ICON "../client/resources/icon.ico" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/runner/runner.cpp b/src/runner/runner.cpp new file mode 100644 index 0000000..01c32d2 --- /dev/null +++ b/src/runner/runner.cpp @@ -0,0 +1,26 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "debugger.hpp" + +int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int) +{ + const auto* const command = "-proc "; + const char* parent_proc = strstr(GetCommandLineA(), command); + + if (parent_proc) + { + const auto pid = DWORD(atoi(parent_proc + strlen(command))); + auto* const process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid); + if (process_handle) + { + //debugger _(pid, strstr(GetCommandLineA(), "-debug ") != nullptr); + WaitForSingleObject(process_handle, INFINITE); + CloseHandle(process_handle); + return 0; + } + } + + return 1; +} diff --git a/src/tlsdll/dllmain.cpp b/src/tlsdll/dllmain.cpp new file mode 100644 index 0000000..56d31a6 --- /dev/null +++ b/src/tlsdll/dllmain.cpp @@ -0,0 +1,7 @@ +#define TLS_PAYLOAD_SIZE 0x2000 +thread_local char tls_data[TLS_PAYLOAD_SIZE]; + +__declspec(dllexport) void* get_tls_data() +{ + return &tls_data[0]; +} diff --git a/src/tlsdll/resource.rc b/src/tlsdll/resource.rc new file mode 100644 index 0000000..dbd2de6 --- /dev/null +++ b/src/tlsdll/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "AlterWare" + VALUE "FileDescription", "TLS index allocation dll" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "TLS DLL" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "tlsdll.dll" + VALUE "ProductName", "tlsdll" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +// Nothing here + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/protoc.exe b/tools/protoc.exe new file mode 100644 index 0000000..cc258a5 Binary files /dev/null and b/tools/protoc.exe differ