├── .poggit.yml ├── LICENSE ├── README.md ├── plugin.yml ├── resources ├── cosmetics.yml ├── models │ ├── cat_headset.json │ ├── devil_tail.json │ ├── firegod.json │ └── phoenix.json ├── required │ ├── default_player_skin.png │ ├── default_player_skinSlim.png │ ├── geometry.humanoid.custom.json │ └── geometry.humanoid.customSlim.json └── textures │ ├── cat_headset.png │ ├── coin.png │ ├── creeper.png │ ├── devil.png │ ├── devil_tail.png │ ├── emoji_angry.png │ ├── emoji_cool.png │ ├── emoji_moyai.png │ ├── emoji_nerd.png │ ├── emoji_sad.png │ ├── emoji_skull.png │ ├── emoji_smirk.png │ ├── emoji_weary.png │ ├── firegod.png │ ├── flag_uk.png │ ├── flag_us.png │ ├── infernal.png │ ├── phoenix.png │ ├── pride.png │ └── zombie.png └── src ├── Vanic └── Cosmetics │ ├── CosmeticsCommand.php │ ├── Costume │ ├── Cosmetic │ │ ├── Cosmetic.php │ │ └── CosmeticType.php │ ├── Costume.php │ └── CostumeManager.php │ ├── Main.php │ └── Utils │ ├── ConfigManager.php │ ├── DatabaseManager.php │ └── SkinUtils.php └── jojoe77777 └── FormAPI ├── CustomForm.php ├── Form.php ├── FormAPI.php ├── ModalForm.php └── SimpleForm.php /.poggit.yml: -------------------------------------------------------------------------------- 1 | --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/Vqnic/Cosmetics 2 | build-by-default: true 3 | branches: 4 | - main 5 | projects: 6 | Cosmetics: 7 | path: "" 8 | ... 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cosmetics v2.0 Plugin For PocketMine-MP 2 | [Download Latest .phar Here](https://poggit.pmmp.io/ci/Vqnic/Cosmetics/~) 3 | 4 | **This is a plugin for MCBE servers that will allow your players to equip fun cosmetics without some of the limitations of other cosmetics plugins.** 5 | - Cosmetics can have custom 3D models and textures. 6 | - Multiple cosmetics can be equipped at once. (Your players can have many combinations of hats, wings, tails and shoes at the same time.) 7 | - Capes can be equipped by your players as well with textures you provide. 8 | - Comes with default models and capes for easy use. 9 | - Each cosmetic has its own permission node, which could be used for VIP perks. 10 | - UI and commands are designed to be easy for players. 11 | 12 | > [!NOTE] 13 | > **The only command is `/cosmetics`, and it is available by default to all players.** 14 | > To restrict *individual cosmetics* to certain players or groups, establish a permission node in that cosmetic's configuration and use an external permission/group management plugin to determine who has that permission. 15 | 16 | 17 | ## What is the difference between v2.0 and the previous version? 18 | This is a complete rewrite of the previous version because I noticed people will still referencing it years later and the code was, quite honestly, bad. 19 | 20 | This version has **multiple cosmetic types** that can be on the body at once (it was just capes and one model before), and **easier configuration**. There are also a lot of **performance changes**. 21 | 22 | ## Future Things For This Project 23 | 24 | **Adding more default cosmetics...** 25 | My goal is to make configuration as easy as possible, and this includes usable examples. 26 | 27 | **Bringing animations back to this plugin...** 28 | I want server owners to be able to specify animations for each individual cosmetic. I don't think the old animation system was good enough. 29 | 30 | **Support for 128x128 player skins...** 31 | Currently, this plugin only supports 64x64 player skins. If a player logs in with a higher resolution skin and tries to equip a cosmetic, it will not use their skin and instead substitute it with Steve. 32 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | name: Cosmetics 2 | author: "Vanic" 3 | description: A plugin that lets player equip multiple 3D cosmetics on their skin through a UI. 4 | api: [5.0.0] 5 | version: 2.0.0 6 | main: Vanic\Cosmetics\Main 7 | load: POSTWORLD 8 | 9 | permissions: 10 | cosmetics.command: 11 | description: "Allows the user to run the /cosmetics command" 12 | default: true -------------------------------------------------------------------------------- /resources/cosmetics.yml: -------------------------------------------------------------------------------- 1 | #CAPE COSMETICS 2 | infernal_cape: 3 | display_name: "Infernal Cape of Doom" #The text that shows up in the UI 4 | type: "CAPE" #Can be CAPE, HEAD, UPPER_BODY, LOWER_BODY, or FEET 5 | texture_filename: "infernal.png" #The texture found in /textures/ 6 | required_permission: 'infernal.wear' #The required permission 7 | enabled: true #Set to false to have the config skip over this 8 | rich_cape: 9 | display_name: "Coin Cape" 10 | type: "CAPE" 11 | texture_filename: "coin.png" 12 | required_permission: 'coin.wear' 13 | enabled: true 14 | mob_creeper_cape: 15 | display_name: "Creeper Cape" 16 | type: "CAPE" 17 | texture_filename: "creeper.png" 18 | required_permission: 'creeper.wear' 19 | enabled: true 20 | mob_zombie_cape: 21 | display_name: "Zombie Cape" 22 | type: "CAPE" 23 | texture_filename: "zombie.png" 24 | required_permission: 'zombie.wear' 25 | enabled: true 26 | moyai_head_emoji_cape: 27 | display_name: "Moyai Head Emoji Cape" 28 | type: "CAPE" 29 | texture_filename: "emoji_moyai.png" 30 | required_permission: 'emoji.moyai.wear' 31 | enabled: true 32 | angry_emoji_cape: 33 | display_name: "Angry Emoji Cape" 34 | type: "CAPE" 35 | texture_filename: "emoji_angry.png" 36 | required_permission: 'emoji.angry.wear' 37 | emoji_cool_cape: 38 | display_name: "Sunglasses Emoji Cape" 39 | type: "CAPE" 40 | texture_filename: "emoji_cool.png" 41 | required_permission: 'emoji.cool.wear' 42 | enabled: true 43 | emoji_nerd_cape: 44 | display_name: "Nerd Emoji Cape" 45 | type: "CAPE" 46 | texture_filename: "emoji_nerd.png" 47 | required_permission: 'emoji.nerd.wear' 48 | enabled: true 49 | emoji_sad_cape: 50 | display_name: "Sad Emoji Cape" 51 | type: "CAPE" 52 | texture_filename: "emoji_sad.png" 53 | required_permission: 'emoji.sad.wear' 54 | enabled: true 55 | emoji_skull_cape: 56 | display_name: "Skull Emoji Cape" 57 | type: "CAPE" 58 | texture_filename: "emoji_skull.png" 59 | required_permission: 'emoji.skull.wear' 60 | enabled: true 61 | emoji_smirk_cape: 62 | display_name: "Smirking Emoji Cape" 63 | type: "CAPE" 64 | texture_filename: "emoji_smirk.png" 65 | required_permission: 'emoji.smirk.wear' 66 | enabled: true 67 | emoji_weary_cape: 68 | display_name: "Weary Emoji Cape" 69 | type: "CAPE" 70 | texture_filename: "emoji_weary.png" 71 | required_permission: 'emoji.weary.wear' 72 | enabled: true 73 | devil_cape: 74 | display_name: "Devilish Cape" 75 | type: "CAPE" 76 | texture_filename: "devil.png" 77 | required_permission: 'devil.wear' 78 | enabled: true 79 | # Other miscellaneous CAPEs disabled by default that can be manually re-enabled if you think they'd be a good fit for your server's community. 80 | flag_us_cape: 81 | display_name: "USA Flag Cape" 82 | type: "CAPE" 83 | texture_filename: "flag_us.png" 84 | required_permission: 'flag_us.wear' 85 | enabled: false 86 | flag_uk_cape: 87 | display_name: "UK Flag Cape" 88 | type: "CAPE" 89 | texture_filename: "flag_uk.png" 90 | required_permission: 'flag_uk.wear' 91 | enabled: false 92 | pride_cape: 93 | display_name: "Pride Cape" 94 | type: "CAPE" 95 | texture_filename: "pride.png" 96 | required_permission: 'pride.wear' 97 | enabled: false 98 | 99 | 100 | 101 | #HEAD COSMETICS 102 | firegod_horns: 103 | display_name: "Firegod Horns" 104 | type: "HEAD" 105 | texture_filename: "firegod.png" 106 | required_permission: 'firegod.wear' 107 | model_filename: "firegod.json" #(The filename in /models/ REQUIRED FOR ALL COSMETIC TYPES THAT AREN'T CAPES!!!! 108 | enabled: true 109 | cat_headset: 110 | display_name: "EGirl Kitty Headset" 111 | type: "HEAD" 112 | texture_filename: "cat_headset.png" 113 | required_permission: 'cat_headset.wear' 114 | model_filename: "cat_headset.json" 115 | enabled: true 116 | 117 | 118 | #UPPER_BODY COSMETICS 119 | phoenix_wings: 120 | display_name: "Phoenix Wings" 121 | type: "UPPER_BODY" 122 | texture_filename: "phoenix.png" 123 | required_permission: 'phoenix.wear' 124 | model_filename: "phoenix.json" 125 | enabled: true 126 | 127 | #LOWER_BODY COSMETICS 128 | devil_tail: 129 | display_name: "Imp Tail" 130 | type: "LOWER_BODY" 131 | texture_filename: "devil_tail.png" 132 | required_permission: 'devil.tail.wear' 133 | model_filename: "devil_tail.json" 134 | enabled: true 135 | #FEET COSMETICS -------------------------------------------------------------------------------- /resources/models/devil_tail.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:geometry": [ 4 | { 5 | "description": { 6 | "identifier": "geometry.devil_tail", 7 | "texture_width": 64, 8 | "texture_height": 64, 9 | "visible_bounds_width": 5, 10 | "visible_bounds_height": 4, 11 | "visible_bounds_offset": [0, 2, 0] 12 | }, 13 | "bones": [ 14 | { 15 | "name": "root", 16 | "pivot": [0, 0, 0] 17 | }, 18 | { 19 | "name": "waist", 20 | "parent": "root", 21 | "pivot": [0, 12, 0] 22 | }, 23 | { 24 | "name": "body", 25 | "parent": "waist", 26 | "pivot": [0, 24, 0], 27 | "cubes": [ 28 | { 29 | "origin": [-4, 12, -2], 30 | "size": [8, 12, 4], 31 | "uv": { 32 | "north": {"uv": [20, 20], "uv_size": [8, 12]}, 33 | "east": {"uv": [16, 20], "uv_size": [4, 12]}, 34 | "south": {"uv": [32, 20], "uv_size": [8, 12]}, 35 | "west": {"uv": [28, 20], "uv_size": [4, 12]}, 36 | "up": {"uv": [20, 16], "uv_size": [8, 4]}, 37 | "down": {"uv": [36, 16], "uv_size": [-8, 4]} 38 | } 39 | } 40 | ] 41 | }, 42 | { 43 | "name": "head", 44 | "parent": "body", 45 | "pivot": [0, 24, 0], 46 | "cubes": [ 47 | { 48 | "origin": [-4, 24, -4], 49 | "size": [8, 8, 8], 50 | "uv": { 51 | "north": {"uv": [8, 8], "uv_size": [8, 8]}, 52 | "east": {"uv": [0, 8], "uv_size": [8, 8]}, 53 | "south": {"uv": [24, 8], "uv_size": [8, 8]}, 54 | "west": {"uv": [16, 10], "uv_size": [8, 8]}, 55 | "up": {"uv": [8, 0], "uv_size": [8, 8]}, 56 | "down": {"uv": [24, 0], "uv_size": [-8, 8]} 57 | } 58 | } 59 | ] 60 | }, 61 | { 62 | "name": "hat", 63 | "parent": "head", 64 | "pivot": [0, 24, 0], 65 | "cubes": [ 66 | { 67 | "origin": [-4, 24, -4], 68 | "size": [8, 8, 8], 69 | "inflate": 0.5, 70 | "uv": { 71 | "north": {"uv": [40, 8], "uv_size": [8, 8]}, 72 | "east": {"uv": [32, 8], "uv_size": [8, 8]}, 73 | "south": {"uv": [56, 8], "uv_size": [8, 8]}, 74 | "west": {"uv": [48, 8], "uv_size": [8, 8]}, 75 | "up": {"uv": [40, 0], "uv_size": [8, 8]}, 76 | "down": {"uv": [56, 0], "uv_size": [-8, 8]} 77 | } 78 | } 79 | ] 80 | }, 81 | { 82 | "name": "cape", 83 | "parent": "body", 84 | "pivot": [0, 24, 3] 85 | }, 86 | { 87 | "name": "leftArm", 88 | "parent": "body", 89 | "pivot": [5, 22, 0], 90 | "cubes": [ 91 | { 92 | "origin": [4, 12, -2], 93 | "size": [4, 12, 4], 94 | "uv": { 95 | "north": {"uv": [36, 52], "uv_size": [4, 12]}, 96 | "east": {"uv": [32, 52], "uv_size": [4, 12]}, 97 | "south": {"uv": [44, 52], "uv_size": [4, 12]}, 98 | "west": {"uv": [40, 52], "uv_size": [4, 12]}, 99 | "up": {"uv": [36, 48], "uv_size": [4, 4]}, 100 | "down": {"uv": [44, 48], "uv_size": [-4, 4]} 101 | } 102 | } 103 | ] 104 | }, 105 | { 106 | "name": "leftSleeve", 107 | "parent": "leftArm", 108 | "pivot": [5, 22, 0], 109 | "cubes": [ 110 | { 111 | "origin": [4, 12, -2], 112 | "size": [4, 12, 4], 113 | "inflate": 0.25, 114 | "uv": { 115 | "north": {"uv": [52, 52], "uv_size": [4, 12]}, 116 | "east": {"uv": [48, 52], "uv_size": [4, 12]}, 117 | "south": {"uv": [60, 52], "uv_size": [4, 12]}, 118 | "west": {"uv": [56, 52], "uv_size": [4, 12]}, 119 | "up": {"uv": [52, 48], "uv_size": [4, 4]}, 120 | "down": {"uv": [60, 48], "uv_size": [-4, 4]} 121 | } 122 | } 123 | ] 124 | }, 125 | { 126 | "name": "leftItem", 127 | "parent": "leftArm", 128 | "pivot": [6, 15, 1] 129 | }, 130 | { 131 | "name": "rightArm", 132 | "parent": "body", 133 | "pivot": [-5, 22, 0], 134 | "cubes": [ 135 | { 136 | "origin": [-8, 12, -2], 137 | "size": [4, 12, 4], 138 | "uv": { 139 | "north": {"uv": [44, 20], "uv_size": [4, 12]}, 140 | "east": {"uv": [40, 20], "uv_size": [4, 12]}, 141 | "south": {"uv": [52, 20], "uv_size": [4, 12]}, 142 | "west": {"uv": [48, 20], "uv_size": [4, 12]}, 143 | "up": {"uv": [44, 16], "uv_size": [4, 4]}, 144 | "down": {"uv": [52, 16], "uv_size": [-4, 4]} 145 | } 146 | } 147 | ] 148 | }, 149 | { 150 | "name": "rightSleeve", 151 | "parent": "rightArm", 152 | "pivot": [-5, 22, 0], 153 | "cubes": [ 154 | { 155 | "origin": [-8, 12, -2], 156 | "size": [4, 12, 4], 157 | "inflate": 0.25, 158 | "uv": { 159 | "north": {"uv": [44, 36], "uv_size": [4, 12]}, 160 | "east": {"uv": [40, 36], "uv_size": [4, 12]}, 161 | "south": {"uv": [52, 36], "uv_size": [4, 12]}, 162 | "west": {"uv": [48, 36], "uv_size": [4, 12]}, 163 | "up": {"uv": [44, 32], "uv_size": [4, 4]}, 164 | "down": {"uv": [52, 32], "uv_size": [-4, 4]} 165 | } 166 | } 167 | ] 168 | }, 169 | { 170 | "name": "rightItem", 171 | "parent": "rightArm", 172 | "pivot": [-6, 15, 1], 173 | "locators": { 174 | "lead_hold": [-6, 15, 1] 175 | } 176 | }, 177 | { 178 | "name": "jacket", 179 | "parent": "body", 180 | "pivot": [0, 24, 0], 181 | "cubes": [ 182 | { 183 | "origin": [-4, 12, -2], 184 | "size": [8, 12, 4], 185 | "inflate": 0.25, 186 | "uv": { 187 | "north": {"uv": [20, 36], "uv_size": [8, 12]}, 188 | "east": {"uv": [16, 36], "uv_size": [4, 12]}, 189 | "south": {"uv": [32, 36], "uv_size": [8, 12]}, 190 | "west": {"uv": [28, 36], "uv_size": [4, 12]}, 191 | "up": {"uv": [20, 32], "uv_size": [8, 4]}, 192 | "down": {"uv": [36, 32], "uv_size": [-8, 4]} 193 | } 194 | } 195 | ] 196 | }, 197 | { 198 | "name": "tail", 199 | "parent": "body", 200 | "pivot": [0, 13, 1], 201 | "rotation": [-50, 0, 0], 202 | "cubes": [ 203 | { 204 | "origin": [-0.5, 13, 1], 205 | "size": [1, 1, 1], 206 | "uv": { 207 | "north": {"uv": [32, 0], "uv_size": [1, 1]}, 208 | "east": {"uv": [32, 0], "uv_size": [1, 1]}, 209 | "south": {"uv": [32, 0], "uv_size": [1, 1]}, 210 | "west": {"uv": [32, 0], "uv_size": [1, 1]}, 211 | "up": {"uv": [33, 1], "uv_size": [-1, -1]}, 212 | "down": {"uv": [33, 1], "uv_size": [-1, -1]} 213 | } 214 | }, 215 | { 216 | "origin": [-0.5, 13, 2], 217 | "size": [1, 1, 1], 218 | "uv": { 219 | "north": {"uv": [32, 0], "uv_size": [1, 1]}, 220 | "east": {"uv": [32, 0], "uv_size": [1, 1]}, 221 | "south": {"uv": [32, 0], "uv_size": [1, 1]}, 222 | "west": {"uv": [32, 0], "uv_size": [1, 1]}, 223 | "up": {"uv": [33, 1], "uv_size": [-1, -1]}, 224 | "down": {"uv": [33, 1], "uv_size": [-1, -1]} 225 | } 226 | }, 227 | { 228 | "origin": [-0.5, 14, 2], 229 | "size": [1, 1, 1], 230 | "uv": { 231 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 232 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 233 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 234 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 235 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 236 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 237 | } 238 | }, 239 | { 240 | "origin": [-0.5, 14, 1], 241 | "size": [1, 1, 1], 242 | "uv": { 243 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 244 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 245 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 246 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 247 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 248 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 249 | } 250 | }, 251 | { 252 | "origin": [-0.5, 14, 0], 253 | "size": [1, 1, 1], 254 | "uv": { 255 | "north": {"uv": [32, 0], "uv_size": [1, 1]}, 256 | "east": {"uv": [32, 0], "uv_size": [1, 1]}, 257 | "south": {"uv": [32, 0], "uv_size": [1, 1]}, 258 | "west": {"uv": [32, 0], "uv_size": [1, 1]}, 259 | "up": {"uv": [33, 1], "uv_size": [-1, -1]}, 260 | "down": {"uv": [33, 1], "uv_size": [-1, -1]} 261 | } 262 | }, 263 | { 264 | "origin": [-0.5, 13, 3], 265 | "size": [1, 1, 1], 266 | "uv": { 267 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 268 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 269 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 270 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 271 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 272 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 273 | } 274 | }, 275 | { 276 | "origin": [-0.25, 14, 3], 277 | "size": [0.5, 2, 1], 278 | "uv": { 279 | "north": {"uv": [32, 5], "uv_size": [0.5, -2]}, 280 | "east": {"uv": [32, 5], "uv_size": [1, -2]}, 281 | "south": {"uv": [32, 5], "uv_size": [0.5, -2]}, 282 | "west": {"uv": [32, 5], "uv_size": [1, -2]}, 283 | "up": {"uv": [32.5, 5], "uv_size": [-0.5, -1]}, 284 | "down": {"uv": [32.5, 4], "uv_size": [-0.5, -1]} 285 | } 286 | }, 287 | { 288 | "origin": [-0.25, 15, 1], 289 | "size": [0.5, 2, 1], 290 | "uv": { 291 | "north": {"uv": [32, 5], "uv_size": [0.5, -2]}, 292 | "east": {"uv": [32, 5], "uv_size": [1, -2]}, 293 | "south": {"uv": [32, 5], "uv_size": [0.5, -2]}, 294 | "west": {"uv": [32, 5], "uv_size": [1, -2]}, 295 | "up": {"uv": [32.5, 5], "uv_size": [-0.5, -1]}, 296 | "down": {"uv": [32.5, 4], "uv_size": [-0.5, -1]} 297 | } 298 | }, 299 | { 300 | "origin": [-0.25, 14, 5], 301 | "size": [0.5, 1, 1], 302 | "uv": { 303 | "north": {"uv": [32, 4], "uv_size": [0.5, 1]}, 304 | "east": {"uv": [32, 4], "uv_size": [1, 1]}, 305 | "south": {"uv": [32, 4], "uv_size": [0.5, 1]}, 306 | "west": {"uv": [32, 4], "uv_size": [1, 1]}, 307 | "up": {"uv": [32.5, 5], "uv_size": [-0.5, -1]}, 308 | "down": {"uv": [32.5, 5], "uv_size": [-0.5, -1]} 309 | } 310 | }, 311 | { 312 | "origin": [-0.5, 13, 4], 313 | "size": [1, 1, 1], 314 | "uv": { 315 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 316 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 317 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 318 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 319 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 320 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 321 | } 322 | }, 323 | { 324 | "origin": [-0.5, 13, 5], 325 | "size": [1, 1, 1], 326 | "uv": { 327 | "north": {"uv": [32, 0], "uv_size": [1, 1]}, 328 | "east": {"uv": [32, 0], "uv_size": [1, 1]}, 329 | "south": {"uv": [32, 0], "uv_size": [1, 1]}, 330 | "west": {"uv": [32, 0], "uv_size": [1, 1]}, 331 | "up": {"uv": [33, 1], "uv_size": [-1, -1]}, 332 | "down": {"uv": [33, 1], "uv_size": [-1, -1]} 333 | } 334 | }, 335 | { 336 | "origin": [-0.5, 13, 6], 337 | "size": [1, 1, 1], 338 | "uv": { 339 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 340 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 341 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 342 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 343 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 344 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 345 | } 346 | } 347 | ] 348 | }, 349 | { 350 | "name": "tail2", 351 | "parent": "tail", 352 | "pivot": [0, 13, 7], 353 | "rotation": [25, 0, 0], 354 | "cubes": [ 355 | { 356 | "origin": [-0.5, 13, 7], 357 | "size": [1, 1, 1], 358 | "uv": { 359 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 360 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 361 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 362 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 363 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 364 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 365 | } 366 | }, 367 | { 368 | "origin": [-0.5, 13, 8], 369 | "size": [1, 1, 1], 370 | "uv": { 371 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 372 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 373 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 374 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 375 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 376 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 377 | } 378 | }, 379 | { 380 | "origin": [-0.25, 14, 8], 381 | "size": [0.5, 1, 1], 382 | "uv": { 383 | "north": {"uv": [32, 5], "uv_size": [0.5, 1]}, 384 | "east": {"uv": [32, 5], "uv_size": [1, 1]}, 385 | "south": {"uv": [32, 5], "uv_size": [0.5, 1]}, 386 | "west": {"uv": [32, 5], "uv_size": [1, 1]}, 387 | "up": {"uv": [32.5, 6], "uv_size": [-0.5, -1]}, 388 | "down": {"uv": [32.5, 6], "uv_size": [-0.5, -1]} 389 | } 390 | }, 391 | { 392 | "origin": [-0.5, 13, 9], 393 | "size": [1, 1, 1], 394 | "uv": { 395 | "north": {"uv": [32, 0], "uv_size": [1, 1]}, 396 | "east": {"uv": [32, 0], "uv_size": [1, 1]}, 397 | "south": {"uv": [32, 0], "uv_size": [1, 1]}, 398 | "west": {"uv": [32, 0], "uv_size": [1, 1]}, 399 | "up": {"uv": [33, 1], "uv_size": [-1, -1]}, 400 | "down": {"uv": [33, 1], "uv_size": [-1, -1]} 401 | } 402 | }, 403 | { 404 | "origin": [-0.5, 13, 10], 405 | "size": [1, 1, 1], 406 | "uv": { 407 | "north": {"uv": [32, 1], "uv_size": [1, 1]}, 408 | "east": {"uv": [32, 1], "uv_size": [1, 1]}, 409 | "south": {"uv": [32, 1], "uv_size": [1, 1]}, 410 | "west": {"uv": [32, 1], "uv_size": [1, 1]}, 411 | "up": {"uv": [33, 2], "uv_size": [-1, -1]}, 412 | "down": {"uv": [33, 2], "uv_size": [-1, -1]} 413 | } 414 | }, 415 | { 416 | "origin": [-0.5, 13, 11], 417 | "size": [1, 1, 1], 418 | "uv": { 419 | "north": {"uv": [32, 2], "uv_size": [1, 1]}, 420 | "east": {"uv": [32, 2], "uv_size": [1, 1]}, 421 | "south": {"uv": [32, 2], "uv_size": [1, 1]}, 422 | "west": {"uv": [32, 2], "uv_size": [1, 1]}, 423 | "up": {"uv": [33, 3], "uv_size": [-1, -1]}, 424 | "down": {"uv": [33, 3], "uv_size": [-1, -1]} 425 | } 426 | } 427 | ] 428 | }, 429 | { 430 | "name": "tail3", 431 | "parent": "tail2", 432 | "pivot": [0, 13, 12], 433 | "rotation": [30, 0, 0], 434 | "cubes": [ 435 | { 436 | "origin": [-0.5, 13, 12], 437 | "size": [1, 1, 1], 438 | "uv": { 439 | "north": {"uv": [32, 2], "uv_size": [1, 1]}, 440 | "east": {"uv": [32, 2], "uv_size": [1, 1]}, 441 | "south": {"uv": [32, 2], "uv_size": [1, 1]}, 442 | "west": {"uv": [32, 2], "uv_size": [1, 1]}, 443 | "up": {"uv": [33, 3], "uv_size": [-1, -1]}, 444 | "down": {"uv": [33, 3], "uv_size": [-1, -1]} 445 | } 446 | }, 447 | { 448 | "origin": [-0.5, 13, 13], 449 | "size": [1, 1, 1], 450 | "uv": { 451 | "north": {"uv": [32, 2], "uv_size": [1, 1]}, 452 | "east": {"uv": [32, 2], "uv_size": [1, 1]}, 453 | "south": {"uv": [32, 2], "uv_size": [1, 1]}, 454 | "west": {"uv": [32, 2], "uv_size": [1, 1]}, 455 | "up": {"uv": [33, 3], "uv_size": [-1, -1]}, 456 | "down": {"uv": [33, 3], "uv_size": [-1, -1]} 457 | } 458 | }, 459 | { 460 | "origin": [-0.5, 13, 14], 461 | "size": [1, 1, 1], 462 | "uv": { 463 | "north": {"uv": [32, 3], "uv_size": [1, 1]}, 464 | "east": {"uv": [32, 3], "uv_size": [1, 1]}, 465 | "south": {"uv": [32, 3], "uv_size": [1, 1]}, 466 | "west": {"uv": [32, 3], "uv_size": [1, 1]}, 467 | "up": {"uv": [33, 4], "uv_size": [-1, -1]}, 468 | "down": {"uv": [33, 4], "uv_size": [-1, -1]} 469 | } 470 | }, 471 | { 472 | "origin": [-0.5, 13, 15], 473 | "size": [1, 1, 1], 474 | "uv": { 475 | "north": {"uv": [32, 2], "uv_size": [1, 1]}, 476 | "east": {"uv": [32, 2], "uv_size": [1, 1]}, 477 | "south": {"uv": [32, 2], "uv_size": [1, 1]}, 478 | "west": {"uv": [32, 2], "uv_size": [1, 1]}, 479 | "up": {"uv": [33, 3], "uv_size": [-1, -1]}, 480 | "down": {"uv": [33, 3], "uv_size": [-1, -1]} 481 | } 482 | }, 483 | { 484 | "origin": [-0.5, 13, 16], 485 | "size": [1, 1, 1], 486 | "uv": { 487 | "north": {"uv": [32, 3], "uv_size": [1, 1]}, 488 | "east": {"uv": [32, 3], "uv_size": [1, 1]}, 489 | "south": {"uv": [32, 3], "uv_size": [1, 1]}, 490 | "west": {"uv": [32, 3], "uv_size": [1, 1]}, 491 | "up": {"uv": [33, 4], "uv_size": [-1, -1]}, 492 | "down": {"uv": [33, 4], "uv_size": [-1, -1]} 493 | } 494 | }, 495 | { 496 | "origin": [-0.5, 13, 17], 497 | "size": [1, 1, 1], 498 | "uv": { 499 | "north": {"uv": [32, 3], "uv_size": [1, 1]}, 500 | "east": {"uv": [32, 3], "uv_size": [1, 1]}, 501 | "south": {"uv": [32, 3], "uv_size": [1, 1]}, 502 | "west": {"uv": [32, 3], "uv_size": [1, 1]}, 503 | "up": {"uv": [33, 4], "uv_size": [-1, -1]}, 504 | "down": {"uv": [33, 4], "uv_size": [-1, -1]} 505 | } 506 | } 507 | ] 508 | }, 509 | { 510 | "name": "tail4", 511 | "parent": "tail3", 512 | "pivot": [0, 14.2, 17.5], 513 | "rotation": [47.5, 0, 0], 514 | "cubes": [ 515 | { 516 | "origin": [-0.5, 13.01915, 16.92642], 517 | "size": [1, 1, 1], 518 | "uv": { 519 | "north": {"uv": [32, 3], "uv_size": [1, 1]}, 520 | "east": {"uv": [32, 3], "uv_size": [1, 1]}, 521 | "south": {"uv": [32, 3], "uv_size": [1, 1]}, 522 | "west": {"uv": [32, 3], "uv_size": [1, 1]}, 523 | "up": {"uv": [33, 4], "uv_size": [-1, -1]}, 524 | "down": {"uv": [33, 4], "uv_size": [-1, -1]} 525 | } 526 | }, 527 | { 528 | "origin": [-0.5, 13.01915, 17.92642], 529 | "size": [1, 1, 1], 530 | "uv": { 531 | "north": {"uv": [32, 4], "uv_size": [1, 1]}, 532 | "east": {"uv": [32, 4], "uv_size": [1, 1]}, 533 | "south": {"uv": [32, 4], "uv_size": [1, 1]}, 534 | "west": {"uv": [32, 4], "uv_size": [1, 1]}, 535 | "up": {"uv": [33, 5], "uv_size": [-1, -1]}, 536 | "down": {"uv": [33, 5], "uv_size": [-1, -1]} 537 | } 538 | }, 539 | { 540 | "origin": [-0.5, 13.21915, 18.40142], 541 | "size": [1, 1, 1], 542 | "pivot": [0, 13.71915, 18.90142], 543 | "rotation": [45, 0, 0], 544 | "uv": { 545 | "north": {"uv": [32, 4], "uv_size": [1, 1]}, 546 | "east": {"uv": [32, 4], "uv_size": [1, 1]}, 547 | "south": {"uv": [32, 4], "uv_size": [1, 1]}, 548 | "west": {"uv": [32, 4], "uv_size": [1, 1]}, 549 | "up": {"uv": [33, 5], "uv_size": [-1, -1]}, 550 | "down": {"uv": [33, 5], "uv_size": [-1, -1]} 551 | } 552 | } 553 | ] 554 | }, 555 | { 556 | "name": "tail5", 557 | "parent": "tail4", 558 | "pivot": [0, 13.8, 19.825], 559 | "rotation": [-40, 0, 0], 560 | "cubes": [ 561 | { 562 | "origin": [-0.5, 13.61915, 18.75142], 563 | "size": [1, 0, 1], 564 | "uv": { 565 | "north": {"uv": [32, 4], "uv_size": [1, 0]}, 566 | "east": {"uv": [32, 4], "uv_size": [1, 0]}, 567 | "south": {"uv": [32, 4], "uv_size": [1, 0]}, 568 | "west": {"uv": [32, 4], "uv_size": [1, 0]}, 569 | "up": {"uv": [33, 5], "uv_size": [-1, -1]} 570 | } 571 | }, 572 | { 573 | "origin": [0.5, 13.61915, 18.75142], 574 | "size": [1, 0, 1], 575 | "uv": { 576 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 577 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 578 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 579 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 580 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 581 | } 582 | }, 583 | { 584 | "origin": [1.5, 13.61915, 18.75142], 585 | "size": [1, 0, 1], 586 | "uv": { 587 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 588 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 589 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 590 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 591 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 592 | } 593 | }, 594 | { 595 | "origin": [-1.5, 13.61915, 18.75142], 596 | "size": [1, 0, 1], 597 | "uv": { 598 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 599 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 600 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 601 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 602 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 603 | } 604 | }, 605 | { 606 | "origin": [-2.5, 13.61915, 18.75142], 607 | "size": [1, 0, 1], 608 | "uv": { 609 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 610 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 611 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 612 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 613 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 614 | } 615 | }, 616 | { 617 | "origin": [-2.5, 13.61915, 17.75142], 618 | "size": [1, 0, 1], 619 | "uv": { 620 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 621 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 622 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 623 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 624 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 625 | } 626 | }, 627 | { 628 | "origin": [-3.5, 13.61915, 16.75142], 629 | "size": [1, 0, 1], 630 | "uv": { 631 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 632 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 633 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 634 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 635 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 636 | } 637 | }, 638 | { 639 | "origin": [2.5, 13.61915, 16.75142], 640 | "size": [1, 0, 1], 641 | "uv": { 642 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 643 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 644 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 645 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 646 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 647 | } 648 | }, 649 | { 650 | "origin": [0.5, 13.61915, 19.75142], 651 | "size": [1, 0, 1], 652 | "uv": { 653 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 654 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 655 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 656 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 657 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 658 | } 659 | }, 660 | { 661 | "origin": [0.5, 13.61915, 20.75142], 662 | "size": [1, 0, 1], 663 | "uv": { 664 | "north": {"uv": [32, 7], "uv_size": [1, 0]}, 665 | "east": {"uv": [32, 7], "uv_size": [1, 0]}, 666 | "south": {"uv": [32, 7], "uv_size": [1, 0]}, 667 | "west": {"uv": [32, 7], "uv_size": [1, 0]}, 668 | "up": {"uv": [33, 8], "uv_size": [-1, -1]} 669 | } 670 | }, 671 | { 672 | "origin": [-1.5, 13.61915, 20.75142], 673 | "size": [1, 0, 1], 674 | "uv": { 675 | "north": {"uv": [32, 7], "uv_size": [1, 0]}, 676 | "east": {"uv": [32, 7], "uv_size": [1, 0]}, 677 | "south": {"uv": [32, 7], "uv_size": [1, 0]}, 678 | "west": {"uv": [32, 7], "uv_size": [1, 0]}, 679 | "up": {"uv": [33, 8], "uv_size": [-1, -1]} 680 | } 681 | }, 682 | { 683 | "origin": [-1.5, 13.61915, 19.75142], 684 | "size": [1, 0, 1], 685 | "uv": { 686 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 687 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 688 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 689 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 690 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 691 | } 692 | }, 693 | { 694 | "origin": [-1.5, 13.61915, 21.75142], 695 | "size": [1, 0, 1], 696 | "uv": { 697 | "north": {"uv": [32, 7], "uv_size": [1, 0]}, 698 | "east": {"uv": [32, 7], "uv_size": [1, 0]}, 699 | "south": {"uv": [32, 7], "uv_size": [1, 0]}, 700 | "west": {"uv": [32, 7], "uv_size": [1, 0]}, 701 | "up": {"uv": [33, 8], "uv_size": [-1, -1]} 702 | } 703 | }, 704 | { 705 | "origin": [0.5, 13.61915, 21.75142], 706 | "size": [1, 0, 1], 707 | "uv": { 708 | "north": {"uv": [32, 7], "uv_size": [1, 0]}, 709 | "east": {"uv": [32, 7], "uv_size": [1, 0]}, 710 | "south": {"uv": [32, 7], "uv_size": [1, 0]}, 711 | "west": {"uv": [32, 7], "uv_size": [1, 0]}, 712 | "up": {"uv": [33, 8], "uv_size": [-1, -1]} 713 | } 714 | }, 715 | { 716 | "origin": [-0.5, 13.61915, 21.75142], 717 | "size": [1, 0, 1], 718 | "uv": { 719 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 720 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 721 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 722 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 723 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 724 | } 725 | }, 726 | { 727 | "origin": [-0.5, 13.61915, 22.75142], 728 | "size": [1, 0, 1], 729 | "uv": { 730 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 731 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 732 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 733 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 734 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 735 | } 736 | }, 737 | { 738 | "origin": [-0.5, 13.61915, 23.75142], 739 | "size": [1, 0, 1], 740 | "uv": { 741 | "north": {"uv": [32, 7], "uv_size": [1, 0]}, 742 | "east": {"uv": [32, 7], "uv_size": [1, 0]}, 743 | "south": {"uv": [32, 7], "uv_size": [1, 0]}, 744 | "west": {"uv": [32, 7], "uv_size": [1, 0]}, 745 | "up": {"uv": [33, 8], "uv_size": [-1, -1]} 746 | } 747 | }, 748 | { 749 | "origin": [1.5, 13.61915, 17.75142], 750 | "size": [1, 0, 1], 751 | "uv": { 752 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 753 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 754 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 755 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 756 | "up": {"uv": [33, 7], "uv_size": [-1, -1]} 757 | } 758 | }, 759 | { 760 | "origin": [-0.5, 13.61915, 19.75142], 761 | "size": [1, 0, 1], 762 | "uv": { 763 | "north": {"uv": [32, 4], "uv_size": [1, 0]}, 764 | "east": {"uv": [32, 4], "uv_size": [1, 0]}, 765 | "south": {"uv": [32, 4], "uv_size": [1, 0]}, 766 | "west": {"uv": [32, 4], "uv_size": [1, 0]}, 767 | "up": {"uv": [33, 5], "uv_size": [-1, -1]}, 768 | "down": {"uv": [33, 5], "uv_size": [-1, -1]} 769 | } 770 | }, 771 | { 772 | "origin": [-0.5, 13.61915, 20.75142], 773 | "size": [1, 0, 1], 774 | "uv": { 775 | "north": {"uv": [32, 6], "uv_size": [1, 0]}, 776 | "east": {"uv": [32, 6], "uv_size": [1, 0]}, 777 | "south": {"uv": [32, 6], "uv_size": [1, 0]}, 778 | "west": {"uv": [32, 6], "uv_size": [1, 0]}, 779 | "up": {"uv": [33, 7], "uv_size": [-1, -1]}, 780 | "down": {"uv": [33, 7], "uv_size": [-1, -1]} 781 | } 782 | } 783 | ] 784 | }, 785 | { 786 | "name": "leftLeg", 787 | "parent": "root", 788 | "pivot": [1.9, 12, 0], 789 | "cubes": [ 790 | { 791 | "origin": [-0.1, 0, -2], 792 | "size": [4, 12, 4], 793 | "uv": { 794 | "north": {"uv": [20, 52], "uv_size": [4, 12]}, 795 | "east": {"uv": [16, 52], "uv_size": [4, 12]}, 796 | "south": {"uv": [28, 52], "uv_size": [4, 12]}, 797 | "west": {"uv": [24, 52], "uv_size": [4, 12]}, 798 | "up": {"uv": [20, 48], "uv_size": [4, 4]}, 799 | "down": {"uv": [28, 48], "uv_size": [-4, 4]} 800 | } 801 | } 802 | ] 803 | }, 804 | { 805 | "name": "leftPants", 806 | "parent": "leftLeg", 807 | "pivot": [1.9, 12, 0], 808 | "cubes": [ 809 | { 810 | "origin": [-0.1, 0, -2], 811 | "size": [4, 12, 4], 812 | "inflate": 0.25, 813 | "uv": { 814 | "north": {"uv": [4, 52], "uv_size": [4, 12]}, 815 | "east": {"uv": [0, 52], "uv_size": [4, 12]}, 816 | "south": {"uv": [12, 52], "uv_size": [4, 12]}, 817 | "west": {"uv": [8, 52], "uv_size": [4, 12]}, 818 | "up": {"uv": [4, 48], "uv_size": [4, 4]}, 819 | "down": {"uv": [12, 48], "uv_size": [-4, 4]} 820 | } 821 | } 822 | ] 823 | }, 824 | { 825 | "name": "rightLeg", 826 | "parent": "root", 827 | "pivot": [-1.9, 12, 0], 828 | "cubes": [ 829 | { 830 | "origin": [-3.9, 0, -2], 831 | "size": [4, 12, 4], 832 | "uv": { 833 | "north": {"uv": [4, 20], "uv_size": [4, 12]}, 834 | "east": {"uv": [0, 20], "uv_size": [4, 12]}, 835 | "south": {"uv": [12, 20], "uv_size": [4, 12]}, 836 | "west": {"uv": [8, 20], "uv_size": [4, 12]}, 837 | "up": {"uv": [4, 16], "uv_size": [4, 4]}, 838 | "down": {"uv": [12, 16], "uv_size": [-4, 4]} 839 | } 840 | } 841 | ] 842 | }, 843 | { 844 | "name": "rightPants", 845 | "parent": "rightLeg", 846 | "pivot": [-1.9, 12, 0], 847 | "cubes": [ 848 | { 849 | "origin": [-3.9, 0, -2], 850 | "size": [4, 12, 4], 851 | "inflate": 0.25, 852 | "uv": { 853 | "north": {"uv": [4, 36], "uv_size": [4, 12]}, 854 | "east": {"uv": [0, 36], "uv_size": [4, 12]}, 855 | "south": {"uv": [12, 36], "uv_size": [4, 12]}, 856 | "west": {"uv": [8, 36], "uv_size": [4, 12]}, 857 | "up": {"uv": [4, 32], "uv_size": [4, 4]}, 858 | "down": {"uv": [12, 32], "uv_size": [-4, 4]} 859 | } 860 | } 861 | ] 862 | } 863 | ] 864 | } 865 | ] 866 | } -------------------------------------------------------------------------------- /resources/models/firegod.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:geometry": [ 4 | { 5 | "description": { 6 | "identifier": "geometry.custom", 7 | "texture_width": 64, 8 | "texture_height": 64, 9 | "visible_bounds_width": 5, 10 | "visible_bounds_height": 4, 11 | "visible_bounds_offset": [0, 2, 0] 12 | }, 13 | "bones": [ 14 | { 15 | "name": "root", 16 | "pivot": [0, 0, 0] 17 | }, 18 | { 19 | "name": "waist", 20 | "parent": "root", 21 | "pivot": [0, 12, 0] 22 | }, 23 | { 24 | "name": "body", 25 | "parent": "waist", 26 | "pivot": [0, 24, 0], 27 | "cubes": [ 28 | { 29 | "origin": [-4, 12, -2], 30 | "size": [8, 12, 4], 31 | "uv": { 32 | "north": {"uv": [20, 20], "uv_size": [8, 12]}, 33 | "east": {"uv": [16, 20], "uv_size": [4, 12]}, 34 | "south": {"uv": [32, 20], "uv_size": [8, 12]}, 35 | "west": {"uv": [28, 20], "uv_size": [4, 12]}, 36 | "up": {"uv": [20, 16], "uv_size": [8, 4]}, 37 | "down": {"uv": [36, 16], "uv_size": [-8, 4]} 38 | } 39 | } 40 | ] 41 | }, 42 | { 43 | "name": "head", 44 | "parent": "body", 45 | "pivot": [0, 24, 0], 46 | "cubes": [ 47 | { 48 | "origin": [-4, 24, -4], 49 | "size": [8, 8, 8], 50 | "uv": { 51 | "north": {"uv": [8, 8], "uv_size": [8, 8]}, 52 | "east": {"uv": [0, 8], "uv_size": [8, 8]}, 53 | "south": {"uv": [24, 8], "uv_size": [8, 8]}, 54 | "west": {"uv": [16, 10], "uv_size": [8, 8]}, 55 | "up": {"uv": [8, 0], "uv_size": [8, 8]}, 56 | "down": {"uv": [24, 0], "uv_size": [-8, 8]} 57 | } 58 | } 59 | ] 60 | }, 61 | { 62 | "name": "hat", 63 | "parent": "head", 64 | "pivot": [0, 24, 0], 65 | "cubes": [ 66 | { 67 | "origin": [-4, 24, -4], 68 | "size": [8, 8, 8], 69 | "inflate": 0.5, 70 | "uv": { 71 | "north": {"uv": [40, 8], "uv_size": [8, 8]}, 72 | "east": {"uv": [32, 8], "uv_size": [8, 8]}, 73 | "south": {"uv": [56, 8], "uv_size": [8, 8]}, 74 | "west": {"uv": [48, 8], "uv_size": [8, 8]}, 75 | "up": {"uv": [40, 0], "uv_size": [8, 8]}, 76 | "down": {"uv": [56, 0], "uv_size": [-8, 8]} 77 | } 78 | } 79 | ] 80 | }, 81 | { 82 | "name": "horns", 83 | "parent": "head", 84 | "pivot": [0, 32, 0] 85 | }, 86 | { 87 | "name": "horn_1", 88 | "parent": "horns", 89 | "pivot": [4, 29, 0], 90 | "rotation": [-2.20462, -12.3071, -9.76228], 91 | "cubes": [ 92 | { 93 | "origin": [4, 30, -1], 94 | "size": [1, 1, 1], 95 | "uv": { 96 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 97 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 98 | "south": {"uv": [1, 0], "uv_size": [-1, 1]}, 99 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 100 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 101 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 102 | } 103 | }, 104 | { 105 | "origin": [6, 35, -1], 106 | "size": [1, 1, 1], 107 | "uv": { 108 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 109 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 110 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 111 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 112 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 113 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 114 | } 115 | }, 116 | { 117 | "origin": [6, 36, -1], 118 | "size": [1, 1, 1], 119 | "uv": { 120 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 121 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 122 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 123 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 124 | "up": {"uv": [0, 2], "uv_size": [1, -1]}, 125 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 126 | } 127 | }, 128 | { 129 | "origin": [6, 37, -1], 130 | "size": [1, 1, 1], 131 | "uv": { 132 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 133 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 134 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 135 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 136 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 137 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 138 | } 139 | }, 140 | { 141 | "origin": [5, 38, -1], 142 | "size": [1, 1, 1], 143 | "uv": { 144 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 145 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 146 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 147 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 148 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 149 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 150 | } 151 | }, 152 | { 153 | "origin": [5, 37, -1], 154 | "size": [1, 1, 1], 155 | "uv": { 156 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 157 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 158 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 159 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 160 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 161 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 162 | } 163 | }, 164 | { 165 | "origin": [5, 36, -1], 166 | "size": [1, 1, 1], 167 | "uv": { 168 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 169 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 170 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 171 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 172 | "up": {"uv": [0, 5], "uv_size": [1, -1]}, 173 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 174 | } 175 | }, 176 | { 177 | "origin": [5, 39, -1], 178 | "size": [1, 1, 1], 179 | "uv": { 180 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 181 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 182 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 183 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 184 | "up": {"uv": [0, 6], "uv_size": [1, -1]}, 185 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 186 | } 187 | }, 188 | { 189 | "origin": [7, 33, -1], 190 | "size": [1, 1, 1], 191 | "uv": { 192 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 193 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 194 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 195 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 196 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 197 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 198 | } 199 | }, 200 | { 201 | "origin": [6, 34, -1], 202 | "size": [1, 1, 1], 203 | "uv": { 204 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 205 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 206 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 207 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 208 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 209 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 210 | } 211 | }, 212 | { 213 | "origin": [7, 34, -1], 214 | "size": [1, 1, 1], 215 | "uv": { 216 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 217 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 218 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 219 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 220 | "up": {"uv": [0, 5], "uv_size": [1, -1]}, 221 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 222 | } 223 | }, 224 | { 225 | "origin": [7, 35, -1], 226 | "size": [1, 1, 1], 227 | "uv": { 228 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 229 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 230 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 231 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 232 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 233 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 234 | } 235 | }, 236 | { 237 | "origin": [7, 36, -1], 238 | "size": [1, 1, 1], 239 | "uv": { 240 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 241 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 242 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 243 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 244 | "up": {"uv": [0, 3], "uv_size": [1, -1]}, 245 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 246 | } 247 | }, 248 | { 249 | "origin": [6, 41, -1], 250 | "size": [1, 1, 1], 251 | "uv": { 252 | "north": {"uv": [0, 6], "uv_size": [1, 1]}, 253 | "east": {"uv": [0, 4], "uv_size": [1, 1]}, 254 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 255 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 256 | "up": {"uv": [1, 6], "uv_size": [-1, -1]}, 257 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 258 | } 259 | }, 260 | { 261 | "origin": [7, 42, -1], 262 | "size": [1, 1, 1], 263 | "uv": { 264 | "north": {"uv": [0, 6], "uv_size": [1, 1]}, 265 | "east": {"uv": [0, 4], "uv_size": [1, 1]}, 266 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 267 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 268 | "up": {"uv": [1, 6], "uv_size": [-1, -1]}, 269 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 270 | } 271 | }, 272 | { 273 | "origin": [9, 42, -1], 274 | "size": [1, 1, 1], 275 | "uv": { 276 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 277 | "east": {"uv": [0, 3], "uv_size": [1, 1]}, 278 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 279 | "west": {"uv": [0, 5], "uv_size": [1, 1]}, 280 | "up": {"uv": [1, 4], "uv_size": [-1, -1]}, 281 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 282 | } 283 | }, 284 | { 285 | "origin": [8, 42, -1], 286 | "size": [1, 1, 1], 287 | "uv": { 288 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 289 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 290 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 291 | "west": {"uv": [0, 2], "uv_size": [1, 1]}, 292 | "up": {"uv": [1, 5], "uv_size": [-1, -1]}, 293 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 294 | } 295 | }, 296 | { 297 | "origin": [7, 41, -1], 298 | "size": [1, 1, 1], 299 | "uv": { 300 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 301 | "east": {"uv": [0, 3], "uv_size": [1, 1]}, 302 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 303 | "west": {"uv": [0, 2], "uv_size": [1, 1]}, 304 | "up": {"uv": [1, 4], "uv_size": [-1, -1]}, 305 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 306 | } 307 | }, 308 | { 309 | "origin": [6, 39, -1], 310 | "size": [1, 1, 1], 311 | "uv": { 312 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 313 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 314 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 315 | "west": {"uv": [0, 2], "uv_size": [1, 1]}, 316 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 317 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 318 | } 319 | }, 320 | { 321 | "origin": [6, 38, -1], 322 | "size": [1, 1, 1], 323 | "uv": { 324 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 325 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 326 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 327 | "west": {"uv": [0, 2], "uv_size": [1, 1]}, 328 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 329 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 330 | } 331 | }, 332 | { 333 | "origin": [6, 40, -1], 334 | "size": [1, 1, 1], 335 | "uv": { 336 | "north": {"uv": [0, 6], "uv_size": [1, 1]}, 337 | "east": {"uv": [0, 4], "uv_size": [1, 1]}, 338 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 339 | "west": {"uv": [0, 2], "uv_size": [1, 1]}, 340 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 341 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 342 | } 343 | }, 344 | { 345 | "origin": [3, 32, -1], 346 | "size": [1, 1, 1], 347 | "uv": { 348 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 349 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 350 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 351 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 352 | "up": {"uv": [0, 6], "uv_size": [1, -1]}, 353 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 354 | } 355 | }, 356 | { 357 | "origin": [2, 31, -1], 358 | "size": [1, 1, 1], 359 | "uv": { 360 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 361 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 362 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 363 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 364 | "up": {"uv": [0, 5], "uv_size": [1, -1]}, 365 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 366 | } 367 | }, 368 | { 369 | "origin": [6, 33, -1], 370 | "size": [1, 1, 1], 371 | "uv": { 372 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 373 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 374 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 375 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 376 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 377 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 378 | } 379 | }, 380 | { 381 | "origin": [6, 32, -1], 382 | "size": [1, 1, 1], 383 | "uv": { 384 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 385 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 386 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 387 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 388 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 389 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 390 | } 391 | }, 392 | { 393 | "origin": [4, 32, -1], 394 | "size": [1, 1, 1], 395 | "uv": { 396 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 397 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 398 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 399 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 400 | "up": {"uv": [0, 6], "uv_size": [1, -1]}, 401 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 402 | } 403 | }, 404 | { 405 | "origin": [4, 31, -1], 406 | "size": [1, 1, 1], 407 | "uv": { 408 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 409 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 410 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 411 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 412 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 413 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 414 | } 415 | }, 416 | { 417 | "origin": [3, 31, -1], 418 | "size": [1, 1, 1], 419 | "uv": { 420 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 421 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 422 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 423 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 424 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 425 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 426 | } 427 | }, 428 | { 429 | "origin": [5, 31, -1], 430 | "size": [1, 1, 1], 431 | "uv": { 432 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 433 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 434 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 435 | "west": {"uv": [1, 2], "uv_size": [-1, 1]}, 436 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 437 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 438 | } 439 | }, 440 | { 441 | "origin": [5, 32, -1], 442 | "size": [1, 1, 1], 443 | "uv": { 444 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 445 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 446 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 447 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 448 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 449 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 450 | } 451 | }, 452 | { 453 | "origin": [5, 33, -1], 454 | "size": [1, 1, 1], 455 | "uv": { 456 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 457 | "east": {"uv": [1, 4], "uv_size": [-1, 1]}, 458 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 459 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 460 | "up": {"uv": [0, 4], "uv_size": [1, -1]}, 461 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 462 | } 463 | } 464 | ] 465 | }, 466 | { 467 | "name": "horn_2", 468 | "parent": "horns", 469 | "pivot": [-4, 29, 0], 470 | "rotation": [-2.20462, 12.3071, 9.76228], 471 | "cubes": [ 472 | { 473 | "origin": [-5, 30, -1], 474 | "size": [1, 1, 1], 475 | "uv": { 476 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 477 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 478 | "south": {"uv": [0, 0], "uv_size": [1, 1]}, 479 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 480 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 481 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 482 | } 483 | }, 484 | { 485 | "origin": [-7, 35, -1], 486 | "size": [1, 1, 1], 487 | "uv": { 488 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 489 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 490 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 491 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 492 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 493 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 494 | } 495 | }, 496 | { 497 | "origin": [-7, 36, -1], 498 | "size": [1, 1, 1], 499 | "uv": { 500 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 501 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 502 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 503 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 504 | "up": {"uv": [1, 2], "uv_size": [-1, -1]}, 505 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 506 | } 507 | }, 508 | { 509 | "origin": [-7, 37, -1], 510 | "size": [1, 1, 1], 511 | "uv": { 512 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 513 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 514 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 515 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 516 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 517 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 518 | } 519 | }, 520 | { 521 | "origin": [-6, 38, -1], 522 | "size": [1, 1, 1], 523 | "uv": { 524 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 525 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 526 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 527 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 528 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 529 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 530 | } 531 | }, 532 | { 533 | "origin": [-6, 37, -1], 534 | "size": [1, 1, 1], 535 | "uv": { 536 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 537 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 538 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 539 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 540 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 541 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 542 | } 543 | }, 544 | { 545 | "origin": [-6, 36, -1], 546 | "size": [1, 1, 1], 547 | "uv": { 548 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 549 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 550 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 551 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 552 | "up": {"uv": [1, 5], "uv_size": [-1, -1]}, 553 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 554 | } 555 | }, 556 | { 557 | "origin": [-6, 39, -1], 558 | "size": [1, 1, 1], 559 | "uv": { 560 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 561 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 562 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 563 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 564 | "up": {"uv": [1, 6], "uv_size": [-1, -1]}, 565 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 566 | } 567 | }, 568 | { 569 | "origin": [-8, 33, -1], 570 | "size": [1, 1, 1], 571 | "uv": { 572 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 573 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 574 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 575 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 576 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 577 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 578 | } 579 | }, 580 | { 581 | "origin": [-7, 34, -1], 582 | "size": [1, 1, 1], 583 | "uv": { 584 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 585 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 586 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 587 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 588 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 589 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 590 | } 591 | }, 592 | { 593 | "origin": [-8, 34, -1], 594 | "size": [1, 1, 1], 595 | "uv": { 596 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 597 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 598 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 599 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 600 | "up": {"uv": [1, 5], "uv_size": [-1, -1]}, 601 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 602 | } 603 | }, 604 | { 605 | "origin": [-8, 35, -1], 606 | "size": [1, 1, 1], 607 | "uv": { 608 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 609 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 610 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 611 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 612 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 613 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 614 | } 615 | }, 616 | { 617 | "origin": [-8, 36, -1], 618 | "size": [1, 1, 1], 619 | "uv": { 620 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 621 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 622 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 623 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 624 | "up": {"uv": [1, 3], "uv_size": [-1, -1]}, 625 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 626 | } 627 | }, 628 | { 629 | "origin": [-7, 41, -1], 630 | "size": [1, 1, 1], 631 | "uv": { 632 | "north": {"uv": [1, 6], "uv_size": [-1, 1]}, 633 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 634 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 635 | "west": {"uv": [1, 4], "uv_size": [-1, 1]}, 636 | "up": {"uv": [0, 6], "uv_size": [1, -1]}, 637 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 638 | } 639 | }, 640 | { 641 | "origin": [-8, 42, -1], 642 | "size": [1, 1, 1], 643 | "uv": { 644 | "north": {"uv": [1, 6], "uv_size": [-1, 1]}, 645 | "east": {"uv": [1, 0], "uv_size": [-1, 1]}, 646 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 647 | "west": {"uv": [1, 4], "uv_size": [-1, 1]}, 648 | "up": {"uv": [0, 6], "uv_size": [1, -1]}, 649 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 650 | } 651 | }, 652 | { 653 | "origin": [-10, 42, -1], 654 | "size": [1, 1, 1], 655 | "uv": { 656 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 657 | "east": {"uv": [1, 5], "uv_size": [-1, 1]}, 658 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 659 | "west": {"uv": [1, 3], "uv_size": [-1, 1]}, 660 | "up": {"uv": [0, 4], "uv_size": [1, -1]}, 661 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 662 | } 663 | }, 664 | { 665 | "origin": [-9, 42, -1], 666 | "size": [1, 1, 1], 667 | "uv": { 668 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 669 | "east": {"uv": [1, 2], "uv_size": [-1, 1]}, 670 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 671 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 672 | "up": {"uv": [0, 5], "uv_size": [1, -1]}, 673 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 674 | } 675 | }, 676 | { 677 | "origin": [-8, 41, -1], 678 | "size": [1, 1, 1], 679 | "uv": { 680 | "north": {"uv": [1, 3], "uv_size": [-1, 1]}, 681 | "east": {"uv": [1, 2], "uv_size": [-1, 1]}, 682 | "south": {"uv": [1, 3], "uv_size": [-1, 1]}, 683 | "west": {"uv": [1, 3], "uv_size": [-1, 1]}, 684 | "up": {"uv": [0, 4], "uv_size": [1, -1]}, 685 | "down": {"uv": [0, 2], "uv_size": [1, -1]} 686 | } 687 | }, 688 | { 689 | "origin": [-7, 39, -1], 690 | "size": [1, 1, 1], 691 | "uv": { 692 | "north": {"uv": [1, 5], "uv_size": [-1, 1]}, 693 | "east": {"uv": [1, 2], "uv_size": [-1, 1]}, 694 | "south": {"uv": [1, 4], "uv_size": [-1, 1]}, 695 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 696 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 697 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 698 | } 699 | }, 700 | { 701 | "origin": [-7, 38, -1], 702 | "size": [1, 1, 1], 703 | "uv": { 704 | "north": {"uv": [1, 4], "uv_size": [-1, 1]}, 705 | "east": {"uv": [1, 2], "uv_size": [-1, 1]}, 706 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 707 | "west": {"uv": [1, 0], "uv_size": [-1, 1]}, 708 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 709 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 710 | } 711 | }, 712 | { 713 | "origin": [-7, 40, -1], 714 | "size": [1, 1, 1], 715 | "uv": { 716 | "north": {"uv": [1, 6], "uv_size": [-1, 1]}, 717 | "east": {"uv": [1, 2], "uv_size": [-1, 1]}, 718 | "south": {"uv": [1, 5], "uv_size": [-1, 1]}, 719 | "west": {"uv": [1, 4], "uv_size": [-1, 1]}, 720 | "up": {"uv": [0, 1], "uv_size": [1, -1]}, 721 | "down": {"uv": [0, 1], "uv_size": [1, -1]} 722 | } 723 | }, 724 | { 725 | "origin": [-4, 32, -1], 726 | "size": [1, 1, 1], 727 | "uv": { 728 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 729 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 730 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 731 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 732 | "up": {"uv": [1, 6], "uv_size": [-1, -1]}, 733 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 734 | } 735 | }, 736 | { 737 | "origin": [-3, 31, -1], 738 | "size": [1, 1, 1], 739 | "uv": { 740 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 741 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 742 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 743 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 744 | "up": {"uv": [1, 5], "uv_size": [-1, -1]}, 745 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 746 | } 747 | }, 748 | { 749 | "origin": [-7, 33, -1], 750 | "size": [1, 1, 1], 751 | "uv": { 752 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 753 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 754 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 755 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 756 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 757 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 758 | } 759 | }, 760 | { 761 | "origin": [-7, 32, -1], 762 | "size": [1, 1, 1], 763 | "uv": { 764 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 765 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 766 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 767 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 768 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 769 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 770 | } 771 | }, 772 | { 773 | "origin": [-5, 32, -1], 774 | "size": [1, 1, 1], 775 | "uv": { 776 | "north": {"uv": [0, 5], "uv_size": [1, 1]}, 777 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 778 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 779 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 780 | "up": {"uv": [1, 6], "uv_size": [-1, -1]}, 781 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 782 | } 783 | }, 784 | { 785 | "origin": [-5, 31, -1], 786 | "size": [1, 1, 1], 787 | "uv": { 788 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 789 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 790 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 791 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 792 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 793 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 794 | } 795 | }, 796 | { 797 | "origin": [-4, 31, -1], 798 | "size": [1, 1, 1], 799 | "uv": { 800 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 801 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 802 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 803 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 804 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 805 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 806 | } 807 | }, 808 | { 809 | "origin": [-6, 31, -1], 810 | "size": [1, 1, 1], 811 | "uv": { 812 | "north": {"uv": [0, 3], "uv_size": [1, 1]}, 813 | "east": {"uv": [0, 2], "uv_size": [1, 1]}, 814 | "south": {"uv": [0, 3], "uv_size": [1, 1]}, 815 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 816 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 817 | "down": {"uv": [1, 2], "uv_size": [-1, -1]} 818 | } 819 | }, 820 | { 821 | "origin": [-6, 32, -1], 822 | "size": [1, 1, 1], 823 | "uv": { 824 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 825 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 826 | "south": {"uv": [0, 4], "uv_size": [1, 1]}, 827 | "west": {"uv": [0, 0], "uv_size": [1, 1]}, 828 | "up": {"uv": [1, 1], "uv_size": [-1, -1]}, 829 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 830 | } 831 | }, 832 | { 833 | "origin": [-6, 33, -1], 834 | "size": [1, 1, 1], 835 | "uv": { 836 | "north": {"uv": [0, 4], "uv_size": [1, 1]}, 837 | "east": {"uv": [0, 0], "uv_size": [1, 1]}, 838 | "south": {"uv": [0, 5], "uv_size": [1, 1]}, 839 | "west": {"uv": [0, 4], "uv_size": [1, 1]}, 840 | "up": {"uv": [1, 4], "uv_size": [-1, -1]}, 841 | "down": {"uv": [1, 1], "uv_size": [-1, -1]} 842 | } 843 | } 844 | ] 845 | }, 846 | { 847 | "name": "ember", 848 | "parent": "horns", 849 | "pivot": [-1, 34, -2], 850 | "cubes": [ 851 | { 852 | "origin": [0, 42, 0], 853 | "size": [0, 1, 1], 854 | "uv": { 855 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 856 | } 857 | }, 858 | { 859 | "origin": [0, 42, -1], 860 | "size": [0, 1, 1], 861 | "uv": { 862 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 863 | } 864 | }, 865 | { 866 | "origin": [0, 42, -2], 867 | "size": [0, 1, 1], 868 | "uv": { 869 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 870 | } 871 | }, 872 | { 873 | "origin": [0, 43, -3], 874 | "size": [0, 1, 1], 875 | "uv": { 876 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 877 | } 878 | }, 879 | { 880 | "origin": [0, 43, -1], 881 | "size": [0, 1, 1], 882 | "uv": { 883 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 884 | } 885 | }, 886 | { 887 | "origin": [0, 44, 0], 888 | "size": [0, 1, 1], 889 | "uv": { 890 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 891 | } 892 | }, 893 | { 894 | "origin": [0, 43, 1], 895 | "size": [0, 1, 1], 896 | "uv": { 897 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 898 | } 899 | }, 900 | { 901 | "origin": [0, 43, 0], 902 | "size": [0, 1, 1], 903 | "uv": { 904 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 905 | } 906 | }, 907 | { 908 | "origin": [0, 44, 1], 909 | "size": [0, 1, 1], 910 | "uv": { 911 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 912 | } 913 | }, 914 | { 915 | "origin": [0, 43, -2], 916 | "size": [0, 1, 1], 917 | "uv": { 918 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 919 | } 920 | }, 921 | { 922 | "origin": [0, 44, -3], 923 | "size": [0, 1, 1], 924 | "uv": { 925 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 926 | } 927 | }, 928 | { 929 | "origin": [0, 44, -2], 930 | "size": [0, 1, 1], 931 | "uv": { 932 | "west": {"uv": [1, 4], "uv_size": [1, 1]} 933 | } 934 | }, 935 | { 936 | "origin": [0, 44, -1], 937 | "size": [0, 1, 1], 938 | "uv": { 939 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 940 | } 941 | }, 942 | { 943 | "origin": [0, 45, -1], 944 | "size": [0, 1, 1], 945 | "uv": { 946 | "west": {"uv": [1, 4], "uv_size": [1, 1]} 947 | } 948 | }, 949 | { 950 | "origin": [0, 46, -1], 951 | "size": [0, 1, 1], 952 | "uv": { 953 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 954 | } 955 | }, 956 | { 957 | "origin": [0, 47, -1], 958 | "size": [0, 1, 1], 959 | "uv": { 960 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 961 | } 962 | }, 963 | { 964 | "origin": [0, 48, 0], 965 | "size": [0, 1, 1], 966 | "uv": { 967 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 968 | } 969 | }, 970 | { 971 | "origin": [0, 46, 0], 972 | "size": [0, 1, 1], 973 | "uv": { 974 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 975 | } 976 | }, 977 | { 978 | "origin": [0, 45, 0], 979 | "size": [0, 1, 1], 980 | "uv": { 981 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 982 | } 983 | }, 984 | { 985 | "origin": [0, 45, -2], 986 | "size": [0, 1, 1], 987 | "uv": { 988 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 989 | } 990 | }, 991 | { 992 | "origin": [0, 46, -2], 993 | "size": [0, 1, 1], 994 | "uv": { 995 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 996 | } 997 | }, 998 | { 999 | "origin": [0, 47, -2], 1000 | "size": [0, 1, 1], 1001 | "uv": { 1002 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 1003 | } 1004 | }, 1005 | { 1006 | "origin": [0, 43, 1], 1007 | "size": [0, 1, 1], 1008 | "uv": { 1009 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1010 | } 1011 | }, 1012 | { 1013 | "origin": [0, 42, 0], 1014 | "size": [0, 1, 1], 1015 | "uv": { 1016 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1017 | } 1018 | } 1019 | ] 1020 | }, 1021 | { 1022 | "name": "ember2", 1023 | "parent": "horns", 1024 | "pivot": [1, 34, -1], 1025 | "rotation": [0, -90, 0], 1026 | "cubes": [ 1027 | { 1028 | "origin": [1.5, 42, 0.5], 1029 | "size": [0, 1, 1], 1030 | "uv": { 1031 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1032 | } 1033 | }, 1034 | { 1035 | "origin": [1.5, 42, -0.5], 1036 | "size": [0, 1, 1], 1037 | "uv": { 1038 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1039 | } 1040 | }, 1041 | { 1042 | "origin": [1.5, 42, -1.5], 1043 | "size": [0, 1, 1], 1044 | "uv": { 1045 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1046 | } 1047 | }, 1048 | { 1049 | "origin": [1.5, 43, -2.5], 1050 | "size": [0, 1, 1], 1051 | "uv": { 1052 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1053 | } 1054 | }, 1055 | { 1056 | "origin": [1.5, 43, -0.5], 1057 | "size": [0, 1, 1], 1058 | "uv": { 1059 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1060 | } 1061 | }, 1062 | { 1063 | "origin": [1.5, 44, 0.5], 1064 | "size": [0, 1, 1], 1065 | "uv": { 1066 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1067 | } 1068 | }, 1069 | { 1070 | "origin": [1.5, 43, 1.5], 1071 | "size": [0, 1, 1], 1072 | "uv": { 1073 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1074 | } 1075 | }, 1076 | { 1077 | "origin": [1.5, 43, 0.5], 1078 | "size": [0, 1, 1], 1079 | "uv": { 1080 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1081 | } 1082 | }, 1083 | { 1084 | "origin": [1.5, 44, 1.5], 1085 | "size": [0, 1, 1], 1086 | "uv": { 1087 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1088 | } 1089 | }, 1090 | { 1091 | "origin": [1.5, 43, -1.5], 1092 | "size": [0, 1, 1], 1093 | "uv": { 1094 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1095 | } 1096 | }, 1097 | { 1098 | "origin": [1.5, 44, -2.5], 1099 | "size": [0, 1, 1], 1100 | "uv": { 1101 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1102 | } 1103 | }, 1104 | { 1105 | "origin": [1.5, 44, -1.5], 1106 | "size": [0, 1, 1], 1107 | "uv": { 1108 | "west": {"uv": [1, 4], "uv_size": [1, 1]} 1109 | } 1110 | }, 1111 | { 1112 | "origin": [1.5, 44, -0.5], 1113 | "size": [0, 1, 1], 1114 | "uv": { 1115 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1116 | } 1117 | }, 1118 | { 1119 | "origin": [1.5, 45, -0.5], 1120 | "size": [0, 1, 1], 1121 | "uv": { 1122 | "west": {"uv": [1, 4], "uv_size": [1, 1]} 1123 | } 1124 | }, 1125 | { 1126 | "origin": [1.5, 46, -0.5], 1127 | "size": [0, 1, 1], 1128 | "uv": { 1129 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 1130 | } 1131 | }, 1132 | { 1133 | "origin": [1.5, 47, -0.5], 1134 | "size": [0, 1, 1], 1135 | "uv": { 1136 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 1137 | } 1138 | }, 1139 | { 1140 | "origin": [1.5, 48, 0.5], 1141 | "size": [0, 1, 1], 1142 | "uv": { 1143 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 1144 | } 1145 | }, 1146 | { 1147 | "origin": [1.5, 46, 0.5], 1148 | "size": [0, 1, 1], 1149 | "uv": { 1150 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 1151 | } 1152 | }, 1153 | { 1154 | "origin": [1.5, 45, 0.5], 1155 | "size": [0, 1, 1], 1156 | "uv": { 1157 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 1158 | } 1159 | }, 1160 | { 1161 | "origin": [1.5, 45, -1.5], 1162 | "size": [0, 1, 1], 1163 | "uv": { 1164 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 1165 | } 1166 | }, 1167 | { 1168 | "origin": [1.5, 46, -1.5], 1169 | "size": [0, 1, 1], 1170 | "uv": { 1171 | "west": {"uv": [1, 3], "uv_size": [1, 1]} 1172 | } 1173 | }, 1174 | { 1175 | "origin": [1.5, 47, -1.5], 1176 | "size": [0, 1, 1], 1177 | "uv": { 1178 | "west": {"uv": [1, 2], "uv_size": [1, 1]} 1179 | } 1180 | }, 1181 | { 1182 | "origin": [1.5, 43, 1.5], 1183 | "size": [0, 1, 1], 1184 | "uv": { 1185 | "west": {"uv": [1, 5], "uv_size": [1, 1]} 1186 | } 1187 | }, 1188 | { 1189 | "origin": [1.5, 42, 0.5], 1190 | "size": [0, 1, 1], 1191 | "uv": { 1192 | "west": {"uv": [1, 6], "uv_size": [1, 1]} 1193 | } 1194 | } 1195 | ] 1196 | }, 1197 | { 1198 | "name": "cape", 1199 | "parent": "body", 1200 | "pivot": [0, 24, 3] 1201 | }, 1202 | { 1203 | "name": "leftArm", 1204 | "parent": "body", 1205 | "pivot": [5, 22, 0], 1206 | "cubes": [ 1207 | { 1208 | "origin": [4, 12, -2], 1209 | "size": [4, 12, 4], 1210 | "uv": { 1211 | "north": {"uv": [36, 52], "uv_size": [4, 12]}, 1212 | "east": {"uv": [32, 52], "uv_size": [4, 12]}, 1213 | "south": {"uv": [44, 52], "uv_size": [4, 12]}, 1214 | "west": {"uv": [40, 52], "uv_size": [4, 12]}, 1215 | "up": {"uv": [36, 48], "uv_size": [4, 4]}, 1216 | "down": {"uv": [44, 48], "uv_size": [-4, 4]} 1217 | } 1218 | } 1219 | ] 1220 | }, 1221 | { 1222 | "name": "leftSleeve", 1223 | "parent": "leftArm", 1224 | "pivot": [5, 22, 0], 1225 | "cubes": [ 1226 | { 1227 | "origin": [4, 12, -2], 1228 | "size": [4, 12, 4], 1229 | "inflate": 0.25, 1230 | "uv": { 1231 | "north": {"uv": [52, 52], "uv_size": [4, 12]}, 1232 | "east": {"uv": [48, 52], "uv_size": [4, 12]}, 1233 | "south": {"uv": [60, 52], "uv_size": [4, 12]}, 1234 | "west": {"uv": [56, 52], "uv_size": [4, 12]}, 1235 | "up": {"uv": [52, 48], "uv_size": [4, 4]}, 1236 | "down": {"uv": [60, 48], "uv_size": [-4, 4]} 1237 | } 1238 | } 1239 | ] 1240 | }, 1241 | { 1242 | "name": "leftItem", 1243 | "parent": "leftArm", 1244 | "pivot": [6, 15, 1] 1245 | }, 1246 | { 1247 | "name": "rightArm", 1248 | "parent": "body", 1249 | "pivot": [-5, 22, 0], 1250 | "cubes": [ 1251 | { 1252 | "origin": [-8, 12, -2], 1253 | "size": [4, 12, 4], 1254 | "uv": { 1255 | "north": {"uv": [44, 20], "uv_size": [4, 12]}, 1256 | "east": {"uv": [40, 20], "uv_size": [4, 12]}, 1257 | "south": {"uv": [52, 20], "uv_size": [4, 12]}, 1258 | "west": {"uv": [48, 20], "uv_size": [4, 12]}, 1259 | "up": {"uv": [44, 16], "uv_size": [4, 4]}, 1260 | "down": {"uv": [52, 16], "uv_size": [-4, 4]} 1261 | } 1262 | } 1263 | ] 1264 | }, 1265 | { 1266 | "name": "rightSleeve", 1267 | "parent": "rightArm", 1268 | "pivot": [-5, 22, 0], 1269 | "cubes": [ 1270 | { 1271 | "origin": [-8, 12, -2], 1272 | "size": [4, 12, 4], 1273 | "inflate": 0.25, 1274 | "uv": { 1275 | "north": {"uv": [44, 36], "uv_size": [4, 12]}, 1276 | "east": {"uv": [40, 36], "uv_size": [4, 12]}, 1277 | "south": {"uv": [52, 36], "uv_size": [4, 12]}, 1278 | "west": {"uv": [48, 36], "uv_size": [4, 12]}, 1279 | "up": {"uv": [44, 32], "uv_size": [4, 4]}, 1280 | "down": {"uv": [52, 32], "uv_size": [-4, 4]} 1281 | } 1282 | } 1283 | ] 1284 | }, 1285 | { 1286 | "name": "rightItem", 1287 | "parent": "rightArm", 1288 | "pivot": [-6, 15, 1], 1289 | "locators": { 1290 | "lead_hold": [-6, 15, 1] 1291 | } 1292 | }, 1293 | { 1294 | "name": "jacket", 1295 | "parent": "body", 1296 | "pivot": [0, 24, 0], 1297 | "cubes": [ 1298 | { 1299 | "origin": [-4, 12, -2], 1300 | "size": [8, 12, 4], 1301 | "inflate": 0.25, 1302 | "uv": { 1303 | "north": {"uv": [20, 36], "uv_size": [8, 12]}, 1304 | "east": {"uv": [16, 36], "uv_size": [4, 12]}, 1305 | "south": {"uv": [32, 36], "uv_size": [8, 12]}, 1306 | "west": {"uv": [28, 36], "uv_size": [4, 12]}, 1307 | "up": {"uv": [20, 32], "uv_size": [8, 4]}, 1308 | "down": {"uv": [36, 32], "uv_size": [-8, 4]} 1309 | } 1310 | } 1311 | ] 1312 | }, 1313 | { 1314 | "name": "leftLeg", 1315 | "parent": "root", 1316 | "pivot": [1.9, 12, 0], 1317 | "cubes": [ 1318 | { 1319 | "origin": [-0.1, 0, -2], 1320 | "size": [4, 12, 4], 1321 | "uv": { 1322 | "north": {"uv": [20, 52], "uv_size": [4, 12]}, 1323 | "east": {"uv": [16, 52], "uv_size": [4, 12]}, 1324 | "south": {"uv": [28, 52], "uv_size": [4, 12]}, 1325 | "west": {"uv": [24, 52], "uv_size": [4, 12]}, 1326 | "up": {"uv": [20, 48], "uv_size": [4, 4]}, 1327 | "down": {"uv": [28, 48], "uv_size": [-4, 4]} 1328 | } 1329 | } 1330 | ] 1331 | }, 1332 | { 1333 | "name": "leftPants", 1334 | "parent": "leftLeg", 1335 | "pivot": [1.9, 12, 0], 1336 | "cubes": [ 1337 | { 1338 | "origin": [-0.1, 0, -2], 1339 | "size": [4, 12, 4], 1340 | "inflate": 0.25, 1341 | "uv": { 1342 | "north": {"uv": [4, 52], "uv_size": [4, 12]}, 1343 | "east": {"uv": [0, 52], "uv_size": [4, 12]}, 1344 | "south": {"uv": [12, 52], "uv_size": [4, 12]}, 1345 | "west": {"uv": [8, 52], "uv_size": [4, 12]}, 1346 | "up": {"uv": [4, 48], "uv_size": [4, 4]}, 1347 | "down": {"uv": [12, 48], "uv_size": [-4, 4]} 1348 | } 1349 | } 1350 | ] 1351 | }, 1352 | { 1353 | "name": "rightLeg", 1354 | "parent": "root", 1355 | "pivot": [-1.9, 12, 0], 1356 | "cubes": [ 1357 | { 1358 | "origin": [-3.9, 0, -2], 1359 | "size": [4, 12, 4], 1360 | "uv": { 1361 | "north": {"uv": [4, 20], "uv_size": [4, 12]}, 1362 | "east": {"uv": [0, 20], "uv_size": [4, 12]}, 1363 | "south": {"uv": [12, 20], "uv_size": [4, 12]}, 1364 | "west": {"uv": [8, 20], "uv_size": [4, 12]}, 1365 | "up": {"uv": [4, 16], "uv_size": [4, 4]}, 1366 | "down": {"uv": [12, 16], "uv_size": [-4, 4]} 1367 | } 1368 | } 1369 | ] 1370 | }, 1371 | { 1372 | "name": "rightPants", 1373 | "parent": "rightLeg", 1374 | "pivot": [-1.9, 12, 0], 1375 | "cubes": [ 1376 | { 1377 | "origin": [-3.9, 0, -2], 1378 | "size": [4, 12, 4], 1379 | "inflate": 0.25, 1380 | "uv": { 1381 | "north": {"uv": [4, 36], "uv_size": [4, 12]}, 1382 | "east": {"uv": [0, 36], "uv_size": [4, 12]}, 1383 | "south": {"uv": [12, 36], "uv_size": [4, 12]}, 1384 | "west": {"uv": [8, 36], "uv_size": [4, 12]}, 1385 | "up": {"uv": [4, 32], "uv_size": [4, 4]}, 1386 | "down": {"uv": [12, 32], "uv_size": [-4, 4]} 1387 | } 1388 | } 1389 | ] 1390 | } 1391 | ] 1392 | } 1393 | ] 1394 | } -------------------------------------------------------------------------------- /resources/required/default_player_skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/required/default_player_skin.png -------------------------------------------------------------------------------- /resources/required/default_player_skinSlim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/required/default_player_skinSlim.png -------------------------------------------------------------------------------- /resources/required/geometry.humanoid.custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:geometry": [ 4 | { 5 | "description": { 6 | "identifier": "geometry.humanoid.custom", 7 | "texture_width": 64, 8 | "texture_height": 64, 9 | "visible_bounds_width": 6, 10 | "visible_bounds_height": 3, 11 | "visible_bounds_offset": [0, 1.5, 0] 12 | }, 13 | "bones": [ 14 | { 15 | "name": "root", 16 | "pivot": [0, 0, 0] 17 | }, 18 | { 19 | "name": "waist", 20 | "parent": "root", 21 | "pivot": [0, 12, 0] 22 | }, 23 | { 24 | "name": "body", 25 | "parent": "waist", 26 | "pivot": [0, 24, 0], 27 | "cubes": [ 28 | { 29 | "origin": [-4, 12, -2], 30 | "size": [8, 12, 4], 31 | "uv": { 32 | "north": {"uv": [20, 20], "uv_size": [8, 12]}, 33 | "east": {"uv": [16, 20], "uv_size": [4, 12]}, 34 | "south": {"uv": [32, 20], "uv_size": [8, 12]}, 35 | "west": {"uv": [28, 20], "uv_size": [4, 12]}, 36 | "up": {"uv": [20, 16], "uv_size": [8, 4]}, 37 | "down": {"uv": [36, 16], "uv_size": [-8, 4]} 38 | } 39 | } 40 | ] 41 | }, 42 | { 43 | "name": "head", 44 | "parent": "body", 45 | "pivot": [0, 24, 0], 46 | "cubes": [ 47 | { 48 | "origin": [-4, 24, -4], 49 | "size": [8, 8, 8], 50 | "uv": { 51 | "north": {"uv": [8, 8], "uv_size": [8, 8]}, 52 | "east": {"uv": [0, 8], "uv_size": [8, 8]}, 53 | "south": {"uv": [24, 8], "uv_size": [8, 8]}, 54 | "west": {"uv": [16, 8], "uv_size": [8, 8]}, 55 | "up": {"uv": [8, 0], "uv_size": [8, 8]}, 56 | "down": {"uv": [24, 0], "uv_size": [-8, 8]} 57 | } 58 | } 59 | ] 60 | }, 61 | { 62 | "name": "hat", 63 | "parent": "head", 64 | "pivot": [0, 24, 0], 65 | "cubes": [ 66 | { 67 | "origin": [-3.75, 24, -4], 68 | "size": [7.5, 8, 8], 69 | "inflate": 0.5, 70 | "uv": { 71 | "north": {"uv": [40, 8], "uv_size": [8, 8]}, 72 | "east": {"uv": [32, 8], "uv_size": [8, 8]}, 73 | "south": {"uv": [56, 8], "uv_size": [8, 8]}, 74 | "west": {"uv": [48, 8], "uv_size": [8, 8]}, 75 | "up": {"uv": [40, 0], "uv_size": [8, 8]}, 76 | "down": {"uv": [56, 0], "uv_size": [-8, 8]} 77 | } 78 | } 79 | ] 80 | }, 81 | { 82 | "name": "cape", 83 | "parent": "body", 84 | "pivot": [0, 24, 3] 85 | }, 86 | { 87 | "name": "leftArm", 88 | "parent": "body", 89 | "pivot": [5, 22, 0], 90 | "cubes": [ 91 | { 92 | "origin": [4, 12, -2], 93 | "size": [4, 12, 4], 94 | "uv": { 95 | "north": {"uv": [36, 52], "uv_size": [4, 12]}, 96 | "east": {"uv": [32, 52], "uv_size": [4, 12]}, 97 | "south": {"uv": [44, 52], "uv_size": [4, 12]}, 98 | "west": {"uv": [40, 52], "uv_size": [4, 12]}, 99 | "up": {"uv": [36, 48], "uv_size": [4, 4]}, 100 | "down": {"uv": [44, 48], "uv_size": [-4, 4]} 101 | } 102 | } 103 | ] 104 | }, 105 | { 106 | "name": "leftSleeve", 107 | "parent": "leftArm", 108 | "pivot": [5, 22, 0], 109 | "cubes": [ 110 | { 111 | "origin": [4, 12, -2], 112 | "size": [4, 12, 4], 113 | "inflate": 0.25, 114 | "uv": { 115 | "north": {"uv": [52, 52], "uv_size": [4, 12]}, 116 | "east": {"uv": [48, 52], "uv_size": [4, 12]}, 117 | "south": {"uv": [60, 52], "uv_size": [4, 12]}, 118 | "west": {"uv": [56, 52], "uv_size": [4, 12]}, 119 | "up": {"uv": [52, 48], "uv_size": [4, 4]}, 120 | "down": {"uv": [60, 48], "uv_size": [-4, 4]} 121 | } 122 | } 123 | ] 124 | }, 125 | { 126 | "name": "leftItem", 127 | "parent": "leftArm", 128 | "pivot": [6, 15, 1] 129 | }, 130 | { 131 | "name": "rightArm", 132 | "parent": "body", 133 | "pivot": [-5, 22, 0], 134 | "cubes": [ 135 | { 136 | "origin": [-8, 12, -2], 137 | "size": [4, 12, 4], 138 | "uv": { 139 | "north": {"uv": [44, 20], "uv_size": [4, 12]}, 140 | "east": {"uv": [40, 20], "uv_size": [4, 12]}, 141 | "south": {"uv": [52, 20], "uv_size": [4, 12]}, 142 | "west": {"uv": [48, 20], "uv_size": [4, 12]}, 143 | "up": {"uv": [44, 16], "uv_size": [4, 4]}, 144 | "down": {"uv": [52, 16], "uv_size": [-4, 4]} 145 | } 146 | } 147 | ] 148 | }, 149 | { 150 | "name": "rightSleeve", 151 | "parent": "rightArm", 152 | "pivot": [-5, 22, 0], 153 | "cubes": [ 154 | { 155 | "origin": [-8, 12, -2], 156 | "size": [4, 12, 4], 157 | "inflate": 0.25, 158 | "uv": { 159 | "north": {"uv": [44, 36], "uv_size": [4, 12]}, 160 | "east": {"uv": [40, 36], "uv_size": [4, 12]}, 161 | "south": {"uv": [52, 36], "uv_size": [4, 12]}, 162 | "west": {"uv": [48, 36], "uv_size": [4, 12]}, 163 | "up": {"uv": [44, 32], "uv_size": [4, 4]}, 164 | "down": {"uv": [52, 32], "uv_size": [-4, 4]} 165 | } 166 | } 167 | ] 168 | }, 169 | { 170 | "name": "rightItem", 171 | "parent": "rightArm", 172 | "pivot": [-6, 15, 1], 173 | "locators": { 174 | "lead_hold": [-6, 15, 1] 175 | } 176 | }, 177 | { 178 | "name": "jacket", 179 | "parent": "body", 180 | "pivot": [0, 24, 0], 181 | "cubes": [ 182 | { 183 | "origin": [-3.8, 12, -2], 184 | "size": [7.55, 12, 4], 185 | "inflate": 0.25, 186 | "uv": { 187 | "north": {"uv": [20, 36], "uv_size": [8, 12]}, 188 | "east": {"uv": [16, 36], "uv_size": [4, 12]}, 189 | "south": {"uv": [32, 36], "uv_size": [8, 12]}, 190 | "west": {"uv": [28, 36], "uv_size": [4, 12]}, 191 | "up": {"uv": [20, 32], "uv_size": [8, 4]}, 192 | "down": {"uv": [36, 32], "uv_size": [-8, 4]} 193 | } 194 | } 195 | ] 196 | }, 197 | { 198 | "name": "leftLeg", 199 | "parent": "root", 200 | "pivot": [1.9, 12, 0], 201 | "cubes": [ 202 | { 203 | "origin": [-0.1, 0, -2], 204 | "size": [4, 12, 4], 205 | "uv": { 206 | "north": {"uv": [20, 52], "uv_size": [4, 12]}, 207 | "east": {"uv": [16, 52], "uv_size": [4, 12]}, 208 | "south": {"uv": [28, 52], "uv_size": [4, 12]}, 209 | "west": {"uv": [24, 52], "uv_size": [4, 12]}, 210 | "up": {"uv": [20, 48], "uv_size": [4, 4]}, 211 | "down": {"uv": [28, 48], "uv_size": [-4, 4]} 212 | } 213 | } 214 | ] 215 | }, 216 | { 217 | "name": "leftPants", 218 | "parent": "leftLeg", 219 | "pivot": [1.9, 12, 0], 220 | "cubes": [ 221 | { 222 | "origin": [-0.1, 0, -2], 223 | "size": [4, 12, 4], 224 | "inflate": 0.25, 225 | "uv": { 226 | "north": {"uv": [4, 52], "uv_size": [4, 12]}, 227 | "east": {"uv": [0, 52], "uv_size": [4, 12]}, 228 | "south": {"uv": [12, 52], "uv_size": [4, 12]}, 229 | "west": {"uv": [8, 52], "uv_size": [4, 12]}, 230 | "up": {"uv": [4, 48], "uv_size": [4, 4]}, 231 | "down": {"uv": [12, 48], "uv_size": [-4, 4]} 232 | } 233 | } 234 | ] 235 | }, 236 | { 237 | "name": "rightLeg", 238 | "parent": "root", 239 | "pivot": [-1.9, 12, 0], 240 | "cubes": [ 241 | { 242 | "origin": [-3.9, 0, -2], 243 | "size": [4, 12, 4], 244 | "uv": { 245 | "north": {"uv": [4, 20], "uv_size": [4, 12]}, 246 | "east": {"uv": [0, 20], "uv_size": [4, 12]}, 247 | "south": {"uv": [12, 20], "uv_size": [4, 12]}, 248 | "west": {"uv": [8, 20], "uv_size": [4, 12]}, 249 | "up": {"uv": [4, 16], "uv_size": [4, 4]}, 250 | "down": {"uv": [12, 16], "uv_size": [-4, 4]} 251 | } 252 | } 253 | ] 254 | }, 255 | { 256 | "name": "rightPants", 257 | "parent": "rightLeg", 258 | "pivot": [-1.9, 12, 0], 259 | "cubes": [ 260 | { 261 | "origin": [-3.9, 0, -2], 262 | "size": [4, 12, 4], 263 | "inflate": 0.25, 264 | "uv": { 265 | "north": {"uv": [4, 36], "uv_size": [4, 12]}, 266 | "east": {"uv": [0, 36], "uv_size": [4, 12]}, 267 | "south": {"uv": [12, 36], "uv_size": [4, 12]}, 268 | "west": {"uv": [8, 36], "uv_size": [4, 12]}, 269 | "up": {"uv": [4, 32], "uv_size": [4, 4]}, 270 | "down": {"uv": [12, 32], "uv_size": [-4, 4]} 271 | } 272 | } 273 | ] 274 | } 275 | ] 276 | } 277 | ] 278 | } -------------------------------------------------------------------------------- /resources/required/geometry.humanoid.customSlim.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:geometry": [ 4 | { 5 | "description": { 6 | "identifier": "geometry.humanoid.customSlim", 7 | "texture_width": 64, 8 | "texture_height": 64, 9 | "visible_bounds_width": 2, 10 | "visible_bounds_height": 3, 11 | "visible_bounds_offset": [0, 1.5, 0] 12 | }, 13 | "bones": [ 14 | { 15 | "name": "root", 16 | "pivot": [0, 0, 0] 17 | }, 18 | { 19 | "name": "waist", 20 | "parent": "root", 21 | "pivot": [0, 12, 0] 22 | }, 23 | { 24 | "name": "body", 25 | "parent": "waist", 26 | "pivot": [0, 24, 0], 27 | "cubes": [ 28 | {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} 29 | ] 30 | }, 31 | { 32 | "name": "head", 33 | "parent": "body", 34 | "pivot": [0, 24, 0], 35 | "cubes": [ 36 | {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} 37 | ] 38 | }, 39 | { 40 | "name": "hat", 41 | "parent": "head", 42 | "pivot": [0, 24, 0], 43 | "cubes": [ 44 | {"origin": [-4, 24, -4], "size": [8, 8, 8], "inflate": 0.5, "uv": [32, 0]} 45 | ] 46 | }, 47 | { 48 | "name": "leftArm", 49 | "parent": "body", 50 | "pivot": [5, 21.5, 0], 51 | "cubes": [ 52 | {"origin": [4, 11.5, -2], "size": [3, 12, 4], "uv": [32, 48]} 53 | ] 54 | }, 55 | { 56 | "name": "leftSleeve", 57 | "parent": "leftArm", 58 | "pivot": [5, 21.5, 0], 59 | "cubes": [ 60 | {"origin": [4, 11.5, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [48, 48]} 61 | ] 62 | }, 63 | { 64 | "name": "leftItem", 65 | "parent": "leftArm", 66 | "pivot": [6, 14.5, 1] 67 | }, 68 | { 69 | "name": "rightArm", 70 | "parent": "body", 71 | "pivot": [-5, 21.5, 0], 72 | "cubes": [ 73 | {"origin": [-7, 11.5, -2], "size": [3, 12, 4], "uv": [40, 16]} 74 | ] 75 | }, 76 | { 77 | "name": "rightSleeve", 78 | "parent": "rightArm", 79 | "pivot": [-5, 21.5, 0], 80 | "cubes": [ 81 | {"origin": [-7, 11.5, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [40, 32]} 82 | ] 83 | }, 84 | { 85 | "name": "rightItem", 86 | "parent": "rightArm", 87 | "pivot": [-6, 14.5, 1], 88 | "locators": { 89 | "lead_hold": [-6, 14.5, 1] 90 | } 91 | }, 92 | { 93 | "name": "jacket", 94 | "parent": "body", 95 | "pivot": [0, 24, 0], 96 | "cubes": [ 97 | {"origin": [-4, 12, -2], "size": [8, 12, 4], "inflate": 0.25, "uv": [16, 32]} 98 | ] 99 | }, 100 | { 101 | "name": "cape", 102 | "parent": "body", 103 | "pivot": [0, 24, -3] 104 | }, 105 | { 106 | "name": "rightLeg", 107 | "parent": "root", 108 | "pivot": [-1.9, 12, 0], 109 | "cubes": [ 110 | {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} 111 | ] 112 | }, 113 | { 114 | "name": "rightPants", 115 | "parent": "rightLeg", 116 | "pivot": [-1.9, 12, 0], 117 | "cubes": [ 118 | {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 32]} 119 | ] 120 | }, 121 | { 122 | "name": "leftLeg", 123 | "parent": "root", 124 | "pivot": [1.9, 12, 0], 125 | "mirror": true, 126 | "cubes": [ 127 | {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [16, 48]} 128 | ] 129 | }, 130 | { 131 | "name": "leftPants", 132 | "parent": "leftLeg", 133 | "pivot": [1.9, 12, 0], 134 | "cubes": [ 135 | {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 48]} 136 | ] 137 | } 138 | ] 139 | } 140 | ] 141 | } -------------------------------------------------------------------------------- /resources/textures/cat_headset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/cat_headset.png -------------------------------------------------------------------------------- /resources/textures/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/coin.png -------------------------------------------------------------------------------- /resources/textures/creeper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/creeper.png -------------------------------------------------------------------------------- /resources/textures/devil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/devil.png -------------------------------------------------------------------------------- /resources/textures/devil_tail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/devil_tail.png -------------------------------------------------------------------------------- /resources/textures/emoji_angry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_angry.png -------------------------------------------------------------------------------- /resources/textures/emoji_cool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_cool.png -------------------------------------------------------------------------------- /resources/textures/emoji_moyai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_moyai.png -------------------------------------------------------------------------------- /resources/textures/emoji_nerd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_nerd.png -------------------------------------------------------------------------------- /resources/textures/emoji_sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_sad.png -------------------------------------------------------------------------------- /resources/textures/emoji_skull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_skull.png -------------------------------------------------------------------------------- /resources/textures/emoji_smirk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_smirk.png -------------------------------------------------------------------------------- /resources/textures/emoji_weary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/emoji_weary.png -------------------------------------------------------------------------------- /resources/textures/firegod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/firegod.png -------------------------------------------------------------------------------- /resources/textures/flag_uk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/flag_uk.png -------------------------------------------------------------------------------- /resources/textures/flag_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/flag_us.png -------------------------------------------------------------------------------- /resources/textures/infernal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/infernal.png -------------------------------------------------------------------------------- /resources/textures/phoenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/phoenix.png -------------------------------------------------------------------------------- /resources/textures/pride.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/pride.png -------------------------------------------------------------------------------- /resources/textures/zombie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vqnic/Cosmetics/1daa32e7077999e9393f28949faabd09393c31a5/resources/textures/zombie.png -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/CosmeticsCommand.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->setPermission("cosmetics.command"); 19 | parent::__construct($name, $description, $usage); 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function execute(CommandSender $sender, string $commandLabel, array $args) { 26 | if($sender instanceof Player) { //Technically, a non-player could run this command. 27 | 28 | $capes = $this->getOwnedCosmetics($sender, CosmeticType::CAPE); 29 | $heads = $this->getOwnedCosmetics($sender, CosmeticType::HEAD); 30 | $upperBodies = $this->getOwnedCosmetics($sender, CosmeticType::UPPER_BODY); 31 | $lowerBodies = $this->getOwnedCosmetics($sender, CosmeticType::LOWER_BODY); 32 | $feet = $this->getOwnedCosmetics($sender, CosmeticType::FEET); 33 | 34 | $form = new CustomForm(function (Player $player, ?array $data) use ($capes, $heads, $upperBodies, $lowerBodies, $feet) { 35 | if($data === null) return true; 36 | 37 | $costumeManager = $this->plugin->getCostumeManager(); 38 | 39 | $capeChoice = $capes["cosmetic_id"][$data[0]]; //"Owned Capes" dropdown results 40 | if($capeChoice !== null) $costumeManager->getCostume($player)->setCosmetic(CosmeticType::CAPE, ConfigManager::getCosmeticByID($capeChoice)); 41 | else $costumeManager->getCostume($player)->setCosmetic(CosmeticType::CAPE, null); 42 | 43 | $headChoice = $heads["cosmetic_id"][$data[1]]; //"Owned Head Cosmetics" dropdown results 44 | if($headChoice !== null) $costumeManager->getCostume($player)->setCosmetic(CosmeticType::HEAD, ConfigManager::getCosmeticByID($headChoice)); 45 | else $costumeManager->getCostume($player)->setCosmetic(CosmeticType::HEAD, null); 46 | 47 | $upperBodyChoice = $upperBodies["cosmetic_id"][$data[2]]; //"Owned Upper Body Cosmetics" dropdown results 48 | if($upperBodyChoice !== null) $costumeManager->getCostume($player)->setCosmetic(CosmeticType::UPPER_BODY, ConfigManager::getCosmeticByID($upperBodyChoice)); 49 | else $costumeManager->getCostume($player)->setCosmetic(CosmeticType::UPPER_BODY, null); 50 | 51 | $lowerBodyChoice = $lowerBodies["cosmetic_id"][$data[3]]; //"Owned Lower Body Cosmetics" dropdown results 52 | if($lowerBodyChoice !== null) $costumeManager->getCostume($player)->setCosmetic(CosmeticType::LOWER_BODY, ConfigManager::getCosmeticByID($lowerBodyChoice)); 53 | else $costumeManager->getCostume($player)->setCosmetic(CosmeticType::LOWER_BODY, null); 54 | 55 | $feetChoice = $feet["cosmetic_id"][$data[4]]; //"Owned Feet Cosmetics" dropdown results 56 | if($feetChoice !== null) $costumeManager->getCostume($player)->setCosmetic(CosmeticType::FEET, ConfigManager::getCosmeticByID($feetChoice)); 57 | else $costumeManager->getCostume($player)->setCosmetic(CosmeticType::FEET, null); 58 | 59 | return true; 60 | }); 61 | $form->setTitle("Equip Cosmetics Here"); 62 | 63 | $form->addDropdown("Owned Capes", $capes["display_name"]); 64 | $form->addDropdown("Owned Head Cosmetics", $heads["display_name"]); 65 | $form->addDropdown("Owned Upper Body Cosmetics", $upperBodies["display_name"]); 66 | $form->addDropdown("Owned Lower Body Cosmetics", $lowerBodies["display_name"]); 67 | $form->addDropdown("Owned Feet Cosmetics", $feet["display_name"]); 68 | 69 | $form->sendToPlayer($sender); 70 | } 71 | } 72 | 73 | private function getOwnedCosmetics(Player $sender, CosmeticType $type) : array { 74 | $ownedCosmetics = array( 75 | "cosmetic_id" => array(null), //always a "no thanks" option for people to remove cosmetics" 76 | "display_name" => array("None") //always a "no thanks" option for people to remove cosmetics" 77 | ); 78 | foreach(ConfigManager::getAllCosmeticsOfType($type) as $cosmetic) { 79 | if($sender->hasPermission($cosmetic["required_permission"])){ 80 | $ownedCosmetics["cosmetic_id"][] = $cosmetic["cosmetic_id"]; 81 | $ownedCosmetics["display_name"][] = $cosmetic["display_name"]; //Add it to the array. 82 | } 83 | } 84 | return $ownedCosmetics; 85 | } 86 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Costume/Cosmetic/Cosmetic.php: -------------------------------------------------------------------------------- 1 | cosmeticID = $key; 17 | $this->type = $type; 18 | $this->texturePath = $texturePath; 19 | } 20 | public function getID(): string { 21 | return $this->cosmeticID; 22 | } 23 | public function getType() : CosmeticType { 24 | return $this->type; 25 | } 26 | public function getTexture() : GdImage{ 27 | return imagecreatefrompng($this->texturePath); 28 | } 29 | public function specifyGeometryModel(string $modelPath): void{ 30 | $this->modelPath = $modelPath; 31 | } 32 | 33 | public function getModelPath() : string { 34 | return $this->modelPath; 35 | } 36 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Costume/Cosmetic/CosmeticType.php: -------------------------------------------------------------------------------- 1 | wearer = $wearer; 19 | $this->cosmetics[CosmeticType::CAPE->value] = $cape; 20 | $this->cosmetics[CosmeticType::HEAD->value] = $head; 21 | $this->cosmetics[CosmeticType::UPPER_BODY->value] = $upperBody; 22 | $this->cosmetics[CosmeticType::LOWER_BODY->value] = $lowerBody; 23 | $this->cosmetics[CosmeticType::FEET->value] = $feet; 24 | $this->wearer->setSkin(SkinUtils::getMergedSkin($this)); //Update skin to show the change. 25 | $this->wearer->sendSkin(); 26 | } 27 | 28 | /** 29 | * @throws \JsonException 30 | */ 31 | public function setCosmetic(CosmeticType $slot, ?Cosmetic $cosmetic): void { 32 | $this->cosmetics[$slot->value] = $cosmetic; //If cosmetic is null, the cosmetic will be entirely removed 33 | $this->wearer->setSkin(SkinUtils::getMergedSkin($this)); //Update skin to show the change. 34 | $this->wearer->sendSkin(); 35 | } 36 | 37 | public function getCosmetic(CosmeticType $type) : ?Cosmetic { 38 | return $this->cosmetics[$type->value]; 39 | } 40 | 41 | public function getWearer() : Player { return $this->wearer; } 42 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Costume/CostumeManager.php: -------------------------------------------------------------------------------- 1 | playerCostumes = array(); 18 | } 19 | 20 | public function loadCostume(PlayerJoinEvent $event): void { 21 | $player = $event->getPlayer(); 22 | DatabaseManager::addPlayer($player); //Also harmless if the player already exists 23 | //Set the player's cosmetic to what was last saved in their data. If there's nothing, that's alright! They just will have blank slots. 24 | $this->playerCostumes[$player->getXuid()] = new Costume($player, 25 | DatabaseManager::getEquippedCosmetic($player, CosmeticType::CAPE), 26 | DatabaseManager::getEquippedCosmetic($player, CosmeticType::HEAD), 27 | DatabaseManager::getEquippedCosmetic($player, CosmeticType::UPPER_BODY), 28 | DatabaseManager::getEquippedCosmetic($player, CosmeticType::LOWER_BODY), 29 | DatabaseManager::getEquippedCosmetic($player, CosmeticType::FEET) 30 | ); 31 | } 32 | 33 | /* 34 | * Until the moment they actually disconnect, their Costume manages all their equipped cosmetic info for them. 35 | * This saves their equipped cosmetics to their playerdata.db file once they finally disconnect so they can be loaded back 36 | * when they next connect to the server. 37 | */ 38 | public function saveCostumeToFile(PlayerQuitEvent $event) : void { 39 | $player = $event->getPlayer(); 40 | $costume = $this->playerCostumes[$player->getXuid()]; 41 | foreach (CosmeticType::cases() as $cosmeticSlot) { //Save each cosmetic of each possible type all to the db 42 | DatabaseManager::savePlayerCosmetic($player, $costume->getCosmetic($cosmeticSlot), $cosmeticSlot); 43 | } 44 | } 45 | 46 | public function getCostume(Player $player) : Costume { 47 | return $this->playerCostumes[$player->getXuid()]; 48 | } 49 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Main.php: -------------------------------------------------------------------------------- 1 | saveResourcesToDataFolder(); 17 | SkinUtils::init($this); 18 | ConfigManager::init($this); 19 | DatabaseManager::init($this); 20 | $this->costumeManager = new CostumeManager(); 21 | $this->getServer()->getPluginManager()->registerEvents($this->costumeManager, $this); 22 | $this->getServer()->getCommandMap()->register($this->getName(), new CosmeticsCommand($this, "cosmetics", "Equip capes, hats, wings and more on your skin!", "/cosmetics")); 23 | } 24 | 25 | public function getCostumeManager() : CostumeManager { 26 | return $this->costumeManager; 27 | } 28 | 29 | private function saveResourcesToDataFolder() : void { 30 | //This is where server owners add or remove cosmetics. 31 | $this->saveResource("cosmetics.yml"); 32 | $folderNames = ["/models/", "/required/", "/textures/"]; //Important folder names to populate with default files if needed. 33 | foreach($folderNames as $folderName) { 34 | $requiredPath = $this->getDataFolder() . $folderName; 35 | if(!file_exists($requiredPath)) { 36 | @mkdir($requiredPath, 0777, true); 37 | foreach(scandir($this->getResourceFolder() . $folderName) as $file) { 38 | $this->saveResource($folderName . $file); 39 | } 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Utils/ConfigManager.php: -------------------------------------------------------------------------------- 1 | getDataFolder(); 18 | self::$cosmeticsConfig = new Config(self::$dataFolder . "cosmetics.yml", Config::YAML); 19 | } 20 | 21 | 22 | public static function getCosmeticByID(string $key) : ?Cosmetic{ 23 | if(!self::validateCosmeticByID($key)) return null; //If something is wrong with the cosmetic, pretend it doesn't exist anymore. 24 | $cosmeticInfo = self::$cosmeticsConfig->get($key); 25 | $cosmeticType = CosmeticType::tryFrom($cosmeticInfo["type"]); 26 | $cosmetic = new Cosmetic($key, $cosmeticType, self::$plugin->getDataFolder() . "/textures/" . $cosmeticInfo["texture_filename"]); 27 | if($cosmeticType === CosmeticType::CAPE) return $cosmetic; //Capes don't need any model info since it's built-in, so goa ahead. 28 | $cosmetic->specifyGeometryModel(self::$plugin->getDataFolder() . "/models/" . $cosmeticInfo["model_filename"]); //Literally anything else does. 29 | return $cosmetic; 30 | } 31 | 32 | /* 33 | * Basically makes sure the specified cosmetic is configured correctly... 34 | * Makes an (elegant) scene on the console so the server owner's can fix it. 35 | * 36 | * Supposed to be called a lot to spam people's console to fix their stuff. 37 | */ 38 | private static function validateCosmeticByID(string $key) : bool { 39 | $cosmeticInfo = self::$cosmeticsConfig->get($key); 40 | $logger = self::$plugin->getLogger(); 41 | if(is_array($cosmeticInfo)) { //Make sure the provided key still exists and wasn't just configured out. 42 | if (array_key_exists("enabled", $cosmeticInfo) && $cosmeticInfo["enabled"]) { //Make sure that the cosmetic is enabled, otherwise pretend it doesn't exist. 43 | $cosmeticType = $cosmeticInfo["type"]; 44 | if (array_key_exists("type", $cosmeticInfo) && (CosmeticType::tryFrom($cosmeticInfo["type"]) instanceof CosmeticType)) { //If the type is a valid cosmetic type. valid types are CAPE, HEAD, UPPER_BODY, LOWER_BODY and FEET, 45 | if (array_key_exists("required_permission", $cosmeticInfo)) { 46 | if (array_key_exists("display_name", $cosmeticInfo)) { 47 | if (array_key_exists("texture_filename", $cosmeticInfo) && file_exists(self::$dataFolder . '/textures/' . $cosmeticInfo["texture_filename"])) { 48 | if ($cosmeticType == CosmeticType::CAPE->value) return true; //Capes have less requirements, so if they made it this far they're okay. 49 | elseif(array_key_exists("model_filename", $cosmeticInfo) && file_exists(self::$dataFolder . '/models/' . $cosmeticInfo["model_filename"])) { 50 | return true; //Cosmetic has all the components it needs to work. 51 | } else $logger->warning("The cosmetic under ID " . $key . " requires a valid model_filename but none was provided! Please provide the name of the .json model in /models/."); 52 | } else $logger->warning("The cosmetic under ID " . $key . " requires a valid texture_filename. Please provide the name of the .png texture in /textures/."); 53 | } else $logger->warning("The cosmetic under ID " . $key . " is missing a display_name."); 54 | } else $logger->warning("The cosmetic under ID " . $key . " is missing a required_permission."); 55 | } else $logger->warning("The cosmetic under ID " . $key . " has an invalid type. Valid types are CAPE, HEAD, UPPER_BODY, LOWER_BODY and FEET."); 56 | } //Deliberately disabled, so no warning needed. 57 | } 58 | return false; 59 | } 60 | 61 | public static function getAllCosmeticsOfType(CosmeticType $type) : array { 62 | $cosmetics = array(); 63 | foreach(self::$cosmeticsConfig->getAll(true) as $cosmeticKey) { 64 | if(!self::validateCosmeticByID($cosmeticKey)) continue; //If this cosmetic is disabled or broken, skip it. 65 | $cosmeticInfo = self::$cosmeticsConfig->get($cosmeticKey); 66 | if(array_key_exists("type", $cosmeticInfo) && $cosmeticInfo["type"] === $type->value) 67 | $cosmetics[] = array( 68 | "cosmetic_id" => $cosmeticKey, 69 | "display_name" => $cosmeticInfo["display_name"], 70 | "required_permission" => $cosmeticInfo["required_permission"] 71 | ); 72 | } 73 | return $cosmetics; 74 | } 75 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Utils/DatabaseManager.php: -------------------------------------------------------------------------------- 1 | getDataFolder() . "playerdata.db"); 15 | //The names of rows in the database are identical to the names of the CosmeticTypes 16 | self::$db->exec('CREATE TABLE IF NOT EXISTS "playerdata" (' . 17 | '"XUID" TEXT PRIMARY KEY,' . 18 | CosmeticType::CAPE->value . ' TEXT ,' . 19 | CosmeticType::HEAD->value . ' TEXT ,' . 20 | CosmeticType::UPPER_BODY->value . ' TEXT ,' . 21 | CosmeticType::LOWER_BODY->value . ' TEXT ,' . 22 | CosmeticType::FEET->value . ' TEXT )'); 23 | } 24 | public static function addPlayer(Player $player) : void { 25 | $playerID = $player->getXuid(); 26 | $sql = 'INSERT OR IGNORE INTO "playerdata" ("XUID") VALUES(' . $playerID . ')'; 27 | self::$db->exec($sql); 28 | } 29 | 30 | public static function getEquippedCosmetic(Player $player, CosmeticType $type) : ?Cosmetic { 31 | $playerID = $player->getXuid(); 32 | $sql = "SELECT DISTINCT " . $type->value . " FROM playerdata WHERE XUID = " . $playerID; 33 | $cosmeticID = self::$db->querySingle($sql); //Could be null 34 | return (is_null($cosmeticID) ? null : ConfigManager::getCosmeticByID($cosmeticID)); //Recreates the cosmetic with info stored in the config, and if it doesn't even exist (or the player doesn't), return null anyway. 35 | } 36 | 37 | public static function savePlayerCosmetic(Player $player, ?Cosmetic $cosmetic, CosmeticType $type) : void { 38 | $sql = "UPDATE playerdata SET " . $type->value . " = '" . (is_null($cosmetic) ? null : $cosmetic->getID()) . "' WHERE XUID = " . $player->getXuid(); 39 | self::$db->exec($sql); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Vanic/Cosmetics/Utils/SkinUtils.php: -------------------------------------------------------------------------------- 1 | getWearer()->getSkin(); 26 | $capeData = ""; //Will be overwritten if the player has a cape cosmetic equipped. 27 | 28 | //Consider the default body type of the player. If they explicitly logged on with a slim skin, keep it that way. Otherwise, set them to the default player model. 29 | $bodyType = "geometry.humanoid.custom"; 30 | if(str_contains($originalSkin->getGeometryName(), "Slim")) $bodyType = "geometry.humanoid.customSlim"; 31 | //This plugin can only work for players wearing 64x64 skins. If a player has too large of a skin, their skin is replaced with one that works. 32 | 33 | $layeredSkin = null; 34 | if(strlen($originalSkin->getSkinData()) != 16384) { //If the player logs on with an unsuable highres custom skin. 35 | if($bodyType === "geometry.humanoid.customSlim") $layeredSkin = imagecreatefrompng(self::$plugin->getDataFolder() . "/required/" . "default_player_skinSlim.png"); 36 | else $layeredSkin = imagecreatefrompng(self::$plugin->getDataFolder() . "/required/" . "default_player_skin.png"); 37 | }else $layeredSkin = self::skinToImage($originalSkin->getSkinData()); //The player's original skin. 38 | 39 | $geometryToMerge[] = json_decode(file_get_contents(self::$plugin->getDataFolder() . "/required/" . "$bodyType.json"), true); //Start off with the default player geometry. 40 | 41 | foreach(CosmeticType::cases() as $type) { 42 | if (!is_null($costume->getCosmetic($type))) { //If that type of cosmetic is equipped at all 43 | if($type === CosmeticType::CAPE) $capeData = self::getDataFromImage($costume->getCosmetic($type)->getTexture()); 44 | else { 45 | $layeredSkin = self::layerPNGs($costume->getCosmetic($type)->getTexture(), $layeredSkin); //Merge the previous image with the new image to make one for the next round 46 | $geometryToMerge[] = json_decode(file_get_contents($costume->getCosmetic($type)->getModelPath()), true); //Keep adding more and more layers. 47 | } 48 | } 49 | } 50 | return new Skin("Custom", self::getDataFromImage($layeredSkin), $capeData, $bodyType, self::mergeJSONToData($geometryToMerge)); 51 | } 52 | 53 | private static function layerPNGs(GdImage $layer1, GdImage $layer2) : GdImage { 54 | imagepalettetotruecolor($layer2); 55 | imagepalettetotruecolor($layer1); 56 | imagesavealpha($layer1, true); 57 | imagealphablending($layer2, true); 58 | imagesavealpha($layer2, true); 59 | imagecopy($layer2, $layer1, 0, 0, 0, 0, 64, 64); 60 | return $layer2; 61 | } 62 | 63 | private static function mergeJSONToData(array $geometryToMerge) : string{ 64 | $baseGeometry = $geometryToMerge[0]; //The base player model with no frills 65 | $combinedBones = array(); 66 | $bonesToSkip = array(); //The key is the bone name, and the value is the parent bone. Both must be identical to something in here to be skipped. 67 | foreach($geometryToMerge as $geometry){ //Get all the json arrays from the different files... 68 | foreach($geometry["minecraft:geometry"][0]["bones"] as $bone){ 69 | $parent = array_key_exists("parent", $bone) ? $bone["parent"] : null; //Special consideration for bones with no parent (root bone) 70 | if(array_key_exists($bone["name"], $bonesToSkip) && $bonesToSkip[$bone["name"]] === $parent) continue; //Skip it if it's a duplicate 71 | $combinedBones[] = $bone; 72 | $bonesToSkip[$bone["name"]] = $parent; //Add it to the list of things already looked over 73 | } 74 | } 75 | $baseGeometry["minecraft:geometry"][0]["bones"] = $combinedBones; //Add all the bones from the other files we just collected into this one 76 | return json_encode($baseGeometry); 77 | } 78 | 79 | //Not my code after this line. 80 | private static function skinToImage(string $skinData){ 81 | // https://github.com/moskadev/EverybodyThonk/blob/master/src/supermaxalex/EverybodyThonk/SkinManager.php 82 | $img = imagecreatetruecolor(64, 64); 83 | imagealphablending($img, false); 84 | imagesavealpha($img, true); 85 | $stream = new BinaryStream($skinData); 86 | 87 | for($y = 0; $y < 64; ++$y){ 88 | for($x = 0; $x < 64; ++$x){ 89 | $r = $stream->getByte(); 90 | $g = $stream->getByte(); 91 | $b = $stream->getByte(); 92 | $a = 127 - (int) floor($stream->getByte() / 2); 93 | 94 | $colour = imagecolorallocatealpha($img, $r, $g, $b, $a); 95 | imagesetpixel($img, $x, $y, $colour); 96 | } 97 | } 98 | return $img; 99 | } 100 | private static function getDataFromImage($image) : string{ 101 | $skinbytes = ""; 102 | for ($y = 0; $y < imagesy($image); $y++) { 103 | for ($x = 0; $x < imagesx($image); $x++) { 104 | $colorat = @imagecolorat($image, $x, $y); 105 | $a = ((~((int)($colorat >> 24))) << 1) & 0xff; 106 | $r = ($colorat >> 16) & 0xff; 107 | $g = ($colorat >> 8) & 0xff; 108 | $b = $colorat & 0xff; 109 | $skinbytes .= chr($r) . chr($g) . chr($b) . chr($a); 110 | } 111 | } 112 | imagedestroy($image); 113 | 114 | return $skinbytes; 115 | } 116 | } -------------------------------------------------------------------------------- /src/jojoe77777/FormAPI/CustomForm.php: -------------------------------------------------------------------------------- 1 | data["type"] = "custom_form"; 20 | $this->data["title"] = ""; 21 | $this->data["content"] = []; 22 | } 23 | 24 | public function processData(&$data) : void { 25 | if($data !== null && !is_array($data)) { 26 | throw new FormValidationException("Expected an array response, got " . gettype($data)); 27 | } 28 | if(is_array($data)) { 29 | if(count($data) !== count($this->validationMethods)) { 30 | throw new FormValidationException("Expected an array response with the size " . count($this->validationMethods) . ", got " . count($data)); 31 | } 32 | $new = []; 33 | foreach($data as $i => $v){ 34 | $validationMethod = $this->validationMethods[$i] ?? null; 35 | if($validationMethod === null) { 36 | throw new FormValidationException("Invalid element " . $i); 37 | } 38 | if(!$validationMethod($v)) { 39 | throw new FormValidationException("Invalid type given for element " . $this->labelMap[$i]); 40 | } 41 | $new[$this->labelMap[$i]] = $v; 42 | } 43 | $data = $new; 44 | } 45 | } 46 | 47 | /** 48 | * @param string $title 49 | */ 50 | public function setTitle(string $title) : void { 51 | $this->data["title"] = $title; 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getTitle() : string { 58 | return $this->data["title"]; 59 | } 60 | 61 | /** 62 | * @param string $text 63 | * @param string|null $label 64 | */ 65 | public function addLabel(string $text, ?string $label = null) : void { 66 | $this->addContent(["type" => "label", "text" => $text]); 67 | $this->labelMap[] = $label ?? count($this->labelMap); 68 | $this->validationMethods[] = static fn($v) => $v === null; 69 | } 70 | 71 | /** 72 | * @param string $text 73 | * @param bool|null $default 74 | * @param string|null $label 75 | */ 76 | public function addToggle(string $text, bool $default = null, ?string $label = null) : void { 77 | $content = ["type" => "toggle", "text" => $text]; 78 | if($default !== null) { 79 | $content["default"] = $default; 80 | } 81 | $this->addContent($content); 82 | $this->labelMap[] = $label ?? count($this->labelMap); 83 | $this->validationMethods[] = static fn($v) => is_bool($v); 84 | } 85 | 86 | /** 87 | * @param string $text 88 | * @param int $min 89 | * @param int $max 90 | * @param int $step 91 | * @param int $default 92 | * @param string|null $label 93 | */ 94 | public function addSlider(string $text, int $min, int $max, int $step = -1, int $default = -1, ?string $label = null) : void { 95 | $content = ["type" => "slider", "text" => $text, "min" => $min, "max" => $max]; 96 | if($step !== -1) { 97 | $content["step"] = $step; 98 | } 99 | if($default !== -1) { 100 | $content["default"] = $default; 101 | } 102 | $this->addContent($content); 103 | $this->labelMap[] = $label ?? count($this->labelMap); 104 | $this->validationMethods[] = static fn($v) => (is_float($v) || is_int($v)) && $v >= $min && $v <= $max; 105 | } 106 | 107 | /** 108 | * @param string $text 109 | * @param array $steps 110 | * @param int $defaultIndex 111 | * @param string|null $label 112 | */ 113 | public function addStepSlider(string $text, array $steps, int $defaultIndex = -1, ?string $label = null) : void { 114 | $content = ["type" => "step_slider", "text" => $text, "steps" => $steps]; 115 | if($defaultIndex !== -1) { 116 | $content["default"] = $defaultIndex; 117 | } 118 | $this->addContent($content); 119 | $this->labelMap[] = $label ?? count($this->labelMap); 120 | $this->validationMethods[] = static fn($v) => is_int($v) && isset($steps[$v]); 121 | } 122 | 123 | /** 124 | * @param string $text 125 | * @param array $options 126 | * @param int $default 127 | * @param string|null $label 128 | */ 129 | public function addDropdown(string $text, array $options, int $default = null, ?string $label = null) : void { 130 | $this->addContent(["type" => "dropdown", "text" => $text, "options" => $options, "default" => $default]); 131 | $this->labelMap[] = $label ?? count($this->labelMap); 132 | $this->validationMethods[] = static fn($v) => is_int($v) && isset($options[$v]); 133 | } 134 | 135 | /** 136 | * @param string $text 137 | * @param string $placeholder 138 | * @param string $default 139 | * @param string|null $label 140 | */ 141 | public function addInput(string $text, string $placeholder = "", string $default = null, ?string $label = null) : void { 142 | $this->addContent(["type" => "input", "text" => $text, "placeholder" => $placeholder, "default" => $default]); 143 | $this->labelMap[] = $label ?? count($this->labelMap); 144 | $this->validationMethods[] = static fn($v) => is_string($v); 145 | } 146 | 147 | /** 148 | * @param array $content 149 | */ 150 | private function addContent(array $content) : void { 151 | $this->data["content"][] = $content; 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/jojoe77777/FormAPI/Form.php: -------------------------------------------------------------------------------- 1 | callable = $callable; 21 | } 22 | 23 | public function sendToPlayer(Player $player) : void { 24 | $player->sendForm($this); 25 | } 26 | 27 | public function getCallable() : ?callable { 28 | return $this->callable; 29 | } 30 | 31 | public function setCallable(?callable $callable) { 32 | $this->callable = $callable; 33 | } 34 | 35 | public function handleResponse(Player $player, $data) : void { 36 | $this->processData($data); 37 | $callable = $this->getCallable(); 38 | if($callable !== null) { 39 | $callable($player, $data); 40 | } 41 | } 42 | 43 | public function processData(&$data) : void { 44 | } 45 | 46 | public function jsonSerialize() : mixed{ 47 | return $this->data; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/jojoe77777/FormAPI/FormAPI.php: -------------------------------------------------------------------------------- 1 | data["type"] = "modal"; 20 | $this->data["title"] = ""; 21 | $this->data["content"] = $this->content; 22 | $this->data["button1"] = ""; 23 | $this->data["button2"] = ""; 24 | } 25 | 26 | public function processData(&$data) : void { 27 | if(!is_bool($data)) { 28 | throw new FormValidationException("Expected a boolean response, got " . gettype($data)); 29 | } 30 | } 31 | 32 | /** 33 | * @param string $title 34 | */ 35 | public function setTitle(string $title) : void { 36 | $this->data["title"] = $title; 37 | } 38 | 39 | /** 40 | * @return string 41 | */ 42 | public function getTitle() : string { 43 | return $this->data["title"]; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function getContent() : string { 50 | return $this->data["content"]; 51 | } 52 | 53 | /** 54 | * @param string $content 55 | */ 56 | public function setContent(string $content) : void { 57 | $this->data["content"] = $content; 58 | } 59 | 60 | /** 61 | * @param string $text 62 | */ 63 | public function setButton1(string $text) : void { 64 | $this->data["button1"] = $text; 65 | } 66 | 67 | /** 68 | * @return string 69 | */ 70 | public function getButton1() : string { 71 | return $this->data["button1"]; 72 | } 73 | 74 | /** 75 | * @param string $text 76 | */ 77 | public function setButton2(string $text) : void { 78 | $this->data["button2"] = $text; 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function getButton2() : string { 85 | return $this->data["button2"]; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/jojoe77777/FormAPI/SimpleForm.php: -------------------------------------------------------------------------------- 1 | data["type"] = "form"; 25 | $this->data["title"] = ""; 26 | $this->data["content"] = $this->content; 27 | $this->data["buttons"] = []; 28 | } 29 | 30 | public function processData(&$data) : void { 31 | if($data !== null){ 32 | if(!is_int($data)) { 33 | throw new FormValidationException("Expected an integer response, got " . gettype($data)); 34 | } 35 | $count = count($this->data["buttons"]); 36 | if($data >= $count || $data < 0) { 37 | throw new FormValidationException("Button $data does not exist"); 38 | } 39 | $data = $this->labelMap[$data] ?? null; 40 | } 41 | } 42 | 43 | /** 44 | * @param string $title 45 | */ 46 | public function setTitle(string $title) : void { 47 | $this->data["title"] = $title; 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function getTitle() : string { 54 | return $this->data["title"]; 55 | } 56 | 57 | /** 58 | * @return string 59 | */ 60 | public function getContent() : string { 61 | return $this->data["content"]; 62 | } 63 | 64 | /** 65 | * @param string $content 66 | */ 67 | public function setContent(string $content) : void { 68 | $this->data["content"] = $content; 69 | } 70 | 71 | /** 72 | * @param string $text 73 | * @param int $imageType 74 | * @param string $imagePath 75 | * @param string $label 76 | */ 77 | public function addButton(string $text, int $imageType = -1, string $imagePath = "", ?string $label = null) : void { 78 | $content = ["text" => $text]; 79 | if($imageType !== -1) { 80 | $content["image"]["type"] = $imageType === 0 ? "path" : "url"; 81 | $content["image"]["data"] = $imagePath; 82 | } 83 | $this->data["buttons"][] = $content; 84 | $this->labelMap[] = $label ?? count($this->labelMap); 85 | } 86 | 87 | } 88 | --------------------------------------------------------------------------------