diff --git a/resources/[jobs]/[weapons]/force-sling/.gitignore b/resources/[jobs]/[weapons]/force-sling/.gitignore deleted file mode 100644 index 1ef5adbbf..000000000 --- a/resources/[jobs]/[weapons]/force-sling/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# Ignore any IDE derived project configs -.idea -.vscode/* -!.vscode/extensions.json -!.vscode/settings.json -/src/node_modules -.vscode/* -.vscode/settings.json -.github/* diff --git a/resources/[jobs]/[weapons]/force-sling/LICENSE b/resources/[jobs]/[weapons]/force-sling/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/resources/[jobs]/[weapons]/force-sling/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - 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 -. diff --git a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/custom.lua b/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/custom.lua deleted file mode 100644 index ccfc2b641..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/custom.lua +++ /dev/null @@ -1,35 +0,0 @@ -if Config.Framework.name ~= "custom" then - return; -end - -Framework = {}; - -function IsPlayerLoaded() - return ESX.IsPlayerLoaded(); -end - -RegisterNetEvent("esx:addInventoryItem") -AddEventHandler("esx:addInventoryItem", function(item) - for k, v in pairs(Config.Weapons) do - if item == k then - Sling.cachedWeapons[item] = v - Sling.cachedWeapons[item].attachments = Inventory:GetWeaponAttachment(item) - break; - end - end -end) - -RegisterNetEvent("esx:removeInventoryItem") -AddEventHandler("esx:removeInventoryItem", function(item) - for k, v in pairs(Config.Weapons) do - if item == k then - Sling.cachedWeapons[item] = nil - if Sling.cachedAttachments[item] then - if DoesEntityExist(Sling.cachedAttachments[item].obj) then - DeleteEntity(Sling.cachedAttachments[item].obj) - end - end - break; - end - end -end) diff --git a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/esx.lua b/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/esx.lua deleted file mode 100644 index aa1ed24e4..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/esx.lua +++ /dev/null @@ -1,45 +0,0 @@ -if Config.Framework.name ~= "esx" then - return; -end - -ESX = exports[(Config.Framework.resource == "auto" and "es_extended" or Config.Framework.resource)]:getSharedObject(); - -Framework = {}; - -function IsPlayerLoaded() - return ESX.IsPlayerLoaded(); -end - -RegisterNetEvent("esx:addInventoryItem") -AddEventHandler("esx:addInventoryItem", function(item) - item = item:lower() - for k, v in pairs(Config.Weapons) do - if item == k then - Sling.cachedWeapons[item] = v - Sling.cachedWeapons[item].attachments = Inventory:GetWeaponAttachment(item) - break; - end - end -end) - -RegisterNetEvent("esx:removeInventoryItem") -AddEventHandler("esx:removeInventoryItem", function(item) - item = item:lower() - for k, v in pairs(Config.Weapons) do - k = k:lower() - if item == k then - if Sling.cachedAttachments[item] then - if DoesEntityExist(Sling.cachedAttachments[item].obj) or DoesEntityExist(Sling.cachedAttachments[item].placeholder) then - DeleteEntity(Sling.cachedAttachments[item].obj) - NetworkUnregisterNetworkedEntity(Sling.cachedAttachments[item].obj) - DeleteObject(Sling.cachedAttachments[item].obj) - DetachEntity(Sling.cachedAttachments[item].placeholder, true, false) - DeleteObject(Sling.cachedAttachments[item].placeholder) - Sling.currentAttachedAmount = Sling.currentAttachedAmount - 1 - end - end - Sling.cachedWeapons[item] = nil - break; - end - end -end) diff --git a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qb.lua b/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qb.lua deleted file mode 100644 index e4b614874..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qb.lua +++ /dev/null @@ -1,61 +0,0 @@ -if Config.Framework.name ~= "qbcore" then - return -end - -QBCore = exports[(Config.Framework.resource == "auto" and "qb-core" or Config.Framework.resource)]:GetCoreObject() - -local isPlayerLoaded = false - -CreateThread(function() - while not LocalPlayer.state.isLoggedIn and not isPlayerLoaded do - Wait(100) - end - isPlayerLoaded = true - - local lower = string.lower - - while true do - local xPlayer = QBCore.Functions.GetPlayerData() - if not xPlayer or not xPlayer.items then - Wait(1000) - else - local cachedItems = {} - for _, v in pairs(xPlayer.items) do - local itemName = lower(v.name) - if Config.Weapons[itemName] then - cachedItems[itemName] = true - Sling.cachedWeapons[itemName] = Config.Weapons[itemName] - Sling.cachedWeapons[itemName].attachments = Inventory:GetWeaponAttachment(itemName) - end - end - - for key, val in pairs(Config.Weapons) do - local lowerKey = lower(key) - if not cachedItems[lowerKey] then - if Sling.cachedAttachments[lowerKey] then - local attachment = Sling.cachedAttachments[lowerKey] - if DoesEntityExist(attachment.obj) or DoesEntityExist(attachment.placeholder) then - DeleteEntity(attachment.obj) - NetworkUnregisterNetworkedEntity(attachment.obj) - DeleteObject(attachment.obj) - DetachEntity(attachment.placeholder, true, false) - DeleteObject(attachment.placeholder) - Sling.currentAttachedAmount = Sling.currentAttachedAmount - 1 - end - end - Sling.cachedWeapons[lowerKey] = nil - end - end - Wait(1500) - end - end -end) - -function IsPlayerLoaded() - return isPlayerLoaded -end - -RegisterNetEvent('QBCore:Client:OnPlayerLoaded') -AddEventHandler('QBCore:Client:OnPlayerLoaded', function() - isPlayerLoaded = true -end) diff --git a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qbx.lua b/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qbx.lua deleted file mode 100644 index 595a6532c..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/custom/frameworks/qbx.lua +++ /dev/null @@ -1,62 +0,0 @@ -if Config.Framework.name ~= "qbx" then - return -end - -local isPlayerLoaded = false - -CreateThread(function() - while not LocalPlayer.state.isLoggedIn and not isPlayerLoaded do - Wait(100) - end - isPlayerLoaded = true - - local cachedItems = {} - local lower = string.lower - local ConfigWeapons = Config.Weapons - local SlingCachedWeapons = Sling.cachedWeapons - local SlingCachedAttachments = Sling.cachedAttachments - - while true do - local xPlayer = exports.qbx_core:GetPlayerData() - if not xPlayer or not xPlayer.items then - Wait(1000) - else - for _, v in pairs(xPlayer.items) do - local itemName = lower(v.name) - if ConfigWeapons[itemName] then - cachedItems[itemName] = true - SlingCachedWeapons[itemName] = ConfigWeapons[itemName] - SlingCachedWeapons[itemName].attachments = Inventory:GetWeaponAttachment(itemName) - end - end - - for key, _ in pairs(ConfigWeapons) do - local lowerKey = lower(key) - if not cachedItems[lowerKey] then - if SlingCachedAttachments[lowerKey] then - local attachment = SlingCachedAttachments[lowerKey] - if DoesEntityExist(attachment.obj) or DoesEntityExist(attachment.placeholder) then - DeleteEntity(attachment.obj) - NetworkUnregisterNetworkedEntity(attachment.obj) - DeleteObject(attachment.obj) - DetachEntity(attachment.placeholder, true, false) - DeleteObject(attachment.placeholder) - Sling.currentAttachedAmount = Sling.currentAttachedAmount - 1 - end - end - SlingCachedWeapons[lowerKey] = nil - end - end - Wait(1500) - end - end -end) - -function IsPlayerLoaded() - return isPlayerLoaded -end - -RegisterNetEvent('QBCore:Client:OnPlayerLoaded') -AddEventHandler('QBCore:Client:OnPlayerLoaded', function() - isPlayerLoaded = true -end) diff --git a/resources/[jobs]/[weapons]/force-sling/client/custom/inventory.lua b/resources/[jobs]/[weapons]/force-sling/client/custom/inventory.lua deleted file mode 100644 index 41762c137..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/custom/inventory.lua +++ /dev/null @@ -1,16 +0,0 @@ -if Config.Inventory ~= "custom" then return end -CustomInventory = {} - -function CustomInventory:GetWeapons() - local weapons = {} - local userInventory - - return weapons -end - -function CustomInventory:GetWeaponAttachment(item) - local components = {} - local userInventory - - return components -end diff --git a/resources/[jobs]/[weapons]/force-sling/client/events.lua b/resources/[jobs]/[weapons]/force-sling/client/events.lua deleted file mode 100644 index 2856ccc85..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/events.lua +++ /dev/null @@ -1,123 +0,0 @@ -local function cleanupEntities() - local function safeDelete(entity) - if DoesEntityExist(entity) then - if IsEntityAttachedToAnyPed(entity) then - DetachEntity(entity, true, true) - end - NetworkUnregisterNetworkedEntity(entity) - DeleteObject(entity) - SetEntityAsNoLongerNeeded(entity) - return true - end - return false - end - - if Sling then - if Sling.object then - safeDelete(Sling.object) - Sling.object = nil - end - - if Sling.cachedAttachments then - for weaponName, attachment in pairs(Sling.cachedAttachments) do - if attachment then - safeDelete(attachment.obj) - safeDelete(attachment.placeholder) - Sling.cachedAttachments[weaponName] = nil - end - end - end - - Sling.currentAttachedAmount = 0 - end - - for playerId, weapons in pairs(otherPlayersWeapons) do - for weaponName, _ in pairs(weapons) do - if Sling and Sling.cachedAttachments and Sling.cachedAttachments[weaponName] then - safeDelete(Sling.cachedAttachments[weaponName].obj) - safeDelete(Sling.cachedAttachments[weaponName].placeholder) - end - end - otherPlayersWeapons[playerId] = nil - end - - collectgarbage("collect") -end - -CreateThread(function() - while not Sling do - Wait(100) - end - - AddEventHandler('onResourceStart', function(resourceName) - if resourceName == GetCurrentResourceName() then - cleanupEntities() - end - end) - - RegisterNetEvent('QBCore:Client:OnPlayerLoaded') - AddEventHandler('QBCore:Client:OnPlayerLoaded', function() - cleanupEntities() - end) - - AddEventHandler('onResourceStop', function(resourceName) - if resourceName == GetCurrentResourceName() then - cleanupEntities() - end - end) - - AddEventHandler('playerDropped', function() - cleanupEntities() - end) -end) - -RegisterNetEvent('force-sling:client:syncWeapons') -AddEventHandler('force-sling:client:syncWeapons', function(playerId, weaponData, action) - if not Sling then return end - if playerId == cache.serverId then return end - - if action == 'attach' then - local targetPed = GetPlayerPed(GetPlayerFromServerId(playerId)) - if not targetPed or not DoesEntityExist(targetPed) then return end - - -- Erstelle einen eindeutigen Key für die Waffe des anderen Spielers - local uniqueWeaponKey = 'player_' .. playerId .. '_' .. weaponData.weaponName - - otherPlayersWeapons[playerId] = otherPlayersWeapons[playerId] or {} - - if not otherPlayersWeapons[playerId][uniqueWeaponKey] then - Utils:CreateAndAttachWeapon( - uniqueWeaponKey, - weaponData.weaponVal, - weaponData.coords, - targetPed, - true -- Flag für andere Spieler - ) - otherPlayersWeapons[playerId][uniqueWeaponKey] = true - end - - elseif action == 'detach' then - local uniqueWeaponKey = 'player_' .. playerId .. '_' .. weaponData.weaponName - if otherPlayersWeapons[playerId] and otherPlayersWeapons[playerId][uniqueWeaponKey] then - Utils:DeleteWeapon(uniqueWeaponKey) - otherPlayersWeapons[playerId][uniqueWeaponKey] = nil - end - end -end) - - -RegisterNetEvent('force-sling:client:cleanupPlayerWeapons') -AddEventHandler('force-sling:client:cleanupPlayerWeapons', function(playerId) - if not Sling then return end - if otherPlayersWeapons[playerId] then - for weaponKey, _ in pairs(otherPlayersWeapons[playerId]) do - Utils:DeleteWeapon(weaponKey) - end - otherPlayersWeapons[playerId] = nil - end -end) - - - - - diff --git a/resources/[jobs]/[weapons]/force-sling/client/functions.lua b/resources/[jobs]/[weapons]/force-sling/client/functions.lua deleted file mode 100644 index c2a16e5e3..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/functions.lua +++ /dev/null @@ -1,388 +0,0 @@ -local POSITION_CLAMP = 0.2 -local DEFAULT_SPEED = 0.001 -local FAST_SPEED = 0.01 -DEFAULT_BONE = 24816 - -Sling = { - isPreset = false, - - cachedPositions = {}, - cachedPresets = {}, - cachedWeapons = {}, - cachedAttachments = {}, - currentAttachedAmount = 0, - - inPositioning = false, - data = { - object = nil, - } -} - -function Sling:SyncWeaponAttachment(weaponName, weaponVal, coords, action) - local weaponData = { - weaponName = weaponName, - weaponVal = weaponVal, - coords = coords - } - TriggerServerEvent('force-sling:server:syncWeapons', weaponData, action) -end - - - -function Sling:InitMain() - Debug("info", "Initializing main thread") - - Sling:InitSling() - Sling:InitCommands() - - Debug("info", "Main thread initialized") -end - -function Sling:InitSling() - local libCallbackAwait = lib.callback.await - Sling.cachedPositions = libCallbackAwait("force-sling:callback:getCachedPositions", false) - Sling.cachedPresets = libCallbackAwait("force-sling:callback:getCachedPresets", false) - Sling.cachedWeapons = Inventory:GetWeapons() - Sling:WeaponThread() - - local function loadBoneOptions() - local bones = {} - for boneName, _ in pairs(Config.Bones) do - table.insert(bones, boneName) - end - return bones - end - - local function loadWeaponOptions() - local weapons = {} - for weaponName, _ in pairs(Config.Weapons) do - table.insert(weapons, weaponName) - end - return weapons - end - - local bones = loadBoneOptions() - local weapons = loadWeaponOptions() - - local selectData = { - boneId = DEFAULT_BONE, - weapon = `w_pi_pistol50`, - weaponName = "weapon_pistol50" - } - - lib.registerMenu({ - id = 'sling_select', - title = locale("slingConfig"), - position = 'top-right', - onSideScroll = function(selected, scrollIndex, args) - if selected == 1 then - selectData.boneId = Config.Bones[args[scrollIndex]] - elseif selected == 2 then - local weapon = Config.Weapons[args[scrollIndex]] - selectData.weapon = weapon.model - selectData.weaponName = args[scrollIndex] - end - end, - onSelected = function(selected, secondary, args) - end, - onClose = function(keyPressed) - Sling.inPositioning = false - end, - options = { - { label = 'Bone', values = bones, args = bones }, - { label = 'Weapon', values = weapons, args = weapons }, - { label = 'Continue' }, - } - }, function(selected, scrollIndex, args) - Debug("info", "Selected weapon: " .. selectData.weapon) - Debug("info", "Selected bone: " .. selectData.boneId) - Sling:StartPositioning(selectData) - end) -end - -function Sling:WeaponThread() - local function handleWeaponAttachment(weaponName, weaponVal, playerPed, weapon) - if not Sling.cachedAttachments[weaponName] then - Sling.cachedAttachments[weaponName] = {} - end - - local isInVehicle = IsPedInAnyVehicle(playerPed, false) - local isSitting = IsPedUsingScenario(playerPed, "PROP_HUMAN_SEAT_CHAIR") - local isRagdoll = IsPedRagdoll(playerPed) - local shouldHideWeapons = isInVehicle or isSitting or isRagdoll - - if weapon == weaponVal.name or shouldHideWeapons then - if DoesEntityExist(Sling.cachedAttachments[weaponName].obj) then - Utils:DeleteWeapon(weaponName) - Sling:SyncWeaponAttachment(weaponName, nil, nil, 'detach') - end - else - if not DoesEntityExist(Sling.cachedAttachments[weaponName].obj) then - local coords = Sling.cachedPositions[weaponName] or Sling.cachedPresets[weaponName] or - { coords = { x = 0.0, y = -0.15, z = 0.0 }, rot = { x = 0.0, y = 0.0, z = 0.0 }, boneId = DEFAULT_BONE } - Utils:CreateAndAttachWeapon(weaponName, weaponVal, coords, playerPed, false) - Sling:SyncWeaponAttachment(weaponName, weaponVal, coords, 'attach') - end - end - end - - CreateThread(function() - local lastState = { - inVehicle = false, - sitting = false, - ragdoll = false - } - - while true do - local playerPed = cache.ped - local weapon = GetSelectedPedWeapon(playerPed) - local currentState = { - inVehicle = IsPedInAnyVehicle(playerPed, false), - sitting = IsPedUsingScenario(playerPed, "PROP_HUMAN_SEAT_CHAIR"), - ragdoll = IsPedRagdoll(playerPed) - } - - local stateChanged = lastState.inVehicle ~= currentState.inVehicle or - lastState.sitting ~= currentState.sitting or - lastState.ragdoll ~= currentState.ragdoll - - if stateChanged then - lastState = Utils:DeepCopy(currentState) - local shouldHideWeapons = currentState.inVehicle or currentState.sitting or currentState.ragdoll - - -- Nur eigene Waffen verarbeiten - for weaponName, weaponVal in pairs(Sling.cachedWeapons) do - if shouldHideWeapons then - if DoesEntityExist(Sling.cachedAttachments[weaponName]?.obj) then - Utils:DeleteWeapon(weaponName) - Sling:SyncWeaponAttachment(weaponName, nil, nil, 'detach') - end - else - if not DoesEntityExist(Sling.cachedAttachments[weaponName]?.obj) then - local coords = Sling.cachedPositions[weaponName] or Sling.cachedPresets[weaponName] or - { coords = { x = 0.0, y = -0.15, z = 0.0 }, rot = { x = 0.0, y = 0.0, z = 0.0 }, boneId = DEFAULT_BONE } - Utils:CreateAndAttachWeapon(weaponName, weaponVal, coords, playerPed, false) - Sling:SyncWeaponAttachment(weaponName, weaponVal, coords, 'attach') - end - end - end - end - - if not (currentState.inVehicle or currentState.sitting or currentState.ragdoll) then - -- Nur eigene Waffen verarbeiten - for weaponName, weaponVal in pairs(Sling.cachedWeapons) do - handleWeaponAttachment(weaponName, weaponVal, playerPed, weapon) - end - end - - Wait(500) - end - end) -end - - -function Sling:OnPositioningDone(coords, selectData) - lib.hideTextUI() - Sling.inPositioning = false - local weapon = selectData.weapon - coords.position = vec3(coords.position.x, coords.position.y, coords.position.z) - local distanceFromMiddle = #(coords.position - vec3(0.0, 0.0, 0.0)) - local distanceFromMiddle2 = #(coords.position - vec3(0.0, 0.0, -0.2)) - local distanceFromMiddle3 = #(coords.position - vec3(0.0, 0.0, 0.2)) - if distanceFromMiddle < 0.14 or distanceFromMiddle2 < 0.14 or distanceFromMiddle3 < 0.14 then - coords.position = vec3(coords.position.x, 0.17, coords.position.z) - end - TriggerServerEvent("force-sling:server:saveWeaponPosition", coords.position, coords.rotation, weapon, - selectData.weaponName, selectData.boneId, Sling.isPreset) - Sling.cachedPositions[selectData.weaponName] = { - coords = coords.position, - rot = coords.rotation, - boneId = selectData.boneId - } - if Sling.cachedAttachments[selectData.weaponName] then - if DoesEntityExist(Sling.cachedAttachments[selectData.weaponName].obj) or DoesEntityExist(Sling.cachedAttachments[selectData.weaponName].placeholder) then - DeleteObject(Sling.cachedAttachments[selectData.weaponName].obj) - DeleteObject(Sling.cachedAttachments[selectData.weaponName].placeholder) - end - end - DeleteObject(Sling.object) - SetModelAsNoLongerNeeded(selectData.weapon) -end - -local function DisableControls() - local controls = { - 25, 44, 45, 51, 140, 141, 143, - 263, 264, 24, 96, 97, 47, 74, 177 - } - for i = 1, #controls do - DisableControlAction(0, controls[i], true) - end -end - -function Sling:StartPositioning(selectData) - if Sling.inPositioning then return end - local coords = { - position = vec3(0.0, 0.0, 0.0), - rotation = vec3(0.0, 0.0, 0.0) - } - - if Sling.cachedAttachments[selectData.weaponName] and DoesEntityExist(Sling.cachedAttachments[selectData.weaponName].obj) then - Utils:DeleteWeapon(selectData.weaponName) - end - if Sling.cachedPositions[selectData.weaponName] and selectData.boneId == Sling.cachedPositions[selectData.weaponName].boneId then - coords.position = Sling.cachedPositions[selectData.weaponName].coords - coords.rotation = Sling.cachedPositions[selectData.weaponName].rot - elseif Sling.cachedPresets[selectData.weaponName] and selectData.boneId == Sling.cachedPresets[selectData.weaponName].boneId then - coords.position = Sling.cachedPresets[selectData.weaponName].coords - coords.rotation = Sling.cachedPresets[selectData.weaponName].rot - end - - Sling.inPositioning = true - CreateThread(function() - local speed = DEFAULT_SPEED - local function updatePosition(axis, delta) - local x, y, z = coords.position.x, coords.position.y, coords.position.z - if axis == 'x' then - x = lib.math.clamp(x + delta, -POSITION_CLAMP, POSITION_CLAMP) - elseif axis == 'y' then - y = lib.math.clamp(y + delta, -POSITION_CLAMP, POSITION_CLAMP) - elseif axis == 'z' then - z = lib.math.clamp(z + delta, -POSITION_CLAMP, POSITION_CLAMP) - end - coords.position = vec3(x, y, z) - AttachEntityToEntity(Sling.object, cache.ped, GetPedBoneIndex(cache.ped, selectData.boneId), - coords.position.x, coords.position.y, coords.position.z, - coords.rotation.x, coords.rotation.y, coords.rotation.z, - true, true, false, true, 2, true) - end - - local function updateRotation(axis, delta) - local x, y, z = coords.rotation.x, coords.rotation.y, coords.rotation.z - if axis == 'x' then - x = x + delta - elseif axis == 'y' then - y = y + delta - elseif axis == 'z' then - z = z + delta - end - coords.rotation = vec3(x, y, z) - AttachEntityToEntity(Sling.object, cache.ped, GetPedBoneIndex(cache.ped, selectData.boneId), - coords.position.x, coords.position.y, coords.position.z, - coords.rotation.x, coords.rotation.y, coords.rotation.z, - true, true, false, true, 2, true) - end - - while Sling.inPositioning do - if not DoesEntityExist(Sling.object) then - if not HasModelLoaded(selectData.weapon) then - lib.requestModel(selectData.weapon) - end - - Sling.object = CreateObject(selectData.weapon, 0, 0, 0, false, true, false) - AttachEntityToEntity(Sling.object, cache.ped, GetPedBoneIndex(cache.ped, selectData.boneId), coords.position.x, - coords.position.y, coords.position.z, coords.rotation.x, coords.rotation.y, coords.rotation.z, true, true, - false, true, 2, true) - SetEntityCollision(Sling.object, false, false) - end - - if IsDisabledControlJustPressed(0, 18) then - Sling:OnPositioningDone(coords, selectData) - break - end - - if IsDisabledControlJustPressed(0, 177) then - DeleteObject(Sling.object) - Sling.inPositioning = false - lib.hideTextUI() - SetModelAsNoLongerNeeded(selectData.weapon) - break - end - - if IsDisabledControlPressed(0, 21) then - speed = FAST_SPEED - end - - if IsDisabledControlReleased(0, 21) then - speed = DEFAULT_SPEED - end - - if IsDisabledControlPressed(0, 44) then updatePosition('x', -speed) end - if IsDisabledControlPressed(0, 46) then updatePosition('x', speed) end - if IsDisabledControlPressed(0, 188) then updatePosition('y', speed) end - if IsDisabledControlPressed(0, 187) then updatePosition('y', -speed) end - if IsDisabledControlPressed(0, 189) then updatePosition('z', speed) end - if IsDisabledControlPressed(0, 190) then updatePosition('z', -speed) end - if IsDisabledControlPressed(0, 96) then updateRotation('x', speed + 1.0) end - if IsDisabledControlPressed(0, 97) then updateRotation('x', -(speed + 1.0)) end - if IsDisabledControlPressed(0, 48) then updateRotation('z', speed + 1.0) end - if IsDisabledControlPressed(0, 73) then updateRotation('z', -(speed + 1.0)) end - if IsDisabledControlPressed(0, 47) then updateRotation('y', speed + 1.0) end - if IsDisabledControlPressed(0, 74) then updateRotation('y', -(speed + 1.0)) end - - local text = ("pos: (%.2f, %.2f, %.2f) | rot: (%.2f, %.2f, %.2f)"):format(coords.position.x, coords.position.y, - coords.position.z, coords.rotation.x, coords.rotation.y, coords.rotation.z) - lib.showTextUI((locale("currentPosition") .. ": %s"):format(text) .. - ' \n ' .. - '[QE] - ' .. - locale("up") .. - '/' .. - locale("down") .. - ' \n' .. - '[Arrows] - ' .. - locale("move") .. - ', XY \n' .. - '[Scroll]- ' .. - locale("rotate") .. - ' \n' .. - '[XZ]- ' .. - locale("rotate") .. - ' \n' .. - '[GH] - ' .. - locale("rotate") .. - ' Z \n' .. - '[Shift] - ' .. - locale("speed") .. ' \n' .. '[ENTER] - ' .. locale("confirm") .. ' \n' .. '[BACKSPACE] - ' .. locale("cancel")) - - DisableControls() - - Wait(4) - end - end) -end - -function Sling:StartConfiguration(isPreset) - Sling.isPreset = isPreset - lib.showMenu('sling_select') -end - -function Sling:InitCommands() - Debug("info", "Initializing commands") - local admin = lib.callback.await("force-sling:callback:isPlayerAdmin", false) - if Config.Debug or admin.isAdmin then - RegisterCommand(Config.Command.name, function(source, args, raw) - if Config.Command.permission ~= "any" and admin ~= Config.Command.permission then return end - Sling:StartConfiguration(false) - end, false) - - RegisterCommand(Config.Command.reset, function(source, args, raw) - if Config.Command.permission ~= "any" and admin ~= Config.Command.permission then return end - local weapon = args[1] and args[1]:lower() or GetSelectedPedWeapon(cache.ped) - if type(weapon) == "number" then - for weaponName, weaponVal in pairs(Sling.cachedWeapons) do - if weaponVal.name == weapon then - weapon = weaponName - break - end - end - end - Sling.cachedPositions = lib.callback.await("force-sling:callback:resetWeaponPositions", false, weapon) - end, false) - - RegisterCommand(Config.Presets.command, function(source, args, raw) - if Config.Presets.permission ~= "any" and admin ~= Config.Presets.permission then return end - Sling:StartConfiguration(true) - end, false) - end - - Debug("info", "Commands initialized") -end diff --git a/resources/[jobs]/[weapons]/force-sling/client/main.lua b/resources/[jobs]/[weapons]/force-sling/client/main.lua deleted file mode 100644 index 6e5f6f55c..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/main.lua +++ /dev/null @@ -1,12 +0,0 @@ -lib.locale(Config.Locale); - -InitFramework() -InitInventory() - -CreateThread(function() - while not IsPlayerLoaded() do - Wait(100) - end - - Sling:InitMain() -end) diff --git a/resources/[jobs]/[weapons]/force-sling/client/misc/inventory.lua b/resources/[jobs]/[weapons]/force-sling/client/misc/inventory.lua deleted file mode 100644 index e739df796..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/misc/inventory.lua +++ /dev/null @@ -1,80 +0,0 @@ -Inventory = {} - -local function SafeInventoryCall(fn) - local success, result = pcall(fn) - if not success then - Debug("error", "Inventory error: " .. tostring(result)) - return nil - end - return result -end - ---- Retrieves the player's weapons from the inventory. ---- @return table A table containing the player's weapons. -function Inventory:GetWeapons() - local weapons = {} - local userInventory = self:GetUserInventory() - - if not userInventory then - Debug("warn", "Unsupported inventory system: " .. tostring(Config.Inventory)) - return weapons - end - - -- Iterate through the user's inventory and match weapons with the configured weapons - for _, v in pairs(userInventory) do - for key, val in pairs(Config.Weapons) do - if v.name:lower() == key:lower() then - weapons[key] = val - weapons[key].attachments = self:GetWeaponAttachment(key) - Debug("info", "Weapon found: " .. key) - break - end - end - end - - return weapons -end - ---- Retrieves the attachments for a specific weapon. ---- @param item string The weapon name. ---- @return table A table containing the weapon's attachments. -function Inventory:GetWeaponAttachment(item) - if not Config.UseWeaponAttachments then return {} end - local components = {} - local userInventory = self:GetUserInventory() - - if not userInventory then - Debug("warn", "Unsupported inventory system: " .. tostring(Config.Inventory)) - return components - end - - -- Iterate through the user's inventory and match attachments with the specified weapon - for _, v in pairs(userInventory) do - if v.name:lower() == item:lower() and v.info and v.info.attachments then - for _, attachment in pairs(v.info.attachments) do - table.insert(components, attachment.component) - Debug("info", "Attachment found for weapon: " .. item .. " component: " .. attachment?.component) - end - end - end - - return components -end - ---- Retrieves the user's inventory based on the configured inventory system. ---- @return table|nil The user's inventory or nil if the inventory system is unsupported. -function Inventory:GetUserInventory() - if Config.Inventory == "qs-inventory" then - return SafeInventoryCall(function() return exports['qs-inventory']:getUserInventory() end) - elseif Config.Inventory == "core_inventory" then - return SafeInventoryCall(function() return exports.core_inventory:getInventory() end) - elseif Config.Inventory == "qb-inventory" then - return QBCore.Functions.GetPlayerData().items - elseif Config.Inventory == "ox_inventory" then - return exports.ox_inventory:GetPlayerItems() - elseif Config.Inventory == "custom" then - return CustomInventory:GetWeapons() - else - return nil - end -end diff --git a/resources/[jobs]/[weapons]/force-sling/client/shared.lua b/resources/[jobs]/[weapons]/force-sling/client/shared.lua deleted file mode 100644 index c0642eb39..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/shared.lua +++ /dev/null @@ -1 +0,0 @@ -otherPlayersWeapons = {} diff --git a/resources/[jobs]/[weapons]/force-sling/client/utils.lua b/resources/[jobs]/[weapons]/force-sling/client/utils.lua deleted file mode 100644 index d438b0723..000000000 --- a/resources/[jobs]/[weapons]/force-sling/client/utils.lua +++ /dev/null @@ -1,244 +0,0 @@ -Utils = {} - -function Utils:CreateAndAttachWeapon(weaponName, weaponVal, coords, playerPed, isOtherPlayer) - if not isOtherPlayer and Sling.currentAttachedAmount >= Config.MaxWeaponsAttached then - Debug("warn", "Max weapons attached reached") - return false - end - - if not weaponVal or not weaponVal.name then - Debug("error", "Invalid weapon data") - return false - end - - -- Initialize the cached attachments for this weapon if it doesn't exist - if not Sling.cachedAttachments[weaponName] then - Sling.cachedAttachments[weaponName] = {} - end - - local weaponObject = CreateWeaponObject(weaponVal.name, 0, coords.coords.x, coords.coords.y, coords.coords.z, true, 1.0, 0) - if not weaponObject then - Debug("error", "Failed to create weapon object") - return false - end - - if NetworkGetEntityIsNetworked(weaponObject) then - NetworkUnregisterNetworkedEntity(weaponObject) - end - - SetEntityCollision(weaponObject, false, false) - - if not isOtherPlayer and Config.UseWeaponAttachments then - weaponVal.attachments = Inventory:GetWeaponAttachment(weaponName) - end - - for _, component in pairs(weaponVal.attachments or {}) do - GiveWeaponComponentToWeaponObject(weaponObject, component) - end - - lib.requestModel(weaponVal.model) - - local placeholder = CreateObjectNoOffset(weaponVal.model, coords.coords.x, coords.coords.y, coords.coords.z, true, true, false) - SetEntityCollision(placeholder, false, false) - SetEntityAlpha(placeholder, 0, false) - - local boneIndex = GetPedBoneIndex(playerPed, (coords.boneId or DEFAULT_BONE)) - - AttachEntityToEntity(placeholder, playerPed, boneIndex, - coords.coords.x, coords.coords.y, coords.coords.z, - coords.rot.x, coords.rot.y, coords.rot.z, - true, true, false, true, 2, true) - - AttachEntityToEntity(weaponObject, placeholder, GetEntityBoneIndexByName(placeholder, "gun_root"), - 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, - true, true, false, true, 2, true) - - Sling.cachedAttachments[weaponName].obj = weaponObject - Sling.cachedAttachments[weaponName].placeholder = placeholder - if not isOtherPlayer then - Sling.currentAttachedAmount = Sling.currentAttachedAmount + 1 - end - - SetModelAsNoLongerNeeded(weaponVal.model) - - return true -end - -function Utils:DeleteWeapon(weaponName) - if not Sling.cachedAttachments[weaponName] then return end - - local attachment = Sling.cachedAttachments[weaponName] - - if attachment.obj and DoesEntityExist(attachment.obj) then - if NetworkGetEntityIsNetworked(attachment.obj) then - NetworkUnregisterNetworkedEntity(attachment.obj) - end - DeleteObject(attachment.obj) - end - - if attachment.placeholder then - if IsEntityAttachedToAnyPed(attachment.placeholder) then - DetachEntity(attachment.placeholder, true, false) - end - if DoesEntityExist(attachment.placeholder) then - DeleteObject(attachment.placeholder) - end - end - - Sling.cachedAttachments[weaponName] = nil - - -- Nur verringern, wenn es keine Waffe eines anderen Spielers ist - if not string.find(weaponName, '_') then - Sling.currentAttachedAmount = math.max(0, Sling.currentAttachedAmount - 1) - end -end - -function Utils:Debug(type, message) - if not Config.Debug then return end - - if type == "error" then - print("^1[ERROR] " .. message .. "^7") - elseif type == "success" then - print("^2[SUCCESS] " .. message .. "^7") - elseif type == "info" then - print("^5[INFO] " .. message .. "^7") - elseif type == "warn" then - print("^3[WARN] " .. message .. "^7") - end -end - -function Utils:Round(num, numDecimalPlaces) - local mult = 10^(numDecimalPlaces or 0) - return math.floor(num * mult + 0.5) / mult -end - -function Utils:TableContains(table, element) - for _, value in pairs(table) do - if value == element then - return true - end - end - return false -end - -function Utils:GetTableLength(table) - local count = 0 - for _ in pairs(table) do - count = count + 1 - end - return count -end - -function Utils:DeepCopy(orig) - local orig_type = type(orig) - local copy - if orig_type == 'table' then - copy = {} - for orig_key, orig_value in next, orig, nil do - copy[Utils:DeepCopy(orig_key)] = Utils:DeepCopy(orig_value) - end - setmetatable(copy, Utils:DeepCopy(getmetatable(orig))) - else - copy = orig - end - return copy -end - -function Utils:MergeTable(t1, t2) - for k, v in pairs(t2) do - if type(v) == "table" and type(t1[k] or false) == "table" then - Utils:MergeTable(t1[k], t2[k]) - else - t1[k] = v - end - end - return t1 -end - -function Utils:GetDistance(coords1, coords2) - return #(coords1 - coords2) -end - -function Utils:DrawText3D(coords, text) - local onScreen, _x, _y = World3dToScreen2d(coords.x, coords.y, coords.z) - local px, py, pz = table.unpack(GetGameplayCamCoords()) - local dist = #(vector3(px, py, pz) - coords) - - local scale = (1 / dist) * 2 - local fov = (1 / GetGameplayCamFov()) * 100 - local scale = scale * fov - - if onScreen then - SetTextScale(0.0 * scale, 0.55 * scale) - SetTextFont(0) - SetTextProportional(1) - SetTextColour(255, 255, 255, 255) - SetTextDropshadow(0, 0, 0, 0, 255) - SetTextEdge(2, 0, 0, 0, 150) - SetTextDropShadow() - SetTextOutline() - SetTextEntry("STRING") - SetTextCentre(1) - AddTextComponentString(text) - DrawText(_x,_y) - end -end - -function Utils:LoadAnimDict(dict) - while not HasAnimDictLoaded(dict) do - RequestAnimDict(dict) - Wait(5) - end -end - -function Utils:PlayAnim(ped, dict, anim, settings) - if not settings then settings = {} end - - Utils:LoadAnimDict(dict) - - TaskPlayAnim(ped, dict, anim, - settings.blendInSpeed or 3.0, - settings.blendOutSpeed or 3.0, - settings.duration or -1, - settings.flag or 49, - settings.playbackRate or 0, - settings.lockX or false, - settings.lockY or false, - settings.lockZ or false - ) - - RemoveAnimDict(dict) -end - -function Utils:CreateBlip(coords, sprite, color, text, scale, category) - local blip = AddBlipForCoord(coords.x, coords.y, coords.z) - SetBlipSprite(blip, sprite) - SetBlipDisplay(blip, 4) - SetBlipScale(blip, scale or 0.8) - SetBlipColour(blip, color) - SetBlipAsShortRange(blip, true) - if category then - SetBlipCategory(blip, category) - end - - BeginTextCommandSetBlipName("STRING") - AddTextComponentString(text) - EndTextCommandSetBlipName(blip) - - return blip -end - -function Utils:DrawMarker(type, coords, size, color, bobUpAndDown) - DrawMarker( - type, - coords.x, coords.y, coords.z, - 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, - size.x, size.y, size.z, - color.r, color.g, color.b, color.a, - false, bobUpAndDown or false, 2, false, nil, nil, false - ) -end - - diff --git a/resources/[jobs]/[weapons]/force-sling/config.lua b/resources/[jobs]/[weapons]/force-sling/config.lua deleted file mode 100644 index a2f0bfbaa..000000000 --- a/resources/[jobs]/[weapons]/force-sling/config.lua +++ /dev/null @@ -1,130 +0,0 @@ -Config = {} - --- Enable or disable debug mode --- @field [boolean] Debug - Set to true to enable debug mode, false to disable -Config.Debug = false - --- Set the locale for the application --- @field [string] Locale - Language code for the locale ("ar", "en", "es", "fr", "pt", "de", "nl", "pl", "ru", "se" or "auto") -Config.Locale = "de" - --- Admin configuration settings --- @field [table] Admin - Configuration for admin settings --- @field [table] Admin.Global - Global admin settings --- @field [boolean] Admin.Global.enabled - Enable or disable global admin commands --- @field [table] Admin.Global.players - List of player identifiers with admin access -Config.Admin = { - Global = { - enabled = true, - ace = "admin", -- Ace permission required for global admin access, set to false to disable - players = { - "discord:453870580374962177", -- Force - "discord:566930948986241024", -- Olpis - } - } -} - --- Framework configuration settings --- @field [table] Framework - Configuration for the framework --- @field [string] Framework.name - Name of the framework ("esx", "qbcore", "qbx", "custom" or "auto") --- @field [string] Framework.resource - Resource name for ESX or QBCore -Config.Framework = { - name = "auto", - resource = "auto" -} - --- Inventory configuration settings --- @field [string] Inventory - Inventory system to use ("none", "auto", "qs-inventory", "qb-inventory", "core_inventory", "ox_inventory" or "custom") --- @field [boolean] UseWeaponAttachments - Enable or disable weapon attachments (may not work with all inventory systems and may lower performance) --- @field [number] MaxWeaponsAttached - Maximum number of weapons that can be attached to the player; the higher the number, the more performance impact -Config.Inventory = "qs-inventory" -Config.UseWeaponAttachments = true -Config.MaxWeaponsAttached = 4 - --- Command configuration settings --- @field [table] Command - Configuration for the sling command --- @field [string] Command.name - Name of the command --- @field [string] Command.reset - Command to reset the sling configuration --- @field [string] Command.description - Description of the command --- @field [string] Command.permission - Permission level required to use the command ("any" or specific permission) -Config.Command = { - name = "sling", - reset = "resetsling", - description = "Configure weapon positions", - permission = "any" -} - --- Preset command configuration settings --- @field [table] Presets - Configuration for the sling preset command --- @field [string] Presets.command - Name of the preset command --- @field [string] Presets.permission - Permission level required to use the preset command ("global" or specific permission) -Config.Presets = { - command = "slingpreset", - permission = "global", -} - --- Bone configuration settings --- @field [table] Bones - Configuration for weapon attachment bones --- @field [number] Bones.Back - Bone ID for back attachment --- @field [number] Bones.Front - Bone ID for front attachment -Config.Bones = { - Back = 24816, - Front = 10706 -} - --- Editable weapon configuration settings --- @field [table] Weapons - Configuration for editable weapons --- @field [table] Weapons[weapon_name] - Configuration for a specific weapon --- @field [string] Weapons[weapon_name].model - Model name for the weapon --- @field [string] Weapons[weapon_name].name - Internal name for the weapon -Config.Weapons = { - ["weapon_advancedrifle"] = { model = `w_ar_advancedrifle`, name = `weapon_advancedrifle` }, - ["weapon_assaultshotgun"] = { model = `w_sg_assaultshotgun`, name = `weapon_assaultshotgun` }, - ["weapon_assaultsmg"] = { model = `w_sb_assaultsmg`, name = `weapon_assaultsmg` }, - ["weapon_bullpuprifle_mk2"] = { model = `w_ar_bullpupriflemk2`, name = `weapon_bullpuprifle_mk2` }, - ["weapon_bullpupshotgun"] = { model = `w_sg_bullpupshotgun`, name = `weapon_bullpupshotgun` }, - ["weapon_carbinerifle"] = { model = `w_ar_carbinerifle`, name = `weapon_carbinerifle` }, - ["weapon_carbinerifle_mk2"] = { model = `w_ar_carbineriflemk2`, name = `weapon_carbinerifle_mk2` }, - ["weapon_combatmg"] = { model = `w_mg_combatmg`, name = `weapon_combatmg` }, - ["weapon_combatmg_mk2"] = { model = `w_mg_combatmgmk2`, name = `weapon_combatmg_mk2` }, - ["weapon_combatpdw"] = { model = `w_sb_pdw`, name = `weapon_combatpdw` }, - ["weapon_combatshotgun"] = { model = `w_sg_pumpshotgunh4`, name = `weapon_combatshotgun` }, - ["weapon_compactrifle"] = { model = `w_ar_assaultrifle_smg`, name = `weapon_compactrifle` }, - ["weapon_firework"] = { model = `w_lr_firework`, name = `weapon_firework` }, - ["weapon_heavyrifle"] = { model = `w_ar_heavyrifleh`, name = `weapon_heavyrifle` }, - ["weapon_heavyshotgun"] = { model = `w_sg_heavyshotgun`, name = `weapon_heavyshotgun` }, - ["weapon_heavysniper"] = { model = `w_sr_heavysniper`, name = `weapon_heavysniper` }, - ["weapon_marksmanrifle"] = { model = `w_sr_marksmanrifle`, name = `weapon_marksmanrifle` }, - ["weapon_marksmanrifle_mk2"] = { model = `w_sr_marksmanriflemk2`, name = `weapon_marksmanrifle_mk2` }, - ["weapon_mg"] = { model = `w_mg_mg`, name = `weapon_mg` }, - ["weapon_militaryrifle"] = { model = `w_ar_bullpuprifleh4`, name = `weapon_militaryrifle` }, - ["weapon_minismg"] = { model = `w_sb_minismg`, name = `weapon_minismg` }, - ["weapon_musket"] = { model = `w_ar_musket`, name = `weapon_musket` }, - ["weapon_pumpshotgun"] = { model = `w_sg_pumpshotgun`, name = `weapon_pumpshotgun` }, - ["weapon_smg"] = { model = `w_sb_smg`, name = `weapon_smg` }, - ["weapon_sniperrifle"] = { model = `w_sr_sniperrifle`, name = `weapon_sniperrifle` }, - ["weapon_huntingrifle"] = { model = `w_sr_huntingrifle`, name = `weapon_huntingrifle` }, - ["weapon_specialcarbine"] = { model = `w_ar_specialcarbine`, name = `weapon_specialcarbine` }, - ["weapon_autoshotgun"] = { model = `w_sg_sweeper`, name = `weapon_autoshotgun` }, - ["weapon_precisionrifle"] = { model = `w_sr_precisionrifle_reh`, name = `weapon_precisionrifle` }, - ["weapon_tacticalrifle"] = { model = `w_ar_carbinerifle_reh`, name = `weapon_tacticalrifle` }, - ["weapon_rayminigun"] = { model = `w_mg_sminigun`, name = `weapon_rayminigun` }, - ["weapon_raycarbine"] = { model = `w_ar_srifle`, name = `weapon_raycarbine` }, - ["weapon_railgun"] = { model = `w_ar_railgun`, name = `weapon_railgun` }, - ["weapon_rpg"] = { model = `w_lr_rpg`, name = `weapon_rpg` }, - ["weapon_hominglauncher"] = { model = `w_lr_homing`, name = `weapon_hominglauncher` }, - ["weapon_minigun"] = { model = `w_mg_minigun`, name = `weapon_minigun` }, - ["weapon_bat"] = { model = `w_me_bat`, name = `weapon_bat` }, - ["weapon_battleaxe"] = { model = `w_me_battleaxe`, name = `weapon_battleaxe` }, - ["weapon_crowbar"] = { model = `w_me_crowbar`, name = `weapon_crowbar` }, - ["weapon_fireextinguisher"] = { model = `w_am_fire_exting`, name = `weapon_fireextinguisher` }, - ["weapon_golfclub"] = { model = `w_me_gclub`, name = `weapon_golfclub` }, - ["weapon_hatchet"] = { model = `w_me_hatchet`, name = `weapon_hatchet` }, - ["weapon_hazardcan"] = { model = `w_ch_jerrycan`, name = `weapon_hazardcan` }, - ["weapon_fertilizercan"] = { model = `w_am_jerrycan_sf`, name = `weapon_fertilizercan` }, - ["weapon_machete"] = { model = `w_me_machette_lr`, name = `weapon_machete` }, - ["weapon_poolcue"] = { model = `w_me_poolcue`, name = `weapon_poolcue` }, - ["weapon_stone_hatchet"] = { model = `w_me_stonehatchet`, name = `weapon_stone_hatchet` }, - ["weapon_wrench"] = { model = `w_me_wrench`, name = `weapon_wrench` }, - ["weapon_candycane"] = { model = `w_me_candy_xm3`, name = `weapon_candycane` }, -} diff --git a/resources/[jobs]/[weapons]/force-sling/fxmanifest.lua b/resources/[jobs]/[weapons]/force-sling/fxmanifest.lua deleted file mode 100644 index 0271ef1c8..000000000 --- a/resources/[jobs]/[weapons]/force-sling/fxmanifest.lua +++ /dev/null @@ -1,44 +0,0 @@ -fx_version "cerulean" -lua54 'yes' -game "gta5" - -author 'Force Developments ' -description 'Fivem Sling system for ESX, QBCore and custom frameworks' -version '1.3.0' - -dependencies { - 'ox_lib', - '/assetpacks', - 'mysql-async' -- oder 'oxmysql', je nachdem was du verwendest -} - -shared_scripts { - '@ox_lib/init.lua', - "shared/variables.lua", - "shared/*.lua", - "config.lua", -} - -server_scripts { - '@mysql-async/lib/MySQL.lua', -- oder '@mysql-async/lib/MySQL.lua' - 'version.lua', - "server/events.lua", - "server/functions.lua", - "server/main.lua", - "server/misc/*.lua", - "server/callbacks.lua" -} - -client_scripts { - "client/utils.lua", - "client/functions.lua", - "client/events.lua", - "client/main.lua", - "client/custom/frameworks/*.lua", - "client/custom/*.lua", - "client/misc/*.lua" -} - -files { - "locales/*.json", -} diff --git a/resources/[jobs]/[weapons]/force-sling/json/positions.json b/resources/[jobs]/[weapons]/force-sling/json/positions.json deleted file mode 100644 index 5311cbc6f..000000000 --- a/resources/[jobs]/[weapons]/force-sling/json/positions.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "license:60b5f8ebf593295e3f65cbf4cb4c85096b37da2a": { - "weapon_specialcarbine": { - "rot": { - "x": -6.00599956512451, - "y": 66.06597900390625, - "z": 196.19642639160157 - }, - "coords": { - "x": 0.0, - "y": 0.20000000298023, - "z": -0.20000000298023 - }, - "boneId": 10706 - } - } -} \ No newline at end of file diff --git a/resources/[jobs]/[weapons]/force-sling/json/presets.json b/resources/[jobs]/[weapons]/force-sling/json/presets.json deleted file mode 100644 index cd76f6ace..000000000 --- a/resources/[jobs]/[weapons]/force-sling/json/presets.json +++ /dev/null @@ -1,236 +0,0 @@ -{ - "weapon_assaultsmg": { - "coords": { - "x": 0.0, - "z": -0.35, - "y": 0.17 - }, - "rot": { - "x": 0.0, - "z": 180.0, - "y": 55.0 - }, - "boneId": 10706 - }, - "weapon_heavyshotgun": { - "coords": { - "x": 0.1, - "z": -0.2, - "y": 0.17 - }, - "rot": { - "x": 0.0, - "z": 190.0, - "y": 60.0 - }, - "boneId": 10706 - }, - "weapon_specialcarbine": { - "coords": { - "x": 0.2275, - "z": 0.03, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 5.0 - }, - "boneId": 24816 - }, - "weapon_tacticalrifle": { - "coords": { - "x": 0.2275, - "z": 0.11, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 2.0, - "y": -15.0 - }, - "boneId": 24816 - }, - "weapon_carbinerifle": { - "coords": { - "x": 0.0, - "z": -0.25, - "y": 0.17 - }, - "rot": { - "x": 0.0, - "z": 180.0, - "y": 75.0 - }, - "boneId": 10706 - }, - "weapon_bullpuprifle": { - "coords": { - "x": 0.2275, - "z": 0.055, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 0.0 - }, - "boneId": 24816 - }, - "weapon_assaultrifle": { - "coords": { - "x": 0.2275, - "z": 0.11, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 2.0, - "y": -15.0 - }, - "boneId": 24816 - }, - "weapon_smg_mk2": { - "coords": { - "x": -0.14, - "z": 0.21, - "y": 0.05 - }, - "rot": { - "x": 90.0, - "z": 50.0, - "y": 120.0 - }, - "boneId": 24816 - }, - "weapon_sniperrifle": { - "coords": { - "x": 0.005, - "z": 0.0, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 2.0, - "y": -15.0 - }, - "boneId": 24816 - }, - "weapon_appistol": { - "coords": { - "x": -0.14, - "z": -0.21, - "y": 0.05 - }, - "rot": { - "x": 90.0, - "z": 50.0, - "y": 90.0 - }, - "boneId": 24816 - }, - "weapon_musket": { - "coords": { - "x": 0.0, - "z": 0.0, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 2.0, - "y": 15.0 - }, - "boneId": 24816 - }, - "weapon_pistol50": { - "coords": { - "x": 0.0, - "y": -0.20000000298023, - "z": 0.18999999761581 - }, - "rot": { - "x": 0.0, - "z": 0.0, - "y": 0.0 - }, - "boneId": 24816 - }, - "weapon_assaultshotgun": { - "coords": { - "x": 0.2275, - "z": 0.015, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 160.0 - }, - "boneId": 24816 - }, - "weapon_pumpshotgun": { - "coords": { - "x": 0.1275, - "z": 0.03, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 25.0 - }, - "boneId": 24816 - }, - "weapon_microsmg": { - "coords": { - "x": -0.2, - "z": -0.21, - "y": 0.05 - }, - "rot": { - "x": 90.0, - "z": 50.0, - "y": 110.0 - }, - "boneId": 24816 - }, - "weapon_carbinerifle_mk2": { - "coords": { - "x": 0.2275, - "z": -0.11, - "y": -0.17 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 20.0 - }, - "boneId": 24816 - }, - "weapon_smg": { - "coords": { - "x": 0.1275, - "z": -0.055, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 35.0 - }, - "boneId": 24816 - }, - "weapon_advancedrifle": { - "coords": { - "x": 0.2275, - "z": -0.055, - "y": -0.16 - }, - "rot": { - "x": 0.0, - "z": 1.0, - "y": 35.0 - }, - "boneId": 24816 - } -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/ar.json b/resources/[jobs]/[weapons]/force-sling/locales/ar.json deleted file mode 100644 index 20d95fd69..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/ar.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "حمالة", - "slingConfig": "إعدادات الحمالة", - "currentPosition": "الموقع الحالي", - "up": "أعلى", - "down": "أسفل", - "move": "تحريك", - "rotate": "تدوير", - "speed": "السرعة", - "confirm": "تأكيد", - "cancel": "إلغاء" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/de.json b/resources/[jobs]/[weapons]/force-sling/locales/de.json deleted file mode 100644 index 54aca8c96..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/de.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Schlinge", - "slingConfig": "Schlingenkonfiguration", - "currentPosition": "Aktuelle Position", - "up": "Oben", - "down": "Unten", - "move": "Bewegen", - "rotate": "Drehen", - "speed": "Geschwindigkeit", - "confirm": "Bestätigen", - "cancel": "Abbrechen" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/en.json b/resources/[jobs]/[weapons]/force-sling/locales/en.json deleted file mode 100644 index bf1bb799c..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/en.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Sling", - "slingConfig": "Sling Configuration", - "currentPosition": "Current Position", - "up": "Up", - "down": "Down", - "move": "Move", - "rotate": "Rotate", - "speed": "Speed", - "confirm": "Confirm", - "cancel": "Cancel" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/es.json b/resources/[jobs]/[weapons]/force-sling/locales/es.json deleted file mode 100644 index 0f09fa0d2..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/es.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Eslinga", - "slingConfig": "Configuración de eslinga", - "currentPosition": "Posición actual", - "up": "Arriba", - "down": "Abajo", - "move": "Mover", - "rotate": "Girar", - "speed": "Velocidad", - "confirm": "Confirmar", - "cancel": "Cancelar" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/fr.json b/resources/[jobs]/[weapons]/force-sling/locales/fr.json deleted file mode 100644 index 48e79cedd..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/fr.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Sangle", - "slingConfig": "Configuration de la sangle", - "currentPosition": "Position actuelle", - "up": "Haut", - "down": "Bas", - "move": "Déplacer", - "rotate": "Pivoter", - "speed": "Vitesse", - "confirm": "Confirmer", - "cancel": "Annuler" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/nl.json b/resources/[jobs]/[weapons]/force-sling/locales/nl.json deleted file mode 100644 index ac63f1f17..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/nl.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Draagband", - "slingConfig": "Draagbandconfiguratie", - "currentPosition": "Huidige positie", - "up": "Omhoog", - "down": "Omlaag", - "move": "Verplaatsen", - "rotate": "Draaien", - "speed": "Snelheid", - "confirm": "Bevestigen", - "cancel": "Annuleren" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/pl.json b/resources/[jobs]/[weapons]/force-sling/locales/pl.json deleted file mode 100644 index d72054827..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/pl.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Pasek", - "slingConfig": "Konfiguracja paska", - "currentPosition": "Aktualna pozycja", - "up": "Góra", - "down": "Dół", - "move": "Przesuń", - "rotate": "Obróć", - "speed": "Prędkość", - "confirm": "Potwierdź", - "cancel": "Anuluj" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/pt.json b/resources/[jobs]/[weapons]/force-sling/locales/pt.json deleted file mode 100644 index 5bd5b58de..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/pt.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Alça", - "slingConfig": "Configuração da alça", - "currentPosition": "Posição atual", - "up": "Cima", - "down": "Baixo", - "move": "Mover", - "rotate": "Girar", - "speed": "Velocidade", - "confirm": "Confirmar", - "cancel": "Cancelar" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/ru.json b/resources/[jobs]/[weapons]/force-sling/locales/ru.json deleted file mode 100644 index fd3401754..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/ru.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Стропа", - "slingConfig": "Настройка стропы", - "currentPosition": "Текущее положение", - "up": "Вверх", - "down": "Вниз", - "move": "Переместить", - "rotate": "Повернуть", - "speed": "Скорость", - "confirm": "Подтвердить", - "cancel": "Отмена" -} diff --git a/resources/[jobs]/[weapons]/force-sling/locales/se.json b/resources/[jobs]/[weapons]/force-sling/locales/se.json deleted file mode 100644 index 9980125cf..000000000 --- a/resources/[jobs]/[weapons]/force-sling/locales/se.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "sling": "Sele", - "slingConfig": "Selekonfiguration", - "currentPosition": "Nuvarande position", - "up": "Upp", - "down": "Ner", - "move": "Flytta", - "rotate": "Rotera", - "speed": "Hastighet", - "confirm": "Bekräfta", - "cancel": "Avbryt" -} diff --git a/resources/[jobs]/[weapons]/force-sling/readme.md b/resources/[jobs]/[weapons]/force-sling/readme.md deleted file mode 100644 index 3e5e89f3c..000000000 --- a/resources/[jobs]/[weapons]/force-sling/readme.md +++ /dev/null @@ -1,143 +0,0 @@ -# FiveM Sling System / Weapons on back - -The resource allows players to manage weapon sling positions in the game, dynamically reflecting the weapons they have in their inventory. This enhances immersion and adds a realistic touch to your FiveM server. [Documentation](https://docs.forcedevelopments.com/) [Forum](https://forum.cfx.re/t/free-sling-system-weapons-on-back-esx-qb-core-custom/5290047) - ---- - -## Features - -- **Debug Mode**: Enable or disable debug mode for troubleshooting. -- **Locale Support**: Set the locale for the resource. -- **Admin Configuration**: Manage admin commands and permissions. -- **Framework Support**: Compatible with ESX, QBCore, and custom frameworks. -- **Inventory System**: Supports various inventory systems including qs-inventory, qb-inventory, core_inventory, and ox_inventory. -- **Weapon Attachments**: Enable or disable weapon attachments. -- **Command Configuration**: Customize commands for configuring weapon positions. -- **Preset Commands**: Use preset configurations for weapon positions. -- **Bone Configuration**: Configure player bones where the weapon can be attached. -- **Editable Weapons**: Manage configurations for editable weapons. - -### Preview - -![Controls while placing](https://gyazo.com/b2210eeaf30198c1e55c5d5add9c3236/raw) -_Controls while placing_ - -![Config menu ingame](https://gyazo.com/21121fb8b2f86d9f8752baf3d91e239c/raw) -_Config menu ingame_ - -![Placement](https://gyazo.com/8f8babbad18d25745ebcc799cad05b2c/raw) -_Placement_ - ---- - -## Prerequisites - -Before setting up the resource, ensure that you have the following dependency installed: - -- **ox_lib**: This library is required for the resource to function correctly. - - **GitHub Repository**: [ox_lib](https://github.com/overextended/ox_lib) - - **Documentation**: [ox_lib Documentation](https://overextended.dev/ox_lib) - ---- - -## Installation - -1. **Download and Install** - - - Clone or download this repository to your `resources` folder in your FiveM server. - -2. **Install ox_lib** - - - Ensure that you have `ox_lib` installed. You can find it on [GitHub](https://github.com/overextended/ox_lib) or refer to the [ox_lib Documentation](https://overextended.dev/ox_lib) for installation instructions. - -3. **Configure** - - - Open the `config.lua` file and modify settings to fit your server’s framework and preferences. - - Example: - ```lua - Config.Locale = "en" -- Change to your preferred language (e.g., "fr", "es", "ru"). - Config.Framework.name = "esx" -- Set to your framework: "esx", "qbcore", or "custom". - Config.Inventory = "ox_inventory" -- Match your inventory system: "auto", "qs_inventory", etc. - ``` - -4. **Add to Server Config** - - - Add the following line to your `server.cfg`: - ```cfg - ensure ox_lib - ensure force-sling - ``` - -5. **Start Your Server** - - - Restart your server or the resource to load the resource. - ---- - -## Configuration - -The resource includes a [config.lua](https://github.com/Force-Developing/force-sling/blob/main/config.lua) file to customize functionality: - -- **Debug Mode**: - - Enable or disable debug logging. -- **Locale**: - - Set the language for the system. - - Supported languages: `ar`, `en`, `es`, `fr`, `pt`, `de`, `nl`, `pl`, `ru`, `se`, or `auto`. -- **Admin Tools**: - - Add admin player identifiers under the `Config.Admin.Global.players` array. -- **Framework Support**: - - Supports ESX, QBCore, or custom frameworks. -- **Inventory Integration**: - - Compatible with popular inventory systems like `ox_inventory` and `qb_inventory`. - -Refer to the Configuration section for detailed information on each setting. - ---- - -## Commands - -The resource provides several commands to manage weapon positions: - -- **`/sling`** - - - **Description**: Configure weapon positions. - - **Permission**: Any player can use this command. - -- **`/resetsling`** - - - **Description**: Reset personal sling position to global. - - **Permission**: Any player can use this command. - -- **`/slingpreset`** - - **Description**: Configure global weapon positions. - - **Permission**: Only admins are allowed to use this by default. - -Refer to the Commands section for a list of available commands and their usage. - ---- - -## License - -This project is licensed under the GPL License. See the [LICENSE](https://github.com/Force-Developing/force-sling/blob/main/LICENSE) file for more details. - ---- - -## Contributing - -We appreciate contributions! To contribute: - -1. Fork the repository. -2. Create a feature branch: `git checkout -b feature-name` -3. Commit your changes: `git commit -m 'Add feature'` -4. Push to the branch: `git push origin feature-name` -5. Create a pull request. - ---- - -## Support - -For questions, issues, or feature requests, please open an [issue](https://github.com/Force-Developing/force-sling/issues) or reach out on our [Discord](https://discord.gg/927gfpcyDe). - ---- - -Thank you for using the resource. We hope this documentation helps you get the most out of the resource. diff --git a/resources/[jobs]/[weapons]/force-sling/server/callbacks.lua b/resources/[jobs]/[weapons]/force-sling/server/callbacks.lua deleted file mode 100644 index 499d9f508..000000000 --- a/resources/[jobs]/[weapons]/force-sling/server/callbacks.lua +++ /dev/null @@ -1,123 +0,0 @@ -local positions = {} -local presets = {} - --- Load positions from database -local function LoadPositionsFromDB() - local result = MySQL.query.await('SELECT * FROM weapon_positions') - if result then - for _, data in ipairs(result) do - local weaponData = { - coords = vector3(data.position_x, data.position_y, data.position_z), - rot = vector3(data.rotation_x, data.rotation_y, data.rotation_z), - boneId = data.bone_id - } - - if data.is_preset == 1 then - presets[data.weapon_name] = weaponData - else - if not positions[data.identifier] then - positions[data.identifier] = {} - end - positions[data.identifier][data.weapon_name] = weaponData - end - end - end -end - --- Save position to database -local function SavePositionToDB(identifier, weaponName, position, rotation, boneId, isPreset) - MySQL.query.await('INSERT INTO weapon_positions (identifier, weapon_name, position_x, position_y, position_z, rotation_x, rotation_y, rotation_z, bone_id, is_preset) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE position_x = VALUES(position_x), position_y = VALUES(position_y), position_z = VALUES(position_z), rotation_x = VALUES(rotation_x), rotation_y = VALUES(rotation_y), rotation_z = VALUES(rotation_z), bone_id = VALUES(bone_id)', { - identifier, - weaponName, - position.x, - position.y, - position.z, - rotation.x, - rotation.y, - rotation.z, - boneId, - isPreset and 1 or 0 - }) -end - --- Delete position from database -local function DeletePositionFromDB(identifier, weaponName) - MySQL.query.await('DELETE FROM weapon_positions WHERE identifier = ? AND weapon_name = ?', { - identifier, - weaponName - }) -end - --- Load data when resource starts -CreateThread(function() - LoadPositionsFromDB() -end) - -lib.callback.register('force-sling:callback:getCachedPositions', function(source) - local src = source - local identifier = GetPlayerIdentifier(src) - return positions[identifier] or {} -end) - -lib.callback.register('force-sling:callback:getCachedPresets', function(source) - return presets -end) - -lib.callback.register('force-sling:callback:isPlayerAdmin', function(source) - local src = source - -- Add your admin check logic here - return {isAdmin = true} -end) - -lib.callback.register('force-sling:callback:resetWeaponPositions', function(source, weapon) - local src = source - local identifier = GetPlayerIdentifier(src) - - if weapon then - if positions[identifier] then - positions[identifier][weapon] = nil - DeletePositionFromDB(identifier, weapon) - end - else - positions[identifier] = {} - MySQL.query.await('DELETE FROM weapon_positions WHERE identifier = ? AND is_preset = 0', {identifier}) - end - - return positions[identifier] or {} -end) - -RegisterNetEvent('force-sling:server:saveWeaponPosition') -AddEventHandler('force-sling:server:saveWeaponPosition', function(position, rotation, weapon, weaponName, boneId, isPreset) - local src = source - local identifier = GetPlayerIdentifier(src) - - local data = { - coords = position, - rot = rotation, - boneId = boneId - } - - if isPreset then - presets[weaponName] = data - SavePositionToDB('preset', weaponName, position, rotation, boneId, true) - else - if not positions[identifier] then - positions[identifier] = {} - end - positions[identifier][weaponName] = data - SavePositionToDB(identifier, weaponName, position, rotation, boneId, false) - end -end) - --- Helper function to get player identifier -function GetPlayerIdentifier(source) - local identifiers = GetPlayerIdentifiers(source) - -- Modify this based on your framework (e.g., for QBCore or ESX) - for _, identifier in pairs(identifiers) do - if string.find(identifier, 'license:') then - return identifier - end - end - return nil -end - diff --git a/resources/[jobs]/[weapons]/force-sling/server/events.lua b/resources/[jobs]/[weapons]/force-sling/server/events.lua deleted file mode 100644 index 539064bc9..000000000 --- a/resources/[jobs]/[weapons]/force-sling/server/events.lua +++ /dev/null @@ -1,58 +0,0 @@ -local function SafeSavePosition(filePath, data) - local success, error = pcall(function() - local fileData = json.decode(LoadResourceFile(GetCurrentResourceName(), filePath)) or {} - fileData = type(fileData) == 'table' and fileData or {} - - for k, v in pairs(data) do - fileData[k] = v - end - - return SaveResourceFile(GetCurrentResourceName(), filePath, json.encode(fileData, { indent = true }), -1) - end) - - if not success then - Debug("error", "Failed to save position data: " .. tostring(error)) - return false - end - return true -end - ---- @param coords table The coordinates of the weapon. ---- @param rot table The rotation of the weapon. ---- @param weapon string The weapon model. ---- @param weaponName string The weapon name. ---- @param boneId number The bone ID to attach the weapon to. ---- @param isPreset boolean Whether the position is a preset. ---- @return nil -RegisterNetEvent("force-sling:server:saveWeaponPosition", function(coords, rot, weapon, weaponName, boneId, isPreset) - Debug("info", "Saving weapon position for weapon: " .. weaponName .. " isPreset: " .. tostring(isPreset)) - - if not isPreset then - local positions = { - [GetPlayerIdentifierByType(source, "license")] = { - [weaponName] = { - coords = coords, - rot = rot, - boneId = boneId - } - } - } - - if SafeSavePosition("json/positions.json", positions) then - Debug("info", - "Weapon position saved for player: " .. GetPlayerIdentifierByType(source, "license") .. " weapon: " .. weaponName) - end - else - local presets = { - [weaponName] = { - coords = coords, - rot = rot, - boneId = boneId - } - } - - if SafeSavePosition("json/presets.json", presets) then - Debug("info", "Weapon preset saved for weapon: " .. weaponName) - end - end -end) diff --git a/resources/[jobs]/[weapons]/force-sling/server/functions.lua b/resources/[jobs]/[weapons]/force-sling/server/functions.lua deleted file mode 100644 index 5fb1cb8f5..000000000 --- a/resources/[jobs]/[weapons]/force-sling/server/functions.lua +++ /dev/null @@ -1,47 +0,0 @@ -Sling = {} - -function Sling:InitMain() - Debug("info", "Initializing main") - - Sling:LoadServerCallbacks() - - Debug("info", "Main initialized") -end - -function Sling:LoadServerCallbacks() - Debug("info", "Loading server callbacks") - - local resourceName = GetCurrentResourceName() - local callbacks = { - ["force-sling:callback:isPlayerAdmin"] = function(source, target) - if not target then target = source end - return Admin:IsPlayerAdmin(target) - end, - ["force-sling:callback:getCachedPositions"] = function(source) - local identifier = GetPlayerIdentifierByType(source, "license") - local positions = json.decode(LoadResourceFile(resourceName, "json/positions.json")) or {} - Debug("info", "Returning cached positions for identifier: " .. tostring(identifier)) - return positions[identifier] or {} - end, - ["force-sling:callback:getCachedPresets"] = function() - Debug("info", "Returning cached presets") - return json.decode(LoadResourceFile(resourceName, "json/presets.json")) or {} - end, - ["force-sling:callback:resetWeaponPositions"] = function(source, weapon) - Debug("info", - "Resetting weapon positions for source = " .. tostring(source) .. " and weapon = " .. tostring(weapon)) - local identifier = GetPlayerIdentifierByType(source, "license") - local positions = json.decode(LoadResourceFile(resourceName, "json/positions.json")) or {} - positions[identifier] = positions[identifier] or {} - positions[identifier][weapon] = nil - SaveResourceFile(resourceName, "json/positions.json", json.encode(positions), -1) - return positions[identifier] - end - } - - for name, func in pairs(callbacks) do - lib.callback.register(name, func) - end - - Debug("info", "Server callbacks loaded") -end diff --git a/resources/[jobs]/[weapons]/force-sling/server/main.lua b/resources/[jobs]/[weapons]/force-sling/server/main.lua deleted file mode 100644 index 5163680c4..000000000 --- a/resources/[jobs]/[weapons]/force-sling/server/main.lua +++ /dev/null @@ -1,183 +0,0 @@ -local positions = {} -local presets = {} -local positionsFile = 'positions.json' -local presetsFile = 'presets.json' -local attachedWeapons = {} - --- Load saved positions from JSON file -local function LoadPositions() - local file = LoadResourceFile(GetCurrentResourceName(), 'json/' .. positionsFile) - if file then - positions = json.decode(file) or {} - end -end - --- Load saved presets from JSON file -local function LoadPresets() - local file = LoadResourceFile(GetCurrentResourceName(), 'json/' .. presetsFile) - if file then - presets = json.decode(file) or {} - end -end - --- Save positions to JSON file -local function SavePositions() - SaveResourceFile(GetCurrentResourceName(), 'json/' .. positionsFile, json.encode(positions), -1) -end - --- Save presets to JSON file -local function SavePresets() - SaveResourceFile(GetCurrentResourceName(), 'json/' .. presetsFile, json.encode(presets), -1) -end - --- Überprüfe ob ein Spieler eine Waffe besitzt -local function DoesPlayerHaveWeapon(source, weaponName) - if Config.Framework.name == "qbcore" then - local Player = QBCore.Functions.GetPlayer(source) - if Player then - for _, item in pairs(Player.PlayerData.items) do - if item.name == weaponName then - return true - end - end - end - elseif Config.Framework.name == "esx" then - local xPlayer = ESX.GetPlayerFromId(source) - if xPlayer then - local hasWeapon = xPlayer.hasWeapon(weaponName) - return hasWeapon - end - end - return false -end - --- Load data when resource starts -CreateThread(function() - LoadPositions() - LoadPresets() -end) - --- Weapon sync with verification -RegisterNetEvent('force-sling:server:syncWeapons') -AddEventHandler('force-sling:server:syncWeapons', function(weaponData, action) - local src = source - - if action == 'attach' then - -- Überprüfe ob der Spieler die Waffe besitzt - if not DoesPlayerHaveWeapon(src, weaponData.weaponName) then - return - end - - attachedWeapons[src] = attachedWeapons[src] or {} - attachedWeapons[src][weaponData.weaponName] = weaponData - elseif action == 'detach' then - if attachedWeapons[src] then - attachedWeapons[src][weaponData.weaponName] = nil - end - end - - TriggerClientEvent('force-sling:client:syncWeapons', -1, src, weaponData, action) -end) - --- Callbacks -lib.callback.register('force-sling:callback:getCachedPositions', function(source) - local src = source - local playerPositions = {} - - -- Filtere nur die Positionen für Waffen, die der Spieler besitzt - for weaponName, posData in pairs(positions) do - if DoesPlayerHaveWeapon(src, weaponName) then - playerPositions[weaponName] = posData - end - end - - return playerPositions -end) - -lib.callback.register('force-sling:callback:getCachedPresets', function(source) - return presets -end) - -lib.callback.register('force-sling:callback:isPlayerAdmin', function(source) - local src = source - if Config.Framework.name == "qbcore" then - local Player = QBCore.Functions.GetPlayer(src) - return Player and Player.PlayerData.admin or false - elseif Config.Framework.name == "esx" then - local xPlayer = ESX.GetPlayerFromId(src) - return xPlayer and xPlayer.getGroup() == 'admin' or false - end - return false -end) - -lib.callback.register('force-sling:callback:resetWeaponPositions', function(source, weapon) - local src = source - if weapon then - if DoesPlayerHaveWeapon(src, weapon) then - positions[weapon] = nil - SavePositions() - end - else - -- Beim kompletten Reset nur die Positionen der Waffen löschen, die der Spieler besitzt - local newPositions = {} - for weaponName, posData in pairs(positions) do - if not DoesPlayerHaveWeapon(src, weaponName) then - newPositions[weaponName] = posData - end - end - positions = newPositions - SavePositions() - end - return positions -end) - -RegisterNetEvent('force-sling:server:saveWeaponPosition') -AddEventHandler('force-sling:server:saveWeaponPosition', function(position, rotation, weapon, weaponName, boneId, isPreset) - local src = source - local data = { - coords = position, - rot = rotation, - boneId = boneId - } - - if isPreset then - -- Nur Admins können Presets speichern - local isAdmin = lib.callback.await('force-sling:callback:isPlayerAdmin', src) - if isAdmin then - presets[weaponName] = data - SavePresets() - end - else - -- Überprüfe ob der Spieler die Waffe besitzt - if DoesPlayerHaveWeapon(src, weaponName) then - positions[weaponName] = data - SavePositions() - end - end -end) - --- Cleanup on player drop -AddEventHandler('playerDropped', function() - local src = source - if attachedWeapons[src] then - TriggerClientEvent('force-sling:client:cleanupPlayerWeapons', -1, src) - attachedWeapons[src] = nil - end -end) - --- Periodische Überprüfung der angehängten Waffen -CreateThread(function() - while true do - for playerId, weapons in pairs(attachedWeapons) do - for weaponName, _ in pairs(weapons) do - if not DoesPlayerHaveWeapon(playerId, weaponName) then - -- Spieler hat die Waffe nicht mehr, entferne sie - TriggerClientEvent('force-sling:client:syncWeapons', -1, playerId, {weaponName = weaponName}, 'detach') - attachedWeapons[playerId][weaponName] = nil - end - end - end - Wait(5000) -- Alle 5 Sekunden überprüfen - end -end) - diff --git a/resources/[jobs]/[weapons]/force-sling/server/misc/admin.lua b/resources/[jobs]/[weapons]/force-sling/server/misc/admin.lua deleted file mode 100644 index fcc75a161..000000000 --- a/resources/[jobs]/[weapons]/force-sling/server/misc/admin.lua +++ /dev/null @@ -1,61 +0,0 @@ -Admin = {} - ---- Checks if a player is an admin. ---- ---- This function determines if a player is an admin by checking their Discord roles ---- and global configuration settings. ---- ---- @param target number The target player. ---- @return boolean | string The player's admin status and type. ---- - `isAdmin` (boolean): Whether the player is an admin. ---- - `adminType` (string): The type of admin ("none" or "global"). -function Admin:IsPlayerAdmin(target) - Debug("info", "Checking if player is admin for target: " .. tostring(target)) - --- @type boolean | string - local admin = false; - - -- Check if the player is an admin via global configuration - if Config.Admin.Global.enabled and not admin then - if Config.Admin.Global.ace then - local isAdceAllowed = IsPlayerAceAllowed(target, Config.Admin.Global.ace) - if isAdceAllowed then - admin = "global" - end - end - - local identifiers = GetPlayerIdentifiers(target) - for _, identifier in ipairs(identifiers) do - if lib.table.contains(Config.Admin.Global.players, identifier) then - admin = "global" - break - end - end - end - - Debug("info", - "Admin check completed for target: " .. - tostring(target) .. " admin: " .. tostring(admin)) - return admin -end - ---- Gets a player's identifier. ---- ---- This function retrieves a specific type of identifier for a given player. ---- It logs the process of finding the identifier and returns the identifier if found. ---- ---- @param target number The target player. ---- @param identifierType string The type of identifier to get. ---- @return string | nil The player's identifier. -function Admin:getPlayerIdentifier(target, identifierType) - Debug("info", - "Getting player identifier for target: " .. tostring(target) .. " identifierType: " .. identifierType) - local identifiers = GetPlayerIdentifiers(target) - for _, identifier in ipairs(identifiers) do - if string.find(identifier, identifierType) then - Debug("info", "Player identifier for target: " .. tostring(target) .. " is: " .. tostring(identifier)) - return identifier - end - end - Debug("info", "Player identifier for target: " .. tostring(target) .. " not found") - return nil -end diff --git a/resources/[jobs]/[weapons]/force-sling/shared/functions.lua b/resources/[jobs]/[weapons]/force-sling/shared/functions.lua deleted file mode 100644 index 8e191bc33..000000000 --- a/resources/[jobs]/[weapons]/force-sling/shared/functions.lua +++ /dev/null @@ -1,56 +0,0 @@ -function IsResourceStartingOrStarted(resource) - return GetResourceState(resource) == "starting" or GetResourceState(resource) == "started" -end - -function Debug(level, message, ...) - if not Config.Debug then return end - - local levels = { - error = function(msg) lib.print.error(msg) end, - warn = function(msg) lib.print.warn(msg) end, - info = function(msg) lib.print.info(msg) end, - debug = function(msg) lib.print.debug(msg) end - } - - local fn = levels[level] or levels.info - fn(string.format(message, ...)) -end - -function InitFramework() - if not Config.Framework.name == "auto" then return end - local frameworks = { - { name = "esx", resource = "es_extended" }, - { name = "qbx", resource = "qbx_core" }, - { name = "qbcore", resource = "qb-core" } - } - - Debug("info", "Initializing framework") - for _, framework in ipairs(frameworks) do - if IsResourceStartingOrStarted(framework.resource) then - Config.Framework = framework - return - end - end - Debug("info", "Framework initialized: " .. Config.Framework.name) -end - -function InitInventory() - if not Config.Inventory == "auto" then return end - local inventories = { - { name = "qs-inventory", resource = "qs-inventory" }, - { name = "core_inventory", resource = "core_inventory" }, - { name = "qb-inventory", resource = "qb-inventory" }, - { name = "ox_inventory", resource = "ox_inventory" } - } - - Debug("info", "Initializing inventory") - for _, inventory in ipairs(inventories) do - if IsResourceStartingOrStarted(inventory.resource) then - Config.Inventory = inventory.name - Debug("info", "Inventory initialized: " .. Config.Inventory) - return - end - end - Config.Inventory = "none" - Debug("info", "Inventory initialized: " .. Config.Inventory) -end diff --git a/resources/[jobs]/[weapons]/force-sling/shared/variables.lua b/resources/[jobs]/[weapons]/force-sling/shared/variables.lua deleted file mode 100644 index c0642eb39..000000000 --- a/resources/[jobs]/[weapons]/force-sling/shared/variables.lua +++ /dev/null @@ -1 +0,0 @@ -otherPlayersWeapons = {} diff --git a/resources/[jobs]/[weapons]/force-sling/version.lua b/resources/[jobs]/[weapons]/force-sling/version.lua deleted file mode 100644 index 95061582c..000000000 --- a/resources/[jobs]/[weapons]/force-sling/version.lua +++ /dev/null @@ -1,93 +0,0 @@ -lib.versionCheck('Force-Developing/force-sling') - -local latestVersionUrl = -"https://gist.githubusercontent.com/Force-Developing/ee739a3263bc3421257d901e53e27b10/raw/force-sling" -local currentVersion = GetResourceMetadata(GetCurrentResourceName(), 'version', 0) - -local function parseVersion(version) - local major, minor, patch = version:match("(%d+)%.(%d+)%.(%d+)") - if not major then return nil end - return { - major = tonumber(major), - minor = tonumber(minor), - patch = tonumber(patch) - } -end - -local function isNewerVersion(current, latest) - local currentParsed = parseVersion(current) - local latestParsed = parseVersion(latest) - - if not currentParsed or not latestParsed then - return false - end - - if latestParsed.major > currentParsed.major then return true end - if latestParsed.major < currentParsed.major then return false end - if latestParsed.minor > currentParsed.minor then return true end - if latestParsed.minor < currentParsed.minor then return false end - return latestParsed.patch > currentParsed.patch -end - -local function formatChangelogs(changelogs) - if not changelogs then return "No changelog available" end - return changelogs:gsub("%-", "\n-"):gsub("^%s*(.-)%s*$", "%1") -end - -local function versionCheck() - PerformHttpRequest(latestVersionUrl, function(err, response, headers) - if err ~= 200 then - lib.print.error(string.format("Version check failed with error code: %s", err)) - return - end - - local success, result = pcall(function() - local version, changelogs = response:match("<(.-)>(.-)<") - if not version then - version = response:match("<(.-)>") - changelogs = response:match(">(.-)<") - end - - if not version then - error("Invalid version format in response") - end - - version = version:gsub("[<>]", "") - local isNewer = isNewerVersion(currentVersion, version) - - local output = string.format([[ -------------- -Current Version: %s -Latest Version: %s -------------- -%s --------------]], - currentVersion, - version, - isNewer and string.format( - "Update available!\nChangelogs:\n%s", - formatChangelogs(changelogs) - ) or "You are running the latest version." - ) - - if isNewer then - lib.print.warn(output) - else - lib.print.info(output) - end - end) - - if not success then - lib.print.error(string.format("Failed to process version check: %s", result)) - end - end, 'GET', '', { - ['Cache-Control'] = 'no-cache', - ['Content-Type'] = 'application/json', - ['User-Agent'] = string.format('force-appearance/%s', currentVersion) - }) -end - -CreateThread(function() - Wait(5000) - versionCheck() -end)