├── .editorconfig
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── phar-build.yml
├── .gitignore
├── .libraries.yml
├── .poggit.yml
├── LICENSE
├── README.md
├── assets
└── logo-min.png
├── generatepets.php
├── plugin.yml
├── resources
├── config.yml
├── mysql.sql
└── sqlite.sql
└── src
└── brokiem
└── simplepets
├── EventListener.php
├── SimplePets.php
├── command
└── Command.php
├── database
└── Database.php
├── manager
└── PetManager.php
└── pets
├── AllayPet.php
├── ArmorstandPet.php
├── ArrowPet.php
├── AxolotlPet.php
├── BatPet.php
├── BeePet.php
├── BlazePet.php
├── BoatPet.php
├── CatPet.php
├── CavespiderPet.php
├── ChestminecartPet.php
├── ChickenPet.php
├── CodPet.php
├── CommandblockminecartPet.php
├── CowPet.php
├── CreeperPet.php
├── DolphinPet.php
├── DonkeyPet.php
├── DragonfireballPet.php
├── DrownedPet.php
├── EggPet.php
├── ElderguardianPet.php
├── ElderguardianghostPet.php
├── EndercrystalPet.php
├── EnderdragonPet.php
├── EndermanPet.php
├── EndermitePet.php
├── EnderpearlPet.php
├── EvocationfangPet.php
├── EvocationillagerPet.php
├── EyeofendersignalPet.php
├── FireballPet.php
├── FoxPet.php
├── GhastPet.php
├── GoatPet.php
├── GuardianPet.php
├── HoglinPet.php
├── HopperminecartPet.php
├── HorsePet.php
├── HuskPet.php
├── IrongolemPet.php
├── LingeringpotionPet.php
├── LlamaPet.php
├── MagmacubePet.php
├── MinecartPet.php
├── MooshroomPet.php
├── MulePet.php
├── OcelotPet.php
├── PandaPet.php
├── ParrotPet.php
├── PhantomPet.php
├── PigPet.php
├── PiglinPet.php
├── PillagerPet.php
├── PolarbearPet.php
├── PufferfishPet.php
├── RabbitPet.php
├── RavagerPet.php
├── SalmonPet.php
├── SheepPet.php
├── ShulkerPet.php
├── ShulkerbulletPet.php
├── SilverfishPet.php
├── SkeletonPet.php
├── SkeletonhorsePet.php
├── SlimePet.php
├── SmallfireballPet.php
├── SnowballPet.php
├── SnowgolemPet.php
├── SpiderPet.php
├── SplashpotionPet.php
├── SquidPet.php
├── StrayPet.php
├── StriderPet.php
├── TntPet.php
├── TntminecartPet.php
├── TropicalfishPet.php
├── TurtlePet.php
├── VexPet.php
├── VillagerPet.php
├── Villagerv2Pet.php
├── VindicatorPet.php
├── WanderingtraderPet.php
├── WardenPet.php
├── WitchPet.php
├── WitherPet.php
├── WitherskeletonPet.php
├── WitherskullPet.php
├── WolfPet.php
├── ZoglinPet.php
├── ZombiePet.php
├── ZombiehorsePet.php
├── ZombiepigmanPet.php
├── ZombievillagerPet.php
├── Zombievillagerv2Pet.php
└── base
├── BasePet.php
└── CustomPet.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = crlf
4 | indent_size = 4
5 | indent_style = space
6 | insert_final_newline = false
7 | max_line_length = 120
8 | tab_width = 4
9 | ij_continuation_indent_size = 8
10 | ij_formatter_off_tag = @formatter:off
11 | ij_formatter_on_tag = @formatter:on
12 | ij_formatter_tags_enabled = false
13 | ij_smart_tabs = false
14 | ij_visual_guides = none
15 | ij_wrap_on_typing = false
16 |
17 | [.editorconfig]
18 | ij_editorconfig_align_group_field_declarations = false
19 | ij_editorconfig_space_after_colon = false
20 | ij_editorconfig_space_after_comma = true
21 | ij_editorconfig_space_before_colon = false
22 | ij_editorconfig_space_before_comma = false
23 | ij_editorconfig_spaces_around_assignment_operators = true
24 |
25 | [{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
26 | ij_xml_align_attributes = true
27 | ij_xml_align_text = false
28 | ij_xml_attribute_wrap = normal
29 | ij_xml_block_comment_at_first_column = true
30 | ij_xml_keep_blank_lines = 2
31 | ij_xml_keep_indents_on_empty_lines = false
32 | ij_xml_keep_line_breaks = true
33 | ij_xml_keep_line_breaks_in_text = true
34 | ij_xml_keep_whitespaces = false
35 | ij_xml_keep_whitespaces_around_cdata = preserve
36 | ij_xml_keep_whitespaces_inside_cdata = false
37 | ij_xml_line_comment_at_first_column = true
38 | ij_xml_space_after_tag_name = false
39 | ij_xml_space_around_equals_in_attribute = false
40 | ij_xml_space_inside_empty_tag = false
41 | ij_xml_text_wrap = normal
42 |
43 | [{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
44 | ij_continuation_indent_size = 4
45 | ij_php_align_assignments = false
46 | ij_php_align_class_constants = false
47 | ij_php_align_group_field_declarations = false
48 | ij_php_align_inline_comments = false
49 | ij_php_align_key_value_pairs = false
50 | ij_php_align_multiline_array_initializer_expression = false
51 | ij_php_align_multiline_binary_operation = false
52 | ij_php_align_multiline_chained_methods = false
53 | ij_php_align_multiline_extends_list = false
54 | ij_php_align_multiline_for = true
55 | ij_php_align_multiline_parameters = true
56 | ij_php_align_multiline_parameters_in_calls = false
57 | ij_php_align_multiline_ternary_operation = false
58 | ij_php_align_phpdoc_comments = false
59 | ij_php_align_phpdoc_param_names = false
60 | ij_php_anonymous_brace_style = end_of_line
61 | ij_php_api_weight = 28
62 | ij_php_array_initializer_new_line_after_left_brace = false
63 | ij_php_array_initializer_right_brace_on_new_line = false
64 | ij_php_array_initializer_wrap = off
65 | ij_php_assignment_wrap = off
66 | ij_php_attributes_wrap = off
67 | ij_php_author_weight = 28
68 | ij_php_binary_operation_sign_on_next_line = false
69 | ij_php_binary_operation_wrap = off
70 | ij_php_blank_lines_after_class_header = 0
71 | ij_php_blank_lines_after_function = 1
72 | ij_php_blank_lines_after_imports = 1
73 | ij_php_blank_lines_after_opening_tag = 0
74 | ij_php_blank_lines_after_package = 0
75 | ij_php_blank_lines_around_class = 1
76 | ij_php_blank_lines_around_constants = 0
77 | ij_php_blank_lines_around_field = 0
78 | ij_php_blank_lines_around_method = 1
79 | ij_php_blank_lines_before_class_end = 0
80 | ij_php_blank_lines_before_imports = 1
81 | ij_php_blank_lines_before_method_body = 0
82 | ij_php_blank_lines_before_package = 1
83 | ij_php_blank_lines_before_return_statement = 0
84 | ij_php_blank_lines_between_imports = 0
85 | ij_php_block_brace_style = end_of_line
86 | ij_php_call_parameters_new_line_after_left_paren = false
87 | ij_php_call_parameters_right_paren_on_new_line = false
88 | ij_php_call_parameters_wrap = off
89 | ij_php_catch_on_new_line = false
90 | ij_php_category_weight = 28
91 | ij_php_class_brace_style = end_of_line
92 | ij_php_comma_after_last_array_element = false
93 | ij_php_concat_spaces = true
94 | ij_php_copyright_weight = 28
95 | ij_php_deprecated_weight = 28
96 | ij_php_do_while_brace_force = never
97 | ij_php_else_if_style = as_is
98 | ij_php_else_on_new_line = false
99 | ij_php_example_weight = 28
100 | ij_php_extends_keyword_wrap = off
101 | ij_php_extends_list_wrap = off
102 | ij_php_fields_default_visibility = private
103 | ij_php_filesource_weight = 28
104 | ij_php_finally_on_new_line = false
105 | ij_php_for_brace_force = never
106 | ij_php_for_statement_new_line_after_left_paren = false
107 | ij_php_for_statement_right_paren_on_new_line = false
108 | ij_php_for_statement_wrap = off
109 | ij_php_force_short_declaration_array_style = false
110 | ij_php_getters_setters_naming_style = camel_case
111 | ij_php_getters_setters_order_style = getters_first
112 | ij_php_global_weight = 28
113 | ij_php_group_use_wrap = on_every_item
114 | ij_php_if_brace_force = never
115 | ij_php_if_lparen_on_next_line = false
116 | ij_php_if_rparen_on_next_line = false
117 | ij_php_ignore_weight = 28
118 | ij_php_import_sorting = alphabetic
119 | ij_php_indent_break_from_case = true
120 | ij_php_indent_case_from_switch = true
121 | ij_php_indent_code_in_php_tags = false
122 | ij_php_internal_weight = 28
123 | ij_php_keep_blank_lines_after_lbrace = 2
124 | ij_php_keep_blank_lines_before_right_brace = 2
125 | ij_php_keep_blank_lines_in_code = 2
126 | ij_php_keep_blank_lines_in_declarations = 2
127 | ij_php_keep_control_statement_in_one_line = true
128 | ij_php_keep_first_column_comment = false
129 | ij_php_keep_indents_on_empty_lines = false
130 | ij_php_keep_line_breaks = true
131 | ij_php_keep_rparen_and_lbrace_on_one_line = false
132 | ij_php_keep_simple_classes_in_one_line = true
133 | ij_php_keep_simple_methods_in_one_line = true
134 | ij_php_lambda_brace_style = end_of_line
135 | ij_php_license_weight = 28
136 | ij_php_line_comment_add_space = false
137 | ij_php_line_comment_at_first_column = true
138 | ij_php_link_weight = 28
139 | ij_php_lower_case_boolean_const = false
140 | ij_php_lower_case_keywords = true
141 | ij_php_lower_case_null_const = false
142 | ij_php_method_brace_style = end_of_line
143 | ij_php_method_call_chain_wrap = off
144 | ij_php_method_parameters_new_line_after_left_paren = false
145 | ij_php_method_parameters_right_paren_on_new_line = false
146 | ij_php_method_parameters_wrap = off
147 | ij_php_method_weight = 28
148 | ij_php_modifier_list_wrap = false
149 | ij_php_multiline_chained_calls_semicolon_on_new_line = false
150 | ij_php_namespace_brace_style = 1
151 | ij_php_new_line_after_php_opening_tag = false
152 | ij_php_null_type_position = in_the_end
153 | ij_php_package_weight = 28
154 | ij_php_param_weight = 0
155 | ij_php_parameters_attributes_wrap = off
156 | ij_php_parentheses_expression_new_line_after_left_paren = false
157 | ij_php_parentheses_expression_right_paren_on_new_line = false
158 | ij_php_phpdoc_blank_line_before_tags = false
159 | ij_php_phpdoc_blank_lines_around_parameters = false
160 | ij_php_phpdoc_keep_blank_lines = true
161 | ij_php_phpdoc_param_spaces_between_name_and_description = 1
162 | ij_php_phpdoc_param_spaces_between_tag_and_type = 1
163 | ij_php_phpdoc_param_spaces_between_type_and_name = 1
164 | ij_php_phpdoc_use_fqcn = false
165 | ij_php_phpdoc_wrap_long_lines = false
166 | ij_php_place_assignment_sign_on_next_line = false
167 | ij_php_place_parens_for_constructor = 0
168 | ij_php_property_read_weight = 28
169 | ij_php_property_weight = 28
170 | ij_php_property_write_weight = 28
171 | ij_php_return_type_on_new_line = false
172 | ij_php_return_weight = 1
173 | ij_php_see_weight = 28
174 | ij_php_since_weight = 28
175 | ij_php_sort_phpdoc_elements = true
176 | ij_php_space_after_colon = true
177 | ij_php_space_after_colon_in_named_argument = true
178 | ij_php_space_after_colon_in_return_type = true
179 | ij_php_space_after_comma = true
180 | ij_php_space_after_for_semicolon = true
181 | ij_php_space_after_quest = true
182 | ij_php_space_after_type_cast = false
183 | ij_php_space_after_unary_not = false
184 | ij_php_space_before_array_initializer_left_brace = false
185 | ij_php_space_before_catch_keyword = true
186 | ij_php_space_before_catch_left_brace = true
187 | ij_php_space_before_catch_parentheses = true
188 | ij_php_space_before_class_left_brace = true
189 | ij_php_space_before_closure_left_parenthesis = false
190 | ij_php_space_before_colon = true
191 | ij_php_space_before_colon_in_named_argument = false
192 | ij_php_space_before_colon_in_return_type = false
193 | ij_php_space_before_comma = false
194 | ij_php_space_before_do_left_brace = true
195 | ij_php_space_before_else_keyword = true
196 | ij_php_space_before_else_left_brace = true
197 | ij_php_space_before_finally_keyword = true
198 | ij_php_space_before_finally_left_brace = true
199 | ij_php_space_before_for_left_brace = true
200 | ij_php_space_before_for_parentheses = true
201 | ij_php_space_before_for_semicolon = false
202 | ij_php_space_before_if_left_brace = true
203 | ij_php_space_before_if_parentheses = true
204 | ij_php_space_before_method_call_parentheses = false
205 | ij_php_space_before_method_left_brace = true
206 | ij_php_space_before_method_parentheses = false
207 | ij_php_space_before_quest = true
208 | ij_php_space_before_short_closure_left_parenthesis = false
209 | ij_php_space_before_switch_left_brace = true
210 | ij_php_space_before_switch_parentheses = true
211 | ij_php_space_before_try_left_brace = true
212 | ij_php_space_before_unary_not = false
213 | ij_php_space_before_while_keyword = true
214 | ij_php_space_before_while_left_brace = true
215 | ij_php_space_before_while_parentheses = true
216 | ij_php_space_between_ternary_quest_and_colon = false
217 | ij_php_spaces_around_additive_operators = true
218 | ij_php_spaces_around_arrow = false
219 | ij_php_spaces_around_assignment_in_declare = false
220 | ij_php_spaces_around_assignment_operators = true
221 | ij_php_spaces_around_bitwise_operators = true
222 | ij_php_spaces_around_equality_operators = true
223 | ij_php_spaces_around_logical_operators = true
224 | ij_php_spaces_around_multiplicative_operators = true
225 | ij_php_spaces_around_null_coalesce_operator = true
226 | ij_php_spaces_around_relational_operators = true
227 | ij_php_spaces_around_shift_operators = true
228 | ij_php_spaces_around_unary_operator = false
229 | ij_php_spaces_around_var_within_brackets = false
230 | ij_php_spaces_within_array_initializer_braces = false
231 | ij_php_spaces_within_brackets = false
232 | ij_php_spaces_within_catch_parentheses = false
233 | ij_php_spaces_within_for_parentheses = false
234 | ij_php_spaces_within_if_parentheses = false
235 | ij_php_spaces_within_method_call_parentheses = false
236 | ij_php_spaces_within_method_parentheses = false
237 | ij_php_spaces_within_parentheses = false
238 | ij_php_spaces_within_short_echo_tags = true
239 | ij_php_spaces_within_switch_parentheses = false
240 | ij_php_spaces_within_while_parentheses = false
241 | ij_php_special_else_if_treatment = false
242 | ij_php_subpackage_weight = 28
243 | ij_php_ternary_operation_signs_on_next_line = false
244 | ij_php_ternary_operation_wrap = off
245 | ij_php_throws_weight = 2
246 | ij_php_todo_weight = 28
247 | ij_php_unknown_tag_weight = 28
248 | ij_php_upper_case_boolean_const = false
249 | ij_php_upper_case_null_const = false
250 | ij_php_uses_weight = 28
251 | ij_php_var_weight = 28
252 | ij_php_variable_naming_style = mixed
253 | ij_php_version_weight = 28
254 | ij_php_while_brace_force = never
255 | ij_php_while_on_new_line = false
256 |
257 | [{*.markdown,*.md}]
258 | ij_markdown_force_one_space_after_blockquote_symbol = true
259 | ij_markdown_force_one_space_after_header_symbol = true
260 | ij_markdown_force_one_space_after_list_bullet = true
261 | ij_markdown_force_one_space_between_words = true
262 | ij_markdown_keep_indents_on_empty_lines = false
263 | ij_markdown_max_lines_around_block_elements = 1
264 | ij_markdown_max_lines_around_header = 1
265 | ij_markdown_max_lines_between_paragraphs = 1
266 | ij_markdown_min_lines_around_block_elements = 1
267 | ij_markdown_min_lines_around_header = 1
268 | ij_markdown_min_lines_between_paragraphs = 1
269 |
270 | [{*.yaml,*.yml}]
271 | indent_size = 2
272 | ij_yaml_align_values_properties = do_not_align
273 | ij_yaml_autoinsert_sequence_marker = true
274 | ij_yaml_block_mapping_on_new_line = false
275 | ij_yaml_indent_sequence_value = true
276 | ij_yaml_keep_indents_on_empty_lines = false
277 | ij_yaml_keep_line_breaks = true
278 | ij_yaml_sequence_on_new_line = false
279 | ij_yaml_space_before_colon = false
280 | ij_yaml_spaces_within_braces = true
281 | ij_yaml_spaces_within_brackets = true
282 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: brokiem
2 | custom: [ 'https://www.paypal.me/brokiem' ]
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 |
16 | 1. Go to '...'
17 | 2. Click on '....'
18 | 3. Scroll down to '....'
19 | 4. See error
20 |
21 | **Expected behavior**
22 | A clear and concise description of what you expected to happen.
23 |
24 | **Screenshots**
25 | If applicable, add screenshots to help explain your problem.
26 |
27 | **SimplePets plugin information**
28 |
29 | - Version: [e.g. 1.0.0]
30 | - Server api: [e.g. 4.0.1]
31 |
32 | **Additional context**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/phar-build.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ push ]
4 |
5 | jobs:
6 | build:
7 | name: Build plugin
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v3
11 |
12 | - name: Prepare directories
13 | run: |
14 | mkdir target
15 | mkdir plugin
16 |
17 | - name: Move files to plugin folder
18 | run: |
19 | mv resources src plugin.yml -t plugin
20 |
21 | - name: Setup PHP 8.1
22 | uses: shivammathur/setup-php@v2
23 | with:
24 | php-version: '8.1'
25 | ini-values: phar.readonly=0
26 |
27 | - name: Read plugin name
28 | id: plugin-name
29 | uses: KJ002/read-yaml@main
30 | with:
31 | file: './plugin/plugin.yml'
32 | key-path: '["name"]'
33 |
34 | - name: Download ConsoleScript
35 | run: wget https://gist.githubusercontent.com/brokiem/3a407df6372ed1410cfb38cf99762a3f/raw/3f7e65b169a13bff5f2ec91669f9b474cf25a6cc/ConsoleScript.php
36 |
37 | - name: Build plugin
38 | run: php ConsoleScript.php --make / --relative plugin --out target/${{ steps.plugin-name.outputs.data }}.phar
39 |
40 | - name: Check libraries file
41 | id: libraries-file
42 | uses: andstor/file-existence-action@v1
43 | with:
44 | files: ".libraries.yml"
45 |
46 | - name: Read libraries
47 | if: steps.libraries-file.outputs.files_exists == 'true'
48 | id: libraries
49 | uses: KJ002/read-yaml@main
50 | with:
51 | file: './.libraries.yml'
52 | key-path: '["libs"]'
53 |
54 | - name: Download virions
55 | if: steps.libraries-file.outputs.files_exists == 'true'
56 | run: php -r 'foreach(${{ steps.libraries.outputs.data }} as $lib){ exec("wget $lib"); echo "Downloaded virion " . basename($lib); }'
57 |
58 | - name: Inject virions
59 | if: steps.libraries-file.outputs.files_exists == 'true'
60 | run: php -r 'foreach(${{ steps.libraries.outputs.data }} as $lib){ exec("php " . basename($lib) . " target/${{ steps.plugin-name.outputs.data }}.phar"); echo "\nInjected virion " . basename($lib); }'
61 |
62 | - name: Compress phar
63 | run: php -r '(new \Phar("./target/${{ steps.plugin-name.outputs.data }}.phar"))->compressFiles(\Phar::GZ); echo "\nFinished compression";'
64 |
65 | - name: Upload Artifact
66 | uses: actions/upload-artifact@v2
67 | with:
68 | name: ${{ steps.plugin-name.outputs.data }}.phar
69 | path: target/${{ steps.plugin-name.outputs.data }}.phar
70 |
71 | prepare-release:
72 | name: Make release
73 | needs: [ build ]
74 | runs-on: ubuntu-latest
75 | if: contains(github.event.head_commit.message, '[release]')
76 | steps:
77 | - uses: actions/checkout@v2
78 |
79 | - name: Download artifact
80 | uses: actions/download-artifact@v2
81 |
82 | - name: Read plugin name
83 | id: plugin-name
84 | uses: KJ002/read-yaml@main
85 | with:
86 | file: './plugin.yml'
87 | key-path: '["name"]'
88 |
89 | - name: Read plugin version
90 | id: plugin-version
91 | uses: KJ002/read-yaml@main
92 | with:
93 | file: './plugin.yml'
94 | key-path: '["version"]'
95 |
96 | - name: Create and publish release
97 | uses: marvinpinto/action-automatic-releases@v1.2.1
98 | with:
99 | automatic_release_tag: "${{ steps.plugin-version.outputs.data }}"
100 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
101 | title: "${{ steps.plugin-name.outputs.data }} v${{ steps.plugin-version.outputs.data }}"
102 | files: |
103 | ${{ steps.plugin-name.outputs.data }}.phar
104 | prerelease: false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | vendor
--------------------------------------------------------------------------------
/.libraries.yml:
--------------------------------------------------------------------------------
1 | libs:
2 | - https://poggit.pmmp.io/r/177279/libasynql_dev-177.phar
3 | - https://poggit.pmmp.io/r/186359/InvMenu_dev-179.phar
4 | - https://poggit.pmmp.io/r/188653/libEasyUI_dev-12.phar
--------------------------------------------------------------------------------
/.poggit.yml:
--------------------------------------------------------------------------------
1 | --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/brokiem/SimplePets
2 | build-by-default: true
3 | branches:
4 | - master
5 | - broki-patch
6 |
7 | projects:
8 | SimplePets:
9 | icon: "/assets/logo-min.png"
10 | libs:
11 | - src: poggit/libasynql/libasynql
12 | version: ^4.1.0
13 | - src: muqsit/InvMenu/InvMenu
14 | version: ^4.4.1
15 | branch: "4.0"
16 | - src: brokiem-pm-pl/EasyUI/libEasyUI
17 | version: 3.0.0
18 | ...
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 broki
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
SimplePets
2 |
3 | An Ultimate Pets plugin made by broki for PocketMine-MP.
4 | [](https://github.com/brokiem/SimplePets)
5 | [](https://github.com/brokiem/SimplePets/stargazers)
6 | [](https://discord.com/invite/jy6abSrjhQ)
7 | [](https://www.paypal.me/brokiem)
8 |
9 | ## ✨ Features
10 |
11 | - MySQL and SQLite database
12 | - Anti sql injection
13 | - Pets with inventory
14 | - Pets can be ridden
15 | - XUID data saving
16 | - Multi world support
17 | - Lightweight & Open Source ❤
18 |
19 | ## 💬 Commands
20 |
21 | For more command info, please look directly at ```/spet help```
22 |
23 | | Command | Description | Permission | Default |
24 | | --- | --- | --- | --- |
25 | | ```/spet``` | ```SimplePets command list``` | ```none``` | ```true``` |
26 | | ```/spet petlist``` | ```Show all pet list``` | ```simplepets.petlist``` | ```op``` |
27 | | ```/spet spawn``` | ```Spawning a pet``` | ```simplepets.spawn``` | ```op``` |
28 | | ```/spet remove``` | ```Removing a pet``` | ```simplepets.remove``` | ```op``` |
29 | | ```/spet inv``` | ```View pet inventory``` | ```simplepets.inv``` | ```true``` |
30 | | ```/spet ride``` | ```Ride a pet``` | ```simplepets.ride``` | ```true``` |
31 |
32 | ## 📝 Todo List
33 |
34 | - UI/Form to manage pets
35 | - Renaming pets
36 |
37 | ## ❔ Issues
38 |
39 | Did you find a bug or error when using this plugin? feel free to open the
40 | issues [here](https://github.com/brokiem/SimplePets/issues/new)
41 |
42 | ## 👑 Donation
43 |
44 | Paypal - https://www.paypal.me/brokiem
45 | Saweria - https://saweria.co/brokiem
46 |
--------------------------------------------------------------------------------
/assets/logo-min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brokiem/SimplePets/0d0e8e21278840eb843209a8214d15c92fae7c53/assets/logo-min.png
--------------------------------------------------------------------------------
/generatepets.php:
--------------------------------------------------------------------------------
1 | $value) {
110 | $const = ucfirst(strtolower(str_replace("_", "", $constant))) . "Pet";
111 |
112 | $contents = "getConstants();
129 | }
130 |
131 | public static function getDefaultPets(): void {
132 | $text = "";
133 | foreach (glob('src/brokiem/simplepets/pets/*.php') as $file) {
134 | $text .= "\"" . str_replace(".php", "", basename($file)) . "\" => \"" . str_replace("/", "\\", str_replace(".php", "", $file)) . "\",\n";
135 | }
136 |
137 | var_dump($text);
138 | }
139 | }
140 |
141 | generatepets::main();
--------------------------------------------------------------------------------
/plugin.yml:
--------------------------------------------------------------------------------
1 | name: SimplePets
2 | main: brokiem\simplepets\SimplePets
3 | version: 1.0.0-beta
4 | api: 4.0.0
5 | authors: [ "broki", "brokiem", "broski" ]
6 |
7 | website: https://github.com/brokiem/SimplePets
8 |
9 | extensions:
10 | Core: '>=8.0'
11 |
12 | permissions:
13 | simplepets.ui:
14 | default: op
15 | simplepets.spawn:
16 | default: op
17 | simplepets.remove:
18 | default: op
19 | simplepets.inv:
20 | default: true
21 | simplepets.ride:
22 | default: true
23 | simplepets.petlist:
24 | default: op
--------------------------------------------------------------------------------
/resources/config.yml:
--------------------------------------------------------------------------------
1 | # Database configuration
2 | database:
3 | # The database types. "sqlite" and "mysql" are supported.
4 | type: sqlite
5 |
6 | # Edit these settings only if you choose "sqlite".
7 | sqlite:
8 | # The file name of the database in the plugin data folder.
9 | # You can also put an absolute path here.
10 | file: simplepets.sqlite
11 |
12 | # Edit these settings only if you choose "mysql".
13 | mysql:
14 | host: 127.0.0.1
15 | # Avoid using the "root" user for security reasons.
16 | username: root
17 | password: ""
18 | schema: simplepets # database
19 |
20 | # The maximum number of simultaneous SQL queries
21 | # Recommended: 1 for sqlite, 2 for MySQL.
22 | # You may want to further increase this value if your MySQL connection is very slow.
23 | worker-limit: 1
24 |
25 | enable-inventory: true
26 | enable-riding: true
27 |
--------------------------------------------------------------------------------
/resources/mysql.sql:
--------------------------------------------------------------------------------
1 | -- # !mysql
2 | -- # {simplepets
3 | -- # {init
4 | -- # {info
5 | CREATE TABLE IF NOT EXISTS simplepets_info
6 | (
7 | id TINYINT UNSIGNED PRIMARY KEY,
8 | db_version TINYINT UNSIGNED NOT NULL DEFAULT 1
9 | );
10 | -- # }
11 | -- # {data
12 | CREATE TABLE IF NOT EXISTS simplepets_pets
13 | (
14 | id INT UNSIGNED AUTO_INCREMENT,
15 | petType VARCHAR(64) NOT NULL,
16 | petName VARCHAR(32) NOT NULL,
17 | petOwner VARCHAR(32) NOT NULL,
18 | petSize FLOAT(2) NOT NULL,
19 | petBaby BOOL NOT NULL,
20 | petVisible INT NOT NULL,
21 | enableInv BOOL NOT NULL,
22 | enableRiding BOOL NOT NULL,
23 | extraData TEXT,
24 | PRIMARY KEY (id)
25 | )
26 | -- # }
27 | -- # }
28 | -- # {get-version
29 | -- # :id int 1
30 | SELECT db_version
31 | FROM simplepets_info
32 | WHERE id = :id;
33 | -- # }
34 | -- # {set-version
35 | -- # :id int 1
36 | -- # :version int
37 | INSERT INTO simplepets_info (id, db_version)
38 | VALUES (:id, :version)
39 | ON DUPLICATE KEY UPDATE db_version = :version;
40 | -- # }
41 | -- # {registerpet
42 | -- # :petType string
43 | -- # :petName string
44 | -- # :petOwner string
45 | -- # :petSize float
46 | -- # :petBaby bool
47 | -- # :petVisible int
48 | -- # :extraData ?string
49 | -- # :enableInv bool
50 | -- # :enableRiding bool
51 | INSERT INTO simplepets_pets (petType, petName, petOwner, petSize, petBaby, petVisible, enableInv, enableRiding,
52 | extraData)
53 | VALUES (:petType, :petName, :petOwner, :petSize, :petBaby, :petVisible, :enableInv, :enableRiding, :extraData);
54 | -- # }
55 | -- # {savepet
56 | -- # :id int
57 | -- # :petType string
58 | -- # :petName string
59 | -- # :petOwner string
60 | -- # :petSize float
61 | -- # :petBaby bool
62 | -- # :petVisible int
63 | -- # :extraData ?string
64 | -- # :enableInv bool
65 | -- # :enableRiding bool
66 | UPDATE simplepets_pets
67 | SET petType = :petType,
68 | petName = :petName,
69 | petOwner = :petOwner,
70 | petSize = :petSize,
71 | petBaby = :petBaby,
72 | petVisible = :petVisible,
73 | enableInv = :enableInv,
74 | enableRiding = :enableRiding,
75 | extraData = :extraData
76 | WHERE id = :id;
77 | -- # }
78 | -- # {getpet
79 | -- # :petName string
80 | -- # :petOwner string
81 | SELECT *
82 | FROM simplepets_pets
83 | WHERE petName = :petName
84 | AND petOwner = :petOwner;
85 | -- # }
86 | -- # {getallpets
87 | -- # :petOwner string
88 | SELECT *
89 | FROM simplepets_pets
90 | WHERE petOwner = :petOwner;
91 | -- # }
92 | -- # {removepet
93 | -- # :id int
94 | DELETE
95 | FROM simplepets_pets
96 | WHERE id = :id;
97 | -- # }
98 | -- #}
99 |
--------------------------------------------------------------------------------
/resources/sqlite.sql:
--------------------------------------------------------------------------------
1 | -- # !mysql
2 | -- # {simplepets
3 | -- # {init
4 | -- # {info
5 | CREATE TABLE IF NOT EXISTS simplepets_info
6 | (
7 | id TINYINT UNSIGNED PRIMARY KEY,
8 | db_version TINYINT UNSIGNED NOT NULL DEFAULT 1
9 | );
10 | -- # }
11 | -- # {data
12 | CREATE TABLE IF NOT EXISTS simplepets_pets
13 | (
14 | id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
15 | petType VARCHAR(64) NOT NULL,
16 | petName VARCHAR(32) NOT NULL,
17 | petOwner VARCHAR(32) NOT NULL,
18 | petSize FLOAT(2) NOT NULL,
19 | petBaby BOOL NOT NULL,
20 | petVisible INT NOT NULL,
21 | enableInv BOOL NOT NULL,
22 | enableRiding BOOL NOT NULL,
23 | extraData TEXT
24 | )
25 | -- # }
26 | -- # }
27 | -- # {get-version
28 | -- # :id int 1
29 | SELECT db_version
30 | FROM simplepets_info
31 | WHERE id = :id;
32 | -- # }
33 | -- # {set-version
34 | -- # :id int 1
35 | -- # :version int
36 | INSERT INTO simplepets_info (id, db_version)
37 | VALUES (:id, :version)
38 | ON DUPLICATE KEY UPDATE db_version = :version;
39 | -- # }
40 | -- # {registerpet
41 | -- # :petType string
42 | -- # :petName string
43 | -- # :petOwner string
44 | -- # :petSize float
45 | -- # :petBaby bool
46 | -- # :petVisible int
47 | -- # :extraData ?string
48 | -- # :enableInv bool
49 | -- # :enableRiding bool
50 | INSERT INTO simplepets_pets (petType, petName, petOwner, petSize, petBaby, petVisible, enableInv, enableRiding,
51 | extraData)
52 | VALUES (:petType, :petName, :petOwner, :petSize, :petBaby, :petVisible, :enableInv, :enableRiding, :extraData);
53 | -- # }
54 | -- # {savepet
55 | -- # :id int
56 | -- # :petType string
57 | -- # :petName string
58 | -- # :petOwner string
59 | -- # :petSize float
60 | -- # :petBaby bool
61 | -- # :petVisible int
62 | -- # :extraData ?string
63 | -- # :enableInv bool
64 | -- # :enableRiding bool
65 | UPDATE simplepets_pets
66 | SET petType = :petType,
67 | petName = :petName,
68 | petOwner = :petOwner,
69 | petSize = :petSize,
70 | petBaby = :petBaby,
71 | petVisible = :petVisible,
72 | enableInv = :enableInv,
73 | enableRiding = :enableRiding,
74 | extraData = :extraData
75 | WHERE id = :id;
76 | -- # }
77 | -- # {getpet
78 | -- # :petName string
79 | -- # :petOwner string
80 | SELECT *
81 | FROM simplepets_pets
82 | WHERE petName = :petName
83 | AND petOwner = :petOwner;
84 | -- # }
85 | -- # {getallpets
86 | -- # :petOwner string
87 | SELECT *
88 | FROM simplepets_pets
89 | WHERE petOwner = :petOwner;
90 | -- # }
91 | -- # {removepet
92 | -- # :id int
93 | DELETE
94 | FROM simplepets_pets
95 | WHERE id = :id;
96 | -- # }
97 | -- #}
98 |
--------------------------------------------------------------------------------
/src/brokiem/simplepets/EventListener.php:
--------------------------------------------------------------------------------
1 | getPlayer();
32 |
33 | SimplePets::getInstance()->addPlayer($player);
34 | Database::getInstance()->respawnPet($player);
35 | }
36 |
37 | public function onQuit(PlayerQuitEvent $event): void {
38 | $player = $event->getPlayer();
39 |
40 | if (isset(PetManager::getInstance()->getActivePets()[$player->getName()])) {
41 | foreach (PetManager::getInstance()->getActivePets()[$player->getName()] as $petName => $petId) {
42 | $pet = $player->getServer()->getWorldManager()->findEntity($petId);
43 |
44 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
45 | $pet->despawn();
46 | PetManager::getInstance()->removeActivePet($player, (string)$petName);
47 | }
48 | }
49 | }
50 |
51 | SimplePets::getInstance()->removePlayer($player);
52 | }
53 |
54 | public function onDamage(EntityDamageEvent $event): void {
55 | $entity = $event->getEntity();
56 |
57 | if ($entity instanceof BasePet || $entity instanceof CustomPet) {
58 | $event->cancel();
59 | }
60 | }
61 |
62 | public function onDataPacket(DataPacketReceiveEvent $event): void {
63 | $packet = $event->getPacket();
64 | $player = $event->getOrigin()->getPlayer();
65 |
66 | if ($player === null) {
67 | return;
68 | }
69 |
70 | if ($packet instanceof PlayerAuthInputPacket) {
71 | if ($packet->getMoveVecX() !== 0.0 or $packet->getMoveVecZ() !== 0.0) {
72 | $pet = PetManager::getInstance()->getRiddenPet($player);
73 | $pet?->walk($packet->getMoveVecX(), $packet->getMoveVecZ(), $player);
74 | }
75 | } elseif ($packet instanceof PlayerInputPacket) {
76 | if ($packet->motionX !== 0.0 or $packet->motionY !== 0.0) {
77 | $pet = PetManager::getInstance()->getRiddenPet($player);
78 | $pet?->walk($packet->motionX, $packet->motionY, $player);
79 | }
80 | } elseif ($packet instanceof InteractPacket) {
81 | if ($packet->action === InteractPacket::ACTION_LEAVE_VEHICLE) {
82 | $entity = $player->getServer()->getWorldManager()->findEntity($packet->targetActorRuntimeId);
83 |
84 | if ($entity instanceof BasePet || $entity instanceof CustomPet) {
85 | if ($entity->getRider()->getXuid() === $player->getXuid()) {
86 | $entity->unlink();
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
93 | public function onDeath(PlayerDeathEvent $event): void {
94 | $player = $event->getPlayer();
95 |
96 | PetManager::getInstance()->removeRiddenPet($player);
97 | }
98 |
99 | public function onTeleport(EntityTeleportEvent $event): void {
100 | $entity = $event->getEntity();
101 |
102 | if ($entity instanceof Player) {
103 | PetManager::getInstance()->removeRiddenPet($entity);
104 |
105 | if (isset(PetManager::getInstance()->getActivePets()[$entity->getName()])) {
106 | foreach (PetManager::getInstance()->getActivePets()[$entity->getName()] as $petName => $petId) {
107 | $pet = $entity->getServer()->getWorldManager()->findEntity($petId);
108 |
109 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
110 | $location = clone $entity->getLocation();
111 | ++$location->y;
112 |
113 | $pet->teleport($location);
114 | }
115 | }
116 | }
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/SimplePets.php:
--------------------------------------------------------------------------------
1 | getLogger()->debug("Checking virions");
34 | $missing = $this->checkVirion();
35 | if (!empty($missing)) {
36 | foreach ($missing as $class => $name) {
37 | $this->getLogger()->alert("Virion $class not found. ($name)");
38 | }
39 |
40 | $this->getLogger()->alert("Please install the virion or download the plugin from poggit! Disabling plugin...");
41 | $this->getServer()->getPluginManager()->disablePlugin($this);
42 | return;
43 | }
44 |
45 | self::setInstance($this);
46 |
47 | $this->getLogger()->debug("Loading pets");
48 | $this->initPets();
49 |
50 | $this->getLogger()->debug("Loading database");
51 | $this->initDatabase();
52 |
53 | $this->getLogger()->debug("Registering listener");
54 | $this->getServer()->getPluginManager()->registerEvents(new EventListener(), $this);
55 |
56 | $this->getLogger()->debug("Registering command");
57 | $this->getServer()->getCommandMap()->register("spet", new Command("spet", "SimplePet commands"));
58 |
59 | $this->getLogger()->debug("Plugin successfully enabled");
60 | }
61 |
62 | private function checkVirion(): array {
63 | $virions = [
64 | libasynql::class => "libasynql",
65 | InvMenu::class => "InvMenu"
66 | ];
67 | $missing = [];
68 |
69 | foreach ($virions as $class => $name) {
70 | if (!class_exists($class)) {
71 | $missing[$class] = $name;
72 | }
73 | }
74 |
75 | return $missing;
76 | }
77 |
78 | private function initDatabase(): void {
79 | $this->database = libasynql::create($this, $this->getConfig()->get("database"), [
80 | "sqlite" => "sqlite.sql",
81 | "mysql" => "mysql.sql"
82 | ]);
83 |
84 | $this->database->executeGeneric(Database::SIMPLEPETS_INIT_INFO);
85 | $this->database->executeGeneric(Database::SIMPLEPETS_INIT_DATA);
86 |
87 | $this->database->waitAll();
88 |
89 | new Database();
90 | }
91 |
92 | private function initPets(): void {
93 | if (!is_dir($this->getDataFolder() . "pets_inventory")) {
94 | mkdir($this->getDataFolder() . "pets_inventory");
95 | }
96 |
97 | if (!InvMenuHandler::isRegistered()) {
98 | InvMenuHandler::register($this);
99 | }
100 |
101 | new PetManager();
102 | }
103 |
104 | public function getDatabase(): DataConnector {
105 | return $this->database;
106 | }
107 |
108 | public function addPlayer(Player $player): void {
109 | if (!isset($this->players[$player->getXuid()])) {
110 | $this->players[$player->getXuid()] = $player->getName();
111 | }
112 | }
113 |
114 | public function getPlayerByXuid(string $xuid): ?Player {
115 | if (isset($this->players[$xuid])) {
116 | return $this->getServer()->getPlayerExact($this->players[$xuid]);
117 | }
118 |
119 | return null;
120 | }
121 |
122 | public function removePlayer(Player $player): void {
123 | if (isset($this->players[$player->getXuid()])) {
124 | unset($this->players[$player->getXuid()]);
125 | }
126 | }
127 |
128 | protected function onDisable(): void {
129 | foreach ($this->getServer()->getWorldManager()->getWorlds() as $world) {
130 | foreach ($world->getEntities() as $entity) {
131 | if ($entity instanceof BasePet || $entity instanceof CustomPet) {
132 | $entity->saveNBT();
133 | }
134 | }
135 | }
136 |
137 | if ($this->database instanceof DataConnector) {
138 | $this->database->waitAll();
139 | $this->database->close();
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/command/Command.php:
--------------------------------------------------------------------------------
1 | testPermission($sender)) {
35 | return;
36 | }
37 |
38 | if (isset($args[0])) {
39 | switch (strtolower($args[0])) {
40 | case "ui":
41 | if (!($sender instanceof Player)) {
42 | return;
43 | }
44 |
45 | if (!$sender->hasPermission("simplepets.ui")) {
46 | $sender->sendMessage("§cYou don't have permission to run this command");
47 | return;
48 | }
49 |
50 | $form = new SimpleForm("Spawn Pet");
51 |
52 | foreach (PetManager::getInstance()->getRegisteredPets() as $type => $class) {
53 | $form->addButton(new Button($type, null, function(Player $player) use ($type) {
54 | $dropdown = new Dropdown("Pet type");
55 | $dropdown->addOption(new Option($type, $type));
56 |
57 | $form = new CustomForm("Spawn $type");
58 | $form->addElement("pet_type", $dropdown);
59 | $form->addElement("pet_name", new Input("Pet name"));
60 |
61 | $form->setSubmitListener(function(Player $player, FormResponse $response) {
62 | $pet_name = $response->getInputSubmittedText("pet_name") ?? $player->getName();
63 | $pet_type = $response->getDropdownSubmittedOptionId("pet_type");
64 |
65 | if ($pet_type === null) {
66 | return;
67 | }
68 |
69 | if (!Player::isValidUserName($pet_name)) {
70 | $player->sendMessage("Invalid pet name. Only supported [A-z] with max 16 length character;");
71 | return;
72 | }
73 |
74 | if (isset(PetManager::getInstance()->getActivePets()[$player->getName()])) {
75 | foreach (PetManager::getInstance()->getActivePets()[$player->getName()] as $petName => $petId) {
76 | $pet = $player->getServer()->getWorldManager()->findEntity($petId);
77 |
78 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
79 | $pet->despawn();
80 | }
81 |
82 | PetManager::getInstance()->removeActivePet($player, (string)$petName);
83 | Database::getInstance()->removePet($player, (string)$petName);
84 | }
85 | }
86 |
87 | PetManager::getInstance()->spawnPet($player, (string)$pet_type, (string)$pet_name);
88 |
89 | $player->sendMessage("§b" . str_replace("Pet", " Pet", $pet_type) . " §awith the name §b" . $pet_name . " §ahas been successfully spawned");
90 | });
91 |
92 | $player->sendForm($form);
93 | }));
94 | }
95 |
96 | $sender->sendForm($form);
97 | break;
98 | case "spawn":
99 | if (!$sender->hasPermission("simplepets.spawn")) {
100 | $sender->sendMessage("§cYou don't have permission to run this command");
101 | return;
102 | }
103 |
104 | if (isset($args[1], $args[2])) {
105 | $player = Server::getInstance()->getPlayerByPrefix($args[1]);
106 |
107 | if ($player === null) {
108 | $sender->sendMessage("§cPlayer with name $args[1] doesnt exists");
109 | return;
110 | }
111 |
112 | if (isset(PetManager::getInstance()->getActivePets()[$player->getName()][$args[2]])) {
113 | $sender->sendMessage("§c{$player->getName()} already have a pet with the name " . $args[2]);
114 | } else {
115 | if (isset(PetManager::getInstance()->getRegisteredPets()[$args[2]])) {
116 | if (isset($args[4]) && is_numeric($args[4]) and (float)$args[4] > 0 and (float)$args[4] < 10) {
117 | if (isset($args[5]) && is_bool($args[5])) {
118 | PetManager::getInstance()->spawnPet($player, $args[2], $args[3], (float)$args[4], (bool)$args[5]);
119 | } else {
120 | PetManager::getInstance()->spawnPet($player, $args[2], $args[3], (float)$args[4]);
121 | }
122 | } else {
123 | PetManager::getInstance()->spawnPet($player, $args[2], $args[3]);
124 | }
125 |
126 | $sender->sendMessage("§b" . str_replace("Pet", " Pet", $args[2]) . " §awith the name §b" . $args[3] . " §ahas been successfully spawned to §b" . $player->getName());
127 | } else {
128 | $sender->sendMessage("§cPet with type §4" . $args[2] . " §cis not registered. §aTry §b/spet petlist §ato view registered pets");
129 | }
130 | }
131 | } else {
132 | $sender->sendMessage("§cUsage: /spet spawn ");
133 | }
134 | break;
135 | case "remove":
136 | case "delete":
137 | if (!$sender->hasPermission("simplepets.remove")) {
138 | $sender->sendMessage("§cYou don't have permission to run this command");
139 | return;
140 | }
141 |
142 | if (isset($args[1], $args[2])) {
143 | $player = Server::getInstance()->getPlayerByPrefix($args[1]);
144 |
145 | if ($player === null) {
146 | $sender->sendMessage("§cPlayer with name $args[1] doesnt exists");
147 | return;
148 | }
149 |
150 | if (isset(PetManager::getInstance()->getActivePets()[$player->getName()][$args[2]])) {
151 | $id = PetManager::getInstance()->getActivePets()[$player->getName()][$args[2]];
152 | $pet = Server::getInstance()->getWorldManager()->findEntity($id);
153 |
154 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
155 | $pet->despawn();
156 | }
157 |
158 | PetManager::getInstance()->removeActivePet($player, (string)$args[2]);
159 | Database::getInstance()->removePet($player, $args[2]);
160 | $sender->sendMessage("§aPet with the name §b" . $args[2] . " §afrom §b{$player->getName()} §ahas been successfully removed");
161 | } else {
162 | $sender->sendMessage("§a{$player->getName()} don't have a pet with the name §b" . $args[2]);
163 | }
164 | } else {
165 | $sender->sendMessage("§cUsage: /spet remove ");
166 | }
167 | break;
168 | case "inventory":
169 | case "inv":
170 | if (!SimplePets::getInstance()->getConfig()->get("enable-inventory")) {
171 | $sender->sendMessage("§cPet inventory feature is disabled!");
172 | return;
173 | }
174 |
175 | if ($sender instanceof Player) {
176 | if (isset($args[2])) {
177 | if (!$sender->hasPermission("simplepets.inv.other")) {
178 | $sender->sendMessage("§cYou don't have permission to run this command");
179 | return;
180 | }
181 |
182 | $player = Server::getInstance()->getPlayerByPrefix($args[1]);
183 |
184 | if ($player === null) {
185 | $sender->sendMessage("§cPlayer with name $args[1] doesnt exists");
186 | } else {
187 | if (isset(PetManager::getInstance()->getActivePets()[$player->getName()][$args[2]])) {
188 | $id = PetManager::getInstance()->getActivePets()[$player->getName()][$args[2]];
189 | $pet = Server::getInstance()->getWorldManager()->findEntity($id);
190 |
191 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
192 | $pet->getInventoryMenu()->send($player, $pet->getName());
193 | }
194 | } else {
195 | $sender->sendMessage("§a{$player->getName()} don't have a pet with the name §b" . $args[2]);
196 | }
197 |
198 | return;
199 | }
200 | } elseif (isset($args[1])) {
201 | if (!$sender->hasPermission("simplepets.inv")) {
202 | $sender->sendMessage("§cYou don't have permission to run this command");
203 | return;
204 | }
205 |
206 | if (isset(PetManager::getInstance()->getActivePets()[$sender->getName()][$args[1]])) {
207 | $id = PetManager::getInstance()->getActivePets()[$sender->getName()][$args[1]];
208 | $pet = Server::getInstance()->getWorldManager()->findEntity($id);
209 |
210 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
211 | if ($pet->isInvEnabled()) {
212 | $pet->getInventoryMenu()->send($sender, $pet->getName());
213 | } else {
214 | $sender->sendMessage("§cInventory access to your pet named §4" . $pet->getName() . " §cis disabled");
215 | }
216 | }
217 | } else {
218 | $sender->sendMessage("§aYou don't have a pet with the name §b" . $args[1]);
219 | }
220 | } else {
221 | $sender->sendMessage("§cUsage: /spet inv ");
222 | }
223 | }
224 | break;
225 | case "ride":
226 | if (!SimplePets::getInstance()->getConfig()->get("enable-riding")) {
227 | $sender->sendMessage("§cPet riding feature is disabled!");
228 | return;
229 | }
230 |
231 | if (!$sender->hasPermission("simplepets.ride")) {
232 | $sender->sendMessage("§cYou don't have permission to run this command");
233 | return;
234 | }
235 |
236 | if ($sender instanceof Player) {
237 | if (isset($args[1])) {
238 | if (isset(PetManager::getInstance()->getActivePets()[$sender->getName()][$args[1]])) {
239 | $id = PetManager::getInstance()->getActivePets()[$sender->getName()][$args[1]];
240 | $pet = Server::getInstance()->getWorldManager()->findEntity($id);
241 |
242 | if ($pet instanceof BasePet || $pet instanceof CustomPet) {
243 | if ($pet->isRidingEnabled()) {
244 | $pet->link($sender);
245 | } else {
246 | $sender->sendMessage("§cRiding access to your pet named §4" . $pet->getName() . " §cis disabled");
247 | }
248 | }
249 | } else {
250 | $sender->sendMessage("§aYou don't have a pet with the name §b" . $args[1]);
251 | }
252 | } else {
253 | $sender->sendMessage("§cUsage: /spet ride ");
254 | }
255 | }
256 | break;
257 | case "petlist":
258 | if (!$sender->hasPermission("simplepets.petlist")) {
259 | $sender->sendMessage("§cYou don't have permission to run this command");
260 | return;
261 | }
262 |
263 | $message = "§bSimplePets pet list:\n";
264 |
265 | foreach (PetManager::getInstance()->getRegisteredPets() as $type => $class) {
266 | $message .= "§b- §a" . $type . "\n";
267 | }
268 |
269 | $sender->sendMessage($message);
270 | break;
271 | case "help":
272 | $sender->sendMessage("\n§7---- ---- ---- - ---- ---- ----\n§eCommand List:\n§2» /spet petlist\n§2» /spet spawn \n§2» /spet remove \n§2» /spet inv \n§2» /spet ride \n§7---- ---- ---- - ---- ---- ----");
273 | break;
274 | default:
275 | $sender->sendMessage(TextFormat::RED . "Subcommand '$args[0]' not found! Try '/spet help' for help.");
276 | }
277 | } else {
278 | $sender->sendMessage("§7---- ---- [ §aSimplePets§7 ] ---- ----\n§bAuthor: @brokiem\n§3Source Code: github.com/brokiem/SimplePets\nVersion " . $this->getOwningPlugin()->getDescription()->getVersion() . "\n§7---- ---- ---- - ---- ---- ----");
279 | }
280 | }
281 |
282 | public function getOwningPlugin(): Plugin {
283 | return SimplePets::getInstance();
284 | }
285 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/database/Database.php:
--------------------------------------------------------------------------------
1 | getDatabase();
38 | $db->executeInsert(self::SIMPLEPETS_REGISTERPET, [
39 | "petType" => $pet->getPetType(),
40 | "petName" => $pet->getPetName(),
41 | "petOwner" => $pet->getPetOwner(),
42 | "petSize" => $pet->getPetSize(),
43 | "petBaby" => $pet->isBabyPet(),
44 | "petVisible" => $pet->getPetVisibility(),
45 | "enableInv" => $pet->isInvEnabled(),
46 | "enableRiding" => $pet->isRidingEnabled(),
47 | "extraData" => null
48 | ]);
49 | }
50 |
51 | public function savePet(BasePet|CustomPet $pet): void {
52 | $db = SimplePets::getInstance()->getDatabase();
53 | $db->executeSelect(self::SIMPLEPETS_GETPET, [
54 | "petName" => $pet->getPetName(),
55 | "petOwner" => $pet->getPetOwner()
56 | ], function(array $rows) use ($pet, $db) {
57 | foreach ($rows as $row) {
58 | $db->executeInsert(self::SIMPLEPETS_SAVEPET, [
59 | "id" => $row["id"],
60 | "petType" => $pet->getPetType(),
61 | "petName" => $pet->getPetName(),
62 | "petOwner" => $pet->getPetOwner(),
63 | "petSize" => $pet->getPetSize(),
64 | "petBaby" => $pet->isBabyPet(),
65 | "petVisible" => $pet->getPetVisibility(),
66 | "enableInv" => $pet->isInvEnabled(),
67 | "enableRiding" => $pet->isRidingEnabled(),
68 | "extraData" => null
69 | ]);
70 | }
71 | });
72 | }
73 |
74 | public function removePet(Player $owner, string $petName): void {
75 | $db = SimplePets::getInstance()->getDatabase();
76 | $db->executeSelect(self::SIMPLEPETS_GETPET, [
77 | "petName" => $petName,
78 | "petOwner" => $owner->getXuid()
79 | ], function(array $rows) use ($db) {
80 | foreach ($rows as $row) {
81 | $db->executeGeneric(self::SIMPLEPETS_REMOVEPET, ["id" => $row["id"]]);
82 | }
83 | });
84 |
85 | $file = SimplePets::getInstance()->getDataFolder() . "pets_inventory/" . $owner->getXuid() . "-" . $petName . ".dat";
86 | if (is_file($file)) {
87 | unlink($file);
88 | }
89 | }
90 |
91 | public function respawnPet(Player $owner): void {
92 | SimplePets::getInstance()->getDatabase()->executeSelect(self::SIMPLEPETS_GETALLPETS, [
93 | "petOwner" => $owner->getXuid()
94 | ], function(array $rows) use ($owner) {
95 | foreach ($rows as $row) {
96 | $type = $row["petType"];
97 | $name = $row["petName"];
98 | $size = $row["petSize"];
99 | $baby = $row["petBaby"];
100 | $visibility = $row["petVisible"];
101 | $enableInv = $row["enableInv"];
102 | $enableRiding = $row["enableRiding"];
103 | $extraData = $row["extraData"];
104 |
105 | PetManager::getInstance()->respawnPet($owner, $type, $name, $size, (bool)$baby, $visibility, (bool)$enableInv, (bool)$enableRiding, $extraData);
106 | }
107 | });
108 | }
109 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/manager/PetManager.php:
--------------------------------------------------------------------------------
1 | AllayPet::class,
129 | "AxolotlPet" => AxolotlPet::class,
130 | "WardenPet" => WardenPet::class,
131 | "GoatPet" => GoatPet::class,
132 | "ArmorstandPet" => ArmorstandPet::class,
133 | "ArrowPet" => ArrowPet::class,
134 | "BatPet" => BatPet::class,
135 | "BeePet" => BeePet::class,
136 | "BlazePet" => BlazePet::class,
137 | "BoatPet" => BoatPet::class,
138 | "CatPet" => CatPet::class,
139 | "CavespiderPet" => CavespiderPet::class,
140 | "ChestminecartPet" => ChestminecartPet::class,
141 | "ChickenPet" => ChickenPet::class,
142 | "CodPet" => CodPet::class,
143 | "CommandblockminecartPet" => CommandblockminecartPet::class,
144 | "CowPet" => CowPet::class,
145 | "CreeperPet" => CreeperPet::class,
146 | "DolphinPet" => DolphinPet::class,
147 | "DonkeyPet" => DonkeyPet::class,
148 | "DragonfireballPet" => DragonfireballPet::class,
149 | "DrownedPet" => DrownedPet::class,
150 | "EggPet" => EggPet::class,
151 | "ElderguardianPet" => ElderguardianPet::class,
152 | "ElderguardianghostPet" => ElderguardianghostPet::class,
153 | "EndercrystalPet" => EndercrystalPet::class,
154 | "EnderdragonPet" => EnderdragonPet::class,
155 | "EndermanPet" => EndermanPet::class,
156 | "EndermitePet" => EndermitePet::class,
157 | "EnderpearlPet" => EnderpearlPet::class,
158 | "EvocationfangPet" => EvocationfangPet::class,
159 | "EvocationillagerPet" => EvocationillagerPet::class,
160 | "EyeofendersignalPet" => EyeofendersignalPet::class,
161 | "FireballPet" => FireballPet::class,
162 | "FoxPet" => FoxPet::class,
163 | "GhastPet" => GhastPet::class,
164 | "GuardianPet" => GuardianPet::class,
165 | "HoglinPet" => HoglinPet::class,
166 | "HopperminecartPet" => HopperminecartPet::class,
167 | "HorsePet" => HorsePet::class,
168 | "HuskPet" => HuskPet::class,
169 | "IrongolemPet" => IrongolemPet::class,
170 | "LingeringpotionPet" => LingeringpotionPet::class,
171 | "LlamaPet" => LlamaPet::class,
172 | "MagmacubePet" => MagmacubePet::class,
173 | "MinecartPet" => MinecartPet::class,
174 | "MooshroomPet" => MooshroomPet::class,
175 | "MulePet" => MulePet::class,
176 | "OcelotPet" => OcelotPet::class,
177 | "PandaPet" => PandaPet::class,
178 | "ParrotPet" => ParrotPet::class,
179 | "PhantomPet" => PhantomPet::class,
180 | "PigPet" => PigPet::class,
181 | "PiglinPet" => PiglinPet::class,
182 | "PillagerPet" => PillagerPet::class,
183 | "PolarbearPet" => PolarbearPet::class,
184 | "PufferfishPet" => PufferfishPet::class,
185 | "RabbitPet" => RabbitPet::class,
186 | "RavagerPet" => RavagerPet::class,
187 | "SalmonPet" => SalmonPet::class,
188 | "SheepPet" => SheepPet::class,
189 | "ShulkerPet" => ShulkerPet::class,
190 | "ShulkerbulletPet" => ShulkerbulletPet::class,
191 | "SilverfishPet" => SilverfishPet::class,
192 | "SkeletonPet" => SkeletonPet::class,
193 | "SkeletonhorsePet" => SkeletonhorsePet::class,
194 | "SlimePet" => SlimePet::class,
195 | "SmallfireballPet" => SmallfireballPet::class,
196 | "SnowballPet" => SnowballPet::class,
197 | "SnowgolemPet" => SnowgolemPet::class,
198 | "SpiderPet" => SpiderPet::class,
199 | "SplashpotionPet" => SplashpotionPet::class,
200 | "SquidPet" => SquidPet::class,
201 | "StrayPet" => StrayPet::class,
202 | "StriderPet" => StriderPet::class,
203 | "TntPet" => TntPet::class,
204 | "TntminecartPet" => TntminecartPet::class,
205 | "TropicalfishPet" => TropicalfishPet::class,
206 | "TurtlePet" => TurtlePet::class,
207 | "VexPet" => VexPet::class,
208 | "VillagerPet" => VillagerPet::class,
209 | "Villagerv2Pet" => Villagerv2Pet::class,
210 | "VindicatorPet" => VindicatorPet::class,
211 | "WanderingtraderPet" => WanderingtraderPet::class,
212 | "WitchPet" => WitchPet::class,
213 | "WitherPet" => WitherPet::class,
214 | "WitherskeletonPet" => WitherskeletonPet::class,
215 | "WitherskullPet" => WitherskullPet::class,
216 | "WolfPet" => WolfPet::class,
217 | "ZoglinPet" => ZoglinPet::class,
218 | "ZombiePet" => ZombiePet::class,
219 | "ZombiehorsePet" => ZombiehorsePet::class,
220 | "ZombiepigmanPet" => ZombiepigmanPet::class,
221 | "ZombievillagerPet" => ZombievillagerPet::class,
222 | "Zombievillagerv2Pet" => Zombievillagerv2Pet::class
223 | ];
224 |
225 | private array $registered_pets = [];
226 | private array $active_pets = [];
227 | private array $ridden_pet = [];
228 |
229 | public const VISIBLE_TO_EVERYONE = 0;
230 | public const VISIBLE_TO_OWNER = 1;
231 | public const INVISIBLE_TO_EVERYONE = 3;
232 |
233 | public function __construct() {
234 | self::setInstance($this);
235 | foreach ($this->default_pets as $type => $class) {
236 | self::registerEntity($class, [$type]);
237 | $this->registerPet($type, $class);
238 | }
239 | }
240 |
241 | public static function registerEntity(string $entityClass, array $saveNames = []): void {
242 | if (!class_exists($entityClass)) {
243 | throw new \RuntimeException("Class $entityClass not found.");
244 | }
245 |
246 | $refClass = new \ReflectionClass($entityClass);
247 | if (is_a($entityClass, BasePet::class, true) || is_a($entityClass, CustomPet::class, true) and !$refClass->isAbstract()) {
248 | if (is_a($entityClass, CustomPet::class, true)) {
249 | EntityFactory::getInstance()->register($entityClass, function(World $world, CompoundTag $nbt) use ($entityClass): Entity {
250 | return new $entityClass(EntityDataHelper::parseLocation($nbt, $world), Human::parseSkinNBT($nbt), $nbt);
251 | }, array_merge([$entityClass], $saveNames));
252 | } else {
253 | EntityFactory::getInstance()->register($entityClass, function(World $world, CompoundTag $nbt) use ($entityClass): Entity {
254 | return new $entityClass(EntityDataHelper::parseLocation($nbt, $world), $nbt);
255 | }, array_merge([$entityClass], $saveNames));
256 | }
257 | }
258 | }
259 |
260 | public function registerPet(string $type, string $class): void {
261 | if (!class_exists($class)) {
262 | throw new \RuntimeException("Class $class not found.");
263 | }
264 |
265 | $refClass = new \ReflectionClass($class);
266 | if (is_a($class, BasePet::class, true) || is_a($class, CustomPet::class, true) and !$refClass->isAbstract()) {
267 | $this->registered_pets[$type] = $class;
268 | }
269 | }
270 |
271 | public function spawnPet(Player $owner, string $petType, string $petName, float $petSize = 1, bool $petBaby = false, int $petVis = PetManager::VISIBLE_TO_EVERYONE, bool $enableInv = true, bool $enableRiding = true, ?string $extraData = "null"): void {
272 | $location = clone $owner->getLocation();
273 | ++$location->y;
274 |
275 | $nbt = $this->createBaseNBT($location);
276 | $nbt->setString("petOwner", $owner->getXuid())
277 | ->setString("petName", $petName)
278 | ->setFloat("petSize", $petSize)
279 | ->setInt("petBaby", (int)$petBaby)
280 | ->setInt("petVisibility", $petVis)
281 | ->setInt("invEnabled", (int)$enableInv)
282 | ->setInt("ridingEnabled", (int)$enableRiding)
283 | ->setString("extraData", $extraData ?? "null");
284 | $pet = $this->createEntity($petType, $location, $nbt);
285 |
286 | if ($pet !== null) {
287 | $pet->setPetName($petName);
288 | $pet->setPetBaby($petBaby);
289 | $pet->setPetVisibility($petVis);
290 | $pet->spawnToAll();
291 |
292 | $this->active_pets[$owner->getName()][$pet->getPetName()] = $pet->getId();
293 | Database::getInstance()->registerPet($pet);
294 | }
295 | }
296 |
297 | public function respawnPet(Player $owner, string $petType, string $petName, float $petSize = 1, bool $petBaby = false, int $petVis = PetManager::VISIBLE_TO_EVERYONE, bool $enableInv = true, bool $enableRiding = true, ?string $extraData = "null"): void {
298 | $location = clone $owner->getLocation();
299 | ++$location->y;
300 |
301 | $nbt = $this->createBaseNBT($location);
302 | $nbt->setString("petOwner", $owner->getXuid())
303 | ->setString("petName", $petName)
304 | ->setFloat("petSize", $petSize)
305 | ->setInt("petBaby", (int)$petBaby)
306 | ->setInt("petVisibility", $petVis)
307 | ->setInt("invEnabled", (int)$enableInv)
308 | ->setInt("ridingEnabled", (int)$enableRiding)
309 | ->setString("extraData", $extraData ?? "null");
310 | $pet = $this->createEntity($petType, $location, $nbt);
311 |
312 | if ($pet !== null) {
313 | $pet->setPetName($petName);
314 | $pet->setPetBaby($petBaby);
315 | $pet->setPetVisibility($petVis);
316 | $pet->spawnToAll();
317 |
318 | $this->active_pets[$owner->getName()][$pet->getPetName()] = $pet->getId();
319 | }
320 | }
321 |
322 | public function addRiddenPet(Player $owner, BasePet|CustomPet $pet): void {
323 | $this->ridden_pet[$owner->getName()] = $pet;
324 | }
325 |
326 | public function getRegisteredPets(): array {
327 | return $this->registered_pets;
328 | }
329 |
330 | public function getActivePets(): array {
331 | return $this->active_pets;
332 | }
333 |
334 | public function getRiddenPet(Player $owner): null|BasePet|CustomPet {
335 | return $this->ridden_pet[$owner->getName()] ?? null;
336 | }
337 |
338 | public function removeRiddenPet(Player $owner): void {
339 | unset($this->ridden_pet[$owner->getName()]);
340 | }
341 |
342 | public function removeActivePet(Player $owner, string $petName): bool {
343 | $this->removeRiddenPet($owner);
344 |
345 | if (isset($this->active_pets[$owner->getName()][$petName])) {
346 | unset($this->active_pets[$owner->getName()][$petName]);
347 | return true;
348 | }
349 |
350 | return false;
351 | }
352 |
353 | /**
354 | * Helper function which creates minimal NBT needed to spawn an entity.
355 | */
356 | public function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null, float $yaw = 0.0, float $pitch = 0.0): CompoundTag {
357 | return CompoundTag::create()
358 | ->setTag("Pos", new ListTag([
359 | new DoubleTag($pos->x),
360 | new DoubleTag($pos->y),
361 | new DoubleTag($pos->z)
362 | ]))
363 | ->setTag("Motion", new ListTag([
364 | new DoubleTag($motion !== null ? $motion->x : 0.0),
365 | new DoubleTag($motion !== null ? $motion->y : 0.0),
366 | new DoubleTag($motion !== null ? $motion->z : 0.0)
367 | ]))
368 | ->setTag("Rotation", new ListTag([
369 | new FloatTag($yaw),
370 | new FloatTag($pitch)
371 | ]));
372 | }
373 |
374 | public function createEntity(string $type, Location $location, CompoundTag $nbt): null|BasePet|CustomPet {
375 | if (isset($this->registered_pets[$type])) {
376 | /** @var BasePet|CustomPet $class */
377 | $class = $this->registered_pets[$type];
378 |
379 | if (is_a($class, BasePet::class, true)) {
380 | return new $class($location, $nbt);
381 | }
382 |
383 | if (is_a($class, CustomPet::class, true)) {
384 | return new $class($location, Human::parseSkinNBT($nbt), $nbt);
385 | }
386 | }
387 |
388 | return null;
389 | }
390 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/pets/AllayPet.php:
--------------------------------------------------------------------------------
1 | petOwner = $nbt->getString("petOwner");
55 | $this->petName = $nbt->getString("petName");
56 | $this->petSize = $nbt->getFloat("petSize", 1);
57 | $this->petBaby = (bool)$nbt->getInt("petBaby", 0);
58 | $this->petVisibility = $nbt->getInt("petVisibility", PetManager::VISIBLE_TO_EVERYONE);
59 | $this->invEnabled = (bool)$nbt->getInt("invEnabled", 1);
60 | $this->ridingEnabled = (bool)$nbt->getInt("ridingEnabled", 1);
61 | $this->extraData = $nbt->getString("extraData") === "" ? null : $nbt->getString("extraData");
62 | }
63 |
64 | parent::__construct($location, $nbt);
65 | $this->setNameTagAlwaysVisible();
66 | $this->setCanSaveWithChunk(false);
67 |
68 | $this->setMaxHealth(20);
69 | $this->setHealth(20);
70 | }
71 |
72 | abstract public static function getNetworkTypeId(): string;
73 |
74 | abstract public function getPetType(): string;
75 |
76 | public function getPetOwner(): ?string {
77 | return $this->petOwner;
78 | }
79 |
80 | public function setPetOwner(string $xuid): void {
81 | $this->petOwner = $xuid;
82 | }
83 |
84 | public function getPetName(): ?string {
85 | return $this->petName;
86 | }
87 |
88 | public function setPetName(string $name): void {
89 | $this->petName = $name;
90 | $this->setNameTag($name);
91 | }
92 |
93 | public function getPetSize(): float {
94 | return $this->petSize;
95 | }
96 |
97 | public function setPetSize(float $size): void {
98 | $this->petSize = $size;
99 | $this->setScale($size);
100 | }
101 |
102 | public function setPetBaby(bool $val): void {
103 | $this->petBaby = $val;
104 |
105 | $this->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::BABY, $val);
106 | }
107 |
108 | public function isBabyPet(): bool {
109 | return $this->petBaby;
110 | }
111 |
112 | public function setPetVisibility(int $val): void {
113 | $this->petVisibility = $val;
114 |
115 | switch ($val) {
116 | case PetManager::VISIBLE_TO_EVERYONE:
117 | $this->despawnFromAll();
118 | $this->spawnToAll();
119 | break;
120 | case PetManager::VISIBLE_TO_OWNER:
121 | if ($this->getPetOwner() !== null) {
122 | $owner = SimplePets::getInstance()->getPlayerByXuid($this->getPetOwner());
123 |
124 | if ($owner !== null) {
125 | $this->despawnFromAll();
126 | $this->spawnTo($owner);
127 | }
128 | }
129 | break;
130 | case PetManager::INVISIBLE_TO_EVERYONE:
131 | $this->despawnFromAll();
132 | break;
133 | }
134 | }
135 |
136 | public function getPetVisibility(): int {
137 | return $this->petVisibility;
138 | }
139 |
140 | public function setInvEnabled(bool $val): void {
141 | $this->invEnabled = $val;
142 | }
143 |
144 | public function isInvEnabled(): bool {
145 | return $this->invEnabled;
146 | }
147 |
148 | public function setRidingEnabled(bool $val): void {
149 | $this->ridingEnabled = $val;
150 | }
151 |
152 | public function isRidingEnabled(): bool {
153 | return $this->ridingEnabled;
154 | }
155 |
156 | public function getPetExtraData(): ?string {
157 | return $this->extraData;
158 | }
159 |
160 | public function link(Player $rider): void {
161 | $rider->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::RIDING, true);
162 | $rider->getNetworkProperties()->setVector3(EntityMetadataProperties::RIDER_SEAT_POSITION, new Vector3(0, $this->getInitialSizeInfo()->getHeight() + 1, 0));
163 |
164 | $pk = new SetActorLinkPacket();
165 | $pk->link = new EntityLink($this->getId(), $rider->getId(), EntityLink::TYPE_RIDER, false, true);
166 | $rider->getServer()->broadcastPackets($this->getViewers(), [$pk]);
167 |
168 | PetManager::getInstance()->addRiddenPet($rider, $this);
169 | $this->rider = $rider->getXuid();
170 | }
171 |
172 | public function unlink(): void {
173 | if ($this->getRider() !== null) {
174 | $this->getRider()->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::RIDING, false);
175 | $this->getRider()->getNetworkProperties()->setVector3(EntityMetadataProperties::RIDER_SEAT_POSITION, new Vector3(0, 0, 0));
176 |
177 | $pk = new SetActorLinkPacket();
178 | $pk->link = new EntityLink($this->getId(), $this->getRider()->getId(), EntityLink::TYPE_REMOVE, false, true);
179 | $this->getRider()->getServer()->broadcastPackets($this->getViewers(), [$pk]);
180 |
181 | PetManager::getInstance()->removeRiddenPet($this->getRider());
182 | }
183 |
184 | $this->rider = null;
185 | }
186 |
187 | public function getRider(): ?Player {
188 | return SimplePets::getInstance()->getPlayerByXuid($this->rider);
189 | }
190 |
191 | public function getName(): string {
192 | return $this->petName ?? "s_pet_no_name";
193 | }
194 |
195 | public function getInventoryMenu(): InvMenu {
196 | return $this->petInventoryMenu;
197 | }
198 |
199 | public function despawn(): void {
200 | if (!$this->isFlaggedForDespawn()) {
201 | $this->flagForDespawn();
202 | }
203 | }
204 |
205 | public function saveInventory(ListTag $petInventoryTag): void {
206 | $nbt = CompoundTag::create()->setTag("PetInventory", $petInventoryTag);
207 | $file = SimplePets::getInstance()->getDataFolder() . "pets_inventory/" . $this->getPetOwner() . "-" . $this->getName() . ".dat";
208 | file_put_contents($file, zlib_encode((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)), ZLIB_ENCODING_GZIP));
209 | }
210 |
211 | public function getSavedInventory(): ?CompoundTag {
212 | $file = SimplePets::getInstance()->getDataFolder() . "pets_inventory/" . $this->getPetOwner() . "-" . $this->getName() . ".dat";
213 |
214 | if (is_file($file)) {
215 | $decompressed = @zlib_decode(file_get_contents($file));
216 | return (new LittleEndianNbtSerializer())->read($decompressed)->mustGetCompoundTag();
217 | }
218 |
219 | return null;
220 | }
221 |
222 | // hehe thx blockpet
223 | public function walk(float $motionX, float $motionZ, Player $rider): void {
224 | $this->location->yaw = $rider->getLocation()->yaw;
225 | $this->location->pitch = $rider->getLocation()->pitch;
226 | $this->scheduleUpdate();
227 |
228 | $direction_plane = $this->getDirectionPlane();
229 | $x = $direction_plane->x / 2.5;
230 | $z = $direction_plane->y / 2.5;
231 |
232 | switch ($motionZ) {
233 | case 1:
234 | $finalMotionX = $x;
235 | $finalMotionZ = $z;
236 | break;
237 | case -1:
238 | $finalMotionX = -$x;
239 | $finalMotionZ = -$z;
240 | break;
241 | default:
242 | $average = $x + $z / 2;
243 | $finalMotionX = $average / 1.414 * $motionZ;
244 | $finalMotionZ = $average / 1.414 * $motionX;
245 | break;
246 | }
247 |
248 | switch ($motionX) {
249 | case 1:
250 | $finalMotionX = $z;
251 | $finalMotionZ = -$x;
252 | break;
253 | case -1:
254 | $finalMotionX = -$z;
255 | $finalMotionZ = $x;
256 | break;
257 | }
258 |
259 | if ($this->shouldJump()) {
260 | $this->jump();
261 | }
262 |
263 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
264 | $this->updateMovement();
265 | }
266 |
267 | public function flagForDespawn(): void {
268 | $this->saveNBT();
269 |
270 | parent::flagForDespawn();
271 | }
272 |
273 | protected function initEntity(CompoundTag $nbt): void {
274 | parent::initEntity($nbt);
275 |
276 | $this->petInventoryMenu = InvMenu::create(InvMenuTypeIds::TYPE_CHEST);
277 |
278 | $petInventoryTag = $this->getSavedInventory();
279 | if ($petInventoryTag !== null) {
280 | $inv = $petInventoryTag->getListTag("PetInventory");
281 | if ($inv !== null) {
282 | /** @var CompoundTag $item */
283 | foreach ($inv as $item) {
284 | $this->petInventoryMenu->getInventory()->setItem($item->getByte("Slot"), Item::nbtDeserialize($item));
285 | }
286 | }
287 | }
288 | }
289 |
290 | public function saveNBT(): CompoundTag {
291 | $nbt = parent::saveNBT();
292 |
293 | if ($this->petInventoryMenu !== null) {
294 | /** @var CompoundTag[] $items */
295 | $items = [];
296 |
297 | $slotCount = $this->petInventoryMenu->getInventory()->getSize();
298 | for ($slot = 0; $slot < $slotCount; ++$slot) {
299 | $item = $this->petInventoryMenu->getInventory()->getItem($slot);
300 | if (!$item->isNull()) {
301 | $items[] = $item->nbtSerialize($slot);
302 | }
303 | }
304 |
305 | $this->saveInventory(new ListTag($items, NBT::TAG_Compound));
306 | }
307 |
308 | return $nbt;
309 | }
310 |
311 | protected function entityBaseTick(int $tickDiff = 1): bool {
312 | if ($this->rider !== null or $this->isClosed()) {
313 | return parent::entityBaseTick($tickDiff);
314 | }
315 |
316 | $this->followOwner();
317 |
318 | if ($this->checkVal <= 0) {
319 | $this->checkVal = 60;
320 |
321 | $owner = $this->getPetOwner();
322 |
323 | if ($owner !== null) {
324 | $target = SimplePets::getInstance()->getPlayerByXuid($owner);
325 |
326 | if (($target !== null) && $this->getPosition()->distance($target->getPosition()) >= 20) {
327 | $this->teleport($target->getPosition());
328 | }
329 | }
330 | }
331 |
332 | --$this->checkVal;
333 | return parent::entityBaseTick($tickDiff);
334 | }
335 |
336 | public function followOwner(): void {
337 | $owner = $this->getPetOwner();
338 |
339 | if ($owner === null) {
340 | return;
341 | }
342 |
343 | $target = SimplePets::getInstance()->getPlayerByXuid($owner);
344 |
345 | if ($target === null) {
346 | return;
347 | }
348 |
349 | if ($this->getPosition()->distance($target->getPosition()) <= 2) {
350 | return;
351 | }
352 |
353 | if ($this->shouldJump()) {
354 | $this->jump();
355 | }
356 |
357 | $x = $target->getLocation()->x - $this->getLocation()->x;
358 | $y = $target->getLocation()->y - $this->getLocation()->y;
359 | $z = $target->getLocation()->z - $this->getLocation()->z;
360 | /** @noinspection RandomApiMigrationInspection */
361 | if ($x * $x + $z * $z < mt_rand(3, 8)) {
362 | $this->motion->x = 0;
363 | $this->motion->z = 0;
364 | } else {
365 | $this->motion->x = 0.17 * ($x / (abs($x) + abs($z)));
366 | $this->motion->z = 0.17 * ($z / (abs($x) + abs($z)));
367 | }
368 |
369 | $this->getLocation()->yaw = rad2deg(atan2(-$x, $z));
370 | $this->getLocation()->pitch = rad2deg(-atan2($y, sqrt($x * $x + $z * $z)));
371 |
372 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
373 | $this->lookAt($target->getPosition());
374 |
375 | $this->updateMovement();
376 | }
377 |
378 | public function shouldJump(): bool {
379 | if ($this->getBlockInFront()->getId() !== BlockLegacyIds::AIR) {
380 | return $this->getBlockInFront(1)->getId() === BlockLegacyIds::AIR;
381 | }
382 |
383 | if ($this->getBlockInFront(-0.9) instanceof Carpet) {
384 | return !($this->getWorld()->getBlock($this->getPosition()->add(0, -0.9, 0)) instanceof Carpet);
385 | }
386 |
387 | if ($this->getBlockInFront() instanceof Flowable) {
388 | return false;
389 | }
390 |
391 | if ($this->getBlockInFront() instanceof Liquid) {
392 | return true;
393 | }
394 |
395 | return false;
396 | }
397 |
398 | public function getBlockInFront(float $y = 0): Block {
399 | $pos = $this->getPosition()->add($this->getDirectionVector()->x * $this->getScale(), $y, $this->getDirectionVector()->z * $this->getScale())->round();
400 | return $this->getWorld()->getBlock($pos);
401 | }
402 | }
--------------------------------------------------------------------------------
/src/brokiem/simplepets/pets/base/CustomPet.php:
--------------------------------------------------------------------------------
1 | petOwner = $nbt->getString("petOwner");
56 | $this->petName = $nbt->getString("petName");
57 | $this->petSize = $nbt->getFloat("petSize", 1);
58 | $this->petBaby = (bool)$nbt->getInt("petBaby", 0);
59 | $this->petVisibility = $nbt->getInt("petVisibility", PetManager::VISIBLE_TO_EVERYONE);
60 | $this->invEnabled = (bool)$nbt->getInt("invEnabled", 1);
61 | $this->ridingEnabled = (bool)$nbt->getInt("ridingEnabled", 1);
62 | $this->extraData = $nbt->getString("extraData") === "" ? null : $nbt->getString("extraData");
63 | }
64 |
65 | parent::__construct($location, $skin, $nbt);
66 | $this->setNameTagAlwaysVisible();
67 | $this->setCanSaveWithChunk(false);
68 |
69 | $this->setMaxHealth(20);
70 | $this->setHealth(20);
71 | }
72 |
73 | abstract public function getPetType(): string;
74 |
75 | public function getPetOwner(): ?string {
76 | return $this->petOwner;
77 | }
78 |
79 | public function setPetOwner(string $xuid): void {
80 | $this->petOwner = $xuid;
81 | }
82 |
83 | public function getPetName(): ?string {
84 | return $this->petName;
85 | }
86 |
87 | public function setPetName(string $name): void {
88 | $this->petName = $name;
89 | $this->setNameTag($name);
90 | }
91 |
92 | public function getPetSize(): float {
93 | return $this->petSize;
94 | }
95 |
96 | public function setPetSize(float $size): void {
97 | $this->petSize = $size;
98 | $this->setScale($size);
99 | }
100 |
101 | public function setPetBaby(bool $val): void {
102 | $this->petBaby = $val;
103 |
104 | $this->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::BABY, $val);
105 | }
106 |
107 | public function isBabyPet(): bool {
108 | return $this->petBaby;
109 | }
110 |
111 | public function setPetVisibility(int $val): void {
112 | $this->petVisibility = $val;
113 |
114 | switch ($val) {
115 | case PetManager::VISIBLE_TO_EVERYONE:
116 | $this->despawnFromAll();
117 | $this->spawnToAll();
118 | break;
119 | case PetManager::VISIBLE_TO_OWNER:
120 | if ($this->getPetOwner() !== null) {
121 | $owner = SimplePets::getInstance()->getPlayerByXuid($this->getPetOwner());
122 |
123 | if ($owner !== null) {
124 | $this->despawnFromAll();
125 | $this->spawnTo($owner);
126 | }
127 | }
128 | break;
129 | case PetManager::INVISIBLE_TO_EVERYONE:
130 | $this->despawnFromAll();
131 | break;
132 | }
133 | }
134 |
135 | public function getPetVisibility(): int {
136 | return $this->petVisibility;
137 | }
138 |
139 | public function setInvEnabled(bool $val): void {
140 | $this->invEnabled = $val;
141 | }
142 |
143 | public function isInvEnabled(): bool {
144 | return $this->invEnabled;
145 | }
146 |
147 | public function setRidingEnabled(bool $val): void {
148 | $this->ridingEnabled = $val;
149 | }
150 |
151 | public function isRidingEnabled(): bool {
152 | return $this->ridingEnabled;
153 | }
154 |
155 | public function getPetExtraData(): ?string {
156 | return $this->extraData;
157 | }
158 |
159 | public function getInventoryMenu(): InvMenu {
160 | return $this->petInventoryMenu;
161 | }
162 |
163 | public function link(Player $rider): void {
164 | $rider->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::RIDING, true);
165 | $rider->getNetworkProperties()->setVector3(EntityMetadataProperties::RIDER_SEAT_POSITION, new Vector3(0, $this->getInitialSizeInfo()->getHeight() + 1, 0));
166 |
167 | $pk = new SetActorLinkPacket();
168 | $pk->link = new EntityLink($this->getId(), $rider->getId(), EntityLink::TYPE_RIDER, false, true);
169 | $rider->getServer()->broadcastPackets($this->getViewers(), [$pk]);
170 |
171 | PetManager::getInstance()->addRiddenPet($rider, $this);
172 | $this->rider = $rider->getXuid();
173 | }
174 |
175 | public function unlink(): void {
176 | if ($this->rider !== null) {
177 | if ($this->getRider() !== null) {
178 | $this->getRider()->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::RIDING, false);
179 | $this->getRider()->getNetworkProperties()->setVector3(EntityMetadataProperties::RIDER_SEAT_POSITION, new Vector3(0, 0, 0));
180 |
181 | $pk = new SetActorLinkPacket();
182 | $pk->link = new EntityLink($this->getId(), $this->getRider()->getId(), EntityLink::TYPE_REMOVE, false, true);
183 | $this->getRider()->getServer()->broadcastPackets($this->getViewers(), [$pk]);
184 |
185 | PetManager::getInstance()->removeRiddenPet($this->getRider());
186 | }
187 |
188 | $this->rider = null;
189 | }
190 | }
191 |
192 | public function getRider(): ?Player {
193 | return SimplePets::getInstance()->getPlayerByXuid($this->rider);
194 | }
195 |
196 | public function despawn(): void {
197 | if (!$this->isFlaggedForDespawn()) {
198 | $this->flagForDespawn();
199 | }
200 | }
201 |
202 | public function saveInventory(ListTag $petInventoryTag): void {
203 | $nbt = CompoundTag::create()->setTag("PetInventory", $petInventoryTag);
204 | $file = SimplePets::getInstance()->getDataFolder() . "pets_inventory/" . $this->getPetOwner() . "-" . $this->getName() . ".dat";
205 | file_put_contents($file, zlib_encode((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)), ZLIB_ENCODING_GZIP));
206 | }
207 |
208 | public function getSavedInventory(): ?CompoundTag {
209 | $file = SimplePets::getInstance()->getDataFolder() . "pets_inventory/" . $this->getPetOwner() . "-" . $this->getName() . ".dat";
210 |
211 | if (is_file($file)) {
212 | $decompressed = @zlib_decode(file_get_contents($file));
213 | return (new LittleEndianNbtSerializer())->read($decompressed)->mustGetCompoundTag();
214 | }
215 |
216 | return null;
217 | }
218 |
219 | public function walk(float $motionX, float $motionZ, Player $rider): void {
220 | $this->location->yaw = $rider->getLocation()->yaw;
221 | $this->location->pitch = $rider->getLocation()->pitch;
222 | $this->scheduleUpdate();
223 |
224 | $direction_plane = $this->getDirectionPlane();
225 | $x = $direction_plane->x / 2.5;
226 | $z = $direction_plane->y / 2.5;
227 |
228 | switch ($motionZ) {
229 | case 1:
230 | $finalMotionX = $x;
231 | $finalMotionZ = $z;
232 | break;
233 | case -1:
234 | $finalMotionX = -$x;
235 | $finalMotionZ = -$z;
236 | break;
237 | default:
238 | $average = $x + $z / 2;
239 | $finalMotionX = $average / 1.414 * $motionZ;
240 | $finalMotionZ = $average / 1.414 * $motionX;
241 | break;
242 | }
243 |
244 | switch ($motionX) {
245 | case 1:
246 | $finalMotionX = $z;
247 | $finalMotionZ = -$x;
248 | break;
249 | case -1:
250 | $finalMotionX = -$z;
251 | $finalMotionZ = $x;
252 | break;
253 | }
254 |
255 | if ($this->shouldJump()) {
256 | $this->jump();
257 | }
258 |
259 | $this->move($finalMotionX, $this->motion->y, $finalMotionZ);
260 | $this->updateMovement();
261 | }
262 |
263 | protected function initEntity(CompoundTag $nbt): void {
264 | parent::initEntity($nbt);
265 |
266 | $this->petInventoryMenu = InvMenu::create(InvMenuTypeIds::TYPE_CHEST);
267 |
268 | $petInventoryTag = $this->getSavedInventory();
269 | if ($petInventoryTag !== null) {
270 | $inv = $petInventoryTag->getListTag("PetInventory");
271 | if ($inv !== null) {
272 | /** @var CompoundTag $item */
273 | foreach ($inv as $item) {
274 | $this->petInventoryMenu->getInventory()->setItem($item->getByte("Slot"), Item::nbtDeserialize($item));
275 | }
276 | }
277 | }
278 | }
279 |
280 | public function saveNBT(): CompoundTag {
281 | $nbt = parent::saveNBT();
282 |
283 | if ($this->petInventoryMenu !== null) {
284 | /** @var CompoundTag[] $items */
285 | $items = [];
286 |
287 | $slotCount = $this->petInventoryMenu->getInventory()->getSize();
288 | for ($slot = 0; $slot < $slotCount; ++$slot) {
289 | $item = $this->petInventoryMenu->getInventory()->getItem($slot);
290 | if (!$item->isNull()) {
291 | $items[] = $item->nbtSerialize($slot);
292 | }
293 | }
294 |
295 | $this->saveInventory(new ListTag($items, NBT::TAG_Compound));
296 | }
297 |
298 | return $nbt;
299 | }
300 |
301 | protected function entityBaseTick(int $tickDiff = 1): bool {
302 | if ($this->rider !== null or $this->isClosed()) {
303 | return parent::entityBaseTick($tickDiff);
304 | }
305 |
306 | $this->followOwner();
307 |
308 | if ($this->checkVal <= 0) {
309 | $this->checkVal = 60;
310 |
311 | $owner = $this->getPetOwner();
312 |
313 | if ($owner !== null) {
314 | $target = SimplePets::getInstance()->getPlayerByXuid($owner);
315 |
316 | if (($target !== null) && $this->getPosition()->distance($target->getPosition()) >= 20) {
317 | $this->teleport($target->getPosition());
318 | }
319 | }
320 | }
321 |
322 | --$this->checkVal;
323 | return parent::entityBaseTick($tickDiff);
324 | }
325 |
326 | public function followOwner(): void {
327 | $owner = $this->getPetOwner();
328 |
329 | if ($owner === null) {
330 | return;
331 | }
332 |
333 | $target = SimplePets::getInstance()->getPlayerByXuid($owner);
334 |
335 | if ($target === null) {
336 | return;
337 | }
338 |
339 | if ($this->getPosition()->distance($target->getPosition()) <= 2) {
340 | return;
341 | }
342 |
343 | if ($this->shouldJump()) {
344 | $this->jump();
345 | }
346 |
347 | $x = $target->getLocation()->x - $this->getLocation()->x;
348 | $y = $target->getLocation()->y - $this->getLocation()->y;
349 | $z = $target->getLocation()->z - $this->getLocation()->z;
350 | /** @noinspection RandomApiMigrationInspection */
351 | if ($x * $x + $z * $z < mt_rand(3, 8)) {
352 | $this->motion->x = 0;
353 | $this->motion->z = 0;
354 | } else {
355 | $this->motion->x = 0.17 * ($x / (abs($x) + abs($z)));
356 | $this->motion->z = 0.17 * ($z / (abs($x) + abs($z)));
357 | }
358 |
359 | $this->getLocation()->yaw = rad2deg(atan2(-$x, $z));
360 | $this->getLocation()->pitch = rad2deg(-atan2($y, sqrt($x * $x + $z * $z)));
361 |
362 | $this->move($this->motion->x, $this->motion->y, $this->motion->z);
363 | $this->lookAt($target->getPosition());
364 |
365 | $this->updateMovement();
366 | }
367 |
368 | public function shouldJump(): bool {
369 | if ($this->getBlockInFront()->getId() !== BlockLegacyIds::AIR) {
370 | return $this->getBlockInFront(1)->getId() === BlockLegacyIds::AIR;
371 | }
372 |
373 | if ($this->getBlockInFront(-0.9) instanceof Carpet) {
374 | return !($this->getWorld()->getBlock($this->getPosition()->add(0, -0.9, 0)) instanceof Carpet);
375 | }
376 |
377 | if ($this->getBlockInFront() instanceof Flowable) {
378 | return false;
379 | }
380 |
381 | if ($this->getBlockInFront() instanceof Liquid) {
382 | return true;
383 | }
384 |
385 | return false;
386 | }
387 |
388 | public function getBlockInFront(float $y = 0): Block {
389 | $pos = $this->getPosition()->add($this->getDirectionVector()->x * $this->getScale(), $y, $this->getDirectionVector()->z * $this->getScale())->round();
390 | return $this->getWorld()->getBlock($pos);
391 | }
392 | }
--------------------------------------------------------------------------------