├── LICENSE ├── README.md ├── client ├── client.lua ├── placeables.lua └── pushables.lua ├── fxmanifest.lua ├── images ├── beachball.png ├── beachtowel.png ├── beachumbrella.png ├── bodybag.png ├── campchair_blue.png ├── campchair_green.png ├── campchair_plaid.png ├── campfire.png ├── candycane.png ├── canopy.png ├── cargobox1.png ├── cargobox2.png ├── cargobox3.png ├── cargobox4.png ├── cargobox5.png ├── cargobox6.png ├── cargobox7.png ├── cargobox8.png ├── carjack.png ├── constructionbarrier.png ├── constructionbarrier2.png ├── constructionbarrier3.png ├── constructiongenerator.png ├── cot.png ├── crate1.png ├── crate2.png ├── crate3.png ├── crate4.png ├── crate5.png ├── drinkcart.png ├── examlight.png ├── folding_chair.png ├── greenscreen.png ├── handtruck.png ├── hazardbin.png ├── hobomattress.png ├── hoboshelter.png ├── hobostove.png ├── hospitalbed1.png ├── hospitalbed2.png ├── hospitalbedtable.png ├── janitorcart1.png ├── janitorcart2.png ├── largetent.png ├── lawnmower.png ├── medbag.png ├── medmachine.png ├── medtable.png ├── meshfence.png ├── metalcart.png ├── metalramp.png ├── microscope.png ├── mopbucket.png ├── oldtent.png ├── oscillator.png ├── pallet1.png ├── pallet2.png ├── pallet3.png ├── pallet4.png ├── pallet5.png ├── plastic_chair.png ├── plastictable.png ├── roadclosedbarrier.png ├── roadcone.png ├── roadconebig.png ├── roadpole.png ├── roadworkahead.png ├── roomtrolly.png ├── ropebarrier.png ├── sexdoll.png ├── shoppingcart.png ├── skateramp.png ├── sleepingbag.png ├── snowman1.png ├── snowman2.png ├── snowman3.png ├── snowman4.png ├── soccerball.png ├── stepladder.png ├── stretcher.png ├── teacart.png ├── tent.png ├── toolchest.png ├── trafficdevice.png ├── trashbin.png ├── trifinishbanner.png ├── tristartbanner.png ├── tristarttable.png ├── warehousetrolly1.png ├── warehousetrolly2.png ├── waterbarrel.png ├── wheelbarrow.png ├── woodramp.png ├── woodtable.png ├── worklight.png ├── worklight2.png ├── worklight3.png ├── xmaspresent.png ├── xmastree1.png └── xmastree2.png ├── server └── server.lua └── shared ├── config.lua └── framework.lua /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /client/client.lua: -------------------------------------------------------------------------------- 1 | function RequestNetworkControlOfObject(netId, itemEntity) 2 | if NetworkDoesNetworkIdExist(netId) then 3 | NetworkRequestControlOfNetworkId(netId) 4 | while not NetworkHasControlOfNetworkId(netId) do 5 | Wait(100) 6 | NetworkRequestControlOfNetworkId(netId) 7 | end 8 | end 9 | 10 | if DoesEntityExist(itemEntity) then 11 | NetworkRequestControlOfEntity(itemEntity) 12 | while not NetworkHasControlOfEntity(itemEntity) do 13 | Wait(100) 14 | NetworkRequestControlOfEntity(itemEntity) 15 | end 16 | end 17 | end 18 | 19 | function LoadAnimDict(dict) 20 | while not HasAnimDictLoaded(dict) do 21 | RequestAnimDict(dict) 22 | Wait(10) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /client/placeables.lua: -------------------------------------------------------------------------------- 1 | local animationDict = "pickup_object" 2 | local animation = "pickup_low" 3 | local isInPlaceItemMode = false 4 | 5 | -- Keeps track of the models that have already been set with target options, ensuring we don't create duplicate options for the same model 6 | -- In some frameworks like OX, if you create targetOptions on a model that already has it, it will append the options, whereas 7 | -- in QB it will override and only the last set of options will be used. We just need to add one option to the target model and then 8 | -- the pickup event will use the statebag to determine the correct item to give back to the player 9 | local targetModels = {} 10 | 11 | local function LoadPropDict(model) 12 | while not HasModelLoaded(GetHashKey(model)) do 13 | RequestModel(GetHashKey(model)) 14 | Wait(10) 15 | end 16 | end 17 | 18 | -- Gets the direction the camera is looking for the raycast function 19 | local function RotationToDirection(rotation) 20 | local adjustedRotation = { 21 | x = (math.pi / 180) * rotation.x, 22 | y = (math.pi / 180) * rotation.y, 23 | z = (math.pi / 180) * rotation.z, 24 | } 25 | local direction = { 26 | x = -math.sin(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)), 27 | y = math.cos(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)), 28 | z = math.sin(adjustedRotation.x), 29 | } 30 | return direction 31 | end 32 | 33 | -- Uses a RayCast to get the entity, coords, and whether we "hit" something with the raycast 34 | -- Object passed in, is the current object that we want the raycast to ignore 35 | local function RayCastGamePlayCamera(distance, object, raycastDetectWorldOnly) 36 | local cameraRotation = GetGameplayCamRot() 37 | local cameraCoord = GetGameplayCamCoord() 38 | local direction = RotationToDirection(cameraRotation) 39 | local destination = { 40 | x = cameraCoord.x + direction.x * distance, 41 | y = cameraCoord.y + direction.y * distance, 42 | z = cameraCoord.z + direction.z * distance, 43 | } 44 | 45 | -- Trace flag 4294967295 means the raycast will intersect with everything (including vehicles) 46 | -- Trace flag 1 means the raycast will only intersect with the world (ignoring other entities like peds, cars, etc) 47 | local traceFlag = 4294967295 48 | if raycastDetectWorldOnly then 49 | traceFlag = 1 50 | end 51 | 52 | local a, hit, coords, d, entity = GetShapeTestResult(StartShapeTestRay(cameraCoord.x, cameraCoord.y, cameraCoord.z, destination.x, destination.y, destination.z, traceFlag, object, 0)) 53 | return hit, coords, entity 54 | end 55 | 56 | -- Used to Draw the text on the screen 57 | local function Draw2DText(content, font, colour, scale, x, y) 58 | SetTextFont(font) 59 | SetTextScale(scale, scale) 60 | SetTextColour(colour[1], colour[2], colour[3], 255) 61 | SetTextEntry("STRING") 62 | SetTextDropShadow(0, 0, 0, 0, 255) 63 | SetTextDropShadow() 64 | SetTextEdge(4, 0, 0, 0, 255) 65 | SetTextOutline() 66 | AddTextComponentString(content) 67 | DrawText(x, y) 68 | end 69 | 70 | -- This handles placing the actual item that is network synced 71 | local function placeItem(item, coords, heading, shouldSnapToGround) 72 | local ped = PlayerPedId() 73 | local itemName = item.item 74 | local itemModel = item.model 75 | local shouldFreezeItem = item.isFrozen 76 | 77 | -- Cancel any active animation 78 | ClearPedTasks(ped) 79 | 80 | Progressbar("place_item", "Placing " .. item.label, 750, false, true, { 81 | disableMovement = false, 82 | disableCarMovement = false, 83 | disableMouse = false, 84 | disableCombat = true, 85 | }, { 86 | animDict = animationDict, 87 | anim = animation, 88 | flags = 0, 89 | }, nil, nil, function() -- Done 90 | -- Stop playing the animation 91 | StopAnimTask(ped, animationDict, animation, 1.0) 92 | 93 | -- Remove the item from the inventory 94 | TriggerServerEvent("wp-placeables:server:RemoveItem", itemName) 95 | 96 | LoadPropDict(itemModel) 97 | 98 | -- Spawn prop on ground at the provided coords and heading 99 | local obj = CreateObject(itemModel, GetEntityCoords(ped), true) 100 | if obj ~= 0 then 101 | SetEntityRotation(obj, 0.0, 0.0, heading, false, false) 102 | SetEntityCoords(obj, coords) 103 | 104 | if shouldFreezeItem then 105 | FreezeEntityPosition(obj, true) 106 | end 107 | 108 | -- Some items dont go to the ground properly with this, and it actually makes them hover 109 | if shouldSnapToGround then 110 | PlaceObjectOnGroundProperly(obj) 111 | end 112 | 113 | -- Use statebag property itemName to set the itemName on the entity. 114 | -- This value is used to grant the correct item back to the player when they pick it up. 115 | -- It also solves the issue of the same model being used for multiple items 116 | Entity(obj).state:set("itemName", itemName, true) 117 | 118 | CreateLog(itemName, true) 119 | end 120 | 121 | SetModelAsNoLongerNeeded(itemModel) 122 | end, function() -- Cancel 123 | StopAnimTask(ped, animationDict, animation, 1.0) 124 | Notify("Canceled..", "error") 125 | end) 126 | end 127 | 128 | -- Starts a thread that puts the player into item placement mode 129 | -- This will spawn a local object that only the player can see and move around to position it 130 | -- Once the player places the object it will delete the local one and then create a new network synced object 131 | local function startItemPlacementMode(item) 132 | -- This is to prevent entering place mode multiple times if its already active 133 | if isInPlaceItemMode then 134 | Notify("Already placing an item", "error", 5000) 135 | return 136 | end 137 | 138 | isInPlaceItemMode = true 139 | local ped = PlayerPedId() 140 | local itemModel = item.model 141 | 142 | -- Create a local object for only this client (not synced to network) and make it transparent 143 | local obj = CreateObject(itemModel, GetEntityCoords(ped), false, false) 144 | SetEntityAlpha(obj, 150, false) 145 | SetEntityCollision(obj, false, false) 146 | 147 | local zOffset = 0 148 | 149 | -- This is used to determine if the raycast should only detect the world or if it should detect everything (including vehicles) 150 | local raycastDetectWorldOnly = true 151 | 152 | CreateThread(function() 153 | while isInPlaceItemMode do 154 | -- Use raycast based on where the camera is pointed 155 | local hit, coords, entity = RayCastGamePlayCamera(Config.ItemPlacementModeRadius, obj, raycastDetectWorldOnly) 156 | 157 | -- Move the object to the coords from the raycast 158 | SetEntityCoords(obj, coords.x, coords.y, coords.z + zOffset) 159 | 160 | -- Display the controls 161 | Draw2DText("[E] Place\n[Shift+E] Place on ground\n[Scroll Up/Down] Rotate\n[Shift+Scroll Up/Down] Raise/lower", 4, { 255, 255, 255, }, 0.4, 0.85, 0.85) 162 | Draw2DText("[Scroll Click] Change mode\n[Right Click / Backspace] Exit place mode", 4, { 255, 255, 255, }, 0.4, 0.85, 0.945) 163 | 164 | -- Handle various key presses and actions 165 | 166 | -- Controls for placing item 167 | 168 | -- Pressed Shift + E - Place object on ground 169 | if IsControlJustReleased(0, 38) and IsControlPressed(0, 21) then 170 | isInPlaceItemMode = false 171 | 172 | local objHeading = GetEntityHeading(obj) 173 | local snapToGround = true 174 | 175 | DeleteEntity(obj) 176 | placeItem(item, vector3(coords.x, coords.y, coords.z + zOffset), objHeading, snapToGround) 177 | 178 | -- Pressed E - Place object at current position 179 | elseif IsControlJustReleased(0, 38) then 180 | isInPlaceItemMode = false 181 | 182 | local objHeading = GetEntityHeading(obj) 183 | local snapToGround = false 184 | 185 | DeleteEntity(obj) 186 | placeItem(item, vector3(coords.x, coords.y, coords.z + zOffset), objHeading, snapToGround) 187 | end 188 | 189 | -- Controls for rotating item 190 | 191 | -- Mouse Wheel Up (and Shift not pressed), rotate by +10 degrees 192 | if IsControlJustReleased(0, 241) and not IsControlPressed(0, 21) then 193 | local objHeading = GetEntityHeading(obj) 194 | SetEntityRotation(obj, 0.0, 0.0, objHeading + 10, false, false) 195 | end 196 | 197 | -- Mouse Wheel Down (and shift not pressed), rotate by -10 degrees 198 | if IsControlJustReleased(0, 242) and not IsControlPressed(0, 21) then 199 | local objHeading = GetEntityHeading(obj) 200 | SetEntityRotation(obj, 0.0, 0.0, objHeading - 10, false, false) 201 | end 202 | 203 | -- Controls for raising/lowering item 204 | 205 | -- Shift + Mouse Wheel Up, move item up 206 | if IsControlPressed(0, 21) and IsControlJustReleased(0, 241) then 207 | zOffset = zOffset + 0.1 208 | if zOffset > Config.maxZOffset then 209 | zOffset = Config.maxZOffset 210 | end 211 | end 212 | 213 | -- Shift + Mouse Wheel Down, move item down 214 | if IsControlPressed(0, 21) and IsControlJustReleased(0, 242) then 215 | zOffset = zOffset - 0.1 216 | if zOffset < Config.minZOffset then 217 | zOffset = Config.minZOffset 218 | end 219 | end 220 | 221 | -- Mouse Wheel Click, change placement mode 222 | if IsControlJustReleased(0, 348) then 223 | raycastDetectWorldOnly = not raycastDetectWorldOnly 224 | end 225 | 226 | -- Right click or Backspace to exit out of placement mode and delete the local object 227 | if IsControlJustReleased(0, 177) then 228 | isInPlaceItemMode = false 229 | DeleteEntity(obj) 230 | end 231 | 232 | Wait(1) 233 | end 234 | end) 235 | end 236 | 237 | -- Handles picking up the prop, deleting it from the world and adding it to the players inventory 238 | local function pickUpItem(itemData) 239 | local ped = PlayerPedId() 240 | local itemEntity = itemData.entity 241 | local itemModel = itemData.itemModel 242 | 243 | -- When picking up the item, try to get the itemName from the statebag property first, else fallback to the itemName from the itemData provided by the target script 244 | -- Using the statebag property ensures we get the correct item name if the prop model is shared by multiple items.. 245 | local itemName = Entity(itemEntity).state.itemName or itemData.itemName 246 | 247 | if itemName then 248 | -- Cancel any active animation 249 | ClearPedTasks(ped) 250 | 251 | Progressbar("pickup_item", "Picking up item", 200, false, true, { 252 | disableMovement = false, 253 | disableCarMovement = false, 254 | disableMouse = false, 255 | disableCombat = true, 256 | }, { 257 | animDict = animationDict, 258 | anim = animation, 259 | flags = 0, 260 | }, nil, nil, function() -- Done 261 | -- Stop playing the animation 262 | StopAnimTask(ped, animationDict, animation, 1.0) 263 | 264 | -- Add the item to the inventory 265 | TriggerServerEvent("wp-placeables:server:AddItem", itemName) 266 | 267 | -- First request control of networkId and wait until have control of netId before deleting it 268 | -- Item will not properly delete if the client doesn't have control of the networkId 269 | local coords = GetEntityCoords(itemEntity) 270 | local netId = NetworkGetNetworkIdFromEntity(itemEntity) 271 | RequestNetworkControlOfObject(netId, itemEntity) 272 | SetEntityAsMissionEntity(itemEntity, true, true) 273 | DeleteEntity(itemEntity) 274 | 275 | local object = { coords = coords, model = itemModel, } 276 | TriggerServerEvent("wp-placeables:server:deleteWorldObject", object) 277 | 278 | CreateLog(itemName, false) 279 | end, function() -- Cancel 280 | StopAnimTask(ped, animationDict, animation, 1.0) 281 | Notify("Canceled..", "error") 282 | end) 283 | end 284 | end 285 | 286 | RegisterNetEvent("wp-placeables:client:placeItem", function(item) 287 | if not IsPedInAnyVehicle(PlayerPedId(), true) then 288 | startItemPlacementMode(item) 289 | else 290 | Notify("You cannot place items while in a vehicle", "error", 5000) 291 | end 292 | end) 293 | 294 | RegisterNetEvent("wp-placeables:client:pickUpItem", function(data) 295 | pickUpItem(data) 296 | end) 297 | 298 | -- Setup each placeable prop to use QB target 299 | -- Itemname is in the options so we know which item to give back when picked up 300 | for _, prop in pairs(Config.PlaceableProps) do 301 | local pickUpEvent = "wp-placeables:client:pickUpItem" 302 | if prop.customPickupEvent then 303 | pickUpEvent = prop.customPickupEvent 304 | end 305 | local targetOptions = { 306 | { 307 | event = pickUpEvent, 308 | icon = "fas fa-hand-holding", 309 | label = "Pick up", 310 | itemName = prop.item, 311 | itemModel = prop.model, 312 | }, 313 | } 314 | 315 | -- Add custom target options to the target options for this item prop 316 | if prop.customTargetOptions then 317 | for _, customOption in pairs(prop.customTargetOptions) do 318 | -- Stamp the itemName and itemModel onto the data so the custom events have access to this info 319 | customOption.itemName = prop.item 320 | customOption.itemModel = prop.model 321 | 322 | targetOptions[#targetOptions + 1] = customOption 323 | end 324 | end 325 | 326 | -- Make sure we only define the target options once for each model 327 | -- If you define the same model twice: 328 | -- In qb-target, it will override the options, and the last one defined is used 329 | -- In ox_target, it will append the options, resulting in N duplicate options 330 | if not targetModels[prop.model] then 331 | AddTargetModel(prop.model, { 332 | options = targetOptions, 333 | distance = 1.5, 334 | }) 335 | targetModels[prop.model] = true 336 | end 337 | end 338 | 339 | -- Delete the world object 340 | -- object = {coords = coords, model = itemModel} 341 | RegisterNetEvent("wp-placeables:client:deleteWorldObject", function(object) 342 | local entity = GetClosestObjectOfType(object.coords.x, object.coords.y, object.coords.z, 0.1, object.model, false, false, false) 343 | if DoesEntityExist(entity) then 344 | SetEntityAsMissionEntity(entity, 1, 1) 345 | DeleteObject(entity) 346 | SetEntityAsNoLongerNeeded(entity) 347 | end 348 | end) 349 | 350 | -- Runs a thread to loop through the deleted world objects table and removes the item if it exists 351 | -- This is to handle cases if the item were to have respawned 352 | -- Disabling this for now since we dont need to care if the item respawns 353 | -- There is currently an issue where this was being used for both player placed objects as well as world props 354 | -- If you placed an item, picked it up and placed the same item down again, the cleanup thread would delete it since its at the same coords. 355 | -- If we want to re-enable this, we need to find a way to only use this cleanup thread on world spawned props 356 | -- AddEventHandler('QBCore:Client:OnPlayerLoaded', function() 357 | -- QBCore.Functions.TriggerCallback('wp-placeables:server:GetDeletedWorldObjects', function(deletedObjects) 358 | -- objects = deletedObjects 359 | -- end) 360 | -- end) 361 | -- CreateThread(function() 362 | -- while true do 363 | -- for k = 1, #objects, 1 do 364 | -- v = objects[k] 365 | -- local entity = GetClosestObjectOfType(v.coords.x, v.coords.y, v.coords.z, 0.1, v.model, false, false, false) 366 | -- if DoesEntityExist(entity) then 367 | -- SetEntityAsMissionEntity(entity, 1, 1) 368 | -- DeleteObject(entity) 369 | -- SetEntityAsNoLongerNeeded(entity) 370 | -- end 371 | -- end 372 | -- Wait(10000) 373 | -- end 374 | -- end) 375 | -------------------------------------------------------------------------------- /client/pushables.lua: -------------------------------------------------------------------------------- 1 | local isAttached = false 2 | local isSittingOnObject = false 3 | local pushableObject = nil 4 | 5 | -- Detaches the object from the player, stops the animation, and resets the variables 6 | local function ReleasePushableObject() 7 | DetachEntity(pushableObject, false, true) 8 | SetEntityCollision(pushableObject, true, true) 9 | ClearPedTasksImmediately(PlayerPedId()) 10 | 11 | -- Reset variables 12 | isAttached = false 13 | isSittingOnObject = false 14 | pushableObject = nil 15 | end 16 | 17 | -- Runs a thread while player is attached to the pushable object, disables some keys and listens for E keypress to release the object 18 | -- Also checks that player is still in the animation, if not then puts them back into the animation 19 | local function PushableObjectAttachedThread(animDict, anim) 20 | CreateThread(function() 21 | while isAttached do 22 | -- Disables attacking controls 23 | DisableControlAction(0, 24, true) -- disable attack 24 | DisableControlAction(0, 25, true) -- disable aim 25 | DisableControlAction(0, 47, true) -- disable weapon 26 | DisableControlAction(0, 58, true) -- disable weapon 27 | DisableControlAction(0, 263, true) -- disable melee 28 | DisableControlAction(0, 264, true) -- disable melee 29 | DisableControlAction(0, 257, true) -- disable melee 30 | DisableControlAction(0, 140, true) -- disable melee 31 | DisableControlAction(0, 141, true) -- disable melee 32 | DisableControlAction(0, 142, true) -- disable melee 33 | DisableControlAction(0, 143, true) -- disable melee 34 | 35 | -- Check to see if animation is still playing, if not then put the player back in the animation 36 | local playerPed = PlayerPedId() 37 | if not IsEntityPlayingAnim(playerPed, animDict, anim, 3) and not IsPedRagdoll(playerPed) then 38 | local animFlag = isSittingOnObject and 5 or 51 39 | ClearPedTasks(playerPed) 40 | LoadAnimDict(animDict) 41 | TaskPlayAnim(playerPed, animDict, anim, 3.0, 3.0, -1, animFlag, 0, 0, 0, 0) 42 | end 43 | 44 | -- Pressed E 45 | if IsControlJustPressed(0, 38) then 46 | ReleasePushableObject() 47 | end 48 | 49 | Wait(5) -- Needs to be a small number so that player doesnt need to spam press E to get it to take 50 | end 51 | end) 52 | end 53 | 54 | -- Attaches the object to the player and plays a pushing animation 55 | local function PushObject(data) 56 | local PlayerPed = PlayerPedId() 57 | 58 | pushableObject = data.entity 59 | 60 | if pushableObject then 61 | local netId = NetworkGetNetworkIdFromEntity(pushableObject) 62 | RequestNetworkControlOfObject(netId, pushableObject) 63 | 64 | LoadAnimDict(data.animationPushOptions.animationDict) 65 | TaskPlayAnim(PlayerPed, data.animationPushOptions.animationDict, data.animationPushOptions.animationName, 8.0, 8.0, -1, 51, 0, 0, 0, 0) 66 | 67 | local offset = data.animationPushOptions.offset 68 | local rotation = data.animationPushOptions.rotation 69 | 70 | SetTimeout(150, function() 71 | isAttached = true 72 | SetEntityCollision(pushableObject, false, false) 73 | AttachEntityToEntity( 74 | pushableObject, 75 | PlayerPed, 76 | GetPedBoneIndex(PlayerPed, 28422), 77 | offset.x, 78 | offset.y, 79 | offset.z, 80 | rotation.x, 81 | rotation.y, 82 | rotation.z, 83 | false, -- p9 84 | false, -- usesoftpinner 85 | true, -- collision 86 | false, -- isPed 87 | 2, -- rotationorder 88 | true -- fixrot 89 | ) 90 | 91 | PushableObjectAttachedThread(data.animationPushOptions.animationDict, data.animationPushOptions.animationName) 92 | end) 93 | end 94 | end 95 | 96 | -- Attaches player to object and plays the sitting animation 97 | local function SitOnObject(data) 98 | local PlayerPed = PlayerPedId() 99 | 100 | pushableObject = data.entity 101 | 102 | if pushableObject ~= nil then 103 | LoadAnimDict(data.animationSitOptions.animationDict) 104 | TaskPlayAnim(PlayerPed, data.animationSitOptions.animationDict, data.animationSitOptions.animationName, 8.0, 8.0, -1, 5, 0, 0, 0, 0) 105 | 106 | local offset = data.animationSitOptions.offset 107 | local rotation = data.animationSitOptions.rotation 108 | 109 | SetTimeout(150, function() 110 | isAttached = true 111 | isSittingOnObject = true 112 | AttachEntityToEntity( 113 | PlayerPed, 114 | pushableObject, 115 | GetPedBoneIndex(PlayerPed, 11816), 116 | offset.x, 117 | offset.y, 118 | offset.z, 119 | rotation.x, 120 | rotation.y, 121 | rotation.z, 122 | false, -- p9 123 | false, -- usesoftpinner 124 | false, -- collision -- if this is true, then the peds body will collide with things as you push it around 125 | true, -- isPed 126 | 2, -- rotationorder 127 | true -- fixrot 128 | ) 129 | 130 | PushableObjectAttachedThread(data.animationSitOptions.animationDict, data.animationSitOptions.animationName) 131 | end) 132 | end 133 | end 134 | 135 | AddEventHandler("onResourceStop", function(resource) 136 | if resource == GetCurrentResourceName() then 137 | if pushableObject then 138 | ReleasePushableObject() 139 | DeleteObject(pushableObject) 140 | ClearPedTasksImmediately(PlayerPedId()) 141 | end 142 | end 143 | end) 144 | 145 | RegisterNetEvent("wp-placeables:client:pushObject", function(data) 146 | PushObject(data) 147 | end) 148 | 149 | RegisterNetEvent("wp-placeables:client:sitOnObject", function(data) 150 | SitOnObject(data) 151 | end) 152 | 153 | local function IsPlayerSittingOnPlaceableProp() 154 | return isSittingOnObject 155 | end 156 | exports("IsPlayerSittingOnPlaceableProp", IsPlayerSittingOnPlaceableProp) 157 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version "cerulean" 2 | game "gta5" 3 | 4 | description "Waypoint Placeables" 5 | author "BackSH00TER - Waypoint RP" 6 | version "1.1.4" 7 | 8 | shared_script { 9 | -- "@ox_lib/init.lua", -- Uncomment this if you are planning to integrate with any ox scripts 10 | "shared/config.lua", 11 | "shared/framework.lua", 12 | } 13 | 14 | client_scripts { 15 | "client/client.lua", 16 | "client/pushables.lua", 17 | "client/placeables.lua", 18 | } 19 | 20 | server_scripts { 21 | "server/server.lua", 22 | } 23 | 24 | lua54 "yes" 25 | -------------------------------------------------------------------------------- /images/beachball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/beachball.png -------------------------------------------------------------------------------- /images/beachtowel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/beachtowel.png -------------------------------------------------------------------------------- /images/beachumbrella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/beachumbrella.png -------------------------------------------------------------------------------- /images/bodybag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/bodybag.png -------------------------------------------------------------------------------- /images/campchair_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/campchair_blue.png -------------------------------------------------------------------------------- /images/campchair_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/campchair_green.png -------------------------------------------------------------------------------- /images/campchair_plaid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/campchair_plaid.png -------------------------------------------------------------------------------- /images/campfire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/campfire.png -------------------------------------------------------------------------------- /images/candycane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/candycane.png -------------------------------------------------------------------------------- /images/canopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/canopy.png -------------------------------------------------------------------------------- /images/cargobox1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox1.png -------------------------------------------------------------------------------- /images/cargobox2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox2.png -------------------------------------------------------------------------------- /images/cargobox3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox3.png -------------------------------------------------------------------------------- /images/cargobox4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox4.png -------------------------------------------------------------------------------- /images/cargobox5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox5.png -------------------------------------------------------------------------------- /images/cargobox6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox6.png -------------------------------------------------------------------------------- /images/cargobox7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox7.png -------------------------------------------------------------------------------- /images/cargobox8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cargobox8.png -------------------------------------------------------------------------------- /images/carjack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/carjack.png -------------------------------------------------------------------------------- /images/constructionbarrier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/constructionbarrier.png -------------------------------------------------------------------------------- /images/constructionbarrier2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/constructionbarrier2.png -------------------------------------------------------------------------------- /images/constructionbarrier3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/constructionbarrier3.png -------------------------------------------------------------------------------- /images/constructiongenerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/constructiongenerator.png -------------------------------------------------------------------------------- /images/cot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/cot.png -------------------------------------------------------------------------------- /images/crate1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/crate1.png -------------------------------------------------------------------------------- /images/crate2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/crate2.png -------------------------------------------------------------------------------- /images/crate3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/crate3.png -------------------------------------------------------------------------------- /images/crate4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/crate4.png -------------------------------------------------------------------------------- /images/crate5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/crate5.png -------------------------------------------------------------------------------- /images/drinkcart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/drinkcart.png -------------------------------------------------------------------------------- /images/examlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/examlight.png -------------------------------------------------------------------------------- /images/folding_chair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/folding_chair.png -------------------------------------------------------------------------------- /images/greenscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/greenscreen.png -------------------------------------------------------------------------------- /images/handtruck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/handtruck.png -------------------------------------------------------------------------------- /images/hazardbin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hazardbin.png -------------------------------------------------------------------------------- /images/hobomattress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hobomattress.png -------------------------------------------------------------------------------- /images/hoboshelter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hoboshelter.png -------------------------------------------------------------------------------- /images/hobostove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hobostove.png -------------------------------------------------------------------------------- /images/hospitalbed1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hospitalbed1.png -------------------------------------------------------------------------------- /images/hospitalbed2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hospitalbed2.png -------------------------------------------------------------------------------- /images/hospitalbedtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/hospitalbedtable.png -------------------------------------------------------------------------------- /images/janitorcart1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/janitorcart1.png -------------------------------------------------------------------------------- /images/janitorcart2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/janitorcart2.png -------------------------------------------------------------------------------- /images/largetent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/largetent.png -------------------------------------------------------------------------------- /images/lawnmower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/lawnmower.png -------------------------------------------------------------------------------- /images/medbag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/medbag.png -------------------------------------------------------------------------------- /images/medmachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/medmachine.png -------------------------------------------------------------------------------- /images/medtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/medtable.png -------------------------------------------------------------------------------- /images/meshfence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/meshfence.png -------------------------------------------------------------------------------- /images/metalcart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/metalcart.png -------------------------------------------------------------------------------- /images/metalramp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/metalramp.png -------------------------------------------------------------------------------- /images/microscope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/microscope.png -------------------------------------------------------------------------------- /images/mopbucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/mopbucket.png -------------------------------------------------------------------------------- /images/oldtent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/oldtent.png -------------------------------------------------------------------------------- /images/oscillator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/oscillator.png -------------------------------------------------------------------------------- /images/pallet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/pallet1.png -------------------------------------------------------------------------------- /images/pallet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/pallet2.png -------------------------------------------------------------------------------- /images/pallet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/pallet3.png -------------------------------------------------------------------------------- /images/pallet4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/pallet4.png -------------------------------------------------------------------------------- /images/pallet5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/pallet5.png -------------------------------------------------------------------------------- /images/plastic_chair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/plastic_chair.png -------------------------------------------------------------------------------- /images/plastictable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/plastictable.png -------------------------------------------------------------------------------- /images/roadclosedbarrier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roadclosedbarrier.png -------------------------------------------------------------------------------- /images/roadcone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roadcone.png -------------------------------------------------------------------------------- /images/roadconebig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roadconebig.png -------------------------------------------------------------------------------- /images/roadpole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roadpole.png -------------------------------------------------------------------------------- /images/roadworkahead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roadworkahead.png -------------------------------------------------------------------------------- /images/roomtrolly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/roomtrolly.png -------------------------------------------------------------------------------- /images/ropebarrier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/ropebarrier.png -------------------------------------------------------------------------------- /images/sexdoll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/sexdoll.png -------------------------------------------------------------------------------- /images/shoppingcart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/shoppingcart.png -------------------------------------------------------------------------------- /images/skateramp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/skateramp.png -------------------------------------------------------------------------------- /images/sleepingbag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/sleepingbag.png -------------------------------------------------------------------------------- /images/snowman1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/snowman1.png -------------------------------------------------------------------------------- /images/snowman2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/snowman2.png -------------------------------------------------------------------------------- /images/snowman3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/snowman3.png -------------------------------------------------------------------------------- /images/snowman4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/snowman4.png -------------------------------------------------------------------------------- /images/soccerball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/soccerball.png -------------------------------------------------------------------------------- /images/stepladder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/stepladder.png -------------------------------------------------------------------------------- /images/stretcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/stretcher.png -------------------------------------------------------------------------------- /images/teacart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/teacart.png -------------------------------------------------------------------------------- /images/tent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/tent.png -------------------------------------------------------------------------------- /images/toolchest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/toolchest.png -------------------------------------------------------------------------------- /images/trafficdevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/trafficdevice.png -------------------------------------------------------------------------------- /images/trashbin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/trashbin.png -------------------------------------------------------------------------------- /images/trifinishbanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/trifinishbanner.png -------------------------------------------------------------------------------- /images/tristartbanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/tristartbanner.png -------------------------------------------------------------------------------- /images/tristarttable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/tristarttable.png -------------------------------------------------------------------------------- /images/warehousetrolly1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/warehousetrolly1.png -------------------------------------------------------------------------------- /images/warehousetrolly2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/warehousetrolly2.png -------------------------------------------------------------------------------- /images/waterbarrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/waterbarrel.png -------------------------------------------------------------------------------- /images/wheelbarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/wheelbarrow.png -------------------------------------------------------------------------------- /images/woodramp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/woodramp.png -------------------------------------------------------------------------------- /images/woodtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/woodtable.png -------------------------------------------------------------------------------- /images/worklight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/worklight.png -------------------------------------------------------------------------------- /images/worklight2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/worklight2.png -------------------------------------------------------------------------------- /images/worklight3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/worklight3.png -------------------------------------------------------------------------------- /images/xmaspresent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/xmaspresent.png -------------------------------------------------------------------------------- /images/xmastree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/xmastree1.png -------------------------------------------------------------------------------- /images/xmastree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaypointRP/wp-placeables/39b9b303369406aad9058fc576ba1d430830b8d1/images/xmastree2.png -------------------------------------------------------------------------------- /server/server.lua: -------------------------------------------------------------------------------- 1 | -- Setup all the placeable props as useable items 2 | for _, prop in pairs(Config.PlaceableProps) do 3 | CreateUseableItem(prop.item, function(source, item) 4 | TriggerClientEvent("wp-placeables:client:placeItem", source, prop) 5 | end) 6 | end 7 | 8 | -- Checks the config to see if the item is valid 9 | local function containsItem(item) 10 | for i = 1, #Config.PlaceableProps do 11 | local v = Config.PlaceableProps[i] 12 | if v.item == item then 13 | return true 14 | end 15 | end 16 | end 17 | 18 | -- This function is to handle the syncing of deleting world props between all clients 19 | RegisterServerEvent("wp-placeables:server:deleteWorldObject", function(object) 20 | TriggerClientEvent("wp-placeables:client:deleteWorldObject", -1, object) 21 | end) 22 | 23 | RegisterNetEvent("wp-placeables:server:RemoveItem", function(itemName) 24 | local src = source 25 | RemoveItem(src, itemName, 1) 26 | end) 27 | 28 | RegisterNetEvent("wp-placeables:server:AddItem", function(itemName) 29 | local src = source 30 | 31 | if not containsItem(itemName) then 32 | print(string.format("%s - tried to spawn an item that does not exist in the config (%s)", src, itemName)) 33 | return 34 | end 35 | 36 | AddItem(src, itemName, 1) 37 | end) 38 | 39 | AddEventHandler("onResourceStart", function(resourceName) 40 | if resourceName == GetCurrentResourceName() then 41 | -- Give the script some time to start 42 | Wait(100) 43 | 44 | ValidateOxLibUsage() 45 | end 46 | end) 47 | -------------------------------------------------------------------------------- /shared/config.lua: -------------------------------------------------------------------------------- 1 | Config = {} 2 | ------------------------------------ 3 | -- FRAMEWORK / SCRIPT CONFIGURATION 4 | -- Adjust these settings to match the framework and scripts you are using 5 | -- Note: If using ox for any option, enable @ox_lib/init.lua in the manifest! 6 | ------------------------------------ 7 | 8 | --- @type "qb" | "qbx" | "esx" 9 | Config.Framework = "qb" 10 | 11 | -- The notification script you are using. 12 | --- @type "qb" | "esx" | "ox" | "none" 13 | Config.Notify = "qb" 14 | 15 | -- The target script you are using. 16 | --- @type "qb" | "ox" 17 | Config.Target = "qb" 18 | 19 | -- The inventory script you are using. 20 | --- @type "qb" | "esx" | "ox" 21 | Config.Inventory = "qb" 22 | 23 | -- The progress bar script you are using. 24 | --- @type "qb" | "ox" | "none" 25 | Config.ProgessBar = "qb" 26 | 27 | -- The logging script you are using. 28 | --- @type "qb" | "none" 29 | Config.Log = "qb" 30 | 31 | ------------------------------------ 32 | --- END FRAMEWORK / SCRIPT CONFIGURATION 33 | ------------------------------------ 34 | 35 | Config.ItemPlacementModeRadius = 10.0 -- Object can only be placed within this radius of the player 36 | 37 | -- These are necessary so people can't place props far away 38 | Config.minZOffset = -2.0 -- The min z offset for placing objects 39 | Config.maxZOffset = 2.0 -- The max z offset for placing objects 40 | 41 | -- Creates a deep copy of the table 42 | -- This is necessary for getting around luas pass by reference of tables 43 | --- @param orig table The table to be copied 44 | --- @return table The deep copied table 45 | local function deepcopy(orig) -- modified the deep copy function from http://lua-users.org/wiki/CopyTable 46 | local orig_type = type(orig) 47 | local copy 48 | if orig_type == "table" then 49 | if not orig.canOpen or orig.canOpen() then 50 | local toRemove = {} 51 | copy = {} 52 | for orig_key, orig_value in next, orig, nil do 53 | if type(orig_value) == "table" then 54 | if not orig_value.canOpen or orig_value.canOpen() then 55 | copy[deepcopy(orig_key)] = deepcopy(orig_value) 56 | else 57 | toRemove[orig_key] = true 58 | end 59 | else 60 | copy[deepcopy(orig_key)] = deepcopy(orig_value) 61 | end 62 | end 63 | for i = 1, #toRemove do table.remove(copy, i) --[[ Using this to make sure all indexes get re-indexed and no empty spaces are in the radialmenu ]] end 64 | if copy and next(copy) then setmetatable(copy, deepcopy(getmetatable(orig))) end 65 | end 66 | elseif orig_type ~= "function" then 67 | copy = orig 68 | end 69 | return copy 70 | end 71 | 72 | -- Helper function to combine default options with custom target options for items 73 | --- @param targetOptions table[] The default target options for the item (e.g., pushTargetOptions for push-only objects and pushAndSitTargetOptions for push-and-sit objects) 74 | --- @param animationPushOptions? table The custom animation options for pushing the object (modifying offsets, rotations, animations) 75 | --- @param animationSitOptions? table The custom animation options for sitting on the object (modifying offsets, rotations, animations) 76 | --- @param otherOptions? table[] Any other custom target options you want to add to the item 77 | --- @return table[] The combined target options with customizations applied 78 | local function setCustomTargetOptions(targetOptions, animationPushOptions, animationSitOptions, otherOptions) 79 | local customTargetOptions = deepcopy(targetOptions) 80 | 81 | if animationPushOptions then 82 | customTargetOptions[1].animationPushOptions = animationPushOptions 83 | end 84 | 85 | if animationSitOptions then 86 | customTargetOptions[2].animationSitOptions = animationSitOptions 87 | end 88 | 89 | if otherOptions then 90 | for i = 1, #otherOptions do 91 | customTargetOptions[#customTargetOptions + 1] = otherOptions[i] 92 | end 93 | end 94 | 95 | return customTargetOptions 96 | end 97 | 98 | -- Default target options 99 | 100 | local pushAndSitTargetOptions = { 101 | { 102 | event = "wp-placeables:client:pushObject", 103 | icon = "fas fa-shopping-cart", 104 | label = "Push object", 105 | animationPushOptions = { 106 | offset = { x = -0.4, y = -1.7, z = -0.3, }, 107 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 108 | animationDict = "missfinale_c2ig_11", 109 | animationName = "pushcar_offcliff_f", 110 | }, 111 | }, 112 | { 113 | event = "wp-placeables:client:sitOnObject", 114 | icon = "fas fa-chair", 115 | label = "Sit on object", 116 | animationSitOptions = { 117 | offset = { x = 0.0, y = 0.15, z = 0.85, }, 118 | rotation = { x = 0.0, y = 10.0, z = 175.0, }, 119 | animationDict = "anim@amb@business@bgen@bgen_no_work@", 120 | animationName = "sit_phone_phoneputdown_idle_nowork", 121 | }, 122 | }, 123 | } 124 | 125 | local pushTargetOptions = { 126 | { 127 | event = "wp-placeables:client:pushObject", 128 | icon = "fas fa-shopping-cart", 129 | label = "Push cart", 130 | animationPushOptions = { 131 | offset = { x = -0.4, y = -1.7, z = -0.3, }, 132 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 133 | animationDict = "missfinale_c2ig_11", 134 | animationName = "pushcar_offcliff_f", 135 | }, 136 | }, 137 | } 138 | 139 | -- Define custom target options here for addon items 140 | 141 | -- Uncomment this line if you are using wp-seats 142 | local chairCustomTargetOptions = { 143 | { 144 | event = "wp-seats:client:sitOnChair", 145 | icon = "fas fa-chair", 146 | label = "Sit down", 147 | }, 148 | } 149 | 150 | -- Uncomment this line if you are using wp-yogamats 151 | -- local yogaCustomTargetOptions = { 152 | -- { 153 | -- event = "wp-yogamats:client:useYogaMat", 154 | -- icon = "fas fa-pray", 155 | -- label = "Do yoga", 156 | -- }, 157 | -- } 158 | 159 | -- Uncomment this line if you are using wp-printer 160 | -- local printerCustomTargetOptions = { 161 | -- { 162 | -- event = "wp-printer:client:UsePrinter", 163 | -- icon = "fas fa-print", 164 | -- label = "Use printer", 165 | -- }, 166 | -- } 167 | 168 | -- Uncomment this line if you are using wp-fireworks 169 | -- local fireworkCustomTargetOptions = { 170 | -- { 171 | -- event = 'wp-fireworks:client:lightFireworkFuse', 172 | -- icon = "fa-solid fa-fire", 173 | -- label = "Light fuse" 174 | -- }, 175 | -- { 176 | -- event = 'wp-fireworks:client:buildFireworkSequence', 177 | -- icon = 'fa-solid fa-link', 178 | -- label = 'Add to sequence' 179 | -- } 180 | -- } 181 | 182 | -- Uncomment this line if you are using wp-trafficlights 183 | -- local trafficLightCustomTargetOptions = { 184 | -- { 185 | -- event = "wp-trafficlights:client:OpenMenu", 186 | -- icon = "fas fa-traffic-light", 187 | -- label = "Remote control traffic light", 188 | -- }, 189 | -- } 190 | 191 | -- Uncomment this line if you are using wp-trafficlights 192 | -- local trafficLightCustomPickupEvent = "wp-trafficlights:RemoveTrafficLight" 193 | 194 | --- @class PlaceableProp 195 | --- @field item string The item name as defined in your items.lua 196 | --- @field label string The label to be used for this item (displayed in the progress bar) 197 | --- @field model string The prop model to be used for this item 198 | --- @field isFrozen boolean Whether or not the prop should be frozen in place when placed 199 | --- @field customTargetOptions? table[] Optional - Custom target options for this item, if it should do more than just pickup 200 | --- @field customPickupEvent? string Optional - If you want to override the default pickup event, set this to the event you want to be called when the "pickup" target option is used 201 | 202 | -- Add the props you want to be placeable here 203 | -- Every prop will have the "pickup" target option added by default (to override use customPickupEvent) 204 | --- @type PlaceableProp[] 205 | Config.PlaceableProps = { 206 | -- Constructions props 207 | { item = "roadworkbarrier", label = "Road Work Ahead Barrier", model = "prop_barrier_work04a", isFrozen = true, }, 208 | { item = "roadclosedbarrier", label = "Road Closed Barrier", model = "xm3_prop_xm3_road_barrier_01a", isFrozen = true, }, 209 | { item = "constructionbarrier", label = "Fold-out Barrier", model = "prop_barrier_work01a", isFrozen = false, }, 210 | { item = "constructionbarrier2", label = "Construction Barrier", model = "prop_barrier_work06a", isFrozen = true, }, 211 | { item = "constructionbarrier3", label = "Construction Barrier", model = "prop_mp_barrier_02b", isFrozen = true, }, 212 | { item = "roadconebig", label = "Big Road Cone", model = "prop_barrier_wat_03a", isFrozen = false, }, 213 | { item = "roadcone", label = "Road Cone", model = "prop_roadcone01a", isFrozen = false, }, 214 | { item = "roadpole", label = "Road Pole", model = "prop_roadpole_01a", isFrozen = false, }, 215 | { item = "worklight", label = "Work Light", model = "prop_worklight_01a", isFrozen = false, }, 216 | { item = "worklight2", label = "Work Light", model = "prop_worklight_04b", isFrozen = false, }, 217 | { item = "worklight3", label = "Work Light", model = "prop_worklight_02a", isFrozen = false, }, 218 | { item = "constructiongenerator", label = "Construction Generator", model = "prop_generator_03b", isFrozen = true, }, 219 | { item = "trafficdevice", label = "Traffic Device (Left)", model = "prop_trafficdiv_01", isFrozen = true, }, 220 | { item = "trafficdevice2", label = "Traffic Device (Right)", model = "prop_trafficdiv_02", isFrozen = true, }, 221 | { item = "meshfence1", label = "Mesh Fence (Small)", model = "prop_fnc_omesh_01a", isFrozen = true, }, 222 | { item = "meshfence2", label = "Mesh Fence (Medium)", model = "prop_fnc_omesh_02a", isFrozen = true, }, 223 | { item = "meshfence3", label = "Mesh Fence (Large)", model = "prop_fnc_omesh_03a", isFrozen = true, }, 224 | { item = "waterbarrel", label = "Water Barrel", model = "prop_barrier_wat_04a", isFrozen = false, }, 225 | 226 | -- Camping + Hobo props 227 | { item = "tent", label = "Old Tent", model = "prop_skid_tent_03", isFrozen = true, }, 228 | { item = "tent2", label = "Tent", model = "prop_skid_tent_01", isFrozen = true, }, 229 | { item = "tent3", label = "Large Tent", model = "ba_prop_battle_tent_02", isFrozen = true, }, 230 | { item = "hobostove", label = "Hobo Stove", model = "prop_hobo_stove_01", isFrozen = true, }, 231 | { item = "campfire", label = "Campfire", model = "prop_beach_fire", isFrozen = true, }, 232 | { item = "hobomattress", label = "Hobo Mattress", model = "prop_rub_matress_01", isFrozen = true, }, 233 | { item = "hoboshelter", label = "Hobo Shelter", model = "prop_homeles_shelter_01", isFrozen = true, }, 234 | { item = "sleepingbag", label = "Sleeping Bag", model = "prop_skid_sleepbag_1", isFrozen = true, }, 235 | { item = "canopy1", label = "Canopy (Green)", model = "prop_gazebo_01", isFrozen = true, }, 236 | { item = "canopy2", label = "Canopy (Blue)", model = "prop_gazebo_02", isFrozen = true, }, 237 | { item = "canopy3", label = "Canopy (White)", model = "prop_gazebo_03", isFrozen = true, }, 238 | { item = "cot", label = "Cot", model = "gr_prop_gr_campbed_01", isFrozen = true, }, 239 | 240 | -- Triathlon props 241 | { item = "tristarttable", label = "Triathlon Start Table", model = "prop_tri_table_01", isFrozen = true, }, 242 | { item = "tristartbanner", label = "Triathlon Start Banner", model = "prop_tri_start_banner", isFrozen = true, }, 243 | { item = "trifinishbanner", label = "Triathlon Finish Banner", model = "prop_tri_finish_banner", isFrozen = true, }, 244 | 245 | -- Table props 246 | { item = "plastictable", label = "Plastic Table", model = "prop_ven_market_table1", isFrozen = true, }, 247 | { item = "plastictable2", label = "Plastic Table", model = "prop_table_03", isFrozen = true, }, 248 | { item = "woodtable", label = "Small Wood Table", model = "prop_rub_table_01", isFrozen = true, }, 249 | { item = "woodtable2", label = "Wood Table", model = "prop_rub_table_02", isFrozen = true, }, 250 | 251 | -- Beach props 252 | { item = "beachtowel", label = "Beach Towel", model = "prop_cs_beachtowel_01", isFrozen = true, }, 253 | { item = "beachumbrella", label = "Beach Umbrella", model = "prop_parasol_04b", isFrozen = true, }, 254 | { item = "beachumbrella2", label = "Beach Umbrella", model = "prop_beach_parasol_02", isFrozen = true, }, 255 | { item = "beachumbrella3", label = "Beach Umbrella", model = "prop_beach_parasol_06", isFrozen = true, }, 256 | { item = "beachumbrella4", label = "Beach Umbrella", model = "prop_beach_parasol_10", isFrozen = true, }, 257 | { item = "beachball", label = "Beach Ball", model = "prop_beachball_02", isFrozen = false, }, 258 | 259 | -- Ramp props 260 | { item = "ramp1", label = "Wood Ramp (Gradual)", model = "prop_mp_ramp_01", isFrozen = true, }, 261 | { item = "ramp2", label = "Wood Ramp (Moderate)", model = "prop_mp_ramp_02", isFrozen = true, }, 262 | { item = "ramp3", label = "Wood Ramp (Steep)", model = "prop_mp_ramp_03", isFrozen = true, }, 263 | { item = "ramp4", label = "Metal Ramp (Large)", model = "xs_prop_arena_pipe_ramp_01a", isFrozen = true, }, 264 | { item = "ramp5", label = "Metal Trailer Ramp", model = "xs_prop_x18_flatbed_ramp", isFrozen = true, }, 265 | { item = "skateramp", label = "Skate Ramp", model = "prop_skate_flatramp", isFrozen = true, }, 266 | { item = "stuntramp1", label = "Stunt Ramp S", model = "stt_prop_ramp_adj_flip_s", isFrozen = true, }, 267 | { item = "stuntramp2", label = "Stunt Ramp M", model = "stt_prop_ramp_adj_flip_m", isFrozen = true, }, 268 | { item = "stuntramp3", label = "Stunt Ramp L", model = "stt_prop_ramp_jump_l", isFrozen = true, }, 269 | { item = "stuntramp4", label = "Stunt Ramp XL", model = "stt_prop_ramp_jump_xl", isFrozen = true, }, 270 | { item = "stuntramp5", label = "Stunt Ramp XXL", model = "stt_prop_ramp_jump_xxl", isFrozen = true, }, 271 | { item = "stuntloop1", label = "Stunt Half Loop", model = "stt_prop_ramp_adj_hloop", isFrozen = true, }, 272 | { item = "stuntloop2", label = "Stunt Loop", model = "stt_prop_ramp_adj_loop", isFrozen = true, }, 273 | { item = "stuntloop3", label = "Stunt Spiral", model = "stt_prop_ramp_spiral_s", isFrozen = true, }, 274 | 275 | -- EMS/Hospital props 276 | { item = "medbag", label = "Medical Bag", model = "xm_prop_x17_bag_med_01a", isFrozen = true, }, 277 | { item = "examlight", label = "Exam Light", model = "v_med_examlight", isFrozen = true, }, 278 | { item = "hazardbin", label = "Hazard Bin", model = "v_med_medwastebin", isFrozen = true, }, 279 | { item = "microscope", label = "Microscope", model = "v_med_microscope", isFrozen = true, }, 280 | { item = "oscillator", label = "Oscillator", model = "v_med_oscillator3", isFrozen = true, }, 281 | { item = "medmachine", label = "Medical Machine", model = "v_med_oscillator4", isFrozen = true, }, 282 | { item = "bodybag", label = "Body Bag", model = "xm_prop_body_bag", isFrozen = true, }, 283 | 284 | -- Chairs 285 | { item = "camp_chair_green", label = "Camp Chair (Green)", model = "prop_skid_chair_01", isFrozen = true, customTargetOptions = chairCustomTargetOptions, }, 286 | { item = "camp_chair_blue", label = "Camp Chair (Blue)", model = "prop_skid_chair_02", isFrozen = true, customTargetOptions = chairCustomTargetOptions, }, 287 | { item = "camp_chair_plaid", label = "Camp Chair (Plaid)", model = "prop_skid_chair_03", isFrozen = true, customTargetOptions = chairCustomTargetOptions, }, 288 | { item = "plastic_chair", label = "Plastic Chair", model = "prop_chair_08", isFrozen = true, customTargetOptions = chairCustomTargetOptions, }, 289 | { item = "folding_chair", label = "Folding Chair", model = "xm3_prop_xm3_folding_chair_01a", isFrozen = true, customTargetOptions = chairCustomTargetOptions, }, 290 | 291 | -- Cargo props 292 | { item = "cargobox1", label = "Large cardboardbox pallet", model = "prop_mb_cargo_03a", isFrozen = false, }, 293 | { item = "cargobox2", label = "Large mixed pallet", model = "prop_mb_cargo_02a", isFrozen = false, }, 294 | { item = "cargobox3", label = "Tall wrapped pallet", model = "hei_prop_carrier_cargo_04b", isFrozen = false, }, 295 | { item = "cargobox4", label = "Cardboardboxes pallet", model = "prop_boxpile_02c", isFrozen = false, }, 296 | { item = "cargobox5", label = "Sprunk boxes pallet", model = "prop_boxpile_03a", isFrozen = false, }, 297 | { item = "cargobox6", label = "Cardboardboxes wrapped", model = "prop_boxpile_04a", isFrozen = false, }, 298 | { item = "cargobox7", label = "Cardboardboxes fragile", model = "prop_boxpile_06a", isFrozen = false, }, 299 | { item = "cargobox8", label = "Cardboardboxes + keg", model = "prop_boxpile_09a", isFrozen = false, }, 300 | { item = "pallet1", label = "Empty pallet", model = "prop_pallet_01a", isFrozen = false, }, 301 | { item = "pallet2", label = "Fertilizer pallet", model = "bkr_prop_fertiliser_pallet_01a", isFrozen = false, }, 302 | { item = "pallet3", label = "Weed bricks pallet", model = "hei_prop_heist_weed_pallet", isFrozen = false, }, 303 | { item = "pallet4", label = "Barrell pallet", model = "xm3_prop_xm3_pallet_ch_01a", isFrozen = false, }, 304 | { item = "pallet5", label = "Slotmachine pallet", model = "sf_prop_sf_slot_pallet_01a", isFrozen = false, }, 305 | { item = "crate1", label = "Gopostal crate", model = "prop_box_wood03a", isFrozen = false, }, 306 | { item = "crate2", label = "Wood crate", model = "prop_box_wood04a", isFrozen = false, }, 307 | { item = "crate3", label = "Cluckinbell crate", model = "vw_prop_vw_boxwood_01a", isFrozen = false, }, 308 | { item = "crate4", label = "Water crate", model = "prop_watercrate_01", isFrozen = false, }, 309 | { item = "crate5", label = "Animal cage", model = "v_med_apecrate", isFrozen = false, }, 310 | 311 | -- Xmas props 312 | { item = "snowman1", label = "Snowman (Red)", model = "xm3_prop_xm3_snowman_01a", isFrozen = true, }, 313 | { item = "snowman2", label = "Snowman (Blue)", model = "xm3_prop_xm3_snowman_01b", isFrozen = true, }, 314 | { item = "snowman3", label = "Snowman (Green)", model = "xm3_prop_xm3_snowman_01c", isFrozen = true, }, 315 | { item = "snowman4", label = "Snowman", model = "prop_prlg_snowpile", isFrozen = true, }, 316 | { item = "xmastree1", label = "Giant Xmas Tree", model = "prop_xmas_ext", isFrozen = true, }, 317 | { item = "xmastree2", label = "Xmas Tree", model = "prop_xmas_tree_int", isFrozen = true, }, 318 | { item = "candycane", label = "Candy Cane", model = "w_me_candy_xm3", isFrozen = true, }, 319 | { item = "xmaspresent", label = "Xmas Present", model = "xm3_prop_xm3_present_01a", isFrozen = true, }, 320 | 321 | -- Misc props 322 | { item = "greenscreen", label = "Green Screen", model = "prop_ld_greenscreen_01", isFrozen = true, }, 323 | { item = "ropebarrier", label = "Rope Barrier", model = "vw_prop_vw_barrier_rope_01a", isFrozen = false, }, 324 | { item = "largesoccerball", label = "Large Soccer Ball", model = "stt_prop_stunt_soccer_ball", isFrozen = false, }, 325 | { item = "soccerball", label = "Soccer Ball", model = "p_ld_soc_ball_01", isFrozen = false, }, 326 | { item = "stepladder", label = "Step Ladder", model = "v_med_cor_stepladder", isFrozen = true, }, 327 | { item = "sexdoll", label = "Sex Doll", model = "prop_defilied_ragdoll_01", isFrozen = true, }, 328 | 329 | -- Pushable items 330 | { item = "shoppingcart1", label = "Shopping Cart (Empty)", model = "prop_rub_trolley01a", isFrozen = false, customTargetOptions = pushAndSitTargetOptions, }, 331 | { item = "shoppingcart2", label = "Shopping Cart (Full)", model = "prop_skid_trolley_2", isFrozen = false, customTargetOptions = pushTargetOptions, }, 332 | { item = "shoppingcart3", label = "Shopping Cart (Empty)", model = "prop_rub_trolley02a", isFrozen = false, customTargetOptions = pushAndSitTargetOptions, }, 333 | { item = "shoppingcart4", label = "Shopping Cart (Full)", model = "prop_skid_trolley_1", isFrozen = false, customTargetOptions = pushTargetOptions, }, 334 | { 335 | item = "wheelbarrow", 336 | label = "Wheelbarrow", 337 | model = "prop_wheelbarrow01a", 338 | isFrozen = false, 339 | customTargetOptions = setCustomTargetOptions( 340 | pushAndSitTargetOptions, { 341 | offset = { x = -0.4, y = -1.8, z = -0.6, }, 342 | rotation = { x = 0.0, y = 20.0, z = 90.0, }, 343 | animationDict = "missfinale_c2ig_11", 344 | animationName = "pushcar_offcliff_f", 345 | }, { 346 | offset = { x = -0.25, y = 0.0, z = 1.4, }, 347 | rotation = { x = 13.0, y = 0.0, z = 255.0, }, 348 | animationDict = "anim@amb@business@bgen@bgen_no_work@", 349 | animationName = "sit_phone_phoneputdown_idle_nowork", 350 | } 351 | ), 352 | }, 353 | { 354 | item = "warehousetrolly1", 355 | label = "Warehouse Trolly (Empty)", 356 | model = "hei_prop_hei_warehousetrolly_02", 357 | isFrozen = false, 358 | customTargetOptions = setCustomTargetOptions( 359 | pushAndSitTargetOptions, { 360 | offset = { x = -0.4, y = -1.5, z = -0.9, }, 361 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 362 | animationDict = "missfinale_c2ig_11", 363 | animationName = "pushcar_offcliff_f", 364 | }, { 365 | offset = { x = -0.15, y = 0.15, z = 1.25, }, 366 | rotation = { x = 0.0, y = 10.0, z = 175.0, }, 367 | animationDict = "anim@amb@business@bgen@bgen_no_work@", 368 | animationName = "sit_phone_phoneputdown_idle_nowork", 369 | } 370 | ), 371 | }, 372 | { 373 | item = "warehousetrolly2", 374 | label = "Warehouse Trolly (Full)", 375 | model = "prop_flattruck_01d", 376 | isFrozen = false, 377 | customTargetOptions = setCustomTargetOptions( 378 | pushTargetOptions, { 379 | offset = { x = -0.4, y = -1.5, z = -0.9, }, 380 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 381 | animationDict = "missfinale_c2ig_11", 382 | animationName = "pushcar_offcliff_f", 383 | } 384 | ), 385 | }, 386 | { 387 | item = "roomtrolly", 388 | label = "Room Trolly", 389 | model = "ch_prop_ch_room_trolly_01a", 390 | isFrozen = false, 391 | customTargetOptions = setCustomTargetOptions( 392 | pushTargetOptions, { 393 | offset = { x = -0.4, y = -1.75, z = -0.8, }, 394 | rotation = { x = 0.0, y = 0.0, z = 90.0, }, 395 | animationDict = "missfinale_c2ig_11", 396 | animationName = "pushcar_offcliff_f", 397 | } 398 | ), 399 | }, 400 | { 401 | item = "janitorcart1", 402 | label = "Janitor Cart", 403 | model = "prop_cleaning_trolly", 404 | isFrozen = false, 405 | customTargetOptions = setCustomTargetOptions( 406 | pushTargetOptions, { 407 | offset = { x = -0.3, y = -1.6, z = -0.9, }, 408 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 409 | animationDict = "missfinale_c2ig_11", 410 | animationName = "pushcar_offcliff_f", 411 | } 412 | ), 413 | }, 414 | { 415 | item = "janitorcart2", 416 | label = "Janitor Cart", 417 | model = "ch_prop_ch_trolly_01a", 418 | isFrozen = false, 419 | customTargetOptions = setCustomTargetOptions( 420 | pushTargetOptions, { 421 | offset = { x = -0.3, y = -1.75, z = -0.3, }, 422 | rotation = { x = 0.0, y = 0.0, z = 270.0, }, 423 | animationDict = "missfinale_c2ig_11", 424 | animationName = "pushcar_offcliff_f", 425 | } 426 | ), 427 | }, 428 | { 429 | item = "mopbucket", 430 | label = "Mop Bucket", 431 | model = "prop_tool_mopbucket", 432 | isFrozen = false, 433 | customTargetOptions = setCustomTargetOptions( 434 | pushTargetOptions, { 435 | offset = { x = -0.3, y = -1.9, z = -0.8, }, 436 | rotation = { x = 0.0, y = 0.0, z = 270.0, }, 437 | animationDict = "missfinale_c2ig_11", 438 | animationName = "pushcar_offcliff_f", 439 | } 440 | ), 441 | }, 442 | { 443 | item = "metalcart", 444 | label = "Metal Cart", 445 | model = "prop_gold_trolly", 446 | isFrozen = false, 447 | customTargetOptions = setCustomTargetOptions( 448 | pushTargetOptions, { 449 | offset = { x = -0.4, y = -1.75, z = -0.35, }, 450 | rotation = { x = 0.0, y = 0.0, z = 270.0, }, 451 | animationDict = "missfinale_c2ig_11", 452 | animationName = "pushcar_offcliff_f", 453 | } 454 | ), 455 | }, 456 | { 457 | item = "teacart", 458 | label = "Tea Cart", 459 | model = "prop_tea_trolly", 460 | isFrozen = false, 461 | customTargetOptions = setCustomTargetOptions( 462 | pushTargetOptions, { 463 | offset = { x = -0.4, y = -1.75, z = -0.4, }, 464 | rotation = { x = 0.0, y = 0.0, z = 90.0, }, 465 | animationDict = "missfinale_c2ig_11", 466 | animationName = "pushcar_offcliff_f", 467 | } 468 | ), 469 | }, 470 | { 471 | item = "drinkcart", 472 | label = "Drink Cart", 473 | model = "h4_int_04_drink_cart", 474 | isFrozen = false, 475 | customTargetOptions = setCustomTargetOptions( 476 | pushTargetOptions, { 477 | offset = { x = -0.4, y = -1.75, z = -0.4, }, 478 | rotation = { x = 0.0, y = 0.0, z = 90.0, }, 479 | animationDict = "missfinale_c2ig_11", 480 | animationName = "pushcar_offcliff_f", 481 | } 482 | ), 483 | }, 484 | { 485 | item = "handtruck1", 486 | label = "Hand Truck", 487 | model = "prop_sacktruck_02a", 488 | isFrozen = false, 489 | customTargetOptions = setCustomTargetOptions( 490 | pushTargetOptions, { 491 | offset = { x = -0.4, y = -1.4, z = -0.8, }, 492 | rotation = { x = -35.0, y = 0.0, z = 180.0, }, 493 | animationDict = "missfinale_c2ig_11", 494 | animationName = "pushcar_offcliff_f", 495 | } 496 | ), 497 | }, 498 | { 499 | item = "handtruck2", 500 | label = "Hand Truck (Boxes)", 501 | model = "prop_sacktruck_02b", 502 | isFrozen = false, 503 | customTargetOptions = setCustomTargetOptions( 504 | pushTargetOptions, { 505 | offset = { x = -0.4, y = -1.4, z = -0.75, }, 506 | rotation = { x = -35.0, y = 0.0, z = 180.0, }, 507 | animationDict = "missfinale_c2ig_11", 508 | animationName = "pushcar_offcliff_f", 509 | } 510 | ), 511 | }, 512 | { 513 | item = "trashbin", 514 | label = "Trash Bin", 515 | model = "prop_cs_bin_01_skinned", 516 | isFrozen = false, 517 | customTargetOptions = setCustomTargetOptions( 518 | pushAndSitTargetOptions, { 519 | offset = { x = -0.4, y = -1.62, z = -0.8, }, 520 | rotation = { x = -15.0, y = 0.0, z = 180.0, }, 521 | animationDict = "missfinale_c2ig_11", 522 | animationName = "pushcar_offcliff_f", 523 | }, { 524 | offset = { x = 0.02, y = 0.15, z = 1.25, }, 525 | rotation = { x = 0.0, y = 0.0, z = 175.0, }, 526 | animationDict = "anim@model_kylie_insta", 527 | animationName = "kylie_insta_clip", 528 | } 529 | ), 530 | }, 531 | { 532 | item = "lawnmower", 533 | label = "Lawn Mower", 534 | model = "prop_lawnmower_01", 535 | isFrozen = false, 536 | customTargetOptions = setCustomTargetOptions( 537 | pushTargetOptions, { 538 | offset = { x = -0.43, y = -1.6, z = -0.83, }, 539 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 540 | animationDict = "missfinale_c2ig_11", 541 | animationName = "pushcar_offcliff_f", 542 | } 543 | ), 544 | }, 545 | { 546 | item = "toolchest", 547 | label = "Tool Chest", 548 | model = "prop_toolchest_03", 549 | isFrozen = false, 550 | customTargetOptions = setCustomTargetOptions( 551 | pushTargetOptions, { 552 | offset = { x = -0.35, y = -1.95, z = -0.83, }, 553 | rotation = { x = 0.0, y = 0.0, z = 90.0, }, 554 | animationDict = "missfinale_c2ig_11", 555 | animationName = "pushcar_offcliff_f", 556 | } 557 | ), 558 | }, 559 | { 560 | item = "carjack", 561 | label = "Car Jack", 562 | model = "prop_carjack", 563 | isFrozen = false, 564 | customTargetOptions = setCustomTargetOptions( 565 | pushTargetOptions, { 566 | offset = { x = -0.35, y = -1.75, z = -0.83, }, 567 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 568 | animationDict = "missfinale_c2ig_11", 569 | animationName = "pushcar_offcliff_f", 570 | } 571 | ), 572 | }, 573 | { 574 | item = "hospitalbedtable", 575 | label = "Hospital Bedside Table", 576 | model = "v_med_bedtable", 577 | isFrozen = false, 578 | customTargetOptions = setCustomTargetOptions( 579 | pushTargetOptions, { 580 | offset = { x = -0.35, y = -1.7, z = -0.35, }, 581 | rotation = { x = 0.0, y = 0.0, z = 180.0, }, 582 | animationDict = "missfinale_c2ig_11", 583 | animationName = "pushcar_offcliff_f", 584 | } 585 | ), 586 | }, 587 | { 588 | item = "medtable", 589 | label = "Medical Table", 590 | model = "v_med_trolley2", 591 | isFrozen = false, 592 | customTargetOptions = setCustomTargetOptions( 593 | pushTargetOptions, { 594 | offset = { x = -0.35, y = -1.75, z = -0.83, }, 595 | rotation = { x = 0.0, y = 0.0, z = 90.0, }, 596 | animationDict = "missfinale_c2ig_11", 597 | animationName = "pushcar_offcliff_f", 598 | } 599 | ), 600 | }, 601 | 602 | -- ADDON ITEMS 603 | 604 | -- Yogamats 605 | -- Uncomment this line if you are using wp-yogamats 606 | -- {item = "yogamat_blue", label = "Yoga mat (Blue)", model = "prop_yoga_mat_01", isFrozen = true, customTargetOptions = yogaCustomTargetOptions}, 607 | -- {item = "yogamat_black", label = "Yoga mat (Black)", model = "prop_yoga_mat_02", isFrozen = true, customTargetOptions = yogaCustomTargetOptions}, 608 | -- {item = "yogamat_red", label = "Yoga mat (Red)", model = "prop_yoga_mat_03", isFrozen = true, customTargetOptions = yogaCustomTargetOptions}, 609 | 610 | -- Printers 611 | -- Uncomment this line if you are using wp-printer 612 | -- {item = "printer", label = "Printer", model = "prop_printer_01", isFrozen = true, customTargetOptions = printerCustomTargetOptions}, 613 | -- {item = "printer2", label = "Printer", model = "prop_printer_02", isFrozen = true, customTargetOptions = printerCustomTargetOptions}, 614 | -- {item = "printer3", label = "Printer", model = "v_res_printer", isFrozen = true, customTargetOptions = printerCustomTargetOptions}, 615 | -- {item = "printer4", label = "Printer", model = "v_ret_gc_print", isFrozen = true, customTargetOptions = printerCustomTargetOptions}, 616 | -- {item = "photocopier", label = "Photocopier", model = "v_med_cor_photocopy", isFrozen = true, customTargetOptions = printerCustomTargetOptions}, 617 | 618 | -- Fireworks 619 | -- Uncomment this line if you are using wp-fireworks 620 | -- {item = "finalefirework1", label = "Finale Firework (White)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 621 | -- {item = "finalefirework2", label = "Finale Firework (Colored)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 622 | -- {item = "finalefirework3", label = "Finale Firework (USA)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 623 | -- {item = "finalefireworklong1", label = "Long Finale Firework (White)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 624 | -- {item = "finalefireworklong2", label = "Long Finale Firework (Colored)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 625 | -- {item = "finalefireworklong3", label = "Long Finale Firework (USA)", model = "bzzz_prop_fireworks_a", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 626 | -- {item = "fountainfirework1", label = "Fountain Firework (White)", model = "ind_prop_firework_03", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 627 | -- {item = "fountainfirework2", label = "Fountain Firework (Colored)", model = "ind_prop_firework_03", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 628 | -- {item = "fountainfirework3", label = "Fountain Firework (USA)", model = "ind_prop_firework_03", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 629 | -- {item = "missilefirework1", label = "Missile Firework (White)", model = "ind_prop_firework_04", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 630 | -- {item = "missilefirework2", label = "Missile Firework (Colored)", model = "ind_prop_firework_04", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 631 | -- {item = "missilefirework3", label = "Missile Firework (USA)", model = "ind_prop_firework_04", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 632 | -- {item = "mortarfirework", label = "Mortar Firework", model = "prop_poster_tube_02", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 633 | -- {item = "strobefirework", label = "Strobe Firework", model = "bzzz_prop_fireworks_b", isFrozen = true, customTargetOptions = fireworkCustomTargetOptions}, 634 | 635 | -- Traffic lights 636 | -- Uncomment this line if you are using wp-trafficlights 637 | -- {item = "trafficlight", label= "Traffic light", model = "prop_traffic_03a", isFrozen = true, customTargetOptions = trafficLightCustomTargetOptions, customPickupEvent = trafficLightCustomPickupEvent}, 638 | 639 | -- ADD YOUR CUSTOM PROPS HERE 640 | } 641 | -------------------------------------------------------------------------------- /shared/framework.lua: -------------------------------------------------------------------------------- 1 | -- IsDuplicityVersion - is used to determine if the function is called by the server or the client (true == from server) 2 | 3 | --------------------- SHARED FUNCTIONS --------------------- 4 | local Core = nil 5 | --- @return table Core The core object of the framework 6 | function GetCoreObject() 7 | if not Core then 8 | if Config.Framework == "esx" then 9 | Core = exports["es_extended"]:getSharedObject() 10 | elseif Config.Framework == "qb" or Config.Framework == "qbx" then 11 | Core = exports["qb-core"]:GetCoreObject() 12 | end 13 | end 14 | return Core 15 | end 16 | 17 | Core = Config.Framework ~= "none" and GetCoreObject() or nil 18 | 19 | --- @param text string The text to show in the notification 20 | --- @param notificationType string The type of notification to show ex: 'success', 'error', 'info' 21 | --- @param src - number|nil The source of the player - only required when called from server side 22 | function Notify(text, notificationType, src) 23 | if IsDuplicityVersion() then 24 | if Config.Notify == "esx" then 25 | TriggerClientEvent("esx:showNotification", src, text) 26 | elseif Config.Notify == "qb" then 27 | TriggerClientEvent("QBCore:Notify", src, text, notificationType) 28 | elseif Config.Notify == "ox" then 29 | TriggerClientEvent("ox_lib:notify", src, { 30 | description = text, 31 | type = notificationType, 32 | }) 33 | end 34 | else 35 | if Config.Notify == "esx" then 36 | Core.ShowNotification(text) 37 | elseif Config.Notify == "qb" then 38 | Core.Functions.Notify(text, notificationType) 39 | elseif Config.Notify == "ox" then 40 | lib.notify({ 41 | description = text, 42 | type = notificationType, 43 | }) 44 | end 45 | end 46 | end 47 | 48 | --- @param source number|nil The source of the player 49 | --- @return table PlayerData The player data of the player 50 | function GetPlayerData(source) 51 | local Core = GetCoreObject() 52 | if IsDuplicityVersion() then 53 | if Config.Framework == "esx" then 54 | -- TODO: does esx not use citizenId? need to find what it uses 55 | return Core.GetPlayerFromId(source) 56 | elseif Config.Framework == "qb" then 57 | return Core.Functions.GetPlayer(source).PlayerData 58 | elseif Config.Framework == "qbx" then 59 | return exports.qbx_core:GetPlayer(source).PlayerData 60 | end 61 | else 62 | if Config.Framework == "esx" then 63 | return Core.GetPlayerData() 64 | elseif Config.Framework == "qb" then 65 | return Core.Functions.GetPlayerData() 66 | elseif Config.Framework == "qbx" then 67 | return exports.qbx_core:GetPlayerData() 68 | end 69 | end 70 | end 71 | 72 | --------------------- CLIENT FUNCTIONS --------------------- 73 | 74 | -- Triggers a progressbar on the client 75 | -- This uses the same method signature as QBCore Progressbar 76 | --- @param name string The name of the progressbar 77 | --- @param label string The label to show on the progressbar 78 | --- @param duration number The duration of the progressbar 79 | --- @param useWhileDead boolean Whether or not the progressbar should be used while dead 80 | --- @param canCancel boolean Whether or not the progressbar can be cancelled 81 | --- @param disableControls table Contains the controls to disable while the progressbar is active (disableMovement, disableCarMovement, disableMouse, disableCombat) 82 | --- @param animation table Contains the animation to play while the progressbar is active (animDict, anim, flags) 83 | --- @param prop table Contains the prop to show while the progressbar is active (model, bone, coords, rotation) 84 | --- @param propTwo table Contains the prop to show while the progressbar is active (model, bone, coords, rotation) 85 | --- @param onFinish function The callback function to call when the progressbar finishes 86 | --- @param onCancel function The callback function to call when the progressbar is cancelled 87 | function Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel) 88 | if IsDuplicityVersion() then return end 89 | if Config.ProgessBar == "none" then 90 | onFinish() 91 | elseif Config.ProgessBar == "qb" then 92 | return Core.Functions.Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel) 93 | elseif Config.ProgessBar == "ox" then 94 | local props = {} 95 | if prop then 96 | props[1] = { 97 | model = prop.model, 98 | bone = prop.bone, 99 | coords = prop.coords, 100 | rotation = prop.rotation, 101 | } 102 | end 103 | if propTwo then 104 | props[2] = { 105 | model = propTwo.model, 106 | bone = propTwo.bone, 107 | coords = propTwo.coords, 108 | rotation = propTwo.rotation, 109 | } 110 | end 111 | 112 | if lib.progressBar({ 113 | name = name, 114 | label = label, 115 | duration = duration, 116 | useWhileDead = useWhileDead, 117 | canCancel = canCancel, 118 | disable = { 119 | move = disableControls.disableMovement, 120 | car = disableControls.disableCarMovement, 121 | mouse = disableControls.disableMouse, 122 | combat = disableControls.disableCombat, 123 | }, 124 | anim = { 125 | dict = animation.animDict, 126 | clip = animation.anim, 127 | flag = animation.flags, 128 | }, 129 | prop = props, 130 | }) then 131 | onFinish() 132 | else 133 | onCancel() 134 | end 135 | else 136 | warn("Invalid Config.ProgessBar: <" .. tostring(Config.ProgessBar) .. ">. Update Progressbar in framework.lua.") 137 | end 138 | end 139 | 140 | -- Takes a prop model and the targetOptions and adds it to the target script so that this prop model is targetable 141 | --- @param model string The name of the prop model to target 142 | --- @param targetOptions table The options to pass to the target script 143 | --- ex: targetOptions = { distance = num, options: { offset = { x = 0.0, y = 0.0, z = 0.0 }, rotation = { x = 0.0, y = 0.0, z = 0.0 } , animationDict = "", animationName = "" } } 144 | function AddTargetModel(modelName, targetOptions) 145 | if IsDuplicityVersion() then return end 146 | if Config.Target == "qb" then 147 | exports["qb-target"]:AddTargetModel(modelName, targetOptions) 148 | elseif Config.Target == "ox" then 149 | -- ox target expects each option to have a distance on it, 150 | -- Append the distance value to each option 151 | for _, option in pairs(targetOptions.options) do 152 | option.distance = targetOptions.distance 153 | end 154 | exports.ox_target:addModel(modelName, targetOptions.options) 155 | else 156 | warn("Invalid Config.Target: <" .. tostring(Config.Target) .. ">. Update AddTargetModel in framework.lua.") 157 | end 158 | end 159 | 160 | -- Creates a log entry when an item is placed or picked up 161 | --- @param itemName string The name of the item that was placed or picked up 162 | --- @param isItemPlaced boolean True if the item was placed, false if the item was picked up 163 | function CreateLog(itemName, isItemPlaced) 164 | if IsDuplicityVersion() or Config.Log == "none" then return end 165 | 166 | local playerId = PlayerId() 167 | local playerName = GetPlayerName(playerId) 168 | local PlayerData = GetPlayerData() 169 | local color = isItemPlaced and "red" or "green" 170 | local action = isItemPlaced and "Placed" or "Picked up" 171 | local logMessage = "**" .. playerName .. "** (" .. PlayerData.charinfo.firstname .. " " .. PlayerData.charinfo.lastname .. ") | CitizenId: " .. PlayerData.citizenid .. "\n Item Name: " .. itemName 172 | 173 | if Config.Log == "none" then 174 | return 175 | elseif Config.Log == "qb" then 176 | -- Be sure to add the 'itemplacement' entry to the qb-log config 177 | TriggerServerEvent("qb-log:server:CreateLog", "itemplacement", "Item " .. action .. " By:", color, logMessage) 178 | else 179 | warn("Invalid Config.Log: <" .. tostring(Config.Log) .. ">. Update CreateLog in framework.lua.") 180 | end 181 | end 182 | 183 | --------------------- SERVER FUNCTIONS --------------------- 184 | 185 | -- Registers a useable item 186 | --- @param itemName string The name of the item to register 187 | --- @param callbackFn function The function to call when the item is used 188 | function CreateUseableItem(itemName, callbackFn) 189 | if not IsDuplicityVersion() then return end 190 | if Config.Framework == "esx" then 191 | -- ESX returns the itemName as the second parameter, itemdata as the third parameter when calling the callback function 192 | -- We are interested in the itemData for our callback 193 | local function ESXCallback(source, itemName, itemData) 194 | callbackFn(source, itemData) 195 | end 196 | 197 | return Core.RegisterUsableItem(itemName, ESXCallback) 198 | elseif Config.Framework == "qb" then 199 | return Core.Functions.CreateUseableItem(itemName, callbackFn) 200 | elseif Config.Framework == "qbx" then 201 | return exports.qbx_core:CreateUseableItem(itemName, callbackFn) 202 | else 203 | warn("Invalid Config.Framework: <" .. tostring(Config.Framework) .. ">. Update CreateUseableItem in framework.lua.") 204 | end 205 | end 206 | 207 | -- Adds item to the players inventory 208 | --- @param source number The source of the player 209 | --- @param itemName string The name of the item to add 210 | --- @param amount number The amount of the item to add 211 | --- @param info table Metadata to add to the item 212 | function AddItem(source, itemName, amount, info) 213 | if not IsDuplicityVersion() then return end 214 | if Config.Inventory == "esx" then 215 | local xPlayer = Core.GetPlayerFromId(source) 216 | return xPlayer.addInventoryItem(itemName, amount) 217 | elseif Config.Inventory == "qb" then 218 | local Player = Core.Functions.GetPlayer(source) 219 | TriggerClientEvent("inventory:client:ItemBox", source, Core.Shared.Items[itemName], "add") 220 | return Player.Functions.AddItem(itemName, amount, nil, info) 221 | elseif Config.Inventory == "ox" then 222 | exports.ox_inventory:AddItem(source, itemName, amount, info) 223 | else 224 | warn("Invalid Config.Inventory: <" .. tostring(Config.Inventory) .. ">. Update AddItem in framework.lua.") 225 | end 226 | end 227 | 228 | -- Removes item from the players inventory 229 | --- @param source number The source of the player 230 | --- @param itemName string The name of the item to remove 231 | --- @param amount number The number of items to remove 232 | --- @param slot number The slot of the item to remove from 233 | function RemoveItem(source, itemName, amount, slot) 234 | if not IsDuplicityVersion() then return end 235 | if Config.Inventory == "esx" then 236 | local xPlayer = Core.GetPlayerFromId(source) 237 | return xPlayer.removeInventoryItem(itemName, amount) 238 | elseif Config.Inventory == "qb" then 239 | local Player = Core.Functions.GetPlayer(source) 240 | TriggerClientEvent("inventory:client:ItemBox", source, Core.Shared.Items[itemName], "remove") 241 | return Player.Functions.RemoveItem(itemName, amount, slot) 242 | elseif Config.Inventory == "ox" then 243 | exports.ox_inventory:RemoveItem(source, itemName, amount, nil, slot) 244 | else 245 | warn("Invalid Config.Inventory: <" .. tostring(Config.Inventory) .. ">. Update RemoveItem in framework.lua.") 246 | end 247 | end 248 | 249 | --- This function checks if any OX scripts are being used in the configuration 250 | --- and throws an error if `ox_lib` is not properly enabled in the `fxmanifest.lua`. 251 | --- 252 | --- **Usage**: Call this function on the server inside an `onResourceStart` event handler. 253 | --- 254 | --- **Example**: 255 | --- ```lua 256 | --- AddEventHandler("onResourceStart", function(resourceName) 257 | --- if GetCurrentResourceName() == resourceName then 258 | --- Wait(100) -- Give the script some time to start 259 | --- ValidateOxLibUsage() 260 | --- end 261 | --- end) 262 | --- ``` 263 | function ValidateOxLibUsage() 264 | if not IsDuplicityVersion() then return end 265 | 266 | local isUsingOxScripts = 267 | Config.Notify == "ox" 268 | or Config.Target == "ox" 269 | or Config.Inventory == "ox" 270 | or Config.ProgessBar == "ox" 271 | 272 | -- Ensure ox_lib is not commented out in the fxmanifest/shared_script section if any OX scripts are used in the Config. 273 | -- If ox_lib is commented out, display an error as the script will not function correctly. 274 | if isUsingOxScripts then 275 | local filePath = GetResourcePath(GetCurrentResourceName()) .. "/fxmanifest.lua" 276 | local file, _errorMsg = io.open(filePath, "r") 277 | if not file then return end 278 | 279 | -- Read through the fxmanifest file 280 | -- Find the line with "@ox_lib/init.lua" and check if it is commented out 281 | local isOxLibCommentedOut = false 282 | for line in file:lines() do 283 | if line:find("@ox_lib/init.lua") then 284 | -- Check if the line is commented out 285 | if line:match("^%s*%-%-") then 286 | isOxLibCommentedOut = true 287 | end 288 | break 289 | end 290 | end 291 | 292 | file:close() 293 | 294 | if isOxLibCommentedOut then 295 | error( 296 | "\n=====================================\n\n" .. 297 | 298 | "YOU ARE USING OX SCRIPTS AND DID NOT UNCOMMENT OX_LIB IN THE FXMANIFEST!\n\n" .. 299 | 300 | "The script will not work until you uncomment it from the fxmanifest.\n\n" .. 301 | 302 | "=====================================\n" 303 | ) 304 | end 305 | end 306 | end --------------------------------------------------------------------------------