├── .gitignore
├── .poggit.yml
├── LICENSE.md
├── README.md
├── plugin.yml
├── resources
├── .version_file
├── BlockPetsLogo.png
├── config.yml
├── database_stmts
│ ├── mysql.sql
│ └── sqlite.sql
├── languages
│ ├── chs.yml
│ ├── cht.yml
│ ├── de.yml
│ ├── en.yml
│ ├── gr.yml
│ ├── ko.yml
│ ├── nl.yml
│ ├── ru.yml
│ └── vi.yml
├── patches
│ ├── mysql.sql
│ └── sqlite.sql
└── pet_properties.yml
└── src
└── BlockHorizons
└── BlockPets
├── Loader.php
├── commands
├── AddPetPointsCommand.php
├── BaseCommand.php
├── ChangePetNameCommand.php
├── ClearPetCommand.php
├── HealPetCommand.php
├── LevelUpPetCommand.php
├── ListPetsCommand.php
├── PetCommand.php
├── PetsTopCommand.php
├── RemovePetCommand.php
├── SpawnPetCommand.php
└── TogglePetCommand.php
├── configurable
├── BlockPetsConfig.php
├── LanguageConfig.php
├── PetMessages.php
└── PetProperties.php
├── events
├── BlockPetsEvent.php
├── PetEvent.php
├── PetInventoryInitializationEvent.php
├── PetLevelUpEvent.php
├── PetRemoveEvent.php
├── PetRespawnEvent.php
└── PetSpawnEvent.php
├── items
└── Saddle.php
├── listeners
├── EventListener.php
└── RidingListener.php
├── pets
├── BasePet.php
├── BouncingPet.php
├── Calculator.php
├── HoveringPet.php
├── IrasciblePet.php
├── LevelCalculator.php
├── PetData.php
├── PetIds.php
├── SmallCreature.php
├── SwimmingPet.php
├── WalkingPet.php
├── creatures
│ ├── AllayPet.php
│ ├── ArrowPet.php
│ ├── AxolotlPet.php
│ ├── BatPet.php
│ ├── BeePet.php
│ ├── BlazePet.php
│ ├── CaveSpiderPet.php
│ ├── ChickenPet.php
│ ├── CowPet.php
│ ├── CreeperPet.php
│ ├── DonkeyPet.php
│ ├── ElderGuardianPet.php
│ ├── EnderCrystalPet.php
│ ├── EnderDragonPet.php
│ ├── EndermanPet.php
│ ├── EndermitePet.php
│ ├── EvokerPet.php
│ ├── FoxPet.php
│ ├── GhastPet.php
│ ├── GoatPet.php
│ ├── GuardianPet.php
│ ├── HorsePet.php
│ ├── HuskPet.php
│ ├── IronGolemPet.php
│ ├── LlamaPet.php
│ ├── MagmaCubePet.php
│ ├── MooshroomPet.php
│ ├── MulePet.php
│ ├── OcelotPet.php
│ ├── PigPet.php
│ ├── PolarBearPet.php
│ ├── RabbitPet.php
│ ├── SheepPet.php
│ ├── SilverFishPet.php
│ ├── SkeletonHorsePet.php
│ ├── SkeletonPet.php
│ ├── SlimePet.php
│ ├── SnowGolemPet.php
│ ├── SpiderPet.php
│ ├── SquidPet.php
│ ├── StrayPet.php
│ ├── StriderPet.php
│ ├── VexPet.php
│ ├── VillagerPet.php
│ ├── VindicatorPet.php
│ ├── WardenPet.php
│ ├── WitchPet.php
│ ├── WitherPet.php
│ ├── WitherSkeletonPet.php
│ ├── WitherSkullPet.php
│ ├── WolfPet.php
│ ├── ZombieHorsePet.php
│ ├── ZombiePet.php
│ ├── ZombiePigmanPet.php
│ └── ZombieVillagerPet.php
├── datastorage
│ ├── BaseDataStorer.php
│ ├── MySQLDataStorer.php
│ ├── SQLDataStorer.php
│ └── SQLiteDataStorer.php
└── inventory
│ └── PetInventoryManager.php
└── tasks
├── BaseTask.php
└── PetRespawnTask.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | .idea/
3 |
--------------------------------------------------------------------------------
/.poggit.yml:
--------------------------------------------------------------------------------
1 | --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/BlockHorizons/BlockPets
2 | branches:
3 | - master
4 | projects:
5 | BlockPets:
6 | path: ""
7 | icon: resources/BlockPetsLogo.png
8 | compressBuilds: false
9 | fullGzip: 9
10 | libs:
11 | - src: poggit/libasynql/libasynql
12 | version: ^4.0.1
13 | - src: muqsit/invmenu/invmenu
14 | version: ^4.4.0
15 | ...
16 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
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 2017 BlockHorizons
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 | # BlockPets
2 | [](https://discord.gg/YynM57V)
3 | [](https://poggit.pmmp.io/p/BlockPets)
4 |
5 | An advanced pets plugin for PocketMine-MP, a server software for Minecraft PE servers in PHP. Implements highly customizable pets with interesting features.
6 | > Third party versions, forks or spoons of PocketMine-MP are **not** supported.
7 | >
8 | > Issues caused by other server softwares than PocketMine-MP will be closed immediately.
9 |
10 | ### Installation
11 | Stable releases of BlockPets will be drafted at the Release tab with a pre-built phar file, and can be found on the Poggit website once released. Alternatively, you can grab a development build from the Poggit button below.
12 | To install:
13 | - Download one of the pre-built phar files from either releases or the Poggit button below.
14 | - Drop the phar file in the plugins folder of your server.
15 | - Restart the server, and enjoy.
16 | [](https://poggit.pmmp.io/ci/BlockHorizons/BlockPets/BlockPets)
17 |
18 | ### Feedback
19 | We'd like to keep our issue tracker as clean as possible, so please take the following in consideration when opening a new issue in the issue tracker:
20 | - If you have an issue with the plugin, check if the issue exists in the Issue tracker, and report it if not.
21 | - If you'd like support or have a question about the plugin, please click the Gitter button under the title.
22 | - If you have a great idea for a new feature or enhancement, please create a new issue in the Issue tracker.
23 | - If you just want to have a talk, please click the Gitter button below the title.
24 |
25 | ### Wiki
26 | Please refer to [BlockPets' wiki](https://github.com/BlockHorizons/BlockPets/wiki) for help with features, translations, commands and permissions.
27 |
--------------------------------------------------------------------------------
/plugin.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: BlockPets
3 | main: BlockHorizons\BlockPets\Loader
4 | version: 2.0.2
5 | api: 4.0.0
6 | author: BlockHorizons
7 | # mcpe-protocol: 448
8 | description: A pets plugin for PocketMine-MP
9 |
10 | permissions:
11 | blockpets:
12 | default: false
13 | description: "Allows access to all BlockPets features."
14 | blockpets.bypass-limit:
15 | default: op
16 | description: "Allows bypassing the pet limit set in the config.yml."
17 | blockpets.bypass-size-limit:
18 | default: op
19 | description: "Allows bypassing the maximum size of pets."
20 | blockpets.command:
21 | default: false
22 | description: "Allows access to all BlockPets command features."
23 | blockpets.command.spawnpet:
24 | default: false
25 | description: "Allows access to use the spawnpet command."
26 | blockpets.command.spawnpet.use:
27 | default: op
28 | description: "Allows access to use the spawnpet command for yourself."
29 | blockpets.command.spawnpet.others:
30 | default: op
31 | description: "Allows access to use the spawnpet command for other players."
32 | blockpets.command.changepetname:
33 | default: false
34 | description: "Allows access to use the changepetname command."
35 | blockpets.command.changepetname.use:
36 | default: op
37 | description: "Allows access to use the changepetname command for yourself."
38 | blockpets.command.changepetname.others:
39 | default: op
40 | description: "Allows access to use the changepetname command for others."
41 | blockpets.command.removepet:
42 | default: op
43 | description: "Allows access to use the removepet command."
44 | blockpets.command.leveluppet:
45 | default: op
46 | description: "Allows access to use the leveluppet command."
47 | blockpets.command.addpetpoints:
48 | default: op
49 | description: "Allows access to use the addpetpoints command."
50 | blockpets.command.healpet:
51 | default: op
52 | description: "Allows access to use the healpet command."
53 | blockpets.command.clearpet:
54 | default: true
55 | description: "Allows access to use the clearpet command."
56 | blockpets.command.togglepet:
57 | default: true
58 | description: "Allows access to use the togglepets command."
59 | blockpets.command.pet:
60 | default: op
61 | description: "Allows access to use the pets command."
62 | blockpets.command.listpets:
63 | default: op
64 | description: "Allows access to use the listpets command."
65 | blockpets.command.petstop:
66 | default: op
67 | description: "Allows access to use the petstop command."
68 | blockpets.pet:
69 | default: false
70 | description: "Allows access to all BlockPets pets."
71 | blockpets.pet.arrow:
72 | default: op
73 | description: "Allows access to use the arrow pet."
74 | blockpets.pet.bat:
75 | default: op
76 | description: "Allows access to use the bat pet."
77 | blockpets.pet.blaze:
78 | default: op
79 | description: "Allows access to use the blaze pet."
80 | blockpets.pet.cavespider:
81 | default: op
82 | description: "Allows access to use the cave spider pet."
83 | blockpets.pet.chicken:
84 | default: op
85 | description: "Allows access to use the chicken pet."
86 | blockpets.pet.cow:
87 | default: op
88 | description: "Allows access to use the cow pet."
89 | blockpets.pet.creeper:
90 | default: op
91 | description: "Allows access to use the creeper pet."
92 | blockpets.pet.donkey:
93 | default: op
94 | description: "Allows access to use the donkey pet."
95 | blockpets.pet.elderguardian:
96 | default: op
97 | description: "Allows access to use the elder guardian pet."
98 | blockpets.pet.endercrystal:
99 | default: op
100 | description: "Allows access to use the ender crystal pet."
101 | blockpets.pet.enderdragon:
102 | default: op
103 | description: "Allows access to use the ender dragon pet."
104 | blockpets.pet.enderman:
105 | default: op
106 | description: "Allows access to use the enderman pet."
107 | blockpets.pet.endermite:
108 | default: op
109 | description: "Allows access to use the endermite pet."
110 | blockpets.pet.evocationfangs:
111 | default: op
112 | description: "Allows access to use the evocation fangs pet."
113 | blockpets.pet.evoker:
114 | default: op
115 | description: "Allows access to use the evoker pet."
116 | blockpets.pet.ghast:
117 | default: op
118 | description: "Allows access to use the ghast pet."
119 | blockpets.pet.guardian:
120 | default: op
121 | description: "Allows access to use the guardian pet."
122 | blockpets.pet.horse:
123 | default: op
124 | description: "Allows access to use the horse pet."
125 | blockpets.pet.husk:
126 | default: op
127 | description: "Allows access to use the husk pet."
128 | blockpets.pet.irongolem:
129 | default: op
130 | description: "Allows access to use the iron golem pet."
131 | blockpets.pet.llama:
132 | default: op
133 | description: "Allows access to use the llama pet."
134 | blockpets.pet.magmacube:
135 | default: op
136 | description: "Allows access to use the magma cube pet."
137 | blockpets.pet.mooshroom:
138 | default: op
139 | description: "Allows access to use the mooshroom pet."
140 | blockpets.pet.mule:
141 | default: op
142 | description: "Allows access to use the mule pet."
143 | blockpets.pet.ocelot:
144 | default: op
145 | description: "Allows access to use the ocelot pet."
146 | blockpets.pet.pig:
147 | default: op
148 | description: "Allows access to use the pig pet."
149 | blockpets.pet.polarbear:
150 | default: op
151 | description: "Allows access to use the polar bear pet."
152 | blockpets.pet.rabbit:
153 | default: op
154 | description: "Allows access to use the rabbit pet."
155 | blockpets.pet.sheep:
156 | default: op
157 | description: "Allows access to use the sheep pet."
158 | blockpets.pet.silverfish:
159 | default: op
160 | description: "Allows access to use the silverfish pet."
161 | blockpets.pet.skeleton:
162 | default: op
163 | description: "Allows access to use the skeleton pet."
164 | blockpets.pet.skeletonhorse:
165 | default: op
166 | description: "Allows access to use the skeleton horse pet."
167 | blockpets.pet.slime:
168 | default: op
169 | description: "Allows access to use the slime pet."
170 | blockpets.pet.snowgolem:
171 | default: op
172 | description: "Allows access to use the snow golem pet."
173 | blockpets.pet.spider:
174 | default: op
175 | description: "Allows access to use the spider pet."
176 | blockpets.pet.squid:
177 | default: op
178 | description: "Allows access to use the squid pet."
179 | blockpets.pet.stray:
180 | default: op
181 | description: "Allows access to use the stray pet."
182 | blockpets.pet.strider:
183 | default: op
184 | description: "Allows access to use the strider pet."
185 | blockpets.pet.vex:
186 | default: op
187 | description: "Allows access to use the vex pet."
188 | blockpets.pet.villager:
189 | default: op
190 | description: "Allows access to use the village pet."
191 | blockpets.pet.vindicator:
192 | default: op
193 | description: "Allows access to use the vindicator pet."
194 | blockpets.pet.witch:
195 | default: op
196 | description: "Allows access to use the witch pet."
197 | blockpets.pet.wither:
198 | default: op
199 | description: "Allows access to use the wither pet."
200 | blockpets.pet.witherskeleton:
201 | default: op
202 | description: "Allows access to use the wither skeleton pet."
203 | blockpets.pet.witherskull:
204 | default: op
205 | description: "Allows access to use the wither skull pet."
206 | blockpets.pet.wolf:
207 | default: op
208 | description: "Allows access to use the wolf pet."
209 | blockpets.pet.zombie:
210 | default: op
211 | description: "Allows access to use the zombie pet."
212 | blockpets.pet.zombiehorse:
213 | default: op
214 | description: "Allows access to use the zombie horse pet."
215 | blockpets.pet.zombiepigman:
216 | default: op
217 | description: "Allows access to use the zombie pigman pet."
218 | blockpets.pet.zombievillager:
219 | default: op
220 | description: "Allows access to use the zombie villager pet."
221 | ...
222 |
--------------------------------------------------------------------------------
/resources/.version_file:
--------------------------------------------------------------------------------
1 | # DO NOT MODIFY THE CONTENTS OF THIS FILE...
2 | # unless you want to break this plugin's versioning system, then you may do so.
3 | version: 1.1.2
--------------------------------------------------------------------------------
/resources/BlockPetsLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlockHorizons/BlockPets/8b1adb7c6c650ece6c7b896f3b3111772088e9d1/resources/BlockPetsLogo.png
--------------------------------------------------------------------------------
/resources/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Configuration file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | # The language to be used in messages in this plugin.
5 | # Available options:
6 | # - en (English)
7 | # - nl (Dutch)
8 | # - vi (Vietnamese)
9 | # - gr (Greek)
10 | # - ko (Korean)
11 | # - cht (繁體中文)
12 | # - chs (简体中文)
13 | Language: en
14 |
15 | # Whether to make pets invulnerable to any damage, or allow damaging them.
16 | Invulnerable-Pets: false
17 |
18 | # Whether to directly follow the player, or search random positions near the player.
19 | Stalk-Owner-Blindly: false
20 |
21 | # Whether to make the pet invulnerable to damage if the owner of it is or not.
22 | Invulnerable-If-Owner-Is: true
23 |
24 | # The time in seconds to wait before spawning a pet that died earlier.
25 | Pet-Respawn-Time: 10
26 |
27 | # Whether to make pets attack the person that attacked them or their owner.
28 | Attacking-Pets: true
29 |
30 | # The limit of pets per player by default.
31 | Pet-Limit: 3
32 |
33 | # The base health a pet will be spawned with. This is equal to the health of a pet with level 0.
34 | Pet-Base-Health: 20
35 |
36 | # The health that gets added each level the pet gets.
37 | Pet-Per-Level-Health: 0.5
38 |
39 | # The size that gets added each level the pet gets.
40 | Pet-Per-Level-Size: 0.02
41 |
42 | # The base damage a pet will be spawned with. This is equal to the damage of a pet with level 0.
43 | Pet-Base-Damage: 4
44 |
45 | # The damage that gets added each level the pet gets.
46 | Pet-Per-Level-Damage: 0.1
47 |
48 | # The experience a pet gets each time it kills a player.
49 | Experience-Points-Per-Player-Kill: 15
50 |
51 | # The experience a pet gets each time it kills an entity.
52 | Experience-Points-Per-Entity-Kill: 10
53 |
54 | # Whether to give the pet some experience if it's being fed by the owner or not.
55 | Give-Experience-For-Feeding: true
56 |
57 | # The database used to store data of pets in. This is only relevant if storage to database is turned to true.
58 | # Options:
59 | # - MySQL
60 | # - SQLite
61 | Database: SQLite
62 |
63 | # MySQL information. This is only relevant if database above is set to MySQL.
64 | MySQL-Info:
65 | Host: 127.0.0.1
66 | User: Admin
67 | Password: Admin
68 | Database: BlockPets
69 | Port: 3306
70 |
71 | # Whether to store pet data to the database set above or not.
72 | Store-To-Database: true
73 |
74 | # WARNING: This will delete all pets and pet data the next restart if set to true.
75 | # Use with caution!
76 | Hard-Reset: false
77 | ...
78 |
--------------------------------------------------------------------------------
/resources/database_stmts/mysql.sql:
--------------------------------------------------------------------------------
1 | -- #!mysql
2 | -- #{ blockpets
3 |
4 | -- # { init
5 | CREATE TABLE IF NOT EXISTS Pets(
6 | Player VARCHAR(16) NOT NULL,
7 | PetName VARCHAR(48) NOT NULL,
8 | EntityName VARCHAR(32) NOT NULL,
9 | PetSize FLOAT NOT NULL DEFAULT 1.0,
10 | IsBaby BOOL NOT NULL DEFAULT false,
11 | Chested BOOL NOT NULL DEFAULT false,
12 | Visible BOOL NOT NULL DEFAULT true,
13 | PetLevel INT UNSIGNED NOT NULL DEFAULT 1,
14 | LevelPoints INT UNSIGNED NOT NULL DEFAULT 0,
15 | Inventory BLOB,
16 | PRIMARY KEY(Player, PetName)
17 | );
18 | -- # }
19 |
20 | -- # { loadplayer
21 | -- # :player string
22 | SELECT
23 | PetName,
24 | EntityName,
25 | PetSize,
26 | IsBaby,
27 | Chested,
28 | PetLevel,
29 | LevelPoints,
30 | Visible,
31 | Inventory
32 | FROM Pets WHERE Player=:player;
33 | -- # }
34 |
35 | -- # { listpets
36 | -- # :player string
37 | -- # :entityname string
38 | SELECT
39 | PetName,
40 | EntityName,
41 | Visible
42 | FROM Pets WHERE Player=:player AND EntityName LIKE :entityname;
43 | -- # }
44 |
45 | -- # { reset
46 | DELETE FROM Pets;
47 | -- # }
48 |
49 | -- # { pet
50 |
51 | -- # { register
52 | -- # :player string
53 | -- # :petname string
54 | -- # :entityname string
55 | -- # :petsize float
56 | -- # :isbaby int
57 | -- # :chested int
58 | -- # :petlevel int
59 | -- # :levelpoints int
60 | INSERT INTO Pets(
61 | Player,
62 | PetName,
63 | EntityName,
64 | PetSize,
65 | IsBaby,
66 | Chested,
67 | PetLevel,
68 | LevelPoints
69 | ) VALUES (
70 | :player,
71 | :petname,
72 | :entityname,
73 | :petsize,
74 | :isbaby,
75 | :chested,
76 | :petlevel,
77 | :levelpoints
78 | ) ON DUPLICATE KEY UPDATE
79 | PetName=VALUES(PetName),
80 | EntityName=VALUES(EntityName),
81 | PetSize=VALUES(PetSize),
82 | IsBaby=VALUES(IsBaby),
83 | Chested=VALUES(Chested),
84 | PetLevel=VALUES(PetLevel),
85 | LevelPoints=VALUES(LevelPoints);
86 | -- # }
87 |
88 | -- # { unregister
89 | -- # :player string
90 | -- # :petname string
91 | DELETE FROM Pets
92 | WHERE Player=:player AND petname=:petname;
93 | -- # }
94 |
95 | -- # { leaderboard
96 | -- # :offset int
97 | -- # :length int
98 | -- # :entityname string
99 | SELECT
100 | Player,
101 | PetName,
102 | EntityName,
103 | PetLevel,
104 | LevelPoints
105 | FROM Pets WHERE EntityName LIKE :entityname ORDER BY LevelPoints, PetLevel DESC LIMIT :offset, :length;
106 | -- # }
107 |
108 | -- # { visibility
109 | -- # { toggle
110 | -- # :player string
111 | -- # :petname string
112 | UPDATE Pets SET Visible=NOT Visible
113 | WHERE Player=:player AND PetName LIKE :petname;
114 | -- # }
115 | -- # { select
116 | -- # :player string
117 | -- # :petname string
118 | SELECT PetName, Visible FROM Pets
119 | WHERE Player=:player AND PetName LIKE :petname;
120 | -- # }
121 | -- # }
122 |
123 | -- # { update
124 | -- # { chested
125 | -- # :chested int
126 | -- # :player string
127 | -- # :petname string
128 | UPDATE Pets SET
129 | Chested=:chested
130 | WHERE Player=:player AND PetName=:petname;
131 | -- # }
132 | -- # { exp
133 | -- # :petlevel int
134 | -- # :levelpoints int
135 | -- # :player string
136 | -- # :petname string
137 | UPDATE Pets SET
138 | PetLevel=:petlevel,
139 | LevelPoints=:levelpoints
140 | WHERE Player=:player AND PetName=:petname;
141 | -- # }
142 | -- # { inv
143 | -- # :inventory string
144 | -- # :player string
145 | -- # :petname string
146 | UPDATE Pets SET
147 | Inventory=:inventory
148 | WHERE Player=:player AND PetName=:petname;
149 | -- # }
150 | -- # }
151 | -- # }
152 |
153 | -- #}
154 |
--------------------------------------------------------------------------------
/resources/database_stmts/sqlite.sql:
--------------------------------------------------------------------------------
1 | -- #!mysql
2 | -- #{ blockpets
3 |
4 | -- # { init
5 | CREATE TABLE IF NOT EXISTS Pets(
6 | Player VARCHAR(16) NOT NULL,
7 | PetName VARCHAR(48) NOT NULL,
8 | EntityName VARCHAR(32) NOT NULL,
9 | PetSize FLOAT NOT NULL DEFAULT 1.0,
10 | IsBaby BOOL NOT NULL DEFAULT false,
11 | Chested BOOL NOT NULL DEFAULT false,
12 | Visible BOOL NOT NULL DEFAULT true,
13 | PetLevel INT UNSIGNED NOT NULL DEFAULT 1,
14 | LevelPoints INT UNSIGNED NOT NULL DEFAULT 0,
15 | Inventory BLOB,
16 | PRIMARY KEY(Player, PetName)
17 | );
18 | -- # }
19 |
20 | -- # { loadplayer
21 | -- # :player string
22 | SELECT
23 | PetName,
24 | EntityName,
25 | PetSize,
26 | IsBaby,
27 | Chested,
28 | PetLevel,
29 | LevelPoints,
30 | Visible,
31 | Inventory
32 | FROM Pets WHERE Player=:player;
33 | -- # }
34 |
35 | -- # { listpets
36 | -- # :player string
37 | -- # :entityname string
38 | SELECT
39 | PetName,
40 | EntityName,
41 | Visible
42 | FROM Pets WHERE Player=:player AND EntityName LIKE :entityname;
43 | -- # }
44 |
45 | -- # { reset
46 | DELETE FROM Pets;
47 | -- # }
48 |
49 | -- # { pet
50 |
51 | -- # { register
52 | -- # :player string
53 | -- # :petname string
54 | -- # :entityname string
55 | -- # :petsize float
56 | -- # :isbaby int
57 | -- # :chested int
58 | -- # :petlevel int
59 | -- # :levelpoints int
60 | INSERT OR REPLACE INTO Pets(
61 | Player,
62 | PetName,
63 | EntityName,
64 | PetSize,
65 | IsBaby,
66 | Chested,
67 | PetLevel,
68 | LevelPoints
69 | ) VALUES (
70 | :player,
71 | :petname,
72 | :entityname,
73 | :petsize,
74 | :isbaby,
75 | :chested,
76 | :petlevel,
77 | :levelpoints
78 | );
79 | -- # }
80 |
81 | -- # { unregister
82 | -- # :player string
83 | -- # :petname string
84 | DELETE FROM Pets
85 | WHERE Player=:player AND petname=:petname;
86 | -- # }
87 |
88 | -- # { leaderboard
89 | -- # :offset int
90 | -- # :length int
91 | -- # :entityname string
92 | SELECT
93 | Player,
94 | PetName,
95 | EntityName,
96 | PetLevel,
97 | LevelPoints
98 | FROM Pets WHERE EntityName LIKE :entityname ORDER BY LevelPoints, PetLevel DESC LIMIT :offset, :length;
99 | -- # }
100 |
101 | -- # { visibility
102 | -- # { toggle
103 | -- # :player string
104 | -- # :petname string
105 | UPDATE Pets SET Visible=NOT Visible
106 | WHERE Player=:player AND PetName LIKE :petname;
107 | -- # }
108 | -- # { select
109 | -- # :player string
110 | -- # :petname string
111 | SELECT PetName, Visible FROM Pets
112 | WHERE Player=:player AND PetName LIKE :petname;
113 | -- # }
114 | -- # }
115 |
116 | -- # { update
117 | -- # { chested
118 | -- # :chested int
119 | -- # :player string
120 | -- # :petname string
121 | UPDATE Pets SET
122 | Chested=:chested
123 | WHERE Player=:player AND PetName=:petname;
124 | -- # }
125 | -- # { exp
126 | -- # :petlevel int
127 | -- # :levelpoints int
128 | -- # :player string
129 | -- # :petname string
130 | UPDATE Pets SET
131 | PetLevel=:petlevel,
132 | LevelPoints=:levelpoints
133 | WHERE Player=:player AND PetName=:petname;
134 | -- # }
135 | -- # { inv
136 | -- # :inventory string
137 | -- # :player string
138 | -- # :petname string
139 | UPDATE Pets SET
140 | Inventory=:inventory
141 | WHERE Player=:player AND PetName=:petname;
142 | -- # }
143 | -- # }
144 | -- # }
145 |
146 | -- #}
147 |
--------------------------------------------------------------------------------
/resources/languages/chs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Simplified Chinese messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6警告&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "当您从控制台只用该命令时,务必填写所有参数"
10 | no-console-use: "该命令仅可由玩家使用"
11 | no-permission: "您并无权限使用该命令"
12 | plugin-cancelled: "插件操作已取消"
13 |
14 | pet:
15 | doesnt-exist: "该名称宠物不存在"
16 | numeric: "宠物的大小必须是一个数值"
17 |
18 | player:
19 | not-found: "无法找到该玩家"
20 | no-pet: "您不能拥有叫这个名称的宠物"
21 | no-pet-other: "该玩家不能拥有叫这个名称的宠物"
22 | already-own-pet: "您已拥有叫这个名称的宠物了"
23 |
24 | changepetname:
25 | no-permission: "您并无权限更改其他玩家的宠物名称"
26 | success: "成功从 %s &r&a 更改名称为 %s!"
27 |
28 | clearpet:
29 | success: "成功清除了宠物 &b%s&a!"
30 |
31 | healpet:
32 | success: "%s &r&a 已成功被治疗!"
33 |
34 | leveluppet:
35 | spawnpet:
36 | success: "宠物已升等: &b%s &r&a %s!"
37 |
38 | no-permission: "您并无权限生成宠物"
39 | no-permission-others: "您并无权限为其他人生成宠物"
40 | success: "成功生成一隻名为 &b%s&a 的宠物!"
41 | success-other: "您收到了一隻名为 &b%s&a 的宠物!"
42 | name: "请于聊天窗中为您宠物取一个名字!"
43 | selecting-name: "%s 正在为他们的宠物取一个名字!"
44 | exceeded-limit: "%s 超出宠物的限制"
45 |
46 | removepet:
47 | success: "成功移除宠物 &b%s&a!"
48 |
49 | togglepet:
50 | no-pet-specified: "您并无指定要切换的宠物"
51 | success: "成功切换了您的宠物 %s!"
52 | success-others: "成功切换宠物 &b%s &r&a %s!"
53 | ...
54 |
--------------------------------------------------------------------------------
/resources/languages/cht.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Traditional Chinese messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6警告&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "當您從控制台只用該指令時,務必填寫所有參數"
10 | no-console-use: "該指令僅可由玩家使用"
11 | no-permission: "您並無權限使用該指令"
12 | plugin-cancelled: "插件操作已取消"
13 |
14 | pet:
15 | doesnt-exist: "該名稱寵物不存在"
16 | numeric: "寵物的大小必須是一個數值"
17 |
18 | player:
19 | not-found: "無法找到該玩家"
20 | no-pet: "您不能擁有叫這個名稱的寵物"
21 | no-pet-other: "該玩家不能擁有叫這個名稱的寵物"
22 | already-own-pet: "您已擁有叫這個名稱的寵物了"
23 |
24 | changepetname:
25 | no-permission: "您並無權限更改其他玩家的寵物名稱"
26 | success: "成功從 %s &r&a 更改名稱為 %s!"
27 |
28 | clearpet:
29 | success: "成功清除了寵物 &b%s&a!"
30 |
31 | healpet:
32 | success: "%s &r&a 已成功被治療!"
33 |
34 | leveluppet:
35 | spawnpet:
36 | success: "寵物已升等: &b%s &r&a %s!"
37 |
38 | no-permission: "您並無權限生成寵物"
39 | no-permission-others: "您並無權限為其他人生成寵物"
40 | success: "成功生成一隻名為 &b%s&a 的寵物!"
41 | success-other: "您收到了一隻名為 &b%s&a 的寵物!"
42 | name: "請於聊天窗中為您寵物取一個名字!"
43 | selecting-name: "%s 正在為他們的寵物取一個名字!"
44 | exceeded-limit: "%s 超出寵物的限制"
45 |
46 | removepet:
47 | success: "成功刪除寵物 &b%s&a!"
48 |
49 | togglepet:
50 | no-pet-specified: "您並無指定要切換的寵物"
51 | success: "成功切換了您的寵物 %s!"
52 | success-others: "成功切換寵物 &b%s &r&a %s!"
53 | ...
54 |
--------------------------------------------------------------------------------
/resources/languages/de.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # German messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Warnung&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "Wenn Sie diesen Befehl von der Konsole aus verwenden, müssen alle Argumente angegeben werden."
10 | no-console-use: "Dieses Kommando können nur Spieler benutzen."
11 | no-permission: "Du hast keine Berechtigung dieses Kommando zu benutzen."
12 | plugin-cancelled: "Ein Plugin hat diese Aktion unterbrochen."
13 |
14 | pet:
15 | doesnt-exist: "Ein Haustier mit diesem Namen gibt es nicht."
16 | numeric: "Die Haustiergröße sollte in Zahlen angegeben werden."
17 |
18 | player:
19 | not-found: "Dieser Spieler konnte nicht gefunden werden."
20 | no-pet: "Du besitzt kein Haustier mit diesem Namen."
21 | no-pet-other: "Dieser Spieler besitzt kein Haustier mit diesem Namen."
22 | already-own-pet: "Du besitzt bereits ein Haustier mit diesem Namen."
23 |
24 | changepetname:
25 | no-permission: "Du hast nicht die Berechtigung um die Namen der Haustiere von anderen zu ändern."
26 | success: "Der Name des Haustieres wurde von %s &r&azu %s geändert!"
27 |
28 | clearpet:
29 | success: "Du hast das Haustier &b%s&a erfolgreich entfernt!"
30 |
31 | healpet:
32 | success: "Das Haustier mit dem Namen %s &r&a wurde geheilt!"
33 |
34 | leveluppet:
35 | success: "Haustierlevel erfolgreich erhöht: &b%s &r&a %s!"
36 |
37 | spawnpet:
38 | no-permission: "Du hast keine Berechtigung dieses Haustier zu erstellen."
39 | no-permission-others: "Du hast keine Berechtigung um anderen Haustiere zu erstellen."
40 | success: "Du hast ein Haustier mit dem Namen &b%s&a erstellt!"
41 | success-other: "Du hast ein Haustier mit dem Namen &b%s&a bekommen!"
42 | name: "Bitte gebe einen Namen für dein Haustier in den Chat ein!"
43 | selecting-name: "%s wählt nun einen Namen für sein/ihr Haustier!"
44 | exceeded-limit: "%s hat das Haustierlimit erreicht."
45 |
46 | removepet:
47 | success: "Das Tier &b%s&a wurde erfolgreich gelöscht!"
48 |
49 | togglepet:
50 | no-pet-specified: "Du hast kein Tier angegeben."
51 | success: "Dein Haustier wurde erfolgreich auf %s umgestellt!"
52 | success-others: "Das Haustier &b%s &r&awurde erfolgreich auf %s gestellt!"
53 | ...
54 |
--------------------------------------------------------------------------------
/resources/languages/en.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # English messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Warning&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "When using that command from the console, all arguments must be provided."
10 | no-console-use: "That command can only be used by players."
11 | no-permission: "You don't have permission to use that command."
12 | plugin-cancelled: "A plugin has cancelled that action."
13 |
14 | pet:
15 | doesnt-exist: "A pet with the given name doesn't exist."
16 | numeric: "The pet scale should be numeric."
17 | none-on-server: "There are no pets on this server."
18 | none-on-server-type: "There are no %s pets on this server."
19 |
20 | player:
21 | not-found: "The given player cannot be found."
22 | no-pet: "You do not own a pet with the given name."
23 | no-pet-other: "The given player does not own a pet with that name."
24 | already-own-pet: "You already own a pet with that name."
25 |
26 | addpetpoints:
27 | success: "Successfully added &b%sxp&a to the pet &b%s&r&a!"
28 |
29 | changepetname:
30 | no-permission: "You don't have permission to change the name of pets from other players."
31 | success: "Successfully changed the name of %s &r&ato %s!"
32 |
33 | clearpet:
34 | success: "Successfully cleared the pet &b%s&a!"
35 |
36 | healpet:
37 | success: "The pet %s &r&a has been healed successfully!"
38 |
39 | leveluppet:
40 | success: "Successfully leveled up the pet: &b%s &r&a %s!"
41 |
42 | listpets:
43 | no-pets-found: "&cYou do not have any pets."
44 | no-pets-found-type: "&cYou do not have any %ss."
45 |
46 | spawnpet:
47 | no-permission: "You don't have permission to spawn that pet."
48 | no-permission-others: "You don't have permission to spawn pets to others."
49 | success: "Successfully spawned a pet with the name &b%s&a!"
50 | success-other: "You have received a pet with the name &b%s&a!"
51 | name: "Please type a name for your pet in chat!"
52 | selecting-name: "%s is now selecting a name for their pet!"
53 | exceeded-limit: "%s exceeded the pet limit."
54 |
55 | removepet:
56 | success: "Successfully removed the pet &b%s&a!"
57 |
58 | togglepet:
59 | no-pet-specified: "You did not specify a pet to toggle."
60 | success: "Successfully toggled your pets %s!"
61 | success-others: "Successfully toggle the pet &b%s &r&a %s!"
62 | success-specific: "Successfully toggled your pet %s %s."
63 | success-specific-others: "Successfully toggled %s's pet %s."
64 | success-diff: "Successfully toggled your pets, visible pets: &b%s."
65 | success-diff-others: "Successfully toggled %s's pets, visible pets: &b%s."
66 | ...
67 |
--------------------------------------------------------------------------------
/resources/languages/gr.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Greek messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Προσοχή&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "Όταν χρησιμοποιείτε αυτήν την εντολή από την κονσόλα, πρέπει να παρέχονται όλα τα δικαιώματα."
10 | no-console-use: "Αυτή η εντολή μπορεί να χρησιμοποιηθεί μόνο από παίκτες."
11 | no-permission: "Δεν έχετε την άδεια να χρησιμοποιήσετε αυτήν την εντολή."
12 | plugin-cancelled: "Ένα άλλο πρόσθετο/plugin ακύρωσε αυτή την ενέργεια."
13 |
14 | pet:
15 | doesnt-exist: "Ένα κατοικίδιο με το συγκεκριμένο όνομα δεν υπάρχει."
16 | numeric: "Η κλίμακα των κατοικίδιων πρέπει να είναι αριθμητική."
17 |
18 | player:
19 | not-found: "Αυτός ο παίκτης δεν βρέθηκε."
20 | no-pet: "Δεν έχετε ένα κατοικίδιο με αυτό το όνομα."
21 | no-pet-other: "Αυτός ο παίκτης δεν έχει ένα κατοικίδιο με αυτό το όνομα."
22 | already-own-pet: "Έχετε ήδη ένα κατοικίδιο με αυτό το όνομα."
23 |
24 | changepetname:
25 | no-permission: "Δεν έχετε άδεια να αλλάξετε το όνομα των κατοικίδιων από άλλους παίκτες."
26 | success: "Αλάξατε με επιτυχία το όνομα του %s &r&aσε %s!"
27 |
28 | clearpet:
29 | success: "Επιτυχής εκκαθάριση του κατοικίδιου &b%s&a!"
30 |
31 | healpet:
32 | success: "Το κατοικίδιο %s &r&a έχει θεραπευτεί με επιτυχία!"
33 |
34 | leveluppet:
35 | success: "Με επιτυχία ανέβηκε επίπεδο το κατοικίδιο: &b%s &r&a %s!"
36 |
37 | spawnpet:
38 | no-permission: "Δεν έχετε την άδεια να δημιουργήσετε αυτό το κατοικίδιο."
39 | no-permission-others: "Δεν έχετε την άδεια να δημιουργήσετε κατοικίδια σε άλλους."
40 | success: "Δημιουργήσατε επιτυχώς ένα κατοικίδιο με το όνομα &b%s&a!"
41 | success-other: "Έχετε λάβει ένα κατοικίδιο με το όνομα &b%s&a!"
42 | name: "Πληκτρολογήστε ένα όνομα για το κατοικίδιο σας στο chat!"
43 | selecting-name: "Ο/Η %s τώρα επιλέγει ένα όνομα για το κατοικίδιο του!"
44 | exceeded-limit: "Ο/Η %s υπερέβη το όριο κατοικίδιων."
45 |
46 | removepet:
47 | success: "Διαγράψατε με επιτυχία το κατοικίδιο &b%s&a!"
48 |
49 | togglepet:
50 | no-pet-specified: "Δεν έχετε ορίσει ένα κατοικίδιο για να αλλάξετε."
51 | success: "Αλλάξατε με επιτυχία τα κατοικίδια σας %s!"
52 | success-others: "Επιτυχώς αλλάξατε το κατοικίδιο &b%s &r&a %s!"
53 | ...
54 |
--------------------------------------------------------------------------------
/resources/languages/ko.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Korean messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6경고&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "콘솔에서 해당 명령어를 사용할 때는 모든 인수가 제공되어야 합니다."
10 | no-console-use: "해당 명령어는 플레이어만 사용할 수 있습니다."
11 | no-permission: "해당 명령어를 사용할 수 있는 권한이 없습니다."
12 | plugin-cancelled: "플러그인이 해당 작업을 취소했습니다."
13 |
14 | pet:
15 | doesnt-exist: "주어진 이름의 애완동물은 없습니다."
16 | numeric: "애완동물 규모는 숫자여야 합니다."
17 | none-on-server: "이 서버에는 애완동물이 없습니다."
18 | none-on-server-type: "이 서버에는 %s 애완동물이 없습니다."
19 |
20 | player:
21 | not-found: "주어진 플레이어를 찾을 수 없습니다."
22 | no-pet: "주어진 이름의 애완동물을 가지고 있지 않습니다."
23 | no-pet-other: "주어진 플레이어는 해당 이름의 애완동물을 가지고 있지 않습니다."
24 | already-own-pet: "이미 해당 이름의 애완동물을 가지고 있습니다."
25 |
26 | addpetpoints:
27 | success: "성공적으로 애완동물 &b%2$s&r&a에게 &b%1$s 경험치&a를 추가했습니다!"
28 |
29 | changepetname:
30 | no-permission: "다른 플레이어의 애완동물의 이름을 변경할 수 있는 권한이 없습니다."
31 | success: "%s의 이름&r&a을 %s(으)로 성공적으로 변경했습니다!"
32 |
33 | clearpet:
34 | success: "애완동물 &b%s&a을(를) 성공적으로 제거했습니다!"
35 |
36 | healpet:
37 | success: "애완동물 %s&r&a이(가) 성공적으로 치유되었습니다!"
38 |
39 | leveluppet:
40 | success: "애완동물을 성공적으로 레벨업했습니다: &b%s &r&a %s!"
41 |
42 | listpets:
43 | no-pets-found: "&c애완동물을 가지고 있지 않습니다."
44 | no-pets-found-type: "&c%s을(를) 가지고 있지 않습니다."
45 |
46 | spawnpet:
47 | no-permission: "해당 애완동물을 생성할 권한이 없습니다."
48 | no-permission-others: "다른 플레이어에게 애완동물을 생성할 권한이 없습니다."
49 | success: "이름 &b%s&a의 애완동물을 성공적으로 생성했습니다!"
50 | success-other: "이름 &b%s&a의 애완동물을 받았습니다!"
51 | name: "애완동물의 이름을 대화에 입력해주세요!"
52 | selecting-name: "%s이(가) 애완동물의 이름을 선택하고 있습니다!"
53 | exceeded-limit: "%s이(가) 애완동물 제한을 넘었습니다."
54 |
55 | removepet:
56 | success: "애완동물 &b%s&a을(를) 성공적으로 제거했습니다!"
57 |
58 | togglepet:
59 | no-pet-specified: "전환할 애완동물을 선택하지 않았습니다."
60 | success: "애완동물을 %s(으)로 성공적으로 전환했습니다!"
61 | success-others: "애완동물 &b%s&r&a을(를) %s(으)로 성공적으로 전환했습니다!"
62 | success-specific: "애완동물 %s을(를) %s(으)로 성공적으로 전환했습니다."
63 | success-specific-others: "%s의 애완동물을 %s(으)로 성공적으로 전환했습니다."
64 | success-diff: "애완동물을 성공적으로 전환했습니다, 보이는 애완동물: &b%s."
65 | success-diff-others: "%s의 애완동물을 성공적으로 전환했습니다, 보이는 애완동물: &b%s."
66 | ...
67 |
--------------------------------------------------------------------------------
/resources/languages/nl.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Dutch messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Waarschuwing&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "Wanneer u die opdracht vanuit de console gebruikt, moeten alle argumenten worden opgegeven."
10 | no-console-use: "Dat commando kan alleen gebruikt worden door spelers."
11 | no-permission: "Je hebt geen permissie om dat commando uit te voeren."
12 | plugin-cancelled: "Een andere plugin heeft die actie onderbroken."
13 |
14 | pet:
15 | doesnt-exist: "Een huisdier type met die naam bestaat niet."
16 | numeric: "De huisdier grootte moet numeriek zijn."
17 |
18 | player:
19 | not-found: "De gegeven speler kon niet gevonden worden."
20 | no-pet: "Je beschikt niet over een huisdier met die naam."
21 | no-pet-other: "De gegeven speler beschikt niet over een huisdier met die naam."
22 | already-own-pet: "Je hebt al een huisdier met die naam."
23 |
24 | changepetname:
25 | no-permission: "Je hebt geen permissie om de naam van huisdieren van andere spelers te veranderen."
26 | success: "Naam van %s &r&asuccesvol veranderd naar %s!"
27 |
28 | clearpet:
29 | success: "Huisdier &b%s&a verwijderen succesvol!"
30 |
31 | healpet:
32 | success: "Het huisdier %s &r&a genezen was succesvol!"
33 |
34 | leveluppet:
35 | success: "Huisdier niveau verhogen succesvol: &b%s &r&a %s!"
36 |
37 | spawnpet:
38 | no-permission: "Je hebt geen permissie om dat huisdier te gebruiken."
39 | no-permission-others: "Je hebt geen permissie om ander spelers huisdieren te geven."
40 | success: "Verschijnen van het huisdier &b%s &awas succesvol!"
41 | success-other: "Je hebt een huisdier gekregen met de naam: &b%s&a!"
42 | name: "Type alsjeblieft een naam voor je huisdier!"
43 | selecting-name: "%s is nu een naam voor zijn huisdier aan het kiezen!"
44 | exceeded-limit: "%s heeft de huisdier limiet overschreden."
45 |
46 | removepet:
47 | success: "Verwijderen van het huisdier &b%s &awas succesvol."
48 |
49 | togglepet:
50 | no-pet-specified: "Je hebt geen huisdier gekozen om aan/uit te zetten."
51 | success: "Je hebt je huisdieren %s gezet!"
52 | success-others: "Je hebt het huisdier &b%s &r&a %s gezet!"
53 | ...
--------------------------------------------------------------------------------
/resources/languages/ru.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Russian messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Предупреждение&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "Командой могут пользоваться только игроки."
10 | no-permission: "Недостаточно прав для использования этой команды."
11 | plugin-cancelled: "Плагин отменил это действие."
12 |
13 | pet:
14 | doesnt-exist: "Питомец с данным именем не существует."
15 | numeric: "Размер питомца должен быть числом."
16 |
17 | player:
18 | not-found: "Данный игрок не найден."
19 | no-pet: "У вас нет питомца с данным именем."
20 | no-pet-other: "У этого игрока нет питомца с данным именем."
21 | already-own-pet: "У вас уже есть питомец с таким именем."
22 |
23 | changepetname:
24 | no-permission: "У вас недостаточно прав для смены имени питомца других игроков."
25 | success: "Успешно изменили имя питомца с %s &r&aна %s!"
26 |
27 | clearpet:
28 | success: "Питомец &b%s&a был успешно очищен!"
29 |
30 | healpet:
31 | success: "Питомец %s &r&a был успешно вылечен!"
32 |
33 | leveluppet:
34 | success: "Успешно повысили уровень питомца: &b%s &r&a %s!"
35 |
36 | spawnpet:
37 | no-permission: "У вас недостаточно прав для спавна этого питомца."
38 | no-permission-others: "У вас недостаточно прав для спавна питомцев другим игрокам."
39 | success: "Питомец &b%s&a был успешно заспавнен!"
40 | success-other: "Вам вручили питомца &b%s&a!"
41 | name: "Напишите новое имя для питомца в чат!"
42 | selecting-name: "%s в данный момент выбирает имя для своего питомца!"
43 | exceeded-limit: "%s достиг лимита питомцев."
44 |
45 | removepet:
46 | success: "Питомец &b%s&a был успешно удалён!"
47 |
48 | togglepet:
49 | no-pet-specified: "Вы не указали питомца для переключения."
50 | success: "Успешно переключили всех питомцев в режим %s!"
51 | success-others: "Успешно переключён питомец &b%s &r&aв режим %s!"
52 | ...
53 |
--------------------------------------------------------------------------------
/resources/languages/vi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Vietnamese messages file for BlockPets, a pets plugin by BlockHorizons.
3 |
4 | prefix:
5 | warning: "&c[&6Cảnh báo&c]"
6 |
7 | commands:
8 | errors:
9 | console-use: "Khi sử dụng lệnh đó từ giao diện điều khiển, tất cả các đối số phải được cung cấp."
10 | no-console-use: "Chạy command trong server!"
11 | no-permission: "Bạn không có quyền sử dụng lệnh này!"
12 | plugin-cancelled: "Plugin đã hủy hành động này!"
13 |
14 | pet:
15 | doesnt-exist: "Không tồn tại tên Pet!"
16 | numeric: "Tên Pet không được phép để kí tự hay chữ số"
17 |
18 | player:
19 | not-found: "Không tìm thấy người chơi"
20 | no-pet: "Bạn không sở hữu pet với cái tên này!"
21 | no-pet-other: "Người chơi này không sở hữu pet với cái tên này!"
22 | already-own-pet: "Bạn đã sử dụng tên này!"
23 |
24 | changepetname:
25 | no-permission: "Bạn không có quyền đổi tên pet của người khác!"
26 | success: "Đổi tên Pet %s &r&asang %s thành công!"
27 |
28 | clearpet:
29 | success: "Hủy bỏ Pet &b%s&a thành công!"
30 |
31 | healpet:
32 | success: "Pet %s &r&a đã được hồi máu!"
33 |
34 | leveluppet:
35 | success: "Pet đã được thăng cấp: &b%s &r&a %s!"
36 |
37 | spawnpet:
38 | no-permission: "Bạn không có quyền spawn pet!"
39 | no-permission-others: "Bạn không có quyền spawn pet cho người khác"
40 | success: "Spawn pet thành công với tên: &b%s&a!"
41 | success-other: "Bạn đã nhận được Pet với tên: &b%s&a!"
42 | name: "Vui lòng đặt tên Pet cho bạn một lần chat (không ghi màu)"
43 | selecting-name: "%s đang chọn tên cho Pet của họ"
44 | exceeded-limit: "%s đã dùng quá số lượng Pet"
45 |
46 | removepet:
47 | success: "Hủy bỏ Pet thành công &b%s&a!"
48 |
49 | togglepet:
50 | no-pet-specified: "Bạn chưa xác định tên Pet để mở!"
51 | success: "Mở Pet thành công %s!"
52 | success-others: "Mở Pet cho người khác thành công &b%s &r&a %s!"
53 | ...
54 |
--------------------------------------------------------------------------------
/resources/patches/mysql.sql:
--------------------------------------------------------------------------------
1 | -- #!mysql
2 | -- #{ version
3 | -- # { 1.1.2
4 | ALTER TABLE Pets ADD COLUMN Visible BOOL NOT NULL DEFAULT TRUE AFTER Chested;
5 | -- # }
6 | -- #}
7 |
--------------------------------------------------------------------------------
/resources/patches/sqlite.sql:
--------------------------------------------------------------------------------
1 | -- #!sqlite
2 | -- #{ version
3 | -- # { 1.1.2
4 | ALTER TABLE Pets ADD COLUMN Visible BOOL NOT NULL DEFAULT TRUE;
5 | -- # }
6 | -- #}
--------------------------------------------------------------------------------
/resources/pet_properties.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Walking Pets
3 | Axolotl:
4 | Can-Attack: true
5 | Can-Be-Ridden: true
6 | Can-Be-Chested: true
7 | Can-Sit-On-Owner: true
8 | Speed: 1.2
9 | Max-Size: 10
10 | CaveSpider:
11 | Can-Attack: true
12 | Can-Be-Ridden: true
13 | Can-Be-Chested: true
14 | Can-Sit-On-Owner: true
15 | Speed: 1.4
16 | Max-Size: 10
17 | Chicken:
18 | Can-Attack: true
19 | Can-Be-Ridden: true
20 | Can-Be-Chested: true
21 | Can-Sit-On-Owner: true
22 | Speed: 1.2
23 | Max-Size: 10
24 | Cow:
25 | Can-Attack: true
26 | Can-Be-Ridden: true
27 | Can-Be-Chested: true
28 | Can-Sit-On-Owner: true
29 | Speed: 1
30 | Max-Size: 10
31 | Creeper:
32 | Can-Attack: true
33 | Can-Be-Ridden: true
34 | Can-Be-Chested: true
35 | Can-Sit-On-Owner: true
36 | Speed: 1.2
37 | Max-Size: 10
38 | Donkey:
39 | Can-Attack: true
40 | Can-Be-Ridden: true
41 | Can-Be-Chested: true
42 | Can-Sit-On-Owner: true
43 | Speed: 1.4
44 | Max-Size: 10
45 | Enderman:
46 | Can-Attack: true
47 | Can-Be-Ridden: true
48 | Can-Be-Chested: true
49 | Can-Sit-On-Owner: true
50 | Speed: 1.4
51 | Max-Size: 10
52 | Endermite:
53 | Can-Attack: true
54 | Can-Be-Ridden: true
55 | Can-Be-Chested: true
56 | Can-Sit-On-Owner: true
57 | Speed: 1.4
58 | Max-Size: 10
59 | Evoker:
60 | Can-Attack: true
61 | Can-Be-Ridden: true
62 | Can-Be-Chested: true
63 | Can-Sit-On-Owner: true
64 | Speed: 1.4
65 | Max-Size: 10
66 | Fox:
67 | Can-Attack: true
68 | Can-Be-Ridden: true
69 | Can-Be-Chested: true
70 | Can-Sit-On-Owner: true
71 | Speed: 1.8
72 | Max-Size: 10
73 | Goat:
74 | Can-Attack: true
75 | Can-Be-Ridden: true
76 | Can-Be-Chested: true
77 | Can-Sit-On-Owner: true
78 | Speed: 1.4
79 | Max-Size: 10
80 | Horse:
81 | Can-Attack: true
82 | Can-Be-Ridden: true
83 | Can-Be-Chested: true
84 | Can-Sit-On-Owner: true
85 | Speed: 1.8
86 | Max-Size: 10
87 | Husk:
88 | Can-Attack: true
89 | Can-Be-Ridden: true
90 | Can-Be-Chested: true
91 | Can-Sit-On-Owner: true
92 | Speed: 1.2
93 | Max-Size: 10
94 | IronGolem:
95 | Can-Attack: true
96 | Can-Be-Ridden: true
97 | Can-Be-Chested: true
98 | Can-Sit-On-Owner: true
99 | Speed: 1.4
100 | Max-Size: 10
101 | Llama:
102 | Can-Attack: true
103 | Can-Be-Ridden: true
104 | Can-Be-Chested: true
105 | Can-Sit-On-Owner: true
106 | Speed: 1.4
107 | Max-Size: 10
108 | Mooshroom:
109 | Can-Attack: true
110 | Can-Be-Ridden: true
111 | Can-Be-Chested: true
112 | Can-Sit-On-Owner: true
113 | Speed: 1.2
114 | Max-Size: 10
115 | Mule:
116 | Can-Attack: true
117 | Can-Be-Ridden: true
118 | Can-Be-Chested: true
119 | Can-Sit-On-Owner: true
120 | Speed: 1.6
121 | Max-Size: 10
122 | Ocelot:
123 | Can-Attack: true
124 | Can-Be-Ridden: true
125 | Can-Be-Chested: true
126 | Can-Sit-On-Owner: true
127 | Speed: 1.8
128 | Max-Size: 10
129 | Pig:
130 | Can-Attack: true
131 | Can-Be-Ridden: true
132 | Can-Be-Chested: true
133 | Can-Sit-On-Owner: true
134 | Speed: 1
135 | Max-Size: 10
136 | PolarBear:
137 | Can-Attack: true
138 | Can-Be-Ridden: true
139 | Can-Be-Chested: true
140 | Can-Sit-On-Owner: true
141 | Speed: 1.2
142 | Max-Size: 10
143 | Sheep:
144 | Can-Attack: true
145 | Can-Be-Ridden: true
146 | Can-Be-Chested: true
147 | Can-Sit-On-Owner: true
148 | Speed: 1
149 | Max-Size: 10
150 | SilverFish:
151 | Can-Attack: true
152 | Can-Be-Ridden: true
153 | Can-Be-Chested: true
154 | Can-Sit-On-Owner: true
155 | Speed: 1.2
156 | Max-Size: 10
157 | SkeletonHorse:
158 | Can-Attack: true
159 | Can-Be-Ridden: true
160 | Can-Be-Chested: true
161 | Can-Sit-On-Owner: true
162 | Speed: 1.4
163 | Max-Size: 10
164 | Skeleton:
165 | Can-Attack: true
166 | Can-Be-Ridden: true
167 | Can-Be-Chested: true
168 | Can-Sit-On-Owner: true
169 | Speed: 1
170 | Max-Size: 10
171 | SnowGolem:
172 | Can-Attack: true
173 | Can-Be-Ridden: true
174 | Can-Be-Chested: true
175 | Can-Sit-On-Owner: true
176 | Speed: 1.2
177 | Max-Size: 10
178 | Spider:
179 | Can-Attack: true
180 | Can-Be-Ridden: true
181 | Can-Be-Chested: true
182 | Can-Sit-On-Owner: true
183 | Speed: 1.4
184 | Max-Size: 10
185 | Stray:
186 | Can-Attack: true
187 | Can-Be-Ridden: true
188 | Can-Be-Chested: true
189 | Can-Sit-On-Owner: true
190 | Speed: 1.2
191 | Max-Size: 10
192 | Strider:
193 | Can-Attack: true
194 | Can-Be-Ridden: true
195 | Can-Be-Chested: false
196 | Can-Sit-On-Owner: true
197 | Speed: 1.2
198 | Max-Size: 4
199 | Villager:
200 | Can-Attack: true
201 | Can-Be-Ridden: true
202 | Can-Be-Chested: true
203 | Can-Sit-On-Owner: true
204 | Speed: 1.2
205 | Max-Size: 10
206 | Vindicator:
207 | Can-Attack: true
208 | Can-Be-Ridden: true
209 | Can-Be-Chested: true
210 | Can-Sit-On-Owner: true
211 | Speed: 1.2
212 | Max-Size: 10
213 | Witch:
214 | Can-Attack: true
215 | Can-Be-Ridden: true
216 | Can-Be-Chested: true
217 | Can-Sit-On-Owner: true
218 | Speed: 1.2
219 | Max-Size: 10
220 | WitherSkeleton:
221 | Can-Attack: true
222 | Can-Be-Ridden: true
223 | Can-Be-Chested: true
224 | Can-Sit-On-Owner: true
225 | Speed: 1.4
226 | Max-Size: 10
227 | Wolf:
228 | Can-Attack: true
229 | Can-Be-Ridden: true
230 | Can-Be-Chested: true
231 | Can-Sit-On-Owner: true
232 | Speed: 1.6
233 | Max-Size: 10
234 | ZombieHorse:
235 | Can-Attack: true
236 | Can-Be-Ridden: true
237 | Can-Be-Chested: true
238 | Can-Sit-On-Owner: true
239 | Speed: 1.4
240 | Max-Size: 10
241 | Zombie:
242 | Can-Attack: true
243 | Can-Be-Ridden: true
244 | Can-Be-Chested: true
245 | Can-Sit-On-Owner: true
246 | Speed: 1
247 | Max-Size: 10
248 | ZombiePigman:
249 | Can-Attack: true
250 | Can-Be-Ridden: true
251 | Can-Be-Chested: true
252 | Can-Sit-On-Owner: true
253 | Speed: 1.2
254 | Max-Size: 10
255 | ZombieVillager:
256 | Can-Attack: true
257 | Can-Be-Ridden: true
258 | Can-Be-Chested: true
259 | Can-Sit-On-Owner: true
260 | Speed: 1.2
261 | Max-Size: 10
262 | Warden:
263 | Can-Attack: true
264 | Can-Be-Ridden: true
265 | Can-Be-Chested: true
266 | Can-Sit-On-Owner: true
267 | Speed: 1
268 | Max-Size: 10
269 |
270 | # Flying Pets
271 | Allay:
272 | Can-Attack: true
273 | Can-Be-Ridden: true
274 | Can-Be-Chested: true
275 | Can-Sit-On-Owner: true
276 | Speed: 1
277 | Flying-Height: 5
278 | Max-Size: 10
279 | Arrow:
280 | Can-Attack: true
281 | Can-Be-Ridden: true
282 | Can-Be-Chested: true
283 | Can-Sit-On-Owner: true
284 | Speed: 3
285 | Flying-Height: 25
286 | Max-Size: 10
287 | Bat:
288 | Can-Attack: true
289 | Can-Be-Ridden: true
290 | Can-Be-Chested: true
291 | Can-Sit-On-Owner: true
292 | Speed: 1
293 | Flying-Height: 8
294 | Max-Size: 10
295 | Bee:
296 | Can-Attack: true
297 | Can-Be-Ridden: true
298 | Can-Be-Chested: true
299 | Can-Sit-On-Owner: true
300 | Speed: 1
301 | Flying-Height: 8
302 | Max-Size: 10
303 | Blaze:
304 | Can-Attack: true
305 | Can-Be-Ridden: true
306 | Can-Be-Chested: true
307 | Can-Sit-On-Owner: true
308 | Speed: 1.2
309 | Flying-Height: 13
310 | Max-Size: 10
311 | EnderCrystal:
312 | Can-Attack: true
313 | Can-Be-Ridden: true
314 | Can-Be-Chested: true
315 | Can-Sit-On-Owner: true
316 | Speed: 1.2
317 | Flying-Height: 13
318 | Max-Size: 10
319 | EnderDragon:
320 | Can-Attack: true
321 | Can-Be-Ridden: true
322 | Can-Be-Chested: true
323 | Can-Sit-On-Owner: true
324 | Speed: 1.8
325 | Flying-Height: 60
326 | Max-Size: 5
327 | Ghast:
328 | Can-Attack: true
329 | Can-Be-Ridden: true
330 | Can-Be-Chested: true
331 | Can-Sit-On-Owner: true
332 | Speed: 1.3
333 | Flying-Height: 25
334 | Max-Size: 10
335 | Vex:
336 | Can-Attack: true
337 | Can-Be-Ridden: true
338 | Can-Be-Chested: true
339 | Can-Sit-On-Owner: true
340 | Speed: 1.4
341 | Flying-Height: 25
342 | Max-Size: 10
343 | Wither:
344 | Can-Attack: true
345 | Can-Be-Ridden: true
346 | Can-Be-Chested: true
347 | Can-Sit-On-Owner: true
348 | Speed: 1.8
349 | Flying-Height: 60
350 | Max-Size: 10
351 | WitherSkull:
352 | Can-Attack: true
353 | Can-Be-Ridden: true
354 | Can-Be-Chested: true
355 | Can-Sit-On-Owner: true
356 | Speed: 1.2
357 | Flying-Height: 13
358 | Max-Size: 10
359 |
360 | # Swimming Pets
361 | ElderGuardian:
362 | Can-Attack: true
363 | Can-Be-Ridden: true
364 | Can-Be-Chested: true
365 | Can-Sit-On-Owner: true
366 | Speed: 1
367 | Swimming-Speed: 2
368 | Jumping-Height: 0.12
369 | Max-Size: 10
370 | Guardian:
371 | Can-Attack: true
372 | Can-Be-Ridden: true
373 | Can-Be-Chested: true
374 | Can-Sit-On-Owner: true
375 | Speed: 1
376 | Swimming-Speed: 1.8
377 | Jumping-Height: 0.1
378 | Max-Size: 10
379 | Squid:
380 | Can-Attack: true
381 | Can-Be-Ridden: true
382 | Can-Be-Chested: true
383 | Can-Sit-On-Owner: true
384 | Speed: 1
385 | Swimming-Speed: 1.4
386 | Jumping-Height: 0.1
387 | Max-Size: 10
388 |
389 | # Bouncing Pets
390 | MagmaCube:
391 | Can-Attack: true
392 | Can-Be-Ridden: true
393 | Can-Be-Chested: true
394 | Can-Sit-On-Owner: true
395 | Speed: 1.4
396 | Jumping-Height: 0.14
397 | Max-Size: 10
398 | Rabbit:
399 | Can-Attack: true
400 | Can-Be-Ridden: true
401 | Can-Be-Chested: true
402 | Can-Sit-On-Owner: true
403 | Speed: 1.2
404 | Jumping-Height: 0.1
405 | Max-Size: 10
406 | Slime:
407 | Can-Attack: true
408 | Can-Be-Ridden: true
409 | Can-Be-Chested: true
410 | Can-Sit-On-Owner: true
411 | Speed: 1.6
412 | Jumping-Height: 0.14
413 | Max-Size: 10
414 | ...
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/Loader.php:
--------------------------------------------------------------------------------
1 | AllayPet::class,
104 | "Arrow" => ArrowPet::class,
105 | "Axolotl" => AxolotlPet::class,
106 | "Bat" => BatPet::class,
107 | "Bee" => BeePet::class,
108 | "Blaze" => BlazePet::class,
109 | "CaveSpider" => CaveSpiderPet::class,
110 | "Chicken" => ChickenPet::class,
111 | "Cow" => CowPet::class,
112 | "Creeper" => CreeperPet::class,
113 | "Donkey" => DonkeyPet::class,
114 | "ElderGuardian" => ElderGuardianPet::class,
115 | "EnderCrystal" => EnderCrystalPet::class,
116 | "EnderDragon" => EnderDragonPet::class,
117 | "Enderman" => EndermanPet::class,
118 | "Endermite" => EndermitePet::class,
119 | "Evoker" => EvokerPet::class,
120 | "Fox" => FoxPet::class,
121 | "Ghast" => GhastPet::class,
122 | "Goat" => GoatPet::class,
123 | "Guardian" => GuardianPet::class,
124 | "Horse" => HorsePet::class,
125 | "Husk" => HuskPet::class,
126 | "IronGolem" => IronGolemPet::class,
127 | "Llama" => LlamaPet::class,
128 | "MagmaCube" => MagmaCubePet::class,
129 | "Mooshroom" => MooshroomPet::class,
130 | "Mule" => MulePet::class,
131 | "Ocelot" => OcelotPet::class,
132 | "Pig" => PigPet::class,
133 | "PolarBear" => PolarBearPet::class,
134 | "Rabbit" => RabbitPet::class,
135 | "Sheep" => SheepPet::class,
136 | "SilverFish" => SilverFishPet::class,
137 | "Skeleton" => SkeletonPet::class,
138 | "SkeletonHorse" => SkeletonHorsePet::class,
139 | "Slime" => SlimePet::class,
140 | "SnowGolem" => SnowGolemPet::class,
141 | "Spider" => SpiderPet::class,
142 | "Squid" => SquidPet::class,
143 | "Stray" => StrayPet::class,
144 | "Strider" => StriderPet::class,
145 | "Vex" => VexPet::class,
146 | "Villager" => VillagerPet::class,
147 | "Vindicator" => VindicatorPet::class,
148 | "Warden" => WardenPet::class,
149 | "Witch" => WitchPet::class,
150 | "Wither" => WitherPet::class,
151 | "WitherSkeleton" => WitherSkeletonPet::class,
152 | "WitherSkull" => WitherSkullPet::class,
153 | "Wolf" => WolfPet::class,
154 | "Zombie" => ZombiePet::class,
155 | "ZombieHorse" => ZombieHorsePet::class,
156 | "ZombiePigman" => ZombiePigmanPet::class,
157 | "ZombieVillager" => ZombieVillagerPet::class
158 | ];
159 |
160 | /** @var string[] */
161 | private array $availableLanguages = [
162 | "en",
163 | "nl",
164 | "vi",
165 | "gr",
166 | "ko",
167 | "de"
168 | ];
169 |
170 | public array $selectingName = [];
171 |
172 | private BlockPetsConfig $bpConfig;
173 | private PetProperties $pProperties;
174 | private LanguageConfig $language;
175 | private ?BaseDataStorer $database = null;
176 |
177 | /** @var BasePet[][] */
178 | private array $playerPets = [];
179 |
180 | protected function onEnable(): void {
181 | if(!is_dir($this->getDataFolder())) {
182 | mkdir($this->getDataFolder());
183 | }
184 |
185 | $this->saveResource(".version_file");
186 |
187 | $database_stmts = Path::join($this->getDataFolder(), "database_stmts");
188 | if(!is_dir($database_stmts)) {
189 | mkdir($database_stmts);
190 | }
191 |
192 | $this->saveResource("database_stmts/mysql.sql", true);
193 | $this->saveResource("database_stmts/sqlite.sql", true);
194 |
195 | $this->registerEntities();
196 | $this->registerItems();
197 | $this->registerCommands();
198 | $this->registerListeners();
199 | PetInventoryManager::init($this);
200 |
201 | $this->bpConfig = new BlockPetsConfig($this);
202 | $this->pProperties = new PetProperties($this);
203 | $this->language = new LanguageConfig($this);
204 | $this->selectDatabase();
205 |
206 | /** @var AttributeFactory $factory */
207 | $factory = AttributeFactory::getInstance();
208 | $factory->register(Attribute::HORSE_JUMP_STRENGTH, 0.0, 3.0, 0.6679779);
209 |
210 | $this->checkVersionChange();
211 | }
212 |
213 | private function checkVersionChange(): void {
214 | $version_file = $this->getDataFolder() . ".version_file";
215 | if(!is_file($version_file)) {
216 | $current_version = "1.1.0";
217 | } else {
218 | $current_version = yaml_parse_file($version_file)["version"];
219 | }
220 |
221 | if(version_compare($this->getDescription()->getVersion(), $current_version, '>')) {
222 | $this->updateVersion($current_version);
223 | }
224 | }
225 |
226 | private function updateVersion(string $current_version): void {
227 | $current = (int) str_replace(".", "", $current_version);
228 | $newest = (int) str_replace(".", "", $this->getDescription()->getVersion());
229 | while($current < $newest) {
230 | ++$current;
231 | $version = implode(".", str_split((string) $current));
232 | $this->onVersionUpdate($version);
233 | }
234 |
235 | $this->saveResource(".version_file", true);
236 | }
237 |
238 | private function onVersionUpdate(string $version): void {
239 | $this->getDatabase()->patch($version);
240 | }
241 |
242 | public function registerCommands(): void {
243 | $this->getServer()->getCommandMap()->registerAll($this->getName(), [
244 | new AddPetPointsCommand($this),
245 | new SpawnPetCommand($this),
246 | new LevelUpPetCommand($this),
247 | new RemovePetCommand($this),
248 | new HealPetCommand($this),
249 | new ClearPetCommand($this),
250 | new TogglePetCommand($this),
251 | new ChangePetNameCommand($this),
252 | new ListPetsCommand($this),
253 | new PetsTopCommand($this),
254 | new PetCommand($this)
255 | ]);
256 | }
257 |
258 | public function registerEntities(): void {
259 | /** @var EntityFactory $entityFactory */
260 | $entityFactory = EntityFactory::getInstance();
261 | /**
262 | * @var string $name
263 | * @var BasePet $petClass
264 | */
265 | foreach(self::PETS as $name => $petClass) {
266 | $entityFactory->register($petClass, function(World $world, CompoundTag $nbt) use ($petClass): Entity {
267 | return new $petClass(EntityDataHelper::parseLocation($nbt, $world), $nbt);
268 | }, [$name, $petClass::NETWORK_NAME]);
269 | }
270 | }
271 |
272 | public function registerItems(): void {
273 | /** @var ItemFactory $factory */
274 | $factory = ItemFactory::getInstance();
275 | $factory->register(new Saddle(), true);
276 | // Item::addCreativeItem(Item::get(Item::SADDLE));
277 | }
278 |
279 | public function registerListeners(): void {
280 | $listeners = [
281 | new EventListener($this),
282 | new RidingListener($this)
283 | ];
284 | foreach($listeners as $listener) {
285 | $this->getServer()->getPluginManager()->registerEvents($listener, $this);
286 | }
287 | }
288 |
289 | /**
290 | * @return string[]
291 | */
292 | public function getAvailableLanguages(): array {
293 | return $this->availableLanguages;
294 | }
295 |
296 | private function selectDatabase(): bool {
297 | switch(strtolower($this->getBlockPetsConfig()->getDatabase())) {
298 | default:
299 | case "mysql":
300 | $this->database = new MySQLDataStorer($this);
301 | break;
302 | case "sqlite":
303 | case "sqlite3":
304 | $this->database = new SQLiteDataStorer($this);
305 | break;
306 | }
307 | return true;
308 | }
309 |
310 | public function getBlockPetsConfig(): BlockPetsConfig {
311 | return $this->bpConfig;
312 | }
313 |
314 | public function translate(string $key, array $params = []): string {
315 | if(!empty($params)) {
316 | return vsprintf($this->getLanguage()->get($key), $params);
317 | }
318 | return $this->getLanguage()->get($key);
319 | }
320 |
321 | public function getLanguage(): LanguageConfig {
322 | return $this->language;
323 | }
324 |
325 | /**
326 | * Checks if a pet type of that name exists.
327 | */
328 | public function petExists(string $entityName): bool {
329 | return $this->getPet($entityName) !== null;
330 | }
331 |
332 | /**
333 | * Tries to match a pet type with the pet type list, and returns the fully qualified name if this could be found. Null if no valid result was found.
334 | */
335 | public function getPet(string $entityName): ?string {
336 | foreach(self::PETS as $pet => $petClass) {
337 | if(strtolower($pet) === strtolower($entityName)) {
338 | return $pet;
339 | }
340 | }
341 | return null;
342 | }
343 |
344 | /**
345 | * Get the class of the relevant pet.
346 | */
347 | public function getPetClass(string $entityName): ?string {
348 | foreach(self::PETS as $pet => $petClass) {
349 | if(strtolower($pet) === strtolower($entityName)) {
350 | return $petClass;
351 | }
352 | }
353 | return null;
354 | }
355 |
356 | /**
357 | * Creates a new pet for the given player.
358 | */
359 | public function createPet(string $entityName, Player $player, string $name, float $scale = 1.0, bool $isBaby = false, int $level = 1, int $levelPoints = 0, bool $chested = false, bool $isVisible = true, ?string $inventory = null): ?BasePet {
360 | $pet = $this->getPetByName($name, $player->getName());
361 | if($pet !== null) {
362 | $this->removePet($pet);
363 | }
364 |
365 | $nbt = CompoundTag::create();
366 | $nbt->setString("petOwner", $player->getName());
367 | $nbt->setFloat("scale", $scale);
368 | $nbt->setString("petName", $name);
369 | $nbt->setInt("petLevel", $level);
370 | $nbt->setInt("petLevelPoints", $levelPoints);
371 | $nbt->setByte("isBaby", (int) $isBaby);
372 | $nbt->setByte("chested", (int) $chested);
373 |
374 | $class = $this->getPetClass($entityName);
375 | if($class === null) {
376 | return null;
377 | }
378 |
379 | $entity = new $class($player->getLocation(), $nbt);
380 | if($entity instanceof BasePet) {
381 | if(!empty($inventory)) {
382 | $entity->getInventoryManager()->load($inventory);
383 | }
384 |
385 | $ev = new PetSpawnEvent($this, $entity);
386 | $ev->call();
387 |
388 | if($ev->isCancelled()) {
389 | $this->removePet($entity);
390 | return null;
391 | }
392 |
393 | if(!$isVisible) {
394 | $entity->updateVisibility(false);
395 | } else {
396 | $entity->spawnToAll();
397 | }
398 |
399 | $this->playerPets[strtolower($player->getName())][strtolower($entity->getPetName())] = $entity;
400 | return $entity;
401 | }
402 |
403 | return null;
404 | }
405 |
406 | /**
407 | * Creates a copy of the given pet and returns it.
408 | */
409 | public function clonePet(PetData $data): ?BasePet {
410 | $owner = $this->getServer()->getPlayerExact($data->getOwnerName());
411 | if($owner === null) {
412 | return null;
413 | }
414 | return $this->createPet(
415 | $data->getPetId(),
416 | $owner,
417 | $data->getPetName(),
418 | $data->getScale(),
419 | $data->isBaby(),
420 | $data->getLevel(),
421 | $data->getLevelPoints(),
422 | $data->isChested(),
423 | $data->isVisible(),
424 | $data->getInventory()
425 | );
426 | }
427 |
428 | /**
429 | * Gets all currently available pets from the given player.
430 | *
431 | * @return BasePet[]
432 | */
433 | public function getPetsFrom(Player $player): array {
434 | return $this->playerPets[strtolower($player->getName())] ?? [];
435 | }
436 |
437 | /**
438 | * Returns the first pet found with the given name.
439 | */
440 | public function getPetByName(string $name, ?string $player = null): ?BasePet {
441 | $name = strtolower($name);
442 | if($player !== null) {
443 | return $this->playerPets[strtolower($player)][$name] ?? null;
444 | }
445 | foreach($this->getServer()->getOnlinePlayers() as $player) {
446 | if(isset($this->playerPets[$k = strtolower($player->getName())][$name])) {
447 | return $this->playerPets[$k][$name];
448 | }
449 | }
450 | return null;
451 | }
452 |
453 | /**
454 | * Closes and removes the specified pet from cache and calls PetRemoveEvent events.
455 | */
456 | public function removePet(BasePet $pet, bool $close = true): void {
457 | // TODO: Call a cancellable event if this method isn't called when pet owner quits
458 | (new PetRemoveEvent($this, $pet))->call();
459 | if($pet->isRidden()) {
460 | $pet->throwRiderOff();
461 | }
462 | if($close && !$pet->isClosed()) {
463 | $pet->close();
464 | }
465 | unset($this->playerPets[strtolower($pet->getPetOwnerName())][strtolower($pet->getPetName())]);
466 | }
467 |
468 | /**
469 | * Returns the database to store and fetch data from.
470 | */
471 | public function getDatabase(): BaseDataStorer {
472 | if($this->database === null) {
473 | throw new \RuntimeException("Attempted to retrieve the database while database storing was unavailable.");
474 | }
475 | return $this->database;
476 | }
477 |
478 | /**
479 | * Gets the pet the given player is currently riding.
480 | */
481 | public function getRiddenPet(Player $player): ?BasePet {
482 | foreach($this->getPetsFrom($player) as $pet) {
483 | if($pet->isRidden()) {
484 | return $pet;
485 | }
486 | }
487 | return null;
488 | }
489 |
490 | /**
491 | * Checks if the given player is currently riding a pet.
492 | */
493 | public function isRidingAPet(Player $player): bool {
494 | foreach($this->getPetsFrom($player) as $pet) {
495 | if($pet->isRidden()) {
496 | return true;
497 | }
498 | }
499 | return false;
500 | }
501 |
502 | public function getPetProperties(): PetProperties {
503 | return $this->pProperties;
504 | }
505 | }
506 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/AddPetPointsCommand.php:
--------------------------------------------------------------------------------
1 | [amount] [player]", ["app"]);
14 | $this->setPermission("blockpets.command.addpetpoints");
15 | }
16 |
17 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
18 | if(!isset($args[0])) {
19 | return false;
20 | }
21 |
22 | $loader = $this->getLoader();
23 | if(($pet = $loader->getPetByName($args[0])) === null) {
24 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist"));
25 | return true;
26 | }
27 |
28 | $amount = 1;
29 | if(isset($args[1])) {
30 | if(is_numeric($args[1])) {
31 | $amount = (int) $args[1];
32 | }
33 | }
34 |
35 | if(isset($args[2])) {
36 | if(($player = $loader->getServer()->getPlayerByPrefix($args[2])) === null) {
37 | $this->sendWarning($sender, $loader->translate("commands.errors.player.not-found"));
38 | return true;
39 | }
40 | if(($pet = $loader->getPetByName($args[0], $player->getName())) === null) {
41 | $this->sendWarning($sender, $loader->translate("commands.errors.player.no-pet-other"));
42 | return true;
43 | }
44 | $pet->addPetLevelPoints($amount);
45 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.addpetpoints.success", [$amount, $pet->getPetName()]));
46 | return true;
47 | }
48 |
49 | $pet->addPetLevelPoints($amount);
50 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.addpetpoints.success", [$amount, $pet->getPetName()]));
51 | return true;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/BaseCommand.php:
--------------------------------------------------------------------------------
1 | sendWarning($sender, $this->getLoader()->translate("commands.errors.no-console-use"));
24 | return;
25 | }
26 | $this->sendWarning($sender, $this->getLoader()->translate("commands.errors.console-use"));
27 | }
28 |
29 | public function sendWarning(CommandSender $sender, string $text): void {
30 | $sender->sendMessage(TF::RED . $this->getLoader()->translate("prefix.warning") . " " . $text);
31 | }
32 |
33 | public function sendPermissionMessage(CommandSender $sender): void {
34 | $this->sendWarning($sender, ($this->getLoader()->translate("commands." . $this->getName() . ".no-permission") !== "" ? $this->getLoader()->translate("commands." . $this->getName() . ".no-permission") : $this->getLoader()->translate("commands.no-permission")));
35 | }
36 |
37 | public function getLoader(): Loader {
38 | return $this->loader;
39 | }
40 |
41 | public function getOwningPlugin(): Loader {
42 | return $this->loader;
43 | }
44 |
45 | /**
46 | * @param string[] $args
47 | */
48 | public final function execute(CommandSender $sender, string $commandLabel, array $args): void {
49 | if(!$this->testPermissionSilent($sender)) {
50 | $this->sendPermissionMessage($sender);
51 | return;
52 | }
53 |
54 | if(!$this->onCommand($sender, $commandLabel, $args) && $this->usageMessage !== "") {
55 | $sender->sendMessage(str_replace("/" . $this->getName(), "/" . $commandLabel, $this->getUsage()));
56 | return;
57 | }
58 | }
59 |
60 | public abstract function onCommand(CommandSender $sender, string $commandLabel, array $args): bool;
61 | }
62 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/ChangePetNameCommand.php:
--------------------------------------------------------------------------------
1 | [player]", ["cpn, chpn"]);
15 | $this->setPermission("blockpets.command.changepetname.use");
16 | }
17 |
18 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
19 | if(!($sender instanceof Player) && count($args) !== 3) {
20 | $this->sendConsoleError($sender);
21 | return false;
22 | }
23 |
24 | if(!isset($args[1]) || empty(trim($args[1]))) {
25 | $this->sendWarning($sender, "The name you entered is invalid.");
26 | return true;
27 | }
28 |
29 | $newName = $args[1];
30 |
31 | if(isset($args[2])) {
32 | if($sender instanceof Player && $sender->hasPermission("blockpets.command.changepetname.others")) {
33 | $this->sendPermissionMessage($sender);
34 | return true;
35 | }
36 | if(($player = $this->getLoader()->getServer()->getPlayerByPrefix($args[2])) === null) {
37 | $this->sendWarning($sender, $this->getLoader()->translate("commands.errors.player.not-found"));
38 | return true;
39 | }
40 | if(($pet = $this->getLoader()->getPetByName($args[0], $player->getName())) === null) {
41 | $this->sendWarning($sender, $this->getLoader()->translate("commands.errors.player.no-pet-other"));
42 | return true;
43 | }
44 | $oldName = $pet->getPetName();
45 | $pet->changeName($newName);
46 | $sender->sendMessage(TF::GREEN . $this->getLoader()->translate("commands.changepetname.success", [
47 | $oldName,
48 | $newName
49 | ]));
50 | return true;
51 | }
52 |
53 | if(($pet = $this->getLoader()->getPetByName($args[0], $sender->getName())) === null) {
54 | $this->sendWarning($sender, $this->getLoader()->translate("commands.errors.player.no-pet"));
55 | return true;
56 | }
57 |
58 | $oldName = $pet->getPetName();
59 | $pet->changeName($newName);
60 | $sender->sendMessage(TF::GREEN . $this->getLoader()->translate("commands.changepetname.success", [
61 | $oldName,
62 | $newName
63 | ]));
64 | return true;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/ClearPetCommand.php:
--------------------------------------------------------------------------------
1 | ", ["cp"]);
15 | $this->setPermission("blockpets.command.clearpet");
16 | }
17 |
18 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
19 | if(!($sender instanceof Player)) {
20 | $this->sendConsoleError($sender, true);
21 | return true;
22 | }
23 |
24 | if(!isset($args[0])) {
25 | return false;
26 | }
27 |
28 | $loader = $this->getLoader();
29 | if(($pet = $loader->getPetByName($args[0], $sender->getName())) === null) {
30 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist"));
31 | return true;
32 | }
33 |
34 | $loader->removePet($pet);
35 | $loader->getDatabase()->unregisterPet($pet);
36 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.removepet.success", [$pet->getPetName()]));
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/HealPetCommand.php:
--------------------------------------------------------------------------------
1 | [player]", ["hp", "petheal"]);
15 | $this->setPermission("blockpets.command.healpet");
16 | }
17 |
18 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
19 | if(!isset($args[0])) {
20 | return false;
21 | }
22 |
23 | $loader = $this->getLoader();
24 | if(($pet = $loader->getPetByName($args[0])) === null) {
25 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist"));
26 | return true;
27 | }
28 |
29 | if(isset($args[1])) {
30 | if(($player = $loader->getServer()->getPlayerByPrefix($args[1])) === null) {
31 | $this->sendWarning($sender, $loader->translate("commands.errors.player.not-found"));
32 | return true;
33 | }
34 | if(($pet = $loader->getPetByName($args[0], $player->getName())) === null) {
35 | $this->sendWarning($sender, $loader->translate("commands.errors.player.no-pet-other"));
36 | return true;
37 | }
38 | }
39 |
40 | $pet->fullHeal();
41 | $pet->getWorld()->addParticle($pet->getLocation()->add(0, 2, 0), new HeartParticle(4));
42 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.healpet.success", [$pet->getPetName()]));
43 | return true;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/LevelUpPetCommand.php:
--------------------------------------------------------------------------------
1 | [amount] [player]", ["lup"]);
14 | $this->setPermission("blockpets.command.leveluppet");
15 | }
16 |
17 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
18 | if(!isset($args[0])) {
19 | return false;
20 | }
21 |
22 | $loader = $this->getLoader();
23 | if(($pet = $loader->getPetByName($args[0])) === null) {
24 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist"));
25 | return true;
26 | }
27 |
28 | $amount = 1;
29 | if(isset($args[1])) {
30 | if(is_numeric($args[1])) {
31 | $amount = (int) $args[1];
32 | }
33 | }
34 |
35 | if(isset($args[2])) {
36 | if(($player = $loader->getServer()->getPlayerByPrefix($args[2])) === null) {
37 | $this->sendWarning($sender, $loader->translate("commands.errors.player.not-found"));
38 | return true;
39 | }
40 | if(($pet = $loader->getPetByName($args[0], $player->getName())) === null) {
41 | $this->sendWarning($sender, $loader->translate("commands.errors.player.no-pet-other"));
42 | return true;
43 | }
44 | $pet->levelUp($amount);
45 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.leveluppet.success", [$pet->getPetName(), ($amount === 1 ? " once" : " " . $amount . " times")]));
46 | return true;
47 | }
48 |
49 | $pet->levelUp($amount);
50 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.leveluppet.success", [$pet->getPetName(), ($amount === 1 ? " once" : " " . $amount . " times")]));
51 | return true;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/ListPetsCommand.php:
--------------------------------------------------------------------------------
1 | setPermission("blockpets.command.listpets");
18 | }
19 |
20 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
21 | if(!($sender instanceof Player)) {
22 | $this->sendConsoleError($sender, true);
23 | return true;
24 | }
25 |
26 | if(isset($args[0])) {
27 | if(isset($args[1])) {
28 | [$list_type, $page] = $args;
29 | } else {
30 | if(is_numeric($args[0])) {
31 | $page = $args[0];
32 | } else {
33 | $list_type = $args[0];
34 | }
35 | }
36 | }
37 |
38 | $loader = $this->getLoader();
39 |
40 | if(isset($list_type)) {
41 | $list_type = $loader->getPet($list_type);
42 | if($list_type === null) {
43 | $sender->sendMessage($loader->translate("commands.errors.pet.doesnt-exist"));
44 | return true;
45 | }
46 | } else {
47 | $list_type = null;
48 | }
49 |
50 | if(isset($page)) {
51 | $page = max(1, (int) $page);
52 | } else {
53 | $page = 1;
54 | }
55 |
56 | $loader->getDatabase()->getPlayerPets(
57 | $sender->getName(),
58 | $list_type,
59 | function(array $rows) use($loader, $list_type, $page, $sender): void {
60 | $pets = [];
61 | $pets_c = 0;
62 |
63 | foreach($rows as ["PetName" => $petName, "EntityName" => $entityName, "Visible" => $isVisible]) {
64 | $row = TextFormat::YELLOW . ++$pets_c . ". " . $petName . ($list_type === null ? TextFormat::GRAY . " (" . $entityName . ") " : "");
65 | if(!$isVisible) {
66 | $row .= TextFormat::GRAY . "[INVISIBLE]";
67 | }
68 | $pets[] = $row;
69 | }
70 |
71 | if(empty($pets)) {
72 | if($list_type === null) {
73 | $sender->sendMessage($loader->translate("commands.listpets.no-pets-found"));
74 | } else {
75 | $sender->sendMessage($loader->translate("commands.listpets.no-pets-found-type", [$list_type]));
76 | }
77 | } else {
78 | $pages = (int) ceil($pets_c / self::ENTRIES_PER_PAGE);
79 | if($page > $pages) {
80 | $page = 1;
81 | }
82 |
83 | $message = TextFormat::GREEN . "--- Your " . ($list_type ?? "Pet") . "s " . TextFormat::YELLOW . $page . "/" . $pages . TextFormat::GREEN . " ---" . TextFormat::EOL;
84 | $message .= implode(TextFormat::EOL, array_slice($pets, 0, self::ENTRIES_PER_PAGE));
85 | $sender->sendMessage($message);
86 | }
87 | }
88 | );
89 | return true;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/PetCommand.php:
--------------------------------------------------------------------------------
1 | [petName|select] [size] [isBaby] [player]: Spawns a new pet with the given data.",
17 | "/removepet [player]: Removes the first pet with the given name, and checks for a player if given.",
18 | "/togglepet [player]: Toggles a pet on/off, depending on the current state.",
19 | "/healpet [player]: Heals the first pet with the given name, and checks for a player if given.",
20 | "/leveluppet [amount] [player]: Levels up the first pet with the given name by the amount, and checks for player if given.",
21 | "/addpetpoints [amount] [player]: Adds pet points to the first pet with the given name by the amount, and checks for player if given.",
22 | "/clearpet : Clears one of your own pets with the given name.",
23 | "/changepetname [player]: Changes the name of one of your pets, or the pet of other players if specified.",
24 | "/listpets [EntityName=ALL] [page=1]: Lists all your pets.",
25 | "/petstop [EntityName=ALL] [page=1]: Displays pets leaderboard.",
26 | ];
27 |
28 | const HELP_MESSAGES_PER_PAGE = 4;//When executed in console, all help messages are displayed irrespective of the page specified.
29 |
30 | /** @var string[][] */
31 | private $help_messages = [];
32 |
33 | public function __construct(Loader $loader) {
34 | parent::__construct($loader, "pet", "Show info or reload BlockPets", "/pet [help|info|reload]", ["pets"]);
35 | $this->setPermission("blockpets.command.pet");
36 | $this->formatHelpMessages();
37 | }
38 |
39 | private function formatHelpMessages(): void {
40 | $messages = [];
41 | $sorted_messages = self::HELP_MESSAGES;
42 | sort($sorted_messages, SORT_STRING);
43 |
44 | foreach($sorted_messages as $message) {
45 | [$command_part, $description] = explode(":", $message, 2);
46 | [$command, $args_string] = explode(" ", $command_part, 2);
47 |
48 | $search_for = null;
49 | $starting_offset = NAN;
50 | $is_optional = null;
51 | $args = [];
52 |
53 | foreach(str_split($args_string) as $offset => $char) {
54 | if($search_for !== null) {
55 | if($char === $search_for) {
56 | $arg = substr($args_string, $starting_offset, $offset - $starting_offset + 1);
57 | if($is_optional) {
58 | $arg = TextFormat::GRAY . $arg;
59 | } else {
60 | $arg = TextFormat::RED . $arg;
61 | }
62 | $args[] = $arg;
63 |
64 | $starting_offset = -1;
65 | $search_for = null;
66 | $is_optional = null;
67 | }
68 | } else {
69 | switch($char) {
70 | case "<":
71 | $search_for = ">";
72 | $starting_offset = $offset;
73 | $is_optional = false;
74 | break;
75 | case "[":
76 | $search_for = "]";
77 | $starting_offset = $offset;
78 | $is_optional = true;
79 | break;
80 | }
81 | }
82 | }
83 |
84 | $messages[substr($command, 1)] = TextFormat::GREEN . $command . " " . implode(" ", $args) . TextFormat::YELLOW . ":" . $description;
85 | }
86 |
87 | $this->help_messages = array_chunk($messages, self::HELP_MESSAGES_PER_PAGE, true);
88 | }
89 |
90 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
91 | if(!isset($args[0])) {
92 | $args[0] = "help";
93 | }
94 |
95 | switch(strtolower($args[0])) {
96 | case "help":
97 | if($sender instanceof ConsoleCommandSender) {
98 | $message = "";
99 | foreach($this->help_messages as $messages) {
100 | foreach($messages as $msg) {
101 | $message .= $msg . TextFormat::EOL;
102 | }
103 | }
104 |
105 | $sender->sendMessage(strtr(self::HELP_MESSAGE_TITLE, [
106 | "{CURRENT_PAGE}" => 1,
107 | "{TOTAL_PAGES}" => 1
108 | ]) . TextFormat::EOL . $message);
109 | return true;
110 | }
111 |
112 | if(!isset($args[1]) || !is_numeric($args[1])) {
113 | $args[1] = 1;
114 | }
115 |
116 | $page = (int) $args[1];
117 | if(!isset($this->help_messages[$page - 1])) {
118 | $page = 1;
119 | }
120 |
121 | $sender->sendMessage(strtr(self::HELP_MESSAGE_TITLE, [
122 | "{CURRENT_PAGE}" => $page,
123 | "{TOTAL_PAGES}" => count($this->help_messages)
124 | ]) . TextFormat::EOL . implode(TextFormat::EOL, $this->help_messages[$page - 1]));
125 | break;
126 | default:
127 | case "info":
128 | $loader = $this->getLoader();
129 | $sender->sendMessage(TextFormat::AQUA . "[BlockPets] Information\n" .
130 | TextFormat::GREEN . "Version: " . TextFormat::YELLOW . $loader->getDescription()->getVersion() . "\n" .
131 | TextFormat::GREEN . "Target API: " . TextFormat::YELLOW . implode(", ", $loader->getDescription()->getCompatibleApis()) . "\n" .
132 | TextFormat::GREEN . "Organization: " . TextFormat::YELLOW . "BlockHorizons (https://github.com/BlockHorizons/BlockPets)\n" .
133 | TextFormat::GREEN . "Authors: " . TextFormat::YELLOW . "Sandertv (@Sandertv), Luke (@lukeeey)");
134 | break;
135 | }
136 | return true;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/PetsTopCommand.php:
--------------------------------------------------------------------------------
1 | setPermission("blockpets.command.petstop");
17 | }
18 |
19 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
20 | $loader = $this->getLoader();
21 |
22 | if(isset($args[1]) || (isset($args[0]) && !is_numeric($args[0]))) {
23 | $entityName = $args[0];
24 | $page = max(1, (int) ($args[1] ?? 1));
25 | } else {
26 | $page = max(1, (int) ($args[0] ?? 1));
27 | $entityName = null;
28 | }
29 |
30 | if($entityName !== null) {
31 | $entityName = $loader->getPet($entityName);
32 | if($entityName === null) {
33 | $sender->sendMessage($loader->translate("commands.errors.pet.doesnt-exist"));
34 | return true;
35 | }
36 | }
37 |
38 | $loader->getDatabase()->getPetsLeaderboard(
39 | ($page - 1) * self::ENTRIES_PER_PAGE,
40 | self::ENTRIES_PER_PAGE,
41 | $entityName,
42 | function(array $rows) use($sender, $page, $commandLabel, $entityName): void {
43 | $pets = "";
44 | $index = PetsTopCommand::ENTRIES_PER_PAGE * ($page - 1);
45 |
46 | foreach($rows as [
47 | "Player" => $player,
48 | "PetName" => $petName,
49 | "EntityName" => $entityName,
50 | "PetLevel" => $petLevel,
51 | "LevelPoints" => $levelPoints
52 | ]) {
53 | $pets .= TextFormat::YELLOW . ++$index . ". " . TextFormat::AQUA . $player . "'s Pet " . $entityName . ", " . TextFormat::YELLOW . $petName;
54 | $pets .= TextFormat::GRAY . "(" . "Lvl " . TextFormat::AQUA . $petLevel . TextFormat::GRAY . ", " . TextFormat::AQUA . $levelPoints . TextFormat::GRAY . " xp)" . TextFormat::EOL;
55 | }
56 |
57 | if($pets === "") {
58 | if($page === 1) {
59 | if($entityName === null) {
60 | $sender->sendMessage(TextFormat::RED . $this->getLoader()->translate("commands.errors.pets.none-on-server"));
61 | } else {
62 | $sender->sendMessage(TextFormat::RED . $this->getLoader()->translate("commands.errors.pets.none-on-server-type", [$entityName]));
63 | }
64 | } else {
65 | if($entityName === null) {
66 | $this->onCommand($sender, $commandLabel, [1]);//send first page.
67 | } else {
68 | $this->onCommand($sender, $commandLabel, [$entityName, 1]);//send first page.
69 | }
70 | }
71 | } else {
72 | $message = TextFormat::GREEN . "--- Pets Leaderboard " . TextFormat::YELLOW . "#" . $page . TextFormat::GREEN . " ---" . TextFormat::EOL;
73 | $message .= $pets;
74 | $sender->sendMessage($message);
75 | }
76 | }
77 | );
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/RemovePetCommand.php:
--------------------------------------------------------------------------------
1 | [player]", ["rmp"]);
14 | $this->setPermission("blockpets.command.removepet");
15 | }
16 |
17 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
18 | if(!isset($args[0])) {
19 | return false;
20 | }
21 |
22 | $loader = $this->getLoader();
23 | if(isset($args[1])) {
24 | if(($player = $loader->getServer()->getPlayerByPrefix($args[1])) === null) {
25 | $this->sendWarning($sender, $loader->translate("commands.errors.player.not-found"));
26 | return true;
27 | }
28 | if(($pet = $loader->getPetByName($args[0], $player->getName())) === null) {
29 | $this->sendWarning($sender, $loader->translate("commands.errors.player.no-pet-other"));
30 | return true;
31 | }
32 | $loader->removePet($pet);
33 | $loader->getDatabase()->unregisterPet($pet);
34 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.removepet.success", [$pet->getPetName()]));
35 | return true;
36 | }
37 |
38 | if(($pet = $loader->getPetByName($args[0])) === null) {
39 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist"));
40 | return true;
41 | }
42 |
43 | $loader->removePet($pet);
44 | $loader->getDatabase()->unregisterPet($pet);
45 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.removepet.success", [$pet->getPetName()]));
46 | return true;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/SpawnPetCommand.php:
--------------------------------------------------------------------------------
1 | [name] [size] [baby] [player]", ["sp"]);
15 | $this->setPermission("blockpets.command.spawnpet.use");
16 | }
17 |
18 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
19 | if(!($sender instanceof Player) && count($args) !== 5) {
20 | $this->sendConsoleError($sender);
21 | //$sender->sendMessage(TF::RED . "When using spawnpet from the console, all arguments must be provided.");
22 | return false;
23 | }
24 |
25 | if($sender instanceof Player) {
26 | if(count($args) > 5 || count($args) < 1) {
27 | return false;
28 | }
29 |
30 | if(!$sender->hasPermission("blockpets.pet." . strtolower($args[0]))) {
31 | $this->sendPermissionMessage($sender);
32 | return true;
33 | }
34 | }
35 |
36 | $player = $sender;
37 | $loader = $this->getLoader();
38 |
39 | if(isset($args[4])) {
40 | if(($player = $loader->getServer()->getPlayerByPrefix($args[4])) === null) {
41 | $this->sendWarning($sender, $loader->translate("commands.errors.player.not-found"));
42 | return true;
43 | }
44 | if(!$sender->hasPermission("blockpets.command.spawnpet.others")) {
45 | $this->sendWarning($sender, $loader->translate("commands.spawnpet.no-permission.others"));
46 | return true;
47 | }
48 | }
49 |
50 | if(!isset($args[1]) || empty(trim($args[1]))) {
51 | /** @phpstan-ignore-next-line */
52 | $args[1] = $player->getDisplayName();
53 | }
54 |
55 | if(isset($args[2])) {
56 | if(!is_numeric($args[2])) {
57 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.numeric"));
58 | return true;
59 | }
60 | }
61 |
62 | if(isset($args[3])) {
63 | if($args[3] === "false" || $args[3] === "no") {
64 | $args[3] = false;
65 | } else {
66 | $args[3] = true;
67 | }
68 | } else {
69 | $args[3] = false;
70 | }
71 | $petName = $loader->getPet($args[0]);
72 | if($petName === null) {
73 | $this->sendWarning($sender, $loader->translate("commands.errors.pet.doesnt-exist", [$args[0]]));
74 | return true;
75 | }
76 | if(count($loader->getPetsFrom($player)) >= $loader->getBlockPetsConfig()->getMaxPets() && !$player->hasPermission("blockpets.bypass-limit")) {
77 | $sender->sendMessage($loader->translate("commands.spawnpet.exceeded-limit", [
78 | $player === $sender ? "You have " : "Your target has "
79 | ]));
80 | return true;
81 | }
82 | if(strtolower($args[1]) === "select") {
83 | if($player !== $sender) {
84 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.spawnpet.selecting-name", [$player->getName()]));
85 | }
86 | $player->sendMessage(TF::GREEN . $loader->translate("commands.spawnpet.name"));
87 | $loader->selectingName[$player->getName()] = [
88 | "petType" => $petName,
89 | "scale" => isset($args[2]) ? (float) $args[2] : 1.0,
90 | "isBaby" => $args[3] ?? false
91 | ];
92 | return true;
93 | }
94 | if($loader->getPetByName($args[1], $player->getName()) !== null) {
95 | $this->sendWarning($sender, $loader->translate("commands.errors.player.already-own-pet"));
96 | return true;
97 | }
98 |
99 | $pet = $loader->createPet((string) $petName, $player, $args[1], isset($args[2]) ? (float) $args[2] : 1.0, $args[3]);
100 | if($pet === null) {
101 | $this->sendWarning($sender, $loader->translate("commands.errors.plugin-cancelled"));
102 | return true;
103 | }
104 | $sender->sendMessage(TF::GREEN . $loader->translate("commands.spawnpet.success", [$args[1]]));
105 | $pet->register();
106 | if($player->getName() !== $sender->getName()) {
107 | $player->sendMessage(TF::GREEN . $loader->translate("commands.spawnpet.success.other", [$args[1]]));
108 | }
109 | return true;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/commands/TogglePetCommand.php:
--------------------------------------------------------------------------------
1 | [player]", ["togglep"]);
15 | $this->setPermission("blockpets.command.togglepet");
16 | }
17 |
18 | public function onCommand(CommandSender $sender, string $commandLabel, array $args): bool {
19 | $loader = $this->getLoader();
20 | if(!isset($args[0])) {
21 | $this->sendWarning($sender, TextFormat::RED . $loader->translate("commands.togglepet.no-pet-specified"));
22 | return false;
23 | }
24 |
25 | if(!($sender instanceof Player) && count($args) !== 2) {
26 | $this->sendConsoleError($sender);
27 | return false;
28 | }
29 |
30 | $player = $sender;
31 | if(isset($args[1])) {
32 | if(($player = $loader->getServer()->getPlayerByPrefix($args[1])) === null) {
33 | $this->sendWarning($sender, TextFormat::RED . $loader->translate("commands.errors.player.not-found"));
34 | return true;
35 | }
36 | }
37 | $loader->getDatabase()->togglePets(
38 | $player = $player->getName(),
39 | $type = $args[0] === "all" ? null : $args[0],
40 | function(array $rows) use($loader, $type, $sender, $player): void {
41 | if(empty($rows)) {
42 | $this->sendWarning($sender, TextFormat::RED . $loader->translate("commands.errors.player.no-pet"));
43 | return;
44 | }
45 |
46 | if($type === null) {
47 | $pets = [];
48 |
49 | foreach($rows as [
50 | "PetName" => $petName,
51 | "Visible" => $isVisible
52 | ]) {
53 | $pet = $loader->getPetByName($petName, $player);
54 | if($pet !== null) {
55 | $pets[$pet->getPetName()] = $isVisible;
56 | $pet->updateVisibility((bool) $isVisible);
57 | }
58 | }
59 |
60 | if(empty($pets)) {
61 | $this->sendWarning($sender, TextFormat::RED . $loader->translate("commands.errors.player.no-pet"));
62 | return;
63 | }
64 |
65 | $visible = array_keys($pets, 1, true);
66 | /** @phpstan-ignore-next-line */
67 | if(count($visible) === 0) {
68 | $sender->sendMessage(TextFormat::GREEN . $loader->translate(
69 | $sender->getName() === $player ? "commands.togglepet.success" : "commands.togglepet.success-others",
70 | $sender->getName() === $player ? ["off"] : [$player, "off"]
71 | ));
72 | } elseif(count($visible) === count($pets)) {
73 | $sender->sendMessage(TextFormat::GREEN . $loader->translate(
74 | $sender->getName() === $player ? "commands.togglepet.success" : "commands.togglepet.success-others",
75 | $sender->getName() === $player ? ["on"] : [$player, "on"]
76 | ));
77 | } else {
78 | $sender->sendMessage(TextFormat::GREEN . $loader->translate(
79 | $sender->getName() === $player ? "commands.togglepet.success-diff" : "commands.togglepet.success-diff-others",
80 | $sender->getName() === $player ? [implode(", ", $visible)] : [$player, implode(", ", $visible)]
81 | ));
82 | }
83 | } else {
84 | ["PetName" => $petName, "Visible" => $isVisible] = array_pop($rows);
85 | $pet = $loader->getPetByName($petName, $player);
86 | if($pet === null) {
87 | $this->sendWarning($sender, TextFormat::RED . $loader->translate("commands.errors.player.no-pet"));
88 | return;
89 | }
90 |
91 | $pet->updateVisibility((bool) $isVisible);
92 | $sender->sendMessage(TextFormat::GREEN . $loader->translate(
93 | $sender->getName() === $player ? "commands.togglepet.success-specific" : "commands.togglepet.success-specific-others",
94 | $sender->getName() === $player ? [$petName, $isVisible ? "on" : "off"] : [$player, $petName, $isVisible ? "on" : "off"]
95 | ));
96 | }
97 | }
98 | );
99 | return true;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/configurable/BlockPetsConfig.php:
--------------------------------------------------------------------------------
1 | saveDefaultConfig();
14 | $this->collectPreferences();
15 | }
16 |
17 | public function collectPreferences(): void {
18 | $data = yaml_parse_file($this->getLoader()->getDataFolder() . "config.yml");
19 | $this->settings = $data;
20 | }
21 |
22 | public function getLoader(): Loader {
23 | return $this->loader;
24 | }
25 |
26 | public function doHardReset(): bool {
27 | return (bool) ($this->settings["Hard-Reset"] ?? false);
28 | }
29 |
30 | public function arePetsInvulnerable(): bool {
31 | return (bool) ($this->settings["Invulnerable-Pets"] ?? false);
32 | }
33 |
34 | public function petsDoAttack(): bool {
35 | return (bool) ($this->settings["Attacking-Pets"] ?? true);
36 | }
37 |
38 | public function getBasePetHealth(): int {
39 | return (int) ($this->settings["Pet-Base-Health"] ?? 20);
40 | }
41 |
42 | public function getPetHealthPerLevel(): float {
43 | return (float) ($this->settings["Pet-Per-Level-Health"] ?? 0.5);
44 | }
45 |
46 | public function getPetSizePerLevel(): float {
47 | return (float) ($this->settings["Pet-Per-Level-Size"] ?? 0.03);
48 | }
49 |
50 | public function getBasePetDamage(): int {
51 | return (int) ($this->settings["Pet-Base-Damage"] ?? 4);
52 | }
53 |
54 | public function getPetDamagePerLevel(): float {
55 | return (float) ($this->settings["Pet-Per-Level-Damage"] ?? 0.1);
56 | }
57 |
58 | public function getRespawnTime(): int {
59 | return (int) ($this->settings["Pet-Respawn-Time"] ?? 10);
60 | }
61 |
62 | public function getPlayerExperiencePoints(): int {
63 | return (int) ($this->settings["Experience-Points-Per-Player-Kill"] ?? 15);
64 | }
65 |
66 | public function getEntityExperiencePoints(): int {
67 | return (int) ($this->settings["Experience-Points-Per-Entity-Kill"] ?? 10);
68 | }
69 |
70 | public function getMySQLInfo(): array {
71 | return (array) ($this->settings["MySQL-Info"] ?? []);
72 | }
73 |
74 | public function storeToDatabase(): bool {
75 | return (bool) ($this->settings["Store-To-Database"] ?? true);
76 | }
77 |
78 | public function getDatabase(): string {
79 | return (string) ($this->settings["Database"] ?? "SQLite");
80 | }
81 |
82 | public function getLanguage(): string {
83 | return (string) ($this->settings["Language"] ?? "en");
84 | }
85 |
86 | public function getMaxPets(): int {
87 | return (int) ($this->settings["Pet-Limit"] ?? 3);
88 | }
89 |
90 | public function arePetsInvulnerableIfOwnerIs(): bool {
91 | return (bool) ($this->settings["Invulnerable-If-Owner-Is"] ?? true);
92 | }
93 |
94 | public function giveExperienceWhenFed(): bool {
95 | return (bool) ($this->settings["Give-Experience-For-Feeding"] ?? true);
96 | }
97 |
98 | public function shouldStalkPetOwner(): bool {
99 | return (bool) ($this->settings["Stalk-Owner-Blindly"] ?? false);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/configurable/LanguageConfig.php:
--------------------------------------------------------------------------------
1 | collectMessages();
15 | }
16 |
17 | public function collectMessages(): void {
18 | $languageSelected = false;
19 | $language = [];
20 | foreach($this->getLoader()->getAvailableLanguages() as $availableLanguage) {
21 | if($this->getLoader()->getBlockPetsConfig()->getLanguage() === $availableLanguage) {
22 | $this->getLoader()->saveResource("languages/" . $availableLanguage . ".yml", true);
23 | $language = yaml_parse_file($this->getLoader()->getDataFolder() . "languages/" . $availableLanguage . ".yml");
24 | $languageSelected = true;
25 | break;
26 | }
27 | }
28 | if(!$languageSelected) {
29 | $this->getLoader()->saveResource("languages/en.yml");
30 | $language = yaml_parse_file($this->getLoader()->getDataFolder() . "languages/en.yml");
31 | }
32 |
33 | $iterator = new \RecursiveTreeIterator(new \RecursiveArrayIterator($language));
34 | $keys = [];
35 |
36 | foreach($iterator as $value) {
37 | $prefix = str_replace("\\", "|", $iterator->getPrefix());
38 |
39 | $index = strpos($prefix, "|-");
40 | if($index !== false) {
41 | $index = max(0, $index / 2);
42 | }
43 |
44 | if(count($keys) > $index) {
45 | $keys = array_slice($keys, 0, $index + 1);
46 | }
47 |
48 | $keys[$index] = $iterator->key();
49 | $entry = $iterator->getEntry();
50 |
51 | if($entry !== "Array") {
52 | $this->messages[implode(".", $keys)] = TextFormat::colorize($entry);
53 | }
54 | }
55 | }
56 |
57 | public function getLoader(): Loader {
58 | return $this->loader;
59 | }
60 |
61 | public function get(string $key): string {
62 | return $this->messages[$key] ?? $key;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/configurable/PetMessages.php:
--------------------------------------------------------------------------------
1 | getLoader()->getDataFolder() . "pet_messages.yml");
17 | $this->messages = $data;
18 | }
19 |
20 | public function getLoader(): Loader {
21 | return $this->loader;
22 | }
23 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/configurable/PetProperties.php:
--------------------------------------------------------------------------------
1 | saveResource("pet_properties.yml");
14 | $this->collectProperties();
15 | }
16 |
17 | public function collectProperties(): void {
18 | $data = yaml_parse_file($this->getLoader()->getDataFolder() . "pet_properties.yml");
19 | $this->properties = $data;
20 | }
21 |
22 | public function getLoader(): Loader {
23 | return $this->loader;
24 | }
25 |
26 | public function getPropertiesFor(string $entityType): array {
27 | if(!$this->propertiesExistFor($entityType)) {
28 | return [];
29 | }
30 | return $this->properties[$entityType];
31 | }
32 |
33 | public function propertiesExistFor(string $entityType): bool {
34 | if(isset($this->properties[$entityType])) {
35 | return true;
36 | }
37 | return false;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/BlockPetsEvent.php:
--------------------------------------------------------------------------------
1 | loader;
17 | }
18 |
19 | public function getPlugin(): Loader {
20 | return $this->loader;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetEvent.php:
--------------------------------------------------------------------------------
1 | pet;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetInventoryInitializationEvent.php:
--------------------------------------------------------------------------------
1 | pet->getPetOwnerName();
18 | }
19 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetLevelUpEvent.php:
--------------------------------------------------------------------------------
1 | from;
24 | }
25 |
26 | /**
27 | * Returns the pet level AFTER adding the levels.
28 | */
29 | public function getTo(): int {
30 | return $this->to;
31 | }
32 |
33 | /**
34 | * Sets the pet level AFTER adding points to the given parameter.
35 | */
36 | public function setTo(int $to): void {
37 | if($to < 1) {
38 | throw new \LogicException("Pet level cannot be negative.");
39 | }
40 |
41 | $this->to = $to;
42 | }
43 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetRemoveEvent.php:
--------------------------------------------------------------------------------
1 | pet->getPetOwnerName();
13 | }
14 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetRespawnEvent.php:
--------------------------------------------------------------------------------
1 | petData;
21 | }
22 |
23 | /**
24 | * Returns the delay in seconds for the pet to respawn.
25 | */
26 | public function getDelay(): int {
27 | return $this->delay;
28 | }
29 |
30 | /**
31 | * Sets the delay for a pet to respawn.
32 | */
33 | public function setDelay(int $secondsDelay): void {
34 | $this->delay = $secondsDelay;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/events/PetSpawnEvent.php:
--------------------------------------------------------------------------------
1 | pet->getPetOwner();
19 | }
20 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/items/Saddle.php:
--------------------------------------------------------------------------------
1 | getEntity();
33 | if($player instanceof Player) {
34 | if($event->getCause() === EntityDamageEvent::CAUSE_FALL) {
35 | if($this->getLoader()->isRidingAPet($player)) {
36 | $event->cancel();
37 | return;
38 | }
39 | }
40 | if($event instanceof EntityDamageByEntityEvent) {
41 | if($event->isCancelled()) {
42 | return;
43 | }
44 | $pets = $this->getLoader()->getPetsFrom($player);
45 | if(!empty($pets)) {
46 | foreach($pets as $pet) {
47 | if(!($pet instanceof IrasciblePet)) {
48 | continue;
49 | }
50 | $attacker = $event->getDamager();
51 | if($attacker instanceof Living) {
52 | $pet->setAngry($attacker);
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | public function getLoader(): Loader {
61 | return $this->loader;
62 | }
63 |
64 | /**
65 | * Used to respawn pets to the player, and fetch pets from the database if this has been configured.
66 | */
67 | public function onPlayerJoin(PlayerJoinEvent $event): void {
68 | $player = $event->getPlayer();
69 | $loader = $this->getLoader();
70 |
71 | if(!$loader->getBlockPetsConfig()->doHardReset()) {
72 | $loader->getDatabase()->load(
73 | $player->getName(),
74 | function(array $petData) use ($player, $loader): void {
75 | $hard_reset = $loader->getBlockPetsConfig()->doHardReset();
76 | foreach($petData as $data) {
77 | $pet = $loader->createPet(
78 | $data["EntityName"],
79 | $player,
80 | $data["PetName"],
81 | $data["PetSize"],
82 | (bool) $data["IsBaby"],
83 | $data["PetLevel"],
84 | $data["LevelPoints"],
85 | (bool) $data["Chested"],
86 | (bool) $data["Visible"],
87 | $data["Inventory"]
88 | );
89 | $pet->spawnToAll();
90 | $pet->setDormant(false);
91 | /** @phpstan-ignore-next-line */
92 | if($hard_reset) {
93 | $pet->close();
94 | }
95 | }
96 | }
97 | );
98 | }
99 | }
100 |
101 | /**
102 | * Used to select a name through chat. Allows for names with spaces and players to choose themselves.
103 | */
104 | public function onChat(PlayerChatEvent $event): void {
105 | $player = $event->getPlayer();
106 | $loader = $this->getLoader();
107 | if(isset($loader->selectingName[$player->getName()])) {
108 | $petName = $event->getMessage();
109 | $event->cancel();
110 | if($loader->getPetByName($petName, $player->getName()) !== null) {
111 | $player->sendMessage(TextFormat::RED . "[Warning] You already own a pet with that name. Please choose a different name.");
112 | return;
113 | }
114 | $data = $loader->selectingName[$player->getName()];
115 |
116 | $loader->createPet($data["petType"], $player, $petName, $data["scale"], $data["isBaby"]);
117 | $player->sendMessage(TextFormat::GREEN . "Successfully obtained a " . $data["petType"] . " with the name " . $event->getMessage());
118 | unset($loader->selectingName[$player->getName()]);
119 | }
120 | }
121 |
122 | public function onEntitySpawn(EntitySpawnEvent $event): void {
123 | $entity = $event->getEntity();
124 | if($entity instanceof BasePet) {
125 | $clearLaggPlugin = $this->getLoader()->getServer()->getPluginManager()->getPlugin("ClearLagg");
126 | if($clearLaggPlugin !== null) {
127 | /** @phpstan-ignore-next-line */
128 | $clearLaggPlugin->exemptEntity($entity);
129 | }
130 | }
131 | }
132 |
133 | public function onEntityDespawn(EntityDespawnEvent $event): void {
134 | $entity = $event->getEntity();
135 | if($entity instanceof BasePet) {
136 | if(!$this->loader->getBlockPetsConfig()->storeToDatabase()) {
137 | $this->loader->getDatabase()->unregisterPet($entity);
138 | $this->loader->removePet($entity, false);
139 | }
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/listeners/RidingListener.php:
--------------------------------------------------------------------------------
1 | getPacket();
25 | if($packet instanceof PlayerAuthInputPacket) {
26 | $loader = $this->getLoader();
27 | $player = $event->getOrigin()->getPlayer();
28 | if($loader->isRidingAPet($player)) {
29 | if(((int)$packet->getMoveVecX()) === 0 && ((int)$packet->getMoveVecZ()) === 0) {
30 | return;
31 | }
32 | $pet = $loader->getRiddenPet($player);
33 | if($pet->isClosed() || $pet->isFlaggedForDespawn()) {
34 | return;
35 | }
36 | $pet->doRidingMovement($packet->getMoveVecX(), $packet->getMoveVecZ());
37 | }
38 | } elseif($packet instanceof InteractPacket) {
39 | if($packet->action === InteractPacket::ACTION_LEAVE_VEHICLE) {
40 | $loader = $this->getLoader();
41 | $player = $event->getOrigin()->getPlayer();
42 | if($loader->isRidingAPet($player)) {
43 | $loader->getRiddenPet($player)->throwRiderOff();
44 | }
45 | }
46 | }
47 | }
48 |
49 | public function getLoader(): Loader {
50 | return $this->loader;
51 | }
52 |
53 | /**
54 | * Used to dismount the player if it warps, just like it does in vanilla.
55 | */
56 | public function onTeleport(EntityTeleportEvent $event): void {
57 | $player = $event->getEntity();
58 | if($player instanceof Player) {
59 | $loader = $this->getLoader();
60 | if($loader->isRidingAPet($player)) {
61 | $loader->getRiddenPet($player)->throwRiderOff();
62 | foreach($loader->getPetsFrom($player) as $pet) {
63 | $pet->dismountFromOwner();
64 | }
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * Used to dismount the player from the ridden pet. This does not matter for the player, but could have a significant effect on the pet's behaviour.
71 | */
72 | public function onPlayerQuit(PlayerQuitEvent $event): void {
73 | $loader = $this->getLoader();
74 | foreach($loader->getPetsFrom($event->getPlayer()) as $pet) {
75 | if($pet->isRidden()) {
76 | $pet->throwRiderOff();
77 | }
78 | $pet->close();
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/BouncingPet.php:
--------------------------------------------------------------------------------
1 | followRangeSq = 9 + $this->getScale();
19 | $this->jumpVelocity = $this->jumpHeight * 12 * $this->getScale();
20 | }
21 |
22 | public function doPetUpdates(int $currentTick): bool {
23 | if(!parent::doPetUpdates($currentTick)) {
24 | return false;
25 | }
26 |
27 | if($this->jumpTicks > 0) {
28 | --$this->jumpTicks;
29 | }
30 |
31 | if(!$this->isOnGround()) {
32 | if($this->motion->y > -$this->gravity * 2) {
33 | $this->motion->y = -$this->gravity * 2;
34 | } else {
35 | $this->motion->y -= $this->gravity;
36 | }
37 | } else {
38 | $this->motion->y -= $this->gravity;
39 | }
40 |
41 | if($this->isRidden()) {
42 | return false;
43 | }
44 |
45 | if($this->isAngry()) {
46 | $this->doAttackingMovement();
47 | } else {
48 | $this->follow($this->getPetOwner(), $this->xOffset, 0.0, $this->zOffset);
49 | }
50 |
51 | $this->updateMovement();
52 | return true;
53 | }
54 |
55 | public function doAttackingMovement(): void {
56 | if(!$this->checkAttackRequirements()) {
57 | return;
58 | }
59 |
60 | $target = $this->getTarget();
61 | $this->follow($target);
62 |
63 | if($this->location->distance($target->location) <= $this->scale + 1 && $this->waitingTime <= 0) {
64 | $event = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $this->getAttackDamage());
65 | $target->attack($event);
66 |
67 | if(!$event->isCancelled() && !$target->isAlive()) {
68 | if($target instanceof Player) {
69 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getPlayerExperiencePoints());
70 | } else {
71 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getEntityExperiencePoints());
72 | }
73 | $this->calmDown();
74 | }
75 |
76 | $this->waitingTime = 12;
77 | } elseif($this->location->distance($this->getPetOwner()->location) > 25 || $this->location->distance($this->getTarget()->location) > 15) {
78 | $this->calmDown();
79 | }
80 |
81 | --$this->waitingTime;
82 | }
83 |
84 | public function jump(): void {
85 | parent::jump();
86 | $this->jumpTicks = 10;
87 | }
88 |
89 | public function doRidingMovement(float $motionX, float $motionZ): void {
90 | $rider = $this->getPetOwner();
91 |
92 | $this->location->pitch = $rider->location->pitch;
93 | $this->location->yaw = $rider->location->yaw;
94 |
95 | $speed_factor = 2 * $this->getSpeed();
96 | $direction_plane = $this->getDirectionPlane();
97 | $x = $direction_plane->x / $speed_factor;
98 | $z = $direction_plane->y / $speed_factor;
99 |
100 | if($this->jumpTicks > 0) {
101 | $this->jumpTicks--;
102 | }
103 |
104 | if(!$this->isOnGround()) {
105 | if($this->motion->y > -$this->gravity * 2) {
106 | $this->motion->y = -$this->gravity * 2;
107 | } else {
108 | $this->motion->y -= $this->gravity;
109 | }
110 | } else {
111 | $this->motion->y -= $this->gravity;
112 | }
113 |
114 | $finalMotionX = 0;
115 | $finalMotionZ = 0;
116 |
117 | switch($motionZ) {
118 | case 1:
119 | $finalMotionX = $x;
120 | $finalMotionZ = $z;
121 | if($this->isOnGround()) {
122 | $this->jump();
123 | }
124 | break;
125 | case 0:
126 | if($this->isOnGround()) {
127 | $this->jump();
128 | }
129 | break;
130 | case -1:
131 | $finalMotionX = -$x;
132 | $finalMotionZ = -$z;
133 | if($this->isOnGround()) {
134 | $this->jump();
135 | }
136 | break;
137 | default:
138 | $average = $x + $z / 2;
139 | $finalMotionX = $average / 1.414 * $motionZ;
140 | $finalMotionZ = $average / 1.414 * $motionX;
141 | if($this->isOnGround()) {
142 | $this->jump();
143 | }
144 | break;
145 | }
146 |
147 | switch($motionX) {
148 | case 1:
149 | $finalMotionX = $z;
150 | $finalMotionZ = -$x;
151 | if($this->isOnGround()) {
152 | $this->jump();
153 | }
154 | break;
155 | case 0:
156 | if($this->isOnGround()) {
157 | $this->jump();
158 | }
159 | break;
160 | case -1:
161 | $finalMotionX = -$z;
162 | $finalMotionZ = $x;
163 | if($this->isOnGround()) {
164 | $this->jump();
165 | }
166 | break;
167 | }
168 |
169 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
170 | $this->updateMovement();
171 | }
172 |
173 | public function attack(EntityDamageEvent $source): void {
174 | if($source->getCause() === $source::CAUSE_FALL) {
175 | $source->cancel();
176 | }
177 | parent::attack($source);
178 | }
179 |
180 | public function useProperties(array $properties): void {
181 | parent::useProperties($properties);
182 | $this->jumpHeight = (float) $properties["Jumping-Height"];
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/Calculator.php:
--------------------------------------------------------------------------------
1 | recalculateHealth();
18 | $this->recalculateSize();
19 | $this->recalculateDamage();
20 | $this->updateNameTag();
21 | }
22 |
23 | /**
24 | * Recalculates maximum health that the pet should have according to its configuration scalings.
25 | */
26 | public function recalculateHealth(): void {
27 | $pet = $this->getPet();
28 | $bpConfig = $pet->getLoader()->getBlockPetsConfig();
29 |
30 | $petLevel = $pet->getPetLevel();
31 | $baseHealth = $bpConfig->getBasePetHealth();
32 | $scalingHealth = $bpConfig->getPetHealthPerLevel();
33 |
34 | $pet->setMaxHealth((int) floor($baseHealth + $scalingHealth * $petLevel));
35 | $pet->fullHeal();
36 | }
37 |
38 | /**
39 | * @return BasePet
40 | */
41 | public function getPet(): BasePet {
42 | return $this->pet;
43 | }
44 |
45 | /**
46 | * Recalculates size that the pet should have according to its configuration scalings.
47 | */
48 | public function recalculateSize(): bool {
49 | $pet = $this->getPet();
50 | $petOwner = $pet->getPetOwner();
51 | if($petOwner === null) {
52 | return false;
53 | }
54 |
55 | if($pet->getScale() > $pet->getMaxSize() && !($petOwner->hasPermission("blockpets.bypass-size-limit"))) {
56 | $pet->setScale($pet->getMaxSize());
57 | } else {
58 | $petLevel = $pet->getPetLevel();
59 | $scalingSize = $pet->getLoader()->getBlockPetsConfig()->getPetSizePerLevel();
60 | $pet->setScale((float) ($pet->getStartingScale() + $scalingSize * $petLevel));
61 | }
62 | return true;
63 | }
64 |
65 | /**
66 | * Recalculates attack damage that the pet should have according to its configuration attack damage.
67 | */
68 | public function recalculateDamage(): void {
69 | $pet = $this->getPet();
70 | $bpConfig = $pet->getLoader()->getBlockPetsConfig();
71 |
72 | $petLevel = $pet->getPetLevel();
73 | $baseDamage = $bpConfig->getBasePetDamage();
74 | $scalingDamage = $bpConfig->getPetDamagePerLevel();
75 |
76 | $pet->setAttackDamage((int) round($baseDamage + $scalingDamage * $petLevel));
77 | }
78 |
79 | /**
80 | * Updates the name tag to include the latest data like level, level points etc.
81 | */
82 | public function updateNameTag(): void {
83 | $pet = $this->getPet();
84 | $percentage = round($pet->getPetLevelPoints() / LevelCalculator::getRequiredLevelPoints($pet->getPetLevel()) * 100, 1);
85 | $pet->setNameTag(
86 | $pet->getPetName() . "\n" .
87 | TextFormat::GRAY . "Lvl." . TextFormat::AQUA . $pet->getPetLevel() . TextFormat::GRAY . " (" . TextFormat::YELLOW . $percentage . TextFormat::GRAY . "%) " . TextFormat::GRAY . $pet->getName() .
88 | TextFormat::RED . " (" . $pet->getHealth() . "/" . $pet->getMaxHealth() . ")"
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/HoveringPet.php:
--------------------------------------------------------------------------------
1 | followRangeSq = 8 + $this->getScale();
27 | }
28 |
29 | public function doPetUpdates(int $currentTick): bool {
30 | if(!parent::doPetUpdates($currentTick)) {
31 | return false;
32 | }
33 |
34 | if($this->isRidden()) {
35 | return false;
36 | }
37 |
38 | if($this->isAngry()) {
39 | $this->doAttackingMovement();
40 | } else {
41 | $this->follow($this->getPetOwner(), $this->xOffset, abs($this->yOffset) + 1.5, $this->zOffset);
42 | }
43 |
44 | $this->updateMovement();
45 | return true;
46 | }
47 |
48 | public function follow(Entity $target, float $xOffset = 0.0, float $yOffset = 0.0, float $zOffset = 0.0): void {
49 | $targetLoc = $target->getLocation();
50 | $currLoc = $this->getLocation();
51 |
52 | $x = $targetLoc->getX() + $xOffset - $currLoc->getX();
53 | $y = $targetLoc->getY() + $yOffset - $currLoc->getY();
54 | $z = $targetLoc->getZ() + $zOffset - $currLoc->getZ();
55 |
56 | $xz_sq = $x * $x + $z * $z;
57 | $xz_modulus = sqrt($xz_sq);
58 |
59 | if($xz_sq < $this->followRangeSq) {
60 | $this->motion->x = 0;
61 | $this->motion->z = 0;
62 | } else {
63 | $speed_factor = $this->getSpeed() * 0.15;
64 | $this->motion->x = $speed_factor * ($x / $xz_modulus);
65 | $this->motion->z = $speed_factor * ($z / $xz_modulus);
66 | }
67 |
68 | if((float) $y !== 0.0) {
69 | $this->motion->y = $this->getSpeed() * 0.25 * $y;
70 | }
71 |
72 | $this->location->yaw = rad2deg(atan2(-$x, $z));
73 | $this->location->pitch = rad2deg(-atan2($y, $xz_modulus));
74 |
75 | if(static::getNetworkTypeId() === EntityIds::ENDER_DRAGON) {
76 | $this->location->yaw += 180;
77 | }
78 |
79 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
80 | }
81 |
82 | public function doAttackingMovement(): void {
83 | if(!$this->checkAttackRequirements()) {
84 | return;
85 | }
86 |
87 | $target = $this->getTarget();
88 | $this->follow($target, 0.0, 0.5, 0.0);
89 |
90 | if($this->location->distance($target->location) <= $this->scale + 1.1 && $this->waitingTime <= 0 && $target->isAlive()) {
91 | $event = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $this->getAttackDamage());
92 | $target->attack($event);
93 |
94 | if(!$event->isCancelled() && !$target->isAlive()) {
95 | if($target instanceof Player) {
96 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getPlayerExperiencePoints());
97 | } else {
98 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getEntityExperiencePoints());
99 | }
100 | $this->calmDown();
101 | }
102 |
103 | $this->waitingTime = 12;
104 | } elseif($this->location->distance($this->getPetOwner()->location) > 25 || $this->location->distance($this->getTarget()->location) > 15) {
105 | $this->calmDown();
106 | }
107 |
108 | --$this->waitingTime;
109 | }
110 |
111 | public function doRidingMovement(float $motionX, float $motionZ): void {
112 | $rider = $this->getPetOwner();
113 |
114 | $this->location->pitch = $rider->location->pitch;
115 | $this->location->yaw = $this instanceof EnderDragonPet ? $rider->location->yaw + 180 : $rider->location->yaw;
116 |
117 | $speed_factor = 2 * $this->getSpeed();
118 | $rider_directionvec = $rider->getDirectionVector();
119 | $x = $rider_directionvec->x / $speed_factor;
120 | $z = $rider_directionvec->z / $speed_factor;
121 | $y = $rider_directionvec->y / $speed_factor;
122 |
123 | $finalMotionX = 0;
124 | $finalMotionZ = 0;
125 |
126 | switch($motionZ) {
127 | case 1:
128 | $finalMotionX = $x;
129 | $finalMotionZ = $z;
130 | break;
131 | case 0:
132 | break;
133 | case -1:
134 | $finalMotionX = -$x;
135 | $finalMotionZ = -$z;
136 | break;
137 | default:
138 | $average = $x + $z / 2;
139 | $finalMotionX = $average / 1.414 * $motionZ;
140 | $finalMotionZ = $average / 1.414 * $motionX;
141 | break;
142 | }
143 |
144 | switch($motionX) {
145 | case 1:
146 | $finalMotionX = $z;
147 | $finalMotionZ = -$x;
148 | break;
149 | case 0:
150 | break;
151 | case -1:
152 | $finalMotionX = -$z;
153 | $finalMotionZ = $x;
154 | break;
155 | }
156 |
157 | if(((float) $y) !== 0.0) {
158 | if($y < 0) {
159 | $this->motion->y = $this->getSpeed() * 0.3 * $y;
160 | } elseif($this->location->y - $this->getWorld()->getHighestBlockAt((int) $this->location->x, (int) $this->location->z) < $this->flyHeight) {
161 | $this->motion->y = $this->getSpeed() * 0.3 * $y;
162 | }
163 | }
164 | if(abs($y) < 0.2) {
165 | $this->motion->y = 0;
166 | }
167 |
168 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
169 | $this->updateMovement();
170 | }
171 |
172 | public function attack(EntityDamageEvent $source): void {
173 | if($source->getCause() === $source::CAUSE_FALL) {
174 | $source->cancel();
175 | }
176 | parent::attack($source);
177 | }
178 |
179 | public function useProperties(array $properties): void {
180 | parent::useProperties($properties);
181 | $this->flyHeight = (float) $properties["Flying-Height"];
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/IrasciblePet.php:
--------------------------------------------------------------------------------
1 | closed || !$this->isAlive()) {
26 | return;
27 | }
28 | $bpConfig = $this->getLoader()->getBlockPetsConfig();
29 | if($bpConfig->arePetsInvulnerable()) {
30 | $source->cancel();
31 | }
32 | if($this->isRidden() && $source->getCause() === $source::CAUSE_FALL) {
33 | $source->cancel();
34 | }
35 | if($bpConfig->arePetsInvulnerableIfOwnerIs() && ($petOwner = $this->getPetOwner()) !== null) {
36 | $ownerDamageEvent = new EntityDamageEvent($petOwner, EntityDamageEvent::CAUSE_CUSTOM, 0);
37 | $ownerDamageEvent->call();
38 | if($ownerDamageEvent->isCancelled()) {
39 | $source->cancel();
40 | }
41 | $ownerDamageEvent->cancel();
42 | }
43 | if($source instanceof EntityDamageByEntityEvent) {
44 | $attacker = $source->getDamager();
45 | if(!$bpConfig->arePetsInvulnerable()) {
46 | if($attacker instanceof Player) {
47 | $nameTag = $attacker->getName();
48 | } else {
49 | $nameTag = $attacker->getNameTag();
50 | }
51 | if($nameTag === $this->getPetOwnerName()) {
52 | $source->cancel();
53 | }
54 | if($bpConfig->petsDoAttack() && $attacker instanceof Living && !$source->isCancelled()) {
55 | $this->setAngry($attacker);
56 | }
57 | }
58 | if($attacker instanceof Player && !$attacker->isSneaking() && $this->canBeRidden && $attacker->getName() === $this->getPetOwnerName()) {
59 | $item = $attacker->getInventory()->getItemInHand();
60 | if($item->getId() === ItemIds::SADDLE) {
61 | $this->setRider($attacker);
62 | $attacker->sendTip(TextFormat::GRAY . "Crouch or jump to dismount...");
63 | $source->cancel();
64 | }
65 | }
66 | }
67 | parent::attack($source);
68 | }
69 |
70 | /**
71 | * Sets the pet angry and it's target to the given entity, making it chase the entity.
72 | */
73 | public function setAngry(Living $entity): bool {
74 | if(!$this->canAttack) {
75 | return false;
76 | }
77 | $this->target = $entity;
78 | if($this instanceof ArrowPet) {
79 | $this->setCritical();
80 | }
81 | return true;
82 | }
83 |
84 | public function doAttackingMovement(): void {
85 | if(!$this->checkAttackRequirements()) {
86 | return;
87 | }
88 |
89 | $target = $this->getTarget();
90 | $this->follow($target);
91 |
92 | if($this->location->distance($target->location) <= $this->scale + 0.5 && $this->waitingTime <= 0) {
93 | $event = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $this->getAttackDamage());
94 | $target->attack($event);
95 |
96 | if(!$event->isCancelled() && !$target->isAlive()) {
97 | if($target instanceof Player) {
98 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getPlayerExperiencePoints());
99 | } else {
100 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getEntityExperiencePoints());
101 | }
102 | $this->calmDown();
103 | }
104 |
105 | $this->waitingTime = 12;
106 | } elseif($this->location->distance($this->getPetOwner()->location) > 25 || $this->location->distance($target->location) > 15) {
107 | $this->calmDown();
108 | }
109 |
110 | --$this->waitingTime;
111 | }
112 |
113 | public function follow(Entity $target, float $xOffset = 0.0, float $yOffset = 0.0, float $zOffset = 0.0): void {
114 | $targetLoc = $target->getLocation();
115 | $currLoc = $this->getLocation();
116 |
117 | $x = $targetLoc->getX() + $xOffset - $currLoc->getX();
118 | $y = $targetLoc->getY() + $yOffset - $currLoc->getY();
119 | $z = $targetLoc->getZ() + $zOffset - $currLoc->getZ();
120 |
121 | $xz_sq = $x * $x + $z * $z;
122 | $xz_modulus = sqrt($xz_sq);
123 |
124 | if($xz_sq < $this->followRangeSq) {
125 | $this->motion->x = 0;
126 | $this->motion->z = 0;
127 | } else {
128 | $speed_factor = $this->getSpeed() * 0.15;
129 | $this->motion->x = $speed_factor * ($x / $xz_modulus);
130 | $this->motion->z = $speed_factor * ($z / $xz_modulus);
131 | }
132 | $this->location->yaw = rad2deg(atan2(-$x, $z));
133 | $this->location->pitch = rad2deg(-atan2($y, $xz_modulus));
134 |
135 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
136 | }
137 |
138 | protected function checkAttackRequirements(): bool {
139 | if($this->closed || !($this->isAlive()) || !($this->isAngry()) || $this->isFlaggedForDespawn()) {
140 | $this->calmDown();
141 | return false;
142 | }
143 | if(!$this->getTarget()->isAlive()) {
144 | $this->calmDown();
145 | return false;
146 | }
147 | return true;
148 | }
149 |
150 | /**
151 | * Returns whether this pet is angry or not.
152 | */
153 | public function isAngry(): bool {
154 | return $this->target !== null;
155 | }
156 |
157 | /**
158 | * Calms down the pet, making it stop chasing it's target.
159 | */
160 | public function calmDown(): void {
161 | $this->target = null;
162 | if($this instanceof ArrowPet) {
163 | $this->setCritical(false);
164 | }
165 | }
166 |
167 | /**
168 | * Returns the current target of this pet.
169 | */
170 | public function getTarget(): ?Living {
171 | return $this->target;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/LevelCalculator.php:
--------------------------------------------------------------------------------
1 | ($req = self::getRequiredLevelPoints($level + $levelled))) {
27 | ++$levelled;
28 | $remaining -= $req;
29 | }
30 |
31 | return $levelled;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/PetData.php:
--------------------------------------------------------------------------------
1 | petId;
27 | }
28 |
29 | public function getOwnerName(): string {
30 | return $this->ownerName;
31 | }
32 |
33 | public function getOwner(): ?Player {
34 | return Server::getInstance()->getPlayerExact($this->ownerName);
35 | }
36 |
37 | public function getPetName(): string {
38 | return $this->petName;
39 | }
40 |
41 | public function setPetName(string $petName): PetData {
42 | $this->petName = $petName;
43 | return $this;
44 | }
45 |
46 | public function getScale(): float {
47 | return $this->scale;
48 | }
49 |
50 | public function setScale(float $scale): PetData {
51 | $this->scale = $scale;
52 | return $this;
53 | }
54 |
55 | public function isBaby(): bool {
56 | return $this->isBaby;
57 | }
58 |
59 | public function setBaby(bool $isBaby): PetData {
60 | $this->isBaby = $isBaby;
61 | return $this;
62 | }
63 |
64 | public function getLevel(): int {
65 | return $this->level;
66 | }
67 |
68 | public function setLevel(int $level): PetData {
69 | $this->level = $level;
70 | return $this;
71 | }
72 |
73 | public function getLevelPoints(): int {
74 | return $this->levelPoints;
75 | }
76 |
77 | public function setLevelPoints(int $levelPoints): PetData {
78 | $this->levelPoints = $levelPoints;
79 | return $this;
80 | }
81 |
82 | public function isChested(): bool {
83 | return $this->chested;
84 | }
85 |
86 | public function setChested(bool $chested): PetData {
87 | $this->chested = $chested;
88 | return $this;
89 | }
90 |
91 | public function isVisible(): bool {
92 | return $this->isVisible;
93 | }
94 |
95 | public function setVisible(bool $isVisible): PetData {
96 | $this->isVisible = $isVisible;
97 | return $this;
98 | }
99 |
100 | public function getInventory(): ?string {
101 | return $this->inventory;
102 | }
103 |
104 | public function setInventory(?string $inventory): PetData {
105 | $this->inventory = $inventory;
106 | return $this;
107 | }
108 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/PetIds.php:
--------------------------------------------------------------------------------
1 | isAngry() && $this->isUnderwater()) {
26 | $petOwner = $this->getPetOwner();
27 | $ownerLoc = $petOwner->getLocation();
28 | $currLoc = $this->getLocation();
29 |
30 | $x = $ownerLoc->getX() + $this->xOffset - $currLoc->getX();
31 | $y = $ownerLoc->getY() + $this->yOffset - $currLoc->getY();
32 | $z = $ownerLoc->getZ() + $this->zOffset - $currLoc->getZ();
33 |
34 | $xz_sq = $x * $x + $z * $z;
35 | $xz_modulus = sqrt($xz_sq);
36 | $speed_factor = $this->getSwimmingSpeed() * 0.25;
37 |
38 | if($xz_sq < 6 + $this->getScale()) {
39 | $this->motion->x = 0;
40 | $this->motion->z = 0;
41 | } else {
42 | $this->motion->x = $speed_factor * ($x / $xz_modulus);
43 | $this->motion->z = $speed_factor * ($z / $xz_modulus);
44 | }
45 | $this->motion->y = $speed_factor * $y;
46 | $this->location->yaw = rad2deg(atan2(-$x, $z));
47 | $this->location->pitch = rad2deg(-atan2($y, $xz_modulus));
48 |
49 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
50 |
51 | $this->updateMovement();
52 | return true;
53 | }
54 |
55 | return true;
56 | }
57 |
58 | public function follow(Entity $target, float $xOffset = 0.0, float $yOffset = 0.0, float $zOffset = 0.0): void {
59 | $targetLoc = $target->getLocation();
60 | $currLoc = $this->getLocation();
61 |
62 | $x = $targetLoc->getX() + $xOffset - $currLoc->getX();
63 | $y = $targetLoc->getY() + $yOffset - $currLoc->getY();
64 | $z = $targetLoc->getZ() + $zOffset - $currLoc->getZ();
65 |
66 | $xz_sq = $x * $x + $z * $z;
67 | $xz_modulus = sqrt($xz_sq);
68 |
69 | if($xz_sq < $this->followRangeSq) {
70 | $this->motion->x = 0;
71 | $this->motion->z = 0;
72 | } else {
73 | $speed_factor = $this->getSwimmingSpeed() * 0.15;
74 | $this->motion->x = $speed_factor * ($x / $xz_modulus);
75 | $this->motion->z = $speed_factor * ($z / $xz_modulus);
76 | }
77 |
78 | if($y !== 0.0) {
79 | $this->motion->y = $this->getSwimmingSpeed() * 0.15 * $y;
80 | }
81 |
82 | $this->location->yaw = rad2deg(atan2(-$x, $z));
83 | $this->location->pitch = rad2deg(-atan2($y, $xz_modulus));
84 |
85 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
86 | }
87 |
88 | public function doAttackingMovement(): void {
89 | if(!$this->checkAttackRequirements()) {
90 | return;
91 | }
92 |
93 | if($this->isUnderwater()) {
94 | $target = $this->getTarget();
95 | $this->follow($target);
96 |
97 | if($this->location->distance($target->location) <= $this->scale + 0.5 && $this->waitingTime <= 0) {
98 | $event = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $this->getAttackDamage());
99 | $target->attack($event);
100 |
101 | if(!$event->isCancelled() && !$target->isAlive()) {
102 | if($target instanceof Player) {
103 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getPlayerExperiencePoints());
104 | } else {
105 | $this->addPetLevelPoints($this->getLoader()->getBlockPetsConfig()->getEntityExperiencePoints());
106 | }
107 | $this->calmDown();
108 | }
109 |
110 | $this->waitingTime = 12;
111 | } elseif($this->location->distance($this->getPetOwner()->location) > 25 || $this->location->distance($target->location) > 15) {
112 | $this->calmDown();
113 | }
114 |
115 | --$this->waitingTime;
116 | return;
117 | }
118 |
119 | parent::doAttackingMovement();
120 | }
121 |
122 | public function getSwimmingSpeed(): float {
123 | return $this->swimmingSpeed;
124 | }
125 |
126 | public function doRidingMovement(float $motionX, float $motionZ): void {
127 | if($this->isUnderwater()) {
128 | $rider = $this->getRider();
129 |
130 | $this->location->pitch = $rider->location->pitch;
131 | $this->location->yaw = $rider->location->yaw;
132 |
133 | $speed_factor = 2 * $this->getSwimmingSpeed();
134 | $rider_directionvec = $rider->getDirectionVector();
135 | $x = $rider_directionvec->x / $speed_factor;
136 | $z = $rider_directionvec->z / $speed_factor;
137 | $y = $rider_directionvec->y / $speed_factor;
138 |
139 | $finalMotionX = 0;
140 | $finalMotionZ = 0;
141 |
142 | switch($motionZ) {
143 | case 1:
144 | $finalMotionX = $x;
145 | $finalMotionZ = $z;
146 | break;
147 | case 0:
148 | break;
149 | case -1:
150 | $finalMotionX = -$x;
151 | $finalMotionZ = -$z;
152 | break;
153 | default:
154 | $average = $x + $z / 2;
155 | $finalMotionX = $average / 1.414 * $motionZ;
156 | $finalMotionZ = $average / 1.414 * $motionX;
157 | break;
158 | }
159 |
160 | switch($motionX) {
161 | case 1:
162 | $finalMotionX = $z;
163 | $finalMotionZ = -$x;
164 | break;
165 | case 0:
166 | break;
167 | case -1:
168 | $finalMotionX = -$z;
169 | $finalMotionZ = $x;
170 | break;
171 | }
172 |
173 | if(((float) $y) !== 0.0) {
174 | $this->motion->y = $this->getSwimmingSpeed() * 0.25 * $y;
175 | }
176 | if(abs($y) < 0.1) {
177 | $this->motion->y = 0;
178 | }
179 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
180 |
181 | $this->updateMovement();
182 | return;
183 | }
184 |
185 | parent::doRidingMovement($motionX, $motionZ);
186 | }
187 |
188 | public function useProperties(array $properties): void {
189 | parent::useProperties($properties);
190 | $this->swimmingSpeed = (float) $properties["Swimming-Speed"];
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/WalkingPet.php:
--------------------------------------------------------------------------------
1 | jumpVelocity = $this->gravity * 10;
15 | }
16 |
17 | public function doPetUpdates(int $currentTick): bool {
18 | if(!parent::doPetUpdates($currentTick)) {
19 | return false;
20 | }
21 |
22 | if($this->jumpTicks > 0) {
23 | --$this->jumpTicks;
24 | }
25 |
26 | if(!$this->isOnGround()) {
27 | if($this->motion->y > -$this->gravity * 4) {
28 | $this->motion->y = -$this->gravity * 4;
29 | } else {
30 | $this->motion->y += $this->isUnderwater() ? $this->gravity : -$this->gravity;
31 | }
32 | } else {
33 | if($this->isCollidedHorizontally && $this->jumpTicks === 0) {
34 | $this->jump();
35 | } else {
36 | $this->motion->y -= $this->gravity;
37 | }
38 | }
39 |
40 | if($this->isRidden()) {
41 | return false;
42 | }
43 |
44 | if($this->isAngry()) {
45 | $this->doAttackingMovement();
46 | } else {
47 | $this->follow($this->getPetOwner(), $this->xOffset, 0.0, $this->zOffset);
48 | }
49 |
50 | $this->updateMovement();
51 | return true;
52 | }
53 |
54 | public function jump(): void {
55 | parent::jump();
56 | $this->jumpTicks = 5;
57 | }
58 |
59 | public function doRidingMovement(float $motionX, float $motionZ): void {
60 | $rider = $this->getPetOwner();
61 |
62 | $this->location->pitch = $rider->location->pitch;
63 | $this->location->yaw = $rider->location->yaw;
64 |
65 | $speed_factor = 2.5 * $this->getSpeed();
66 | $direction_plane = $this->getDirectionPlane();
67 | $x = $direction_plane->x / $speed_factor;
68 | $z = $direction_plane->y / $speed_factor;
69 |
70 | switch($motionZ) {
71 | case 1:
72 | $finalMotionX = $x;
73 | $finalMotionZ = $z;
74 | break;
75 | case -1:
76 | $finalMotionX = -$x;
77 | $finalMotionZ = -$z;
78 | break;
79 | default:
80 | $average = $x + $z / 2;
81 | $finalMotionX = $average / 1.414 * $motionZ;
82 | $finalMotionZ = $average / 1.414 * $motionX;
83 | break;
84 | }
85 |
86 | switch($motionX) {
87 | case 1:
88 | $finalMotionX = $z;
89 | $finalMotionZ = -$x;
90 | break;
91 | case -1:
92 | $finalMotionX = -$z;
93 | $finalMotionZ = $x;
94 | break;
95 | }
96 |
97 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
98 | $this->updateMovement();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/AllayPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setGenericFlag(EntityMetadataFlags::CRITICAL, $value);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/AxolotlPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setGenericFlag(EntityMetadataFlags::CAN_CLIMB, true);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/ChickenPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setGenericFlag(EntityMetadataFlags::ELDER, true);
27 | }
28 |
29 | public function attack(EntityDamageEvent $source): void {
30 | if($source instanceof EntityDamageByEntityEvent) {
31 | $attacker = $source->getDamager();
32 | if($attacker instanceof Player && random_int(0, 1)) {
33 | $attacker->getNetworkSession()->sendDataPacket(LevelEventPacket::create(2006, 0, $attacker->getLocation()));
34 | }
35 | }
36 | parent::attack($source);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/EnderCrystalPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setGenericFlag(EntityMetadataFlags::EVOKER_SPELL, (bool) $isCasting);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/FoxPet.php:
--------------------------------------------------------------------------------
1 | setVariant($this->getRandomType(), $this->getRandomColor());
38 | }
39 |
40 | public function getRandomType(): int {
41 | return array_rand([
42 | self::TYPE_NONE,
43 | self::TYPE_WHITE,
44 | self::TYPE_WHITE_FIELD,
45 | self::TYPE_WHITE_DOTS,
46 | self::TYPE_BLACK_DOTS
47 | ]);
48 | }
49 |
50 | public function getRandomColor(): int {
51 | return array_rand([
52 | self::COLOR_WHITE,
53 | self::COLOR_CREAMY,
54 | self::COLOR_CHESTNUT,
55 | self::COLOR_BROWN,
56 | self::COLOR_BLACK,
57 | self::COLOR_GRAY,
58 | self::COLOR_DARKBROWN
59 | ]);
60 | }
61 |
62 | public function getVariant(): int {
63 | return $this->variant;
64 | }
65 |
66 | public function setVariant(int $type, int $colour): void {
67 | $this->variant = $colour | $type << 8;
68 | $this->getNetworkProperties()->setInt(EntityMetadataProperties::VARIANT, $colour | $type << 8);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/HuskPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setInt(EntityMetadataProperties::VARIANT, $randomVariant);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/MagmaCubePet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setInt(EntityMetadataProperties::VARIANT, $randomVariant);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/PigPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setInt(EntityMetadataProperties::VARIANT, $randomVariant);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/SheepPet.php:
--------------------------------------------------------------------------------
1 | setColor(random_int(0, 15));
23 | }
24 |
25 | public function setColor(int $color): void {
26 | $this->color = $color % 16;
27 | $this->getNetworkProperties()->setByte(EntityMetadataProperties::COLOR, $color % 16);
28 | }
29 |
30 | public function getColor(): int {
31 | return $this->color;
32 | }
33 |
34 | public function doPetUpdates(int $currentTick): bool {
35 | if($currentTick % 10 === 0 && $this->getPetName() === "jeb_") {
36 | $this->setColor($this->getColor() + 1);
37 | }
38 | return parent::doPetUpdates($currentTick);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/SilverFishPet.php:
--------------------------------------------------------------------------------
1 | getPetName() !== "shoghicp") {
22 | return;
23 | }
24 | $this->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::SHEARED, true);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/SpiderPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setGenericFlag(EntityMetadataFlags::CAN_CLIMB, true);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/SquidPet.php:
--------------------------------------------------------------------------------
1 | canCollide = false;
22 | }
23 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/VillagerPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setInt(EntityMetadataProperties::VARIANT, $randomVariant);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/VindicatorPet.php:
--------------------------------------------------------------------------------
1 | getNetworkProperties()->setLong(EntityMetadataProperties::OWNER_EID, $eid);
25 | $this->getNetworkProperties()->setByte(EntityMetadataProperties::COLOR, $randomColour);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/creatures/ZombieHorsePet.php:
--------------------------------------------------------------------------------
1 | prepare();
13 | if($loader->getBlockPetsConfig()->doHardReset()) {
14 | $this->reset();
15 | $this->getLoader()->getConfig()->set("Hard-Reset", false);
16 | }
17 | }
18 |
19 | /**
20 | * Called during class construction to let
21 | * databases create and initialize their
22 | * instances.
23 | */
24 | protected abstract function prepare(): void;
25 |
26 | /**
27 | * Called when the plugin updates so database
28 | * can perform patches (if any).
29 | */
30 | public abstract function patch(string $version): void;
31 |
32 | protected function getLoader(): Loader {
33 | return $this->loader;
34 | }
35 |
36 | /**
37 | * Resets all values in the database.
38 | */
39 | protected abstract function reset(): void;
40 |
41 | /**
42 | * Registers pet to the database.
43 | * If the pet's entry already exists in the
44 | * database, the database will perform an
45 | * UPDATE-ALL-VALUES instead.
46 | */
47 | public abstract function registerPet(BasePet $pet): void;
48 |
49 | /**
50 | * Deletes the pet's entry from the database
51 | * if exists.
52 | */
53 | public abstract function unregisterPet(BasePet $pet): void;
54 |
55 | /**
56 | * Updates pet's level and level points if it's
57 | * entry exists in the database.
58 | */
59 | public abstract function updateExperience(BasePet $pet): void;
60 |
61 | /**
62 | * Retrieves all of the owner's pets from the
63 | * database and then calls the callable to
64 | * initialize the fetched entries.
65 | */
66 | public abstract function load(string $ownerName, callable $callable): void;
67 |
68 | /**
69 | * Fetches all pets' names of the specified player
70 | * from the database and calls the callable to get
71 | * the list of pet names.
72 | * If $entityName is not null, only entities with the
73 | * specified entity name will be fetched.
74 | */
75 | public abstract function getPlayerPets(string $ownerName, ?string $entityName = null, callable $callable = null): void;
76 |
77 | /**
78 | * Fetches all pets sorted by their level and points
79 | * and calls the callable to get the list of sorted
80 | * pets.
81 | * If $entityName is not null, only entities with the
82 | * specified entity name will be fetched.
83 | */
84 | public abstract function getPetsLeaderboard(int $offset = 0, int $length = 1, ?string $entityName = null, callable $callable = null): void;
85 |
86 | /**
87 | * Toggles pets on or off from the database.
88 | */
89 | public abstract function togglePets(string $owner, ?string $petName, callable $callable): void;
90 |
91 | /**
92 | * Updates the database with whether the pet is
93 | * chested or not.
94 | */
95 | public abstract function updateChested(BasePet $pet): void;
96 |
97 | /**
98 | * Updates the database with the pet's inventory
99 | * contents.
100 | */
101 | public abstract function updateInventory(BasePet $pet): void;
102 |
103 | /**
104 | * Called during plugin disable to let databases
105 | * close their instances.
106 | */
107 | protected abstract function close(): void;
108 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/datastorage/MySQLDataStorer.php:
--------------------------------------------------------------------------------
1 | database->executeChange(SQLDataStorer::REGISTER_PET, [
36 | "player" => $pet->getPetOwnerName(),
37 | "petname" => $pet->getPetName(),
38 | "entityname" => $pet->getEntityType(),
39 | "petsize" => $pet->getScale(),
40 | "isbaby" => (int) $pet->isBaby(),
41 | "chested" => (int) $pet->isChested(),
42 | "petlevel" => $pet->getPetLevel(),
43 | "levelpoints" => $pet->getPetLevelPoints()
44 | ]);
45 | }
46 |
47 | public function unregisterPet(BasePet $pet): void {
48 | $this->database->executeChange(SQLDataStorer::UNREGISTER_PET, [
49 | "player" => $pet->getPetOwnerName(),
50 | "petname" => $pet->getPetName()
51 | ]);
52 | }
53 |
54 | public function load(string $player, callable $callable): void {
55 | $this->database->executeSelect(SQLDataStorer::LOAD_PLAYER_PETS, [
56 | "player" => $player
57 | ], $callable);
58 | }
59 |
60 | public function getPlayerPets(string $player, ?string $entityName = null, callable $callable = null): void {
61 | $this->database->executeSelect(SQLDataStorer::LIST_PLAYER_PETS, [
62 | "player" => $player,
63 | "entityname" => $entityName ?? "%"
64 | ], $callable);
65 | }
66 |
67 | public function getPetsLeaderboard(int $offset = 0, int $length = 1, ?string $entityName = null, callable $callable = null): void {
68 | $this->database->executeSelect(SQLDataStorer::PET_LEADERBOARD, [
69 | "offset" => $offset,
70 | "length" => $length,
71 | "entityname" => $entityName ?? "%"
72 | ], $callable);
73 | }
74 |
75 | public function togglePets(string $ownerName, ?string $petName, callable $callable): void {
76 | $this->database->executeChange(SQLDataStorer::UPDATE_PET_VISIBILITY, [
77 | "player" => $ownerName,
78 | "petname" => $petName ?? "%"
79 | ], function(int $changed) use ($ownerName, $petName, $callable): void {
80 | if($changed === 0) {
81 | $callable([]);
82 | } else {
83 | $this->database->executeSelect(SQLDataStorer::PET_VISIBILITY, [
84 | "player" => $ownerName,
85 | "petname" => $petName ?? "%"
86 | ], $callable);
87 | }
88 | });
89 | }
90 |
91 | public function updateExperience(BasePet $pet): void {
92 | $this->database->executeChange(SQLDataStorer::UPDATE_PET_EXPERIENCE, [
93 | "petlevel" => $pet->getPetLevel(),
94 | "levelpoints" => $pet->getPetLevelPoints(),
95 | "player" => $pet->getPetOwnerName(),
96 | "petname" => $pet->getPetName()
97 | ]);
98 | }
99 |
100 | public function updateChested(BasePet $pet): void {
101 | $this->database->executeChange(SQLDataStorer::UPDATE_PET_CHESTED, [
102 | "chested" => (int) $pet->isChested(),
103 | "player" => $pet->getPetOwnerName(),
104 | "petname" => $pet->getPetName()
105 | ]);
106 | }
107 |
108 | public function updateInventory(BasePet $pet): void {
109 | $this->database->executeChange(SQLDataStorer::UPDATE_PET_INVENTORY, [
110 | "inventory" => $pet->getInventoryManager()->compressContents(),
111 | "player" => $pet->getPetOwnerName(),
112 | "petname" => $pet->getPetName()
113 | ]);
114 | }
115 |
116 | protected function prepare(): void {
117 | $loader = $this->getLoader();
118 |
119 | $config = $loader->getBlockPetsConfig();
120 | $this->type = strtolower($config->getDatabase());
121 | $mc = $config->getMySQLInfo();
122 |
123 | $libasynql_friendly_config = [
124 | "type" => $this->type,
125 | "sqlite" => [
126 | "file" => $loader->getDataFolder() . "pets.sqlite3"
127 | ],
128 | "mysql" => array_combine(
129 | ["host", "username", "password", "schema", "port"],
130 | [$mc["Host"], $mc["User"], $mc["Password"], $mc["Database"], $mc["Port"]]
131 | )
132 | ];
133 |
134 | $this->database = libasynql::create($loader, $libasynql_friendly_config, [
135 | "mysql" => "database_stmts/mysql.sql",
136 | "sqlite" => "database_stmts/sqlite.sql"
137 | ]);
138 |
139 | $this->database->executeGeneric(SQLDataStorer::INITIALIZE_TABLES);
140 |
141 | $resource = $this->getLoader()->getResource("patches/" . $this->type . ".sql");
142 | if($resource !== null) {
143 | $this->database->loadQueryFile($resource); //calls fclose($resource)
144 | }
145 | }
146 |
147 | public function patch(string $version): void {
148 | switch($version) {
149 | case "1.1.2":
150 | $this->database->executeGeneric(str_replace("{VERSION}", $version, SQLDataStorer::VERSION_PATCH));
151 | break;
152 | }
153 | }
154 |
155 | protected function close(): void {
156 | $this->database->close();
157 | }
158 |
159 | protected function reset(): void {
160 | $this->database->executeChange(SQLDataStorer::RESET);
161 | }
162 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/datastorage/SQLiteDataStorer.php:
--------------------------------------------------------------------------------
1 | database->executeSelect(SQLDataStorer::LOAD_PLAYER_PETS, [
14 | "player" => $player
15 | ], function(array $rows) use($callable): void {
16 | foreach($rows as &$row) {
17 | if(isset($row["Inventory"])) {
18 | $row["Inventory"] = base64_decode($row["Inventory"]);
19 | }
20 | }
21 | $callable($rows);
22 | });
23 | }
24 |
25 | public function updateInventory(BasePet $pet): void {
26 | $this->database->executeChange(SQLDataStorer::UPDATE_PET_INVENTORY, [
27 | "inventory" => base64_encode($pet->getInventoryManager()->compressContents()),
28 | "player" => $pet->getPetOwnerName(),
29 | "petname" => $pet->getPetName()
30 | ]);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/pets/inventory/PetInventoryManager.php:
--------------------------------------------------------------------------------
1 | menu = InvMenu::create(InvMenu::TYPE_CHEST);
34 | $this->menu->setInventoryCloseListener(function(): void {
35 | $pet = $this->getPet();
36 | $loader = $pet->getLoader();
37 | if($loader->getBlockPetsConfig()->storeToDatabase()) {
38 | $loader->getDatabase()->updateInventory($pet);
39 | }
40 | });
41 | $this->setName($pet->getPetName());
42 | }
43 |
44 | public function setName(string $name): void {
45 | $this->menu->setName($name . "'s Inventory");
46 | }
47 |
48 | public function getPet(): BasePet {
49 | return $this->pet;
50 | }
51 |
52 | public function getInventory(): Inventory {
53 | return $this->menu->getInventory();
54 | }
55 |
56 | public function openAs(Player $player, ?int $forceId = null): void {
57 | $this->menu->send($player, $forceId);
58 | }
59 |
60 | public function load(string $compressed): void {
61 | $contents = [];
62 |
63 | /** @var CompoundTag $nbt */
64 | foreach(self::$nbtSerializer->read($compressed)->mustGetCompoundTag()->getListTag("Inventory") as $nbt) {
65 | $contents[$nbt->getByte("Slot")] = Item::nbtDeserialize($nbt);
66 | }
67 |
68 | $this->getInventory()->setContents($contents);
69 | }
70 |
71 | public function compressContents(): string {
72 | $contents = [];
73 |
74 | foreach($this->getInventory()->getContents() as $slot => $item) {
75 | $contents[] = $item->nbtSerialize($slot);
76 | }
77 |
78 | $tag = CompoundTag::create()->setTag("Inventory", new ListTag($contents, NBT::TAG_Compound));
79 |
80 | return self::$nbtSerializer->write(new TreeRoot($tag));
81 | }
82 | }
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/tasks/BaseTask.php:
--------------------------------------------------------------------------------
1 | loader;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/BlockHorizons/BlockPets/tasks/PetRespawnTask.php:
--------------------------------------------------------------------------------
1 | pet->spawnToAll();
17 | $this->pet->setDormant(false);
18 | }
19 | }
--------------------------------------------------------------------------------