├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── run └── kubejs │ └── client_scripts │ ├── block_entity_nbt.js │ ├── getting-started.js │ ├── particles.js │ ├── removeEntity.js │ ├── section_animation.js │ ├── set-replace-modify.js │ ├── shear_sheep.js │ └── tags.js ├── settings.gradle.kts └── src └── main ├── java └── com │ └── almostreliable │ └── ponderjs │ ├── KubePlugin.java │ ├── PonderBuilderJS.java │ ├── PonderEvents.java │ ├── PonderItemTagEventJS.java │ ├── PonderJS.java │ ├── PonderJSMod.java │ ├── PonderJSPlugin.java │ ├── PonderLang.java │ ├── PonderRegistryEventJS.java │ ├── PonderStoriesManager.java │ ├── api │ ├── CustomPonderOverlayElement.java │ ├── CustomPonderSceneElement.java │ ├── OnElementAction.java │ ├── OnRenderOverlay.java │ ├── OnRenderWorld.java │ └── package-info.java │ ├── commands │ └── GenerateKubeJSLangCommand.java │ ├── extension │ ├── OverlayInstructionExtension.java │ ├── SceneBuilderExtension.java │ ├── WorldInstructionExtension.java │ └── package-info.java │ ├── mixin │ ├── KubeJSClientMixin.java │ ├── ParticleAccessor.java │ ├── PonderClientMixin.java │ ├── PonderIndexAccessor.java │ ├── PonderIndexMixin.java │ ├── PonderInstructionMixin.java │ ├── PonderLocalizationMixin.java │ ├── PonderOverlayInstructionsMixin.java │ ├── PonderSceneBuilderMixin.java │ ├── PonderSceneRegistryMixin.java │ ├── PonderSpecialInstructionsMixin.java │ ├── PonderTagRegistryAccessor.java │ ├── PonderWorldAccessor.java │ ├── PonderWorldInstructionMixin.java │ ├── SceneBuildingUtilMixin.java │ └── package-info.java │ ├── package-info.java │ ├── particles │ ├── ParticleDataBuilder.java │ ├── ParticleInstructions.java │ └── ParticleTransformation.java │ └── util │ ├── BlockStateFunction.java │ ├── DyeColorWrapper.java │ ├── PonderErrorHelper.java │ └── Util.java └── resources ├── META-INF └── neoforge.mods.toml ├── assets └── ponderjs │ └── ponder │ ├── basic.nbt │ ├── block_entity_tutorial.nbt │ └── the_cake_is_a_lie.nbt ├── kubejs.plugins.txt ├── pack.mcmeta └── ponderjs.mixins.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 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 = 120 15 | ij_wrap_on_typing = false 16 | 17 | [*.java] 18 | ij_visual_guides = none 19 | ij_java_align_consecutive_assignments = false 20 | ij_java_align_consecutive_variable_declarations = false 21 | ij_java_align_group_field_declarations = false 22 | ij_java_align_multiline_annotation_parameters = false 23 | ij_java_align_multiline_array_initializer_expression = true 24 | ij_java_align_multiline_assignment = false 25 | ij_java_align_multiline_binary_operation = true 26 | ij_java_align_multiline_chained_methods = false 27 | ij_java_align_multiline_extends_list = true 28 | ij_java_align_multiline_for = true 29 | ij_java_align_multiline_method_parentheses = false 30 | ij_java_align_multiline_parameters = true 31 | ij_java_align_multiline_parameters_in_calls = false 32 | ij_java_align_multiline_parenthesized_expression = true 33 | ij_java_align_multiline_records = true 34 | ij_java_align_multiline_resources = true 35 | ij_java_align_multiline_ternary_operation = true 36 | ij_java_align_multiline_text_blocks = false 37 | ij_java_align_multiline_throws_list = true 38 | ij_java_align_subsequent_simple_methods = false 39 | ij_java_align_throws_keyword = false 40 | ij_java_annotation_parameter_wrap = off 41 | ij_java_array_initializer_new_line_after_left_brace = true 42 | ij_java_array_initializer_right_brace_on_new_line = true 43 | ij_java_array_initializer_wrap = on_every_item 44 | ij_java_assert_statement_colon_on_next_line = false 45 | ij_java_assert_statement_wrap = off 46 | ij_java_assignment_wrap = off 47 | ij_java_binary_operation_sign_on_next_line = false 48 | ij_java_binary_operation_wrap = normal 49 | ij_java_blank_lines_after_anonymous_class_header = 0 50 | ij_java_blank_lines_after_class_header = 0 51 | ij_java_blank_lines_after_imports = 1 52 | ij_java_blank_lines_after_package = 1 53 | ij_java_blank_lines_around_class = 1 54 | ij_java_blank_lines_around_field = 0 55 | ij_java_blank_lines_around_field_in_interface = 0 56 | ij_java_blank_lines_around_initializer = 1 57 | ij_java_blank_lines_around_method = 1 58 | ij_java_blank_lines_around_method_in_interface = 1 59 | ij_java_blank_lines_before_class_end = 0 60 | ij_java_blank_lines_before_imports = 1 61 | ij_java_blank_lines_before_method_body = 0 62 | ij_java_blank_lines_before_package = 0 63 | ij_java_block_brace_style = end_of_line 64 | ij_java_block_comment_at_first_column = true 65 | ij_java_builder_methods = none 66 | ij_java_call_parameters_new_line_after_left_paren = false 67 | ij_java_call_parameters_right_paren_on_new_line = false 68 | ij_java_call_parameters_wrap = on_every_item 69 | ij_java_case_statement_on_separate_line = true 70 | ij_java_catch_on_new_line = false 71 | ij_java_class_annotation_wrap = split_into_lines 72 | ij_java_class_brace_style = end_of_line 73 | ij_java_class_count_to_use_import_on_demand = 5 74 | ij_java_class_names_in_javadoc = 1 75 | ij_java_do_not_indent_top_level_class_members = false 76 | ij_java_do_not_wrap_after_single_annotation = false 77 | ij_java_do_while_brace_force = if_multiline 78 | ij_java_doc_add_blank_line_after_description = true 79 | ij_java_doc_add_blank_line_after_param_comments = false 80 | ij_java_doc_add_blank_line_after_return = false 81 | ij_java_doc_add_p_tag_on_empty_lines = true 82 | ij_java_doc_align_exception_comments = true 83 | ij_java_doc_align_param_comments = true 84 | ij_java_doc_do_not_wrap_if_one_line = false 85 | ij_java_doc_enable_formatting = true 86 | ij_java_doc_enable_leading_asterisks = true 87 | ij_java_doc_indent_on_continuation = false 88 | ij_java_doc_keep_empty_lines = true 89 | ij_java_doc_keep_empty_parameter_tag = true 90 | ij_java_doc_keep_empty_return_tag = true 91 | ij_java_doc_keep_empty_throws_tag = true 92 | ij_java_doc_keep_invalid_tags = true 93 | ij_java_doc_param_description_on_new_line = false 94 | ij_java_doc_preserve_line_breaks = false 95 | ij_java_doc_use_throws_not_exception_tag = true 96 | ij_java_else_on_new_line = false 97 | ij_java_enum_constants_wrap = split_into_lines 98 | ij_java_extends_keyword_wrap = normal 99 | ij_java_extends_list_wrap = normal 100 | ij_java_field_annotation_wrap = normal 101 | ij_java_finally_on_new_line = false 102 | ij_java_for_brace_force = if_multiline 103 | ij_java_for_statement_new_line_after_left_paren = false 104 | ij_java_for_statement_right_paren_on_new_line = false 105 | ij_java_for_statement_wrap = off 106 | ij_java_generate_final_locals = false 107 | ij_java_generate_final_parameters = false 108 | ij_java_if_brace_force = if_multiline 109 | ij_java_imports_layout = *, |, javax.**, java.**, |, $* 110 | ij_java_indent_case_from_switch = true 111 | ij_java_insert_inner_class_imports = false 112 | ij_java_insert_override_annotation = true 113 | ij_java_keep_blank_lines_before_right_brace = 2 114 | ij_java_keep_blank_lines_between_package_declaration_and_header = 2 115 | ij_java_keep_blank_lines_in_code = 2 116 | ij_java_keep_blank_lines_in_declarations = 2 117 | ij_java_keep_builder_methods_indents = false 118 | ij_java_keep_control_statement_in_one_line = true 119 | ij_java_keep_first_column_comment = true 120 | ij_java_keep_indents_on_empty_lines = false 121 | ij_java_keep_line_breaks = true 122 | ij_java_keep_multiple_expressions_in_one_line = false 123 | ij_java_keep_simple_blocks_in_one_line = false 124 | ij_java_keep_simple_classes_in_one_line = true 125 | ij_java_keep_simple_lambdas_in_one_line = true 126 | ij_java_keep_simple_methods_in_one_line = true 127 | ij_java_label_indent_absolute = false 128 | ij_java_label_indent_size = 0 129 | ij_java_lambda_brace_style = end_of_line 130 | ij_java_layout_static_imports_separately = true 131 | ij_java_line_comment_add_space = false 132 | ij_java_line_comment_at_first_column = true 133 | ij_java_method_annotation_wrap = split_into_lines 134 | ij_java_method_brace_style = end_of_line 135 | ij_java_method_call_chain_wrap = on_every_item 136 | ij_java_method_parameters_new_line_after_left_paren = false 137 | ij_java_method_parameters_right_paren_on_new_line = false 138 | ij_java_method_parameters_wrap = off 139 | ij_java_modifier_list_wrap = false 140 | ij_java_names_count_to_use_import_on_demand = 3 141 | ij_java_new_line_after_lparen_in_record_header = false 142 | ij_java_packages_to_use_import_on_demand = java.awt.*, javax.swing.* 143 | ij_java_parameter_annotation_wrap = off 144 | ij_java_parentheses_expression_new_line_after_left_paren = false 145 | ij_java_parentheses_expression_right_paren_on_new_line = false 146 | ij_java_place_assignment_sign_on_next_line = false 147 | ij_java_prefer_longer_names = true 148 | ij_java_prefer_parameters_wrap = false 149 | ij_java_record_components_wrap = normal 150 | ij_java_repeat_synchronized = true 151 | ij_java_replace_instanceof_and_cast = false 152 | ij_java_replace_null_check = true 153 | ij_java_replace_sum_lambda_with_method_ref = true 154 | ij_java_resource_list_new_line_after_left_paren = false 155 | ij_java_resource_list_right_paren_on_new_line = false 156 | ij_java_resource_list_wrap = off 157 | ij_java_rparen_on_new_line_in_record_header = false 158 | ij_java_space_after_closing_angle_bracket_in_type_argument = false 159 | ij_java_space_after_colon = true 160 | ij_java_space_after_comma = true 161 | ij_java_space_after_comma_in_type_arguments = true 162 | ij_java_space_after_for_semicolon = true 163 | ij_java_space_after_quest = true 164 | ij_java_space_after_type_cast = true 165 | ij_java_space_before_annotation_array_initializer_left_brace = false 166 | ij_java_space_before_annotation_parameter_list = false 167 | ij_java_space_before_array_initializer_left_brace = false 168 | ij_java_space_before_catch_keyword = true 169 | ij_java_space_before_catch_left_brace = true 170 | ij_java_space_before_catch_parentheses = true 171 | ij_java_space_before_class_left_brace = true 172 | ij_java_space_before_colon = true 173 | ij_java_space_before_colon_in_foreach = true 174 | ij_java_space_before_comma = false 175 | ij_java_space_before_do_left_brace = true 176 | ij_java_space_before_else_keyword = true 177 | ij_java_space_before_else_left_brace = true 178 | ij_java_space_before_finally_keyword = true 179 | ij_java_space_before_finally_left_brace = true 180 | ij_java_space_before_for_left_brace = true 181 | ij_java_space_before_for_parentheses = true 182 | ij_java_space_before_for_semicolon = false 183 | ij_java_space_before_if_left_brace = true 184 | ij_java_space_before_if_parentheses = true 185 | ij_java_space_before_method_call_parentheses = false 186 | ij_java_space_before_method_left_brace = true 187 | ij_java_space_before_method_parentheses = false 188 | ij_java_space_before_opening_angle_bracket_in_type_parameter = false 189 | ij_java_space_before_quest = true 190 | ij_java_space_before_switch_left_brace = true 191 | ij_java_space_before_switch_parentheses = true 192 | ij_java_space_before_synchronized_left_brace = true 193 | ij_java_space_before_synchronized_parentheses = true 194 | ij_java_space_before_try_left_brace = true 195 | ij_java_space_before_try_parentheses = true 196 | ij_java_space_before_type_parameter_list = false 197 | ij_java_space_before_while_keyword = true 198 | ij_java_space_before_while_left_brace = true 199 | ij_java_space_before_while_parentheses = true 200 | ij_java_space_inside_one_line_enum_braces = false 201 | ij_java_space_within_empty_array_initializer_braces = false 202 | ij_java_space_within_empty_method_call_parentheses = false 203 | ij_java_space_within_empty_method_parentheses = false 204 | ij_java_spaces_around_additive_operators = true 205 | ij_java_spaces_around_assignment_operators = true 206 | ij_java_spaces_around_bitwise_operators = true 207 | ij_java_spaces_around_equality_operators = true 208 | ij_java_spaces_around_lambda_arrow = true 209 | ij_java_spaces_around_logical_operators = true 210 | ij_java_spaces_around_method_ref_dbl_colon = false 211 | ij_java_spaces_around_multiplicative_operators = true 212 | ij_java_spaces_around_relational_operators = true 213 | ij_java_spaces_around_shift_operators = true 214 | ij_java_spaces_around_type_bounds_in_type_parameters = true 215 | ij_java_spaces_around_unary_operator = false 216 | ij_java_spaces_within_angle_brackets = false 217 | ij_java_spaces_within_annotation_parentheses = false 218 | ij_java_spaces_within_array_initializer_braces = true 219 | ij_java_spaces_within_braces = false 220 | ij_java_spaces_within_brackets = false 221 | ij_java_spaces_within_cast_parentheses = false 222 | ij_java_spaces_within_catch_parentheses = false 223 | ij_java_spaces_within_for_parentheses = false 224 | ij_java_spaces_within_if_parentheses = false 225 | ij_java_spaces_within_method_call_parentheses = false 226 | ij_java_spaces_within_method_parentheses = false 227 | ij_java_spaces_within_parentheses = false 228 | ij_java_spaces_within_record_header = false 229 | ij_java_spaces_within_switch_parentheses = false 230 | ij_java_spaces_within_synchronized_parentheses = false 231 | ij_java_spaces_within_try_parentheses = false 232 | ij_java_spaces_within_while_parentheses = false 233 | ij_java_special_else_if_treatment = true 234 | ij_java_subclass_name_suffix = Impl 235 | ij_java_ternary_operation_signs_on_next_line = true 236 | ij_java_ternary_operation_wrap = normal 237 | ij_java_test_name_suffix = Test 238 | ij_java_throws_keyword_wrap = off 239 | ij_java_throws_list_wrap = normal 240 | ij_java_use_external_annotations = false 241 | ij_java_use_fq_class_names = false 242 | ij_java_use_relative_indents = false 243 | ij_java_use_single_class_imports = true 244 | ij_java_variable_annotation_wrap = split_into_lines 245 | ij_java_visibility = public 246 | ij_java_while_brace_force = if_multiline 247 | ij_java_while_on_new_line = false 248 | ij_java_wrap_comments = false 249 | ij_java_wrap_first_method_in_call_chain = true 250 | ij_java_wrap_long_lines = false 251 | 252 | [*.nbtt] 253 | max_line_length = 150 254 | ij_continuation_indent_size = 4 255 | ij_visual_guides = none 256 | ij_nbtt_keep_indents_on_empty_lines = false 257 | ij_nbtt_space_after_colon = true 258 | ij_nbtt_space_after_comma = true 259 | ij_nbtt_space_before_colon = true 260 | ij_nbtt_space_before_comma = false 261 | ij_nbtt_spaces_within_brackets = false 262 | ij_nbtt_spaces_within_parentheses = false 263 | 264 | [*.properties] 265 | ij_visual_guides = none 266 | ij_properties_align_group_field_declarations = false 267 | ij_properties_keep_blank_lines = false 268 | ij_properties_key_value_delimiter = equals 269 | ij_properties_spaces_around_key_value_delimiter = false 270 | 271 | [*.scala] 272 | indent_size = 2 273 | tab_width = 2 274 | ij_continuation_indent_size = 2 275 | ij_visual_guides = none 276 | ij_scala_align_composite_pattern = true 277 | ij_scala_align_extends_with = 0 278 | ij_scala_align_group_field_declarations = false 279 | ij_scala_align_if_else = false 280 | ij_scala_align_in_columns_case_branch = false 281 | ij_scala_align_multiline_binary_operation = false 282 | ij_scala_align_multiline_chained_methods = false 283 | ij_scala_align_multiline_for = true 284 | ij_scala_align_multiline_parameters = true 285 | ij_scala_align_multiline_parameters_in_calls = false 286 | ij_scala_align_multiline_parenthesized_expression = false 287 | ij_scala_align_tuple_elements = false 288 | ij_scala_align_types_in_multiline_declarations = false 289 | ij_scala_alternate_continuation_indent_for_params = 4 290 | ij_scala_binary_operation_wrap = off 291 | ij_scala_blank_lines_after_anonymous_class_header = 0 292 | ij_scala_blank_lines_after_class_header = 0 293 | ij_scala_blank_lines_after_imports = 1 294 | ij_scala_blank_lines_after_package = 1 295 | ij_scala_blank_lines_around_class = 1 296 | ij_scala_blank_lines_around_class_in_inner_scopes = 0 297 | ij_scala_blank_lines_around_field = 0 298 | ij_scala_blank_lines_around_field_in_inner_scopes = 0 299 | ij_scala_blank_lines_around_field_in_interface = 0 300 | ij_scala_blank_lines_around_method = 1 301 | ij_scala_blank_lines_around_method_in_inner_scopes = 1 302 | ij_scala_blank_lines_around_method_in_interface = 1 303 | ij_scala_blank_lines_before_class_end = 0 304 | ij_scala_blank_lines_before_imports = 1 305 | ij_scala_blank_lines_before_method_body = 0 306 | ij_scala_blank_lines_before_package = 0 307 | ij_scala_block_brace_style = end_of_line 308 | ij_scala_block_comment_at_first_column = true 309 | ij_scala_call_parameters_new_line_after_lparen = 0 310 | ij_scala_call_parameters_right_paren_on_new_line = false 311 | ij_scala_call_parameters_wrap = off 312 | ij_scala_case_clause_brace_force = never 313 | ij_scala_catch_on_new_line = false 314 | ij_scala_class_annotation_wrap = split_into_lines 315 | ij_scala_class_brace_style = end_of_line 316 | ij_scala_closure_brace_force = never 317 | ij_scala_do_not_align_block_expr_params = true 318 | ij_scala_do_not_indent_case_clause_body = false 319 | ij_scala_do_not_indent_tuples_close_brace = true 320 | ij_scala_do_while_brace_force = never 321 | ij_scala_else_on_new_line = false 322 | ij_scala_enable_scaladoc_formatting = true 323 | ij_scala_enforce_functional_syntax_for_unit = true 324 | ij_scala_extends_keyword_wrap = off 325 | ij_scala_extends_list_wrap = off 326 | ij_scala_field_annotation_wrap = split_into_lines 327 | ij_scala_finally_brace_force = never 328 | ij_scala_finally_on_new_line = false 329 | ij_scala_for_brace_force = never 330 | ij_scala_for_statement_wrap = off 331 | ij_scala_formatter = 0 332 | ij_scala_if_brace_force = never 333 | ij_scala_implicit_value_class_suffix = Ops 334 | ij_scala_indent_braced_function_args = true 335 | ij_scala_indent_case_from_switch = true 336 | ij_scala_indent_first_parameter = true 337 | ij_scala_indent_first_parameter_clause = false 338 | ij_scala_indent_type_arguments = true 339 | ij_scala_indent_type_parameters = true 340 | ij_scala_indent_yield_after_one_line_enumerators = true 341 | ij_scala_keep_blank_lines_before_right_brace = 2 342 | ij_scala_keep_blank_lines_in_code = 2 343 | ij_scala_keep_blank_lines_in_declarations = 2 344 | ij_scala_keep_comments_on_same_line = true 345 | ij_scala_keep_first_column_comment = false 346 | ij_scala_keep_indents_on_empty_lines = false 347 | ij_scala_keep_line_breaks = true 348 | ij_scala_keep_one_line_lambdas_in_arg_list = false 349 | ij_scala_keep_simple_blocks_in_one_line = false 350 | ij_scala_keep_simple_methods_in_one_line = false 351 | ij_scala_keep_xml_formatting = false 352 | ij_scala_line_comment_at_first_column = true 353 | ij_scala_method_annotation_wrap = split_into_lines 354 | ij_scala_method_brace_force = never 355 | ij_scala_method_brace_style = end_of_line 356 | ij_scala_method_call_chain_wrap = off 357 | ij_scala_method_parameters_new_line_after_left_paren = false 358 | ij_scala_method_parameters_right_paren_on_new_line = false 359 | ij_scala_method_parameters_wrap = off 360 | ij_scala_modifier_list_wrap = false 361 | ij_scala_multiline_string_align_dangling_closing_quotes = false 362 | ij_scala_multiline_string_closing_quotes_on_new_line = true 363 | ij_scala_multiline_string_insert_margin_on_enter = true 364 | ij_scala_multiline_string_margin_char = | 365 | ij_scala_multiline_string_margin_indent = 2 366 | ij_scala_multiline_string_opening_quotes_on_new_line = true 367 | ij_scala_multiline_string_process_margin_on_copy_paste = true 368 | ij_scala_newline_after_annotations = false 369 | ij_scala_not_continuation_indent_for_params = false 370 | ij_scala_parameter_annotation_wrap = off 371 | ij_scala_parentheses_expression_new_line_after_left_paren = false 372 | ij_scala_parentheses_expression_right_paren_on_new_line = false 373 | ij_scala_place_closure_parameters_on_new_line = false 374 | ij_scala_place_self_type_on_new_line = true 375 | ij_scala_prefer_parameters_wrap = false 376 | ij_scala_preserve_space_after_method_declaration_name = false 377 | ij_scala_reformat_on_compile = false 378 | ij_scala_replace_case_arrow_with_unicode_char = false 379 | ij_scala_replace_for_generator_arrow_with_unicode_char = false 380 | ij_scala_replace_lambda_with_greek_letter = false 381 | ij_scala_replace_map_arrow_with_unicode_char = false 382 | ij_scala_scalafmt_fallback_to_default_settings = false 383 | ij_scala_scalafmt_reformat_on_files_save = false 384 | ij_scala_scalafmt_show_invalid_code_warnings = true 385 | ij_scala_scalafmt_use_intellij_formatter_for_range_format = true 386 | ij_scala_sd_align_exception_comments = true 387 | ij_scala_sd_align_list_item_content = true 388 | ij_scala_sd_align_other_tags_comments = true 389 | ij_scala_sd_align_parameters_comments = true 390 | ij_scala_sd_align_return_comments = true 391 | ij_scala_sd_blank_line_after_parameters_comments = false 392 | ij_scala_sd_blank_line_after_return_comments = false 393 | ij_scala_sd_blank_line_before_parameters = false 394 | ij_scala_sd_blank_line_before_tags = true 395 | ij_scala_sd_blank_line_between_parameters = false 396 | ij_scala_sd_keep_blank_lines_between_tags = false 397 | ij_scala_sd_preserve_spaces_in_tags = false 398 | ij_scala_space_after_comma = true 399 | ij_scala_space_after_for_semicolon = true 400 | ij_scala_space_after_modifiers_constructor = false 401 | ij_scala_space_after_type_colon = true 402 | ij_scala_space_before_brace_method_call = true 403 | ij_scala_space_before_class_left_brace = true 404 | ij_scala_space_before_for_parentheses = true 405 | ij_scala_space_before_if_parentheses = true 406 | ij_scala_space_before_infix_like_method_parentheses = false 407 | ij_scala_space_before_infix_method_call_parentheses = false 408 | ij_scala_space_before_infix_operator_like_method_call_parentheses = true 409 | ij_scala_space_before_method_call_parentheses = false 410 | ij_scala_space_before_method_left_brace = true 411 | ij_scala_space_before_method_parentheses = false 412 | ij_scala_space_before_type_colon = false 413 | ij_scala_space_before_type_parameter_in_def_list = false 414 | ij_scala_space_before_type_parameter_leading_context_bound_colon = false 415 | ij_scala_space_before_type_parameter_leading_context_bound_colon_hk = true 416 | ij_scala_space_before_type_parameter_list = false 417 | ij_scala_space_before_type_parameter_rest_context_bound_colons = true 418 | ij_scala_space_before_while_parentheses = true 419 | ij_scala_space_inside_closure_braces = true 420 | ij_scala_space_inside_self_type_braces = true 421 | ij_scala_space_within_empty_method_call_parentheses = false 422 | ij_scala_spaces_around_at_in_patterns = false 423 | ij_scala_spaces_in_imports = false 424 | ij_scala_spaces_in_one_line_blocks = false 425 | ij_scala_spaces_within_brackets = false 426 | ij_scala_spaces_within_for_parentheses = false 427 | ij_scala_spaces_within_if_parentheses = false 428 | ij_scala_spaces_within_method_call_parentheses = false 429 | ij_scala_spaces_within_method_parentheses = false 430 | ij_scala_spaces_within_parentheses = false 431 | ij_scala_spaces_within_while_parentheses = false 432 | ij_scala_special_else_if_treatment = true 433 | ij_scala_trailing_comma_arg_list_enabled = true 434 | ij_scala_trailing_comma_import_selector_enabled = false 435 | ij_scala_trailing_comma_mode = trailing_comma_keep 436 | ij_scala_trailing_comma_params_enabled = true 437 | ij_scala_trailing_comma_pattern_arg_list_enabled = false 438 | ij_scala_trailing_comma_tuple_enabled = false 439 | ij_scala_trailing_comma_tuple_type_enabled = false 440 | ij_scala_trailing_comma_type_params_enabled = false 441 | ij_scala_try_brace_force = never 442 | ij_scala_type_annotation_exclude_constant = true 443 | ij_scala_type_annotation_exclude_in_dialect_sources = true 444 | ij_scala_type_annotation_exclude_in_test_sources = false 445 | ij_scala_type_annotation_exclude_member_of_anonymous_class = false 446 | ij_scala_type_annotation_exclude_member_of_private_class = false 447 | ij_scala_type_annotation_exclude_when_type_is_stable = true 448 | ij_scala_type_annotation_function_parameter = false 449 | ij_scala_type_annotation_implicit_modifier = true 450 | ij_scala_type_annotation_local_definition = false 451 | ij_scala_type_annotation_private_member = false 452 | ij_scala_type_annotation_protected_member = true 453 | ij_scala_type_annotation_public_member = true 454 | ij_scala_type_annotation_structural_type = true 455 | ij_scala_type_annotation_underscore_parameter = false 456 | ij_scala_type_annotation_unit_type = true 457 | ij_scala_use_alternate_continuation_indent_for_params = false 458 | ij_scala_use_scala3_indentation_based_syntax = true 459 | ij_scala_use_scaladoc2_formatting = false 460 | ij_scala_variable_annotation_wrap = off 461 | ij_scala_while_brace_force = never 462 | ij_scala_while_on_new_line = false 463 | ij_scala_wrap_before_with_keyword = false 464 | ij_scala_wrap_first_method_in_call_chain = false 465 | ij_scala_wrap_long_lines = false 466 | 467 | [.editorconfig] 468 | ij_visual_guides = none 469 | ij_editorconfig_align_group_field_declarations = false 470 | ij_editorconfig_space_after_colon = false 471 | ij_editorconfig_space_after_comma = true 472 | ij_editorconfig_space_before_colon = false 473 | ij_editorconfig_space_before_comma = false 474 | ij_editorconfig_spaces_around_assignment_operators = true 475 | 476 | [{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.jspx, *.pom, *.rng, *.tagx, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}] 477 | ij_visual_guides = none 478 | ij_xml_align_attributes = true 479 | ij_xml_align_text = false 480 | ij_xml_attribute_wrap = normal 481 | ij_xml_block_comment_at_first_column = true 482 | ij_xml_keep_blank_lines = 2 483 | ij_xml_keep_indents_on_empty_lines = false 484 | ij_xml_keep_line_breaks = true 485 | ij_xml_keep_line_breaks_in_text = true 486 | ij_xml_keep_whitespaces = false 487 | ij_xml_keep_whitespaces_around_cdata = preserve 488 | ij_xml_keep_whitespaces_inside_cdata = false 489 | ij_xml_line_comment_at_first_column = true 490 | ij_xml_space_after_tag_name = false 491 | ij_xml_space_around_equals_in_attribute = false 492 | ij_xml_space_inside_empty_tag = false 493 | ij_xml_text_wrap = normal 494 | ij_xml_use_custom_settings = false 495 | 496 | [{*.bash, *.sh, *.zsh}] 497 | indent_size = 2 498 | tab_width = 2 499 | ij_visual_guides = none 500 | ij_shell_binary_ops_start_line = false 501 | ij_shell_keep_column_alignment_padding = false 502 | ij_shell_minify_program = false 503 | ij_shell_redirect_followed_by_space = false 504 | ij_shell_switch_cases_indented = false 505 | ij_shell_use_unix_line_separator = true 506 | 507 | [{*.gant, *.gradle, *.groovy, *.gy}] 508 | ij_visual_guides = none 509 | ij_groovy_align_group_field_declarations = false 510 | ij_groovy_align_multiline_array_initializer_expression = false 511 | ij_groovy_align_multiline_assignment = false 512 | ij_groovy_align_multiline_binary_operation = false 513 | ij_groovy_align_multiline_chained_methods = false 514 | ij_groovy_align_multiline_extends_list = false 515 | ij_groovy_align_multiline_for = true 516 | ij_groovy_align_multiline_list_or_map = true 517 | ij_groovy_align_multiline_method_parentheses = false 518 | ij_groovy_align_multiline_parameters = true 519 | ij_groovy_align_multiline_parameters_in_calls = false 520 | ij_groovy_align_multiline_resources = true 521 | ij_groovy_align_multiline_ternary_operation = false 522 | ij_groovy_align_multiline_throws_list = false 523 | ij_groovy_align_named_args_in_map = true 524 | ij_groovy_align_throws_keyword = false 525 | ij_groovy_array_initializer_new_line_after_left_brace = false 526 | ij_groovy_array_initializer_right_brace_on_new_line = false 527 | ij_groovy_array_initializer_wrap = off 528 | ij_groovy_assert_statement_wrap = off 529 | ij_groovy_assignment_wrap = off 530 | ij_groovy_binary_operation_wrap = off 531 | ij_groovy_blank_lines_after_class_header = 0 532 | ij_groovy_blank_lines_after_imports = 1 533 | ij_groovy_blank_lines_after_package = 1 534 | ij_groovy_blank_lines_around_class = 1 535 | ij_groovy_blank_lines_around_field = 0 536 | ij_groovy_blank_lines_around_field_in_interface = 0 537 | ij_groovy_blank_lines_around_method = 1 538 | ij_groovy_blank_lines_around_method_in_interface = 1 539 | ij_groovy_blank_lines_before_imports = 1 540 | ij_groovy_blank_lines_before_method_body = 0 541 | ij_groovy_blank_lines_before_package = 0 542 | ij_groovy_block_brace_style = end_of_line 543 | ij_groovy_block_comment_at_first_column = true 544 | ij_groovy_call_parameters_new_line_after_left_paren = false 545 | ij_groovy_call_parameters_right_paren_on_new_line = false 546 | ij_groovy_call_parameters_wrap = off 547 | ij_groovy_catch_on_new_line = false 548 | ij_groovy_class_annotation_wrap = split_into_lines 549 | ij_groovy_class_brace_style = end_of_line 550 | ij_groovy_class_count_to_use_import_on_demand = 5 551 | ij_groovy_do_while_brace_force = never 552 | ij_groovy_else_on_new_line = false 553 | ij_groovy_enum_constants_wrap = off 554 | ij_groovy_extends_keyword_wrap = off 555 | ij_groovy_extends_list_wrap = off 556 | ij_groovy_field_annotation_wrap = split_into_lines 557 | ij_groovy_finally_on_new_line = false 558 | ij_groovy_for_brace_force = never 559 | ij_groovy_for_statement_new_line_after_left_paren = false 560 | ij_groovy_for_statement_right_paren_on_new_line = false 561 | ij_groovy_for_statement_wrap = off 562 | ij_groovy_if_brace_force = never 563 | ij_groovy_import_annotation_wrap = 2 564 | ij_groovy_imports_layout = *, |, javax.**, java.**, |, $* 565 | ij_groovy_indent_case_from_switch = true 566 | ij_groovy_indent_label_blocks = true 567 | ij_groovy_insert_inner_class_imports = false 568 | ij_groovy_keep_blank_lines_before_right_brace = 2 569 | ij_groovy_keep_blank_lines_in_code = 2 570 | ij_groovy_keep_blank_lines_in_declarations = 2 571 | ij_groovy_keep_control_statement_in_one_line = true 572 | ij_groovy_keep_first_column_comment = true 573 | ij_groovy_keep_indents_on_empty_lines = false 574 | ij_groovy_keep_line_breaks = true 575 | ij_groovy_keep_multiple_expressions_in_one_line = false 576 | ij_groovy_keep_simple_blocks_in_one_line = false 577 | ij_groovy_keep_simple_classes_in_one_line = true 578 | ij_groovy_keep_simple_lambdas_in_one_line = true 579 | ij_groovy_keep_simple_methods_in_one_line = true 580 | ij_groovy_label_indent_absolute = false 581 | ij_groovy_label_indent_size = 0 582 | ij_groovy_lambda_brace_style = end_of_line 583 | ij_groovy_layout_static_imports_separately = true 584 | ij_groovy_line_comment_add_space = false 585 | ij_groovy_line_comment_at_first_column = true 586 | ij_groovy_method_annotation_wrap = split_into_lines 587 | ij_groovy_method_brace_style = end_of_line 588 | ij_groovy_method_call_chain_wrap = off 589 | ij_groovy_method_parameters_new_line_after_left_paren = false 590 | ij_groovy_method_parameters_right_paren_on_new_line = false 591 | ij_groovy_method_parameters_wrap = off 592 | ij_groovy_modifier_list_wrap = false 593 | ij_groovy_names_count_to_use_import_on_demand = 3 594 | ij_groovy_parameter_annotation_wrap = off 595 | ij_groovy_parentheses_expression_new_line_after_left_paren = false 596 | ij_groovy_parentheses_expression_right_paren_on_new_line = false 597 | ij_groovy_prefer_parameters_wrap = false 598 | ij_groovy_resource_list_new_line_after_left_paren = false 599 | ij_groovy_resource_list_right_paren_on_new_line = false 600 | ij_groovy_resource_list_wrap = off 601 | ij_groovy_space_after_assert_separator = true 602 | ij_groovy_space_after_colon = true 603 | ij_groovy_space_after_comma = true 604 | ij_groovy_space_after_comma_in_type_arguments = true 605 | ij_groovy_space_after_for_semicolon = true 606 | ij_groovy_space_after_quest = true 607 | ij_groovy_space_after_type_cast = true 608 | ij_groovy_space_before_annotation_parameter_list = false 609 | ij_groovy_space_before_array_initializer_left_brace = false 610 | ij_groovy_space_before_assert_separator = false 611 | ij_groovy_space_before_catch_keyword = true 612 | ij_groovy_space_before_catch_left_brace = true 613 | ij_groovy_space_before_catch_parentheses = true 614 | ij_groovy_space_before_class_left_brace = true 615 | ij_groovy_space_before_closure_left_brace = true 616 | ij_groovy_space_before_colon = true 617 | ij_groovy_space_before_comma = false 618 | ij_groovy_space_before_do_left_brace = true 619 | ij_groovy_space_before_else_keyword = true 620 | ij_groovy_space_before_else_left_brace = true 621 | ij_groovy_space_before_finally_keyword = true 622 | ij_groovy_space_before_finally_left_brace = true 623 | ij_groovy_space_before_for_left_brace = true 624 | ij_groovy_space_before_for_parentheses = true 625 | ij_groovy_space_before_for_semicolon = false 626 | ij_groovy_space_before_if_left_brace = true 627 | ij_groovy_space_before_if_parentheses = true 628 | ij_groovy_space_before_method_call_parentheses = false 629 | ij_groovy_space_before_method_left_brace = true 630 | ij_groovy_space_before_method_parentheses = false 631 | ij_groovy_space_before_quest = true 632 | ij_groovy_space_before_switch_left_brace = true 633 | ij_groovy_space_before_switch_parentheses = true 634 | ij_groovy_space_before_synchronized_left_brace = true 635 | ij_groovy_space_before_synchronized_parentheses = true 636 | ij_groovy_space_before_try_left_brace = true 637 | ij_groovy_space_before_try_parentheses = true 638 | ij_groovy_space_before_while_keyword = true 639 | ij_groovy_space_before_while_left_brace = true 640 | ij_groovy_space_before_while_parentheses = true 641 | ij_groovy_space_in_named_argument = true 642 | ij_groovy_space_in_named_argument_before_colon = false 643 | ij_groovy_space_within_empty_array_initializer_braces = false 644 | ij_groovy_space_within_empty_method_call_parentheses = false 645 | ij_groovy_spaces_around_additive_operators = true 646 | ij_groovy_spaces_around_assignment_operators = true 647 | ij_groovy_spaces_around_bitwise_operators = true 648 | ij_groovy_spaces_around_equality_operators = true 649 | ij_groovy_spaces_around_lambda_arrow = true 650 | ij_groovy_spaces_around_logical_operators = true 651 | ij_groovy_spaces_around_multiplicative_operators = true 652 | ij_groovy_spaces_around_regex_operators = true 653 | ij_groovy_spaces_around_relational_operators = true 654 | ij_groovy_spaces_around_shift_operators = true 655 | ij_groovy_spaces_within_annotation_parentheses = false 656 | ij_groovy_spaces_within_array_initializer_braces = false 657 | ij_groovy_spaces_within_braces = true 658 | ij_groovy_spaces_within_brackets = false 659 | ij_groovy_spaces_within_cast_parentheses = false 660 | ij_groovy_spaces_within_catch_parentheses = false 661 | ij_groovy_spaces_within_for_parentheses = false 662 | ij_groovy_spaces_within_gstring_injection_braces = false 663 | ij_groovy_spaces_within_if_parentheses = false 664 | ij_groovy_spaces_within_list_or_map = false 665 | ij_groovy_spaces_within_method_call_parentheses = false 666 | ij_groovy_spaces_within_method_parentheses = false 667 | ij_groovy_spaces_within_parentheses = false 668 | ij_groovy_spaces_within_switch_parentheses = false 669 | ij_groovy_spaces_within_synchronized_parentheses = false 670 | ij_groovy_spaces_within_try_parentheses = false 671 | ij_groovy_spaces_within_tuple_expression = false 672 | ij_groovy_spaces_within_while_parentheses = false 673 | ij_groovy_special_else_if_treatment = true 674 | ij_groovy_ternary_operation_wrap = off 675 | ij_groovy_throws_keyword_wrap = off 676 | ij_groovy_throws_list_wrap = off 677 | ij_groovy_use_flying_geese_braces = false 678 | ij_groovy_use_fq_class_names = false 679 | ij_groovy_use_fq_class_names_in_javadoc = true 680 | ij_groovy_use_relative_indents = false 681 | ij_groovy_use_single_class_imports = true 682 | ij_groovy_variable_annotation_wrap = off 683 | ij_groovy_while_brace_force = never 684 | ij_groovy_while_on_new_line = false 685 | ij_groovy_wrap_long_lines = false 686 | 687 | [{*.gradle.kts, *.kt, *.kts, *.main.kts, *.space.kts}] 688 | ij_visual_guides = none 689 | ij_kotlin_align_in_columns_case_branch = false 690 | ij_kotlin_align_multiline_binary_operation = false 691 | ij_kotlin_align_multiline_extends_list = false 692 | ij_kotlin_align_multiline_method_parentheses = false 693 | ij_kotlin_align_multiline_parameters = true 694 | ij_kotlin_align_multiline_parameters_in_calls = false 695 | ij_kotlin_allow_trailing_comma = false 696 | ij_kotlin_allow_trailing_comma_on_call_site = false 697 | ij_kotlin_assignment_wrap = normal 698 | ij_kotlin_blank_lines_after_class_header = 0 699 | ij_kotlin_blank_lines_around_block_when_branches = 0 700 | ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 701 | ij_kotlin_block_comment_at_first_column = true 702 | ij_kotlin_call_parameters_new_line_after_left_paren = true 703 | ij_kotlin_call_parameters_right_paren_on_new_line = true 704 | ij_kotlin_call_parameters_wrap = on_every_item 705 | ij_kotlin_catch_on_new_line = false 706 | ij_kotlin_class_annotation_wrap = split_into_lines 707 | ij_kotlin_continuation_indent_for_chained_calls = false 708 | ij_kotlin_continuation_indent_for_expression_bodies = false 709 | ij_kotlin_continuation_indent_in_argument_lists = false 710 | ij_kotlin_continuation_indent_in_elvis = false 711 | ij_kotlin_continuation_indent_in_if_conditions = false 712 | ij_kotlin_continuation_indent_in_parameter_lists = false 713 | ij_kotlin_continuation_indent_in_supertype_lists = false 714 | ij_kotlin_else_on_new_line = false 715 | ij_kotlin_enum_constants_wrap = off 716 | ij_kotlin_extends_list_wrap = normal 717 | ij_kotlin_field_annotation_wrap = split_into_lines 718 | ij_kotlin_finally_on_new_line = false 719 | ij_kotlin_if_rparen_on_new_line = true 720 | ij_kotlin_import_nested_classes = false 721 | ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^ 722 | ij_kotlin_insert_whitespaces_in_simple_one_line_method = true 723 | ij_kotlin_keep_blank_lines_before_right_brace = 2 724 | ij_kotlin_keep_blank_lines_in_code = 2 725 | ij_kotlin_keep_blank_lines_in_declarations = 2 726 | ij_kotlin_keep_first_column_comment = true 727 | ij_kotlin_keep_indents_on_empty_lines = false 728 | ij_kotlin_keep_line_breaks = true 729 | ij_kotlin_lbrace_on_next_line = false 730 | ij_kotlin_line_comment_add_space = false 731 | ij_kotlin_line_comment_at_first_column = true 732 | ij_kotlin_method_annotation_wrap = split_into_lines 733 | ij_kotlin_method_call_chain_wrap = normal 734 | ij_kotlin_method_parameters_new_line_after_left_paren = true 735 | ij_kotlin_method_parameters_right_paren_on_new_line = true 736 | ij_kotlin_method_parameters_wrap = on_every_item 737 | ij_kotlin_name_count_to_use_star_import = 5 738 | ij_kotlin_name_count_to_use_star_import_for_members = 3 739 | ij_kotlin_packages_to_use_import_on_demand = java.util.*, kotlinx.android.synthetic.**, io.ktor.** 740 | ij_kotlin_parameter_annotation_wrap = off 741 | ij_kotlin_space_after_comma = true 742 | ij_kotlin_space_after_extend_colon = true 743 | ij_kotlin_space_after_type_colon = true 744 | ij_kotlin_space_before_catch_parentheses = true 745 | ij_kotlin_space_before_comma = false 746 | ij_kotlin_space_before_extend_colon = true 747 | ij_kotlin_space_before_for_parentheses = true 748 | ij_kotlin_space_before_if_parentheses = true 749 | ij_kotlin_space_before_lambda_arrow = true 750 | ij_kotlin_space_before_type_colon = false 751 | ij_kotlin_space_before_when_parentheses = true 752 | ij_kotlin_space_before_while_parentheses = true 753 | ij_kotlin_spaces_around_additive_operators = true 754 | ij_kotlin_spaces_around_assignment_operators = true 755 | ij_kotlin_spaces_around_equality_operators = true 756 | ij_kotlin_spaces_around_function_type_arrow = true 757 | ij_kotlin_spaces_around_logical_operators = true 758 | ij_kotlin_spaces_around_multiplicative_operators = true 759 | ij_kotlin_spaces_around_range = false 760 | ij_kotlin_spaces_around_relational_operators = true 761 | ij_kotlin_spaces_around_unary_operator = false 762 | ij_kotlin_spaces_around_when_arrow = true 763 | ij_kotlin_variable_annotation_wrap = off 764 | ij_kotlin_while_on_new_line = false 765 | ij_kotlin_wrap_elvis_expressions = 1 766 | ij_kotlin_wrap_expression_body_functions = 1 767 | ij_kotlin_wrap_first_method_in_call_chain = false 768 | 769 | [{*.har, *.json, mcmod.info, pack.mcmeta}] 770 | indent_size = 2 771 | max_line_length = 150 772 | tab_width = 2 773 | ij_continuation_indent_size = 4 774 | ij_visual_guides = none 775 | ij_json_keep_blank_lines_in_code = 0 776 | ij_json_keep_indents_on_empty_lines = false 777 | ij_json_keep_line_breaks = true 778 | ij_json_space_after_colon = true 779 | ij_json_space_after_comma = true 780 | ij_json_space_before_colon = true 781 | ij_json_space_before_comma = false 782 | ij_json_spaces_within_braces = false 783 | ij_json_spaces_within_brackets = false 784 | ij_json_wrap_long_lines = false 785 | 786 | [{*.htm, *.html, *.sht, *.shtm, *.shtml}] 787 | ij_visual_guides = none 788 | ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 789 | ij_html_align_attributes = true 790 | ij_html_align_text = false 791 | ij_html_attribute_wrap = normal 792 | ij_html_block_comment_at_first_column = true 793 | ij_html_do_not_align_children_of_min_lines = 0 794 | ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p 795 | ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot 796 | ij_html_enforce_quotes = false 797 | ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var 798 | ij_html_keep_blank_lines = 2 799 | ij_html_keep_indents_on_empty_lines = false 800 | ij_html_keep_line_breaks = true 801 | ij_html_keep_line_breaks_in_text = true 802 | ij_html_keep_whitespaces = false 803 | ij_html_keep_whitespaces_inside = span, pre, textarea 804 | ij_html_line_comment_at_first_column = true 805 | ij_html_new_line_after_last_attribute = never 806 | ij_html_new_line_before_first_attribute = never 807 | ij_html_quote_style = double 808 | ij_html_remove_new_line_before_tags = br 809 | ij_html_space_after_tag_name = false 810 | ij_html_space_around_equality_in_attribute = false 811 | ij_html_space_inside_empty_tag = false 812 | ij_html_text_wrap = normal 813 | ij_html_uniform_ident = false 814 | 815 | [{*.markdown, *.md}] 816 | ij_visual_guides = none 817 | ij_markdown_force_one_space_after_blockquote_symbol = true 818 | ij_markdown_force_one_space_after_header_symbol = true 819 | ij_markdown_force_one_space_after_list_bullet = true 820 | ij_markdown_force_one_space_between_words = true 821 | ij_markdown_keep_indents_on_empty_lines = false 822 | ij_markdown_max_lines_around_block_elements = 1 823 | ij_markdown_max_lines_around_header = 1 824 | ij_markdown_max_lines_between_paragraphs = 1 825 | ij_markdown_min_lines_around_block_elements = 1 826 | ij_markdown_min_lines_around_header = 1 827 | ij_markdown_min_lines_between_paragraphs = 1 828 | 829 | [{*.toml, Cargo.lock, Cargo.toml.orig, Gopkg.lock, Pipfile, poetry.lock}] 830 | ij_visual_guides = none 831 | ij_toml_keep_indents_on_empty_lines = false 832 | 833 | [{*.yaml, *.yml}] 834 | indent_size = 2 835 | ij_visual_guides = none 836 | ij_yaml_align_values_properties = do_not_align 837 | ij_yaml_autoinsert_sequence_marker = true 838 | ij_yaml_block_mapping_on_new_line = false 839 | ij_yaml_indent_sequence_value = true 840 | ij_yaml_keep_indents_on_empty_lines = false 841 | ij_yaml_keep_line_breaks = true 842 | ij_yaml_sequence_on_new_line = false 843 | ij_yaml_space_before_colon = false 844 | ij_yaml_spaces_within_braces = true 845 | ij_yaml_spaces_within_brackets = true 846 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | * text eol=lf 5 | *.bat text eol=crlf 6 | *.patch text eol=lf 7 | *.java text eol=lf 8 | *.gradle text eol=crlf 9 | *.png binary 10 | *.gif binary 11 | *.exe binary 12 | *.dll binary 13 | *.jar binary 14 | *.lzma binary 15 | *.zip binary 16 | *.pyd binary 17 | *.cfg text eol=lf 18 | *.jks binary 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - "1.21.1" 8 | tags-ignore: 9 | - "**" 10 | paths: 11 | - "gradle/**" 12 | - "**.java" 13 | - "**.kts" 14 | - "**.properties" 15 | - "**/build.yml" 16 | pull_request: 17 | branches: 18 | - "1.21.1" 19 | paths: 20 | - "gradle/**" 21 | - "**.java" 22 | - "**.kts" 23 | - "**.properties" 24 | - "**/build.yml" 25 | 26 | concurrency: 27 | group: ${{ github.workflow }}-${{ github.ref }} 28 | cancel-in-progress: true 29 | 30 | jobs: 31 | redirect: 32 | uses: AlmostReliable/.github/.github/workflows/build.yml@main 33 | with: 34 | java-distribution: "microsoft" 35 | java-version: "21" 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | target_version: 7 | type: string 8 | required: false 9 | description: "mod version | empty = next option" 10 | update_type: 11 | type: choice 12 | required: false 13 | description: "update type" 14 | default: "minor" 15 | options: 16 | - "major" 17 | - "minor" 18 | - "patch" 19 | - "none" 20 | release_type: 21 | type: choice 22 | required: true 23 | description: "type of release" 24 | default: "release" 25 | options: 26 | - "alpha" 27 | - "beta" 28 | - "release" 29 | debug: 30 | type: boolean 31 | required: false 32 | default: false 33 | description: "enable debug mode (GitHub only)" 34 | 35 | jobs: 36 | redirect: 37 | uses: AlmostReliable/.github/.github/workflows/release-nf.yml@main 38 | secrets: inherit 39 | with: 40 | java-distribution: "microsoft" 41 | java-version: "21" 42 | mod_name: "PonderJS" 43 | curseforge_id: "622888" 44 | modrinth_id: "5A34Stj8" 45 | dependencies: | 46 | kubejs(required){curseforge:238086}{modrinth:umyGl7zF} 47 | target_version: ${{ github.event.inputs.target_version }} 48 | update_type: ${{ github.event.inputs.update_type }} 49 | release_type: ${{ github.event.inputs.release_type }} 50 | loaders: "neoforge" 51 | debug: ${{ github.event.inputs.debug }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Run directory, we want client_scripts 115 | run/** 116 | !run/kubejs/ 117 | !run/kubejs/client_scripts/ 118 | !run/kubejs/client_scripts/** 119 | 120 | server/ 121 | 122 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 123 | !gradle-wrapper.jar 124 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | - / 5 | 6 | ## [2.1.2] - 2025-06-02 7 | - Fix [#32](https://github.com/AlmostReliable/ponderjs/issues/32) 8 | 9 | ## [2.1.1] - 2025-05-22 10 | - Fix #[29](https://github.com/AlmostReliable/ponderjs/issues/29) 11 | 12 | ## [2.1.0] - 2025-05-21 13 | - Alpha update for 1.21.1. Please report issues :-) 14 | 15 | ## [2.0.5] 16 | 17 | - Fix missing lang entries for scenes 18 | 19 | ## [2.0.4] 20 | 21 | - Allow better creation of tags 22 | - Allow localization with custom namespaces 23 | - Add missing tags to the ponder index 24 | 25 | ## [2.0.3] 26 | 27 | - Fix [#26](https://github.com/AlmostReliable/ponderjs/issues/26) again 28 | 29 | ## [2.0.2] 30 | 31 | - Fix [#25](https://github.com/AlmostReliable/ponderjs/issues/25) 32 | - Fix [#26](https://github.com/AlmostReliable/ponderjs/issues/26) 33 | 34 | ## [2.0.1] 35 | 36 | - Fix [#22](https://github.com/AlmostReliable/ponderjs/issues/22) 37 | 38 | ## [2.0.0] 39 | - Update to ponder standalone 40 | 41 | ## [1.4.0] 42 | - Add custom render elements 43 | 44 | ## [1.3.1] 45 | - Fix crash with new kubejs version 46 | 47 | ## [1.3.0] 48 | - Update to 1.20.1 49 | 50 | ## [1.2.0] 51 | - Update to KubeJS 6.1 52 | 53 | ## [1.1.12] 54 | - Update to Create 0.5.1 55 | - `modifyTileNBT` is now deprecated and will be removed in the future. Please use `modifyBlockEntityNBT` instead. 56 | 57 | ## [1.1.11] 58 | - Fix potential startup crash 59 | 60 | ## [1.1.10] 61 | - Fix crash with new kubejs version 62 | 63 | ## [1.1.9] 64 | - Crash on startup with new Rhino version ([#9](https://github.com/AlmostReliable/ponderjs/issues/9)) 65 | 66 | ## [1.1.8] 67 | - Add `encapsulateBounds` for scene instructions 68 | 69 | ## [1.1.7] 70 | - Add `removeEntity` for world instructions 71 | 72 | ## [1.1.6-beta] 73 | - Fix https://github.com/AlmostReliable/ponderjs/issues/4 74 | 75 | ## [1.1.5-beta] 76 | - Fix type in SceneBuildingUtil for `getSelect` 77 | 78 | ## [1.1.4-beta] 79 | - Internal refactoring 80 | - Bump version for Rhino and KubeJS 81 | 82 | ## [1.1.3-beta] 83 | - Add lang file generation 84 | - Fix type wrapping 85 | 86 | ## [1.1.2-beta] 87 | - Add structures for the tutorials 88 | 89 | ## [1.1.1-beta] 90 | - 1.18.2! 91 | - Add ParticleInstructions 92 | - Add shorter versions for showing controls & tags 93 | - Scenes are now reloadable 94 | - Default structure will be used if no structure provided 95 | 96 | 97 | [2.1.2]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.21.1-neoforge-2.1.2 98 | [2.1.1]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.21.1-neoforge-2.1.1 99 | [2.1.0]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.21.1-neoforge-2.1.0 100 | [1.3.0]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.20.1-1.3.0 101 | [1.2.0]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.2.0 102 | [1.1.11]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.11 103 | [1.1.10]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.10 104 | [1.1.9]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.9 105 | [1.1.8]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.8 106 | [1.1.7]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.7 107 | [1.1.6-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.6-beta 108 | [1.1.5-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.5-beta 109 | [1.1.4-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.4-beta 110 | [1.1.3-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.3-beta 111 | [1.1.2-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.2-beta 112 | [1.1.1-beta]: https://github.com/AlmostReliable/ponderjs/releases/tag/v1.18-1.1.1-beta 113 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Almost Reliable 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 NON INFRINGEMENT. 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. 22 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("net.neoforged.moddev") version "2.0.39-beta" 3 | id("com.almostreliable.almostgradle") version "1.1.+" 4 | } 5 | 6 | repositories { 7 | maven("https://maven.latvian.dev/releases") 8 | maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") 9 | maven("https://maven.createmod.net") 10 | maven("https://maven.tterrag.com") 11 | maven("https://jitpack.io") 12 | maven("https://www.cursemaven.com") 13 | } 14 | 15 | almostgradle.setup { 16 | testMod = true 17 | } 18 | 19 | dependencies { 20 | val kubejsVersion: String by project 21 | implementation("dev.latvian.mods:kubejs-neoforge:${kubejsVersion}") 22 | testImplementation("dev.latvian.mods:kubejs-neoforge:${kubejsVersion}") 23 | 24 | val flywheelVersion: String by project 25 | jarJar("dev.engine-room.flywheel:flywheel-neoforge-${almostgradle.minecraftVersion}:${flywheelVersion}") 26 | implementation("dev.engine-room.flywheel:flywheel-neoforge-${almostgradle.minecraftVersion}:${flywheelVersion}") 27 | 28 | val ponderVersion: String by project 29 | jarJar("net.createmod.ponder:Ponder-NeoForge-${almostgradle.minecraftVersion}:${ponderVersion}") 30 | implementation("net.createmod.ponder:Ponder-NeoForge-${almostgradle.minecraftVersion}:${ponderVersion}") 31 | 32 | testLocalRuntime(almostgradle.recipeViewers.emi.dependency) 33 | } 34 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = com.almostreliable 2 | license = MIT 3 | 4 | # Mod options 5 | modId = ponderjs 6 | modName = PonderJS 7 | modVersion = 2.1.2 8 | modAuthor = AlmostReliable 9 | modDescription = Allows creating ponder scenes and tags with KubeJS. 10 | modAuthors= kotakotik22, AlmostReliable 11 | modCredits= Continuation of kotakotik22 mod. 12 | 13 | # Common 14 | minecraftVersion = 1.21.1 15 | neoforgeVersion = 21.1.93 16 | kubejsVersion = 2101.7.1-build.181 17 | 18 | # Deps 19 | ponderVersion = 1.0.46 20 | flywheelVersion = 1.0.4-27 21 | 22 | # AlmostGradle 23 | almostgradle.launchArgs.resizeClient = true 24 | almostgradle.launchArgs.autoWorldJoin = true 25 | 26 | almostgradle.recipeViewers.emi.version = 1.1.12 27 | almostgradle.recipeViewers.emi.minecraftVersion = 1.21 28 | 29 | # Parchment 30 | neoForge.parchment.minecraftVersion = 1.21 31 | neoForge.parchment.mappingsVersion = 2024.07.07 32 | 33 | # Gradle 34 | org.gradle.jvmargs = -Xmx3G 35 | org.gradle.daemon = false 36 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlmostReliable/ponderjs/5ecb4d103d54c53dd50a516261ea8220ae6255c4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase = GRADLE_USER_HOME 2 | distributionPath = wrapper/dists 3 | distributionUrl = https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | zipStoreBase = GRADLE_USER_HOME 5 | zipStorePath = wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/block_entity_nbt.js: -------------------------------------------------------------------------------- 1 | Ponder.registry((event) => { 2 | event 3 | .create("minecraft:paper") 4 | .scene("block_entity_nbt", "Set NBT for blocks", "ponderjs:block_entity_tutorial", (scene, util) => { 5 | scene.showStructure(); 6 | scene.scaleSceneView(0.90); 7 | scene.setSceneOffsetY(-1) 8 | scene.idle(20); 9 | 10 | scene.world.modifyBlockEntityNBT([2, 3, 3], (nbt) => { 11 | nbt.Patterns = [ 12 | { 13 | Color: 0, 14 | Pattern: "pig" 15 | } 16 | ] 17 | }); 18 | 19 | scene.world.modifyBlockEntityNBT([3, 3, 2], (nbt) => { 20 | nbt.Patterns = [ 21 | { 22 | Color: 0, 23 | Pattern: "cre" 24 | } 25 | ] 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/getting-started.js: -------------------------------------------------------------------------------- 1 | Ponder.tags((event) => { 2 | /** 3 | * "kubejs:getting_started" -> The tag name 4 | * "minecraft:paper" -> The icon 5 | * "Getting Started" -> The title 6 | * "This is a description" -> The description 7 | * [...items] -> Default items 8 | */ 9 | event.createTag("kubejs:getting_started", "minecraft:paper", "Getting started.", "We ponder now!", [ 10 | // some default items! 11 | "minecraft:paper", 12 | "minecraft:apple", 13 | "minecraft:emerald_block", 14 | ]); 15 | }); 16 | 17 | Ponder.registry((event) => { 18 | event.create("minecraft:paper").scene("our_first_scene", "First example scene", (scene, util) => { 19 | /** 20 | * Show the full strucutre. 21 | * Alternative you can just use `scene.showBasePlate()` to only show the base plate. 22 | * This is useful for animateing different parts from the structure. 23 | */ 24 | scene.showStructure(); 25 | 26 | /** 27 | * Encapsulate the structure bounds to given positions. This is useful if the custom structure has no proper bounds. 28 | * scene.showStructure() automatically encapsulates the bounds. 29 | */ 30 | // scene.encapsulateBounds(blockPos) 31 | 32 | /** 33 | * Use idle(ticks) or idleSeconds(seconds) to wait for a certain amount of time. 34 | */ 35 | scene.idle(10); 36 | 37 | /** 38 | * [x, y, z] is the position. You can use any kubejs way to represent a position. 39 | * 40 | * `.createEntity()` returns an entity link from Create, 41 | * which will be used in the future refer the entity. 42 | * Please dont modify the entity directly. 43 | */ 44 | const creeperLink = scene.world.createEntity("creeper", [2.5, 1, 2.5]); 45 | 46 | /** 47 | * 50 -> The tick length of the instruction. 48 | * [x, y, z] -> The position where the text should point at. 49 | */ 50 | scene 51 | .text(60, "Example text", [2.0, 2.5, 2.5]) 52 | /** 53 | * Optional. Set the color of the text. 54 | * Possible values: 55 | * - PonderPalette.WHITE, PonderPalette.BLACK 56 | * - PonderPalette.RED, PonderPalette.GREEN, PonderPalette.BLUE 57 | * - PonderPalette.SLOW, PonderPalette.MEDIUM, PonderPalette.FAST 58 | * - PonderPalette.INPUT, PonderPalette.OUTPUT 59 | */ 60 | .colored(PonderPalette.RED) 61 | /** 62 | * Optional. Will place the text closer to the target position. 63 | */ 64 | .placeNearTarget() 65 | /** 66 | * Optional. Will add a keyframe to the scene. 67 | */ 68 | .attachKeyFrame(); 69 | 70 | /** 71 | * 120 -> The tick length of the instruction. 72 | * [x, y, z] -> The position where the controls should point at. 73 | * "down" -> The direction where the controls should point at. 74 | */ 75 | scene 76 | .showControls(60, [2.5, 3, 2.5], "down") 77 | /** 78 | * Use mouse right click as icon. Alternative you can use `.leftClick()`, 79 | * or `.showing(icon)` with a custom icon. 80 | */ 81 | .rightClick() 82 | /** 83 | * Which item should be shown together with the icon 84 | */ 85 | .withItem("shears") 86 | /** 87 | * Optional. You cannot use `.whileSneaking()` and `withCTRL()` together. 88 | */ 89 | .whileSneaking() 90 | /** 91 | * Optional 92 | */ 93 | .whileCTRL(); 94 | }); 95 | }); 96 | 97 | // Ponder.registry((event) => { 98 | // /** 99 | // * Additional structure 100 | // */ 101 | // event 102 | // .create("minecraft:paper") 103 | // .scene( 104 | // "our_first_scene", 105 | // "Example scene for paper with structure", 106 | // "kubejs:your_structure_id", 107 | // (scene, util) => { 108 | // // your scene code here 109 | // } 110 | // ); 111 | // }); 112 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/particles.js: -------------------------------------------------------------------------------- 1 | Ponder.tags((event) => { 2 | event.createTag("particle_test", "minecraft:blaze_powder", "All the particles", "Use PonderJS with particles!", [ 3 | "minecraft:blaze_powder", 4 | ]); 5 | }); 6 | 7 | const TICK_LENGTH = 20; 8 | const IDLE_TICK_LENGTH = TICK_LENGTH * 3; 9 | 10 | Ponder.registry((event) => { 11 | /** 12 | * Prints all particle names in the client.txt which can be used for `scene.particles.simple()`. 13 | */ 14 | // event.printParticleNames(); 15 | 16 | event 17 | .create("minecraft:blaze_powder") 18 | .scene("particles", "How to particle", (scene, util) => { 19 | scene.showStructure(); 20 | scene.idle(10); 21 | 22 | const pos = [4, 1.5, 4]; 23 | const start = [0, 1, 0]; 24 | const end = [2, 2, 3]; 25 | 26 | /** 27 | * Using `scene.particles.` returns an object to set additional options 28 | * 29 | * .density(number) -> Sets the density of the particles. 30 | * .gravity(number) -> Sets the gravity of the particles. 31 | * .physics(true or false) -> Sets if the particles have physics. 32 | * .collision(true or false) -> Sets if the particles stop by collision. 33 | * .roll(number) -> Do a barrell roll! 34 | * .scale(number) -> Scale the particles between 0.01 and 4. 35 | * .lifetime(number) -> Set the lifetime of the particles. 36 | * 37 | * .motion(vec3) -> Sets the motion of the particles. 38 | * .speed(vec3) -> Sets the speed of the particles. Affects the motion if given. 39 | * .area(vec3) -> Sets the area of the particles. 40 | * .delta(vec3) -> Sets the delta of the particles. Same as the particle command. 41 | * .withinBlockSpace() -> Sets the particles to be within the block space. 42 | * 43 | * .transform((tick, position, motion) => { ... }) -> return [newPosition, newVector] 44 | * .transformPosition((tick, position) => { ... }) -> return newPosition 45 | * .transformMotion((tick, motion) => { ... }) -> return newMotion 46 | */ 47 | scene.addKeyframe(); 48 | scene.particles.simple(TICK_LENGTH, "glow", pos); 49 | scene.particles.simple(TICK_LENGTH, "glow", start).density(10).area(end); 50 | scene.idle(IDLE_TICK_LENGTH); 51 | 52 | scene.addKeyframe(); 53 | scene.particles.simple(TICK_LENGTH, "small_flame", pos); 54 | scene.particles.simple(TICK_LENGTH, "small_flame", start).density(10).motion([0, 0, -0.1]).area(end); 55 | scene.idle(IDLE_TICK_LENGTH); 56 | 57 | scene.addKeyframe(); 58 | scene.particles.item(TICK_LENGTH, "minecraft:diamond_block", pos).motion([-0.09, 0.3, 0]).density(8); 59 | scene.particles.item(TICK_LENGTH, "minecraft:diamond_block", start).area(end); 60 | scene.idle(IDLE_TICK_LENGTH); 61 | 62 | scene.addKeyframe(); 63 | scene.particles.block(TICK_LENGTH, "minecraft:diamond_block", pos); 64 | scene.particles.block(TICK_LENGTH, "minecraft:diamond_block", start).density(4).area(end); 65 | scene.idle(IDLE_TICK_LENGTH); 66 | 67 | scene.addKeyframe(); 68 | scene.particles.dust(TICK_LENGTH, "#00FFF0", start).density(5).motion([0, 0, -0.1]).area(end).roll(10); 69 | scene.idle(IDLE_TICK_LENGTH); 70 | 71 | scene.addKeyframe(); 72 | scene.particles 73 | .dust(TICK_LENGTH, "#FF0000", "#0000FF", start) 74 | .density(2) 75 | .scale(2.1) 76 | .motion([0, 0, -0.1]) 77 | .area(end) 78 | .roll(3); 79 | scene.idle(IDLE_TICK_LENGTH); 80 | 81 | scene.addKeyframe(); 82 | scene.particles.simple(TICK_LENGTH, "portal", start).density(6).withinBlockSpace(); 83 | scene.idle(IDLE_TICK_LENGTH); 84 | }) 85 | .scene("custom_transform", "Use some custom transformations", (scene, util) => { 86 | scene.showStructure(); 87 | scene.idle(10); 88 | 89 | scene.particles.simple(TICK_LENGTH * 3, "glow", [1, 1.5, 0]).transformPosition((tick, p) => { 90 | return [p.x(), p.y(), p.z() + (tick / TICK_LENGTH) * 1.6]; 91 | }); 92 | 93 | scene.particles.simple(TICK_LENGTH * 3, "sneeze", [2.5, 1.5, 0]).transformMotion((tick, m) => { 94 | return [0, 0, (tick / TICK_LENGTH) * 0.2]; 95 | }); 96 | 97 | /** 98 | * You also can directly transform all in once. 99 | * Must return [ position_vector, motion_vector ] or [ [x, y, z], [mx, my, mz] ] 100 | */ 101 | scene.particles.simple(TICK_LENGTH * 3, "small_flame", [4, 1.5, 0]).transform((tick, p, m) => { 102 | return [ 103 | [p.x(), p.y(), Math.random() * 5], 104 | [(tick / TICK_LENGTH) * 0.2, 0, (tick / TICK_LENGTH) * 0.2], 105 | ]; 106 | }); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/removeEntity.js: -------------------------------------------------------------------------------- 1 | Ponder.registry((event) => { 2 | event 3 | .create("minecraft:dirt") 4 | .scene("removing_an_entity", "Yeet", (scene, util) => { 5 | scene.showStructure(); 6 | scene.idle(10); 7 | 8 | const centerBlockPos = util.grid.at(2, 0, 2); 9 | const centerTop = util.vector.topOf(centerBlockPos); 10 | 11 | const entity = scene.world.createEntity("sheep", centerTop); 12 | scene.idle(30); 13 | scene.world.removeEntity(entity); 14 | scene.idle(60); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/section_animation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper function for fading in a section. 3 | * 4 | * scene => the scene to fade in the section in. 5 | * section => the section to fade in. 6 | * movingOffset => the offset to move the section by. (Not a position!) 7 | * direction => fade direction. 8 | * idleTicks => number of ticks to idle. 9 | */ 10 | function fadeInSection(scene, selection, movingOffset, direction, idleTicks) { 11 | let link = scene.world.showIndependentSection(selection, direction); 12 | scene.world.moveSection(link, movingOffset, 0); // 0 to make moving instant 13 | scene.idle(idleTicks); 14 | scene.world.hideIndependentSection(link, direction); 15 | scene.idle(idleTicks); 16 | } 17 | 18 | Ponder.registry((event) => { 19 | event.create("minecraft:hopper").scene("section_fading", "Let's fade", (scene, util) => { 20 | 21 | /** 22 | * We will use these blocks for fading. So we don't show them directly. 23 | * 24 | * If you are using a custom structure, you can directly add the blocks to your structure file. 25 | */ 26 | scene.world.setBlocks([4, 1, 2], "minecraft:dispenser"); 27 | scene.world.setBlocks([3, 1, 2], "minecraft:chest"); 28 | scene.world.setBlocks([2, 1, 2], "minecraft:dropper"); 29 | 30 | scene.world.setBlocks([2, 2, 2], "minecraft:hopper"); 31 | 32 | /** 33 | * We only want to show the base plate and the hopper we manually placed right now! 34 | */ 35 | scene.showBasePlate(); 36 | scene.world.showSection([2, 2, 2], Facing.DOWN); 37 | scene.idle(20); 38 | 39 | fadeInSection(scene, [4, 1, 2], [-2, 0, 0], Direction.EAST, 15); 40 | fadeInSection(scene, [3, 1, 2], [-1, 0, 0], Direction.EAST, 15); 41 | fadeInSection(scene, [2, 1, 2], [0, 0, 0], Direction.EAST, 15); 42 | }); 43 | }); 44 | 45 | Ponder.registry((event) => { 46 | event 47 | .create("minecraft:cake") 48 | .scene("animate_section", "The cake is a lie.", "ponderjs:the_cake_is_a_lie", (scene, util) => { 49 | /** 50 | * Layer 0 51 | */ 52 | for (let x = 0; x < 5; x++) { 53 | for (let z = 0; z < 5; z++) { 54 | scene.world.showSection([x, 0, z], Facing.DOWN); 55 | } 56 | /** 57 | * With idle we can can create a cool animation. 58 | */ 59 | scene.idle(3); 60 | } 61 | 62 | /** 63 | * Layer 1 64 | */ 65 | for (let z = 0; z < 5; z++) { 66 | for (let x = 0; x < 5; x++) { 67 | scene.world.showSection([x, 1, z], Facing.DOWN); 68 | } 69 | scene.idle(3); 70 | } 71 | 72 | /** 73 | * Layer 2 74 | */ 75 | for (let x = 0; x < 5; x++) { 76 | for (let z = 0; z < 5; z++) { 77 | scene.world.showSection([x, 2, z], Facing.DOWN); 78 | scene.idle(2); 79 | } 80 | } 81 | 82 | /** 83 | * Top layer 84 | */ 85 | for (let x = 0; x < 5; x++) { 86 | for (let z = 0; z < 5; z++) { 87 | scene.world.showSection([x, 3, z], Facing.DOWN); 88 | scene.idle(1); 89 | } 90 | } 91 | 92 | scene.text(30, "What a great cake!", [2.5, 3.5, 2.5]); 93 | scene.idle(40); 94 | 95 | scene.world.hideSection( 96 | [ 97 | [0, 0, 0], 98 | [1, 4, 1], 99 | ], 100 | Facing.NORTH 101 | ); 102 | scene.text(30, "Yummy!", [1, 1.5, 2.5]).colored(PonderPalette.MEDIUM); 103 | scene.idle(40); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/set-replace-modify.js: -------------------------------------------------------------------------------- 1 | Ponder.registry((event) => { 2 | event.create("minecraft:stone").scene("set_replace_modify_tutorial", "Set, Replace, Modify.", (scene, util) => { 3 | scene.showStructure(); 4 | 5 | /** 6 | * The last argument is for spawning particles. 7 | * true if yes, false if no 8 | */ 9 | scene.world.setBlocks([0, 1, 0, 4, 1, 4], "minecraft:brick_slab", true); 10 | scene.world.setBlock([0, 1, 1], "minecraft:stone_slab", false); 11 | 12 | scene.world.modifyBlocks([2, 1, 2, 2, 1, 3], (curState) => curState.with("type", "double"), true); 13 | scene.world.modifyBlock([0, 1, 4], (curState) => curState.with("type", "top"), true); 14 | 15 | /** 16 | * Or we directly return a new blockstate 17 | */ 18 | scene.world.modifyBlock([0, 1, 3], () => Block.id("minecraft:jungle_slab").with("type", "top"), true); 19 | 20 | scene.world.replaceBlocks([3, 1, 0, 4, 1, 4], "minecraft:oak_slab", false); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/shear_sheep.js: -------------------------------------------------------------------------------- 1 | Ponder.tags((event) => { 2 | event.createTag("lytho:ponder_test", "minecraft:shears", "Some testing", "Some test description!", [ 3 | "minecraft:blaze_powder", 4 | "minecraft:shears", 5 | ]); 6 | }); 7 | 8 | Ponder.registry((event) => { 9 | event 10 | .create("minecraft:shears") 11 | .scene("shear_sheep", "How to shear a sheep", (scene, util) => { 12 | scene.showStructure(); 13 | scene.idle(10); 14 | 15 | const centerBlockPos = util.grid.at(2, 0, 2); 16 | const centerTop = util.vector.topOf(centerBlockPos); 17 | 18 | const entity = scene.world.createEntity("sheep", centerTop); 19 | 20 | scene.idle(10); 21 | /** 22 | * down, up, left, right to set where it should point at 23 | */ 24 | scene.showControls(120, centerBlockPos.above(2), "down").rightClick().withItem("shears"); 25 | 26 | scene.addKeyframe(); 27 | /** 28 | * [2.5, 2.5, 2.5] -> position at [x, y, z] 29 | */ 30 | scene.text(50, "Right-click to shear the sheep", [2.5, 2.5, 2.5]).placeNearTarget(); 31 | scene.idle(60); 32 | 33 | scene.addKeyframe(); 34 | scene.idle(10); 35 | scene 36 | .text(40, "Shearing will drop 1 - 3 wool of the corresponding color", centerBlockPos.above(2)) 37 | .placeNearTarget(); 38 | 39 | scene.world.modifyEntity(entity, (e) => { 40 | e.setSheared(true); 41 | }); 42 | scene.playSound("entity.sheep.shear", 1); 43 | 44 | /** 45 | * The first argument is the position, the second one the motion vector. I tried to simulate "shearing" :D 46 | */ 47 | scene.world.createItemEntity(centerTop.add(0, 0.5, 0), util.vector.of(-0.07, 0.4, 0), "white_wool"); 48 | scene.world.createItemEntity(centerTop.add(0, 0.5, 0), util.vector.of(-0.07, 0.4, -0.07), "white_wool"); 49 | scene.world.createItemEntity(centerTop.add(0, 0.5, 0), util.vector.of(0, 0.4, -0.07), "white_wool"); 50 | 51 | scene.idle(60); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /run/kubejs/client_scripts/tags.js: -------------------------------------------------------------------------------- 1 | Ponder.tags((event) => { 2 | event.createTag("ponderjs:custom_tag", "minecraft:nether_star", "Custom Tag Title", "Custom Tag Description", [ 3 | "minecraft:blaze_powder", 4 | "minecraft:shears", 5 | ]); 6 | 7 | event.createTag("ponderjs:with_index_no_add", tag => { 8 | tag.icon("minecraft:diamond"); 9 | tag.title("Add to index, but dont add icon"); 10 | tag.description("Diamond Description"); 11 | tag.noIndex(); 12 | }); 13 | 14 | event.createTag("ponderjs:with_index_with_add", tag => { 15 | tag.icon("minecraft:emerald"); 16 | tag.title("Add to index, but dont add icon"); 17 | tag.description("Emerald Description"); 18 | // tag.noIndex(); 19 | tag.addIconToItems(); 20 | }); 21 | 22 | if (Platform.isLoaded("create")) { 23 | event.add("create:kinetic_appliances", "minecraft:dirt"); 24 | event.remove("create:kinetic_appliances", ["create:deployer", "create:encased_fan"]); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" 3 | } 4 | 5 | val modName: String by extra 6 | val minecraftVersion: String by extra 7 | rootProject.name = "$modName-$minecraftVersion" 8 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/KubePlugin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import com.almostreliable.ponderjs.particles.ParticleTransformation; 4 | import com.almostreliable.ponderjs.util.BlockStateFunction; 5 | import com.almostreliable.ponderjs.util.Util; 6 | import dev.latvian.mods.kubejs.event.EventGroupRegistry; 7 | import dev.latvian.mods.kubejs.plugin.KubeJSPlugin; 8 | import dev.latvian.mods.kubejs.script.BindingRegistry; 9 | import dev.latvian.mods.kubejs.script.TypeWrapperRegistry; 10 | import net.createmod.catnip.math.Pointing; 11 | import net.createmod.ponder.api.PonderPalette; 12 | import net.createmod.ponder.api.element.ParrotElement; 13 | import net.createmod.ponder.api.scene.Selection; 14 | import net.createmod.ponder.foundation.PonderTag; 15 | import net.createmod.ponder.foundation.element.InputWindowElement; 16 | import net.minecraft.world.level.block.state.BlockState; 17 | 18 | public class KubePlugin implements KubeJSPlugin { 19 | 20 | @Override 21 | public void registerBindings(BindingRegistry bindings) { 22 | if (!bindings.type().isClient()) { 23 | return; 24 | } 25 | 26 | bindings.add("PonderPalette", PonderPalette.class); 27 | bindings.add("ParrotElement", ParrotElement.class); 28 | bindings.add("PonderInputWindowElement", InputWindowElement.class); 29 | bindings.add("PonderInput", InputWindowElement.class); 30 | bindings.add("PonderPointing", Pointing.class); 31 | } 32 | 33 | @Override 34 | public void registerTypeWrappers(TypeWrapperRegistry registry) { 35 | if (!registry.scriptType().isClient()) { 36 | return; 37 | } 38 | 39 | registry.register(Selection.class, Util::selectionOf); 40 | registry.register(PonderTag.class, Util::ponderTagOf); 41 | registry.register(BlockStateFunction.class, BlockStateFunction::of); 42 | registry.register(ParticleTransformation.Data.class, ParticleTransformation.Data::of); 43 | } 44 | 45 | @Override 46 | public void registerEvents(EventGroupRegistry registry) { 47 | registry.register(PonderEvents.GROUP); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderBuilderJS.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import com.almostreliable.ponderjs.util.PonderErrorHelper; 4 | import net.createmod.ponder.api.registration.PonderSceneRegistrationHelper; 5 | import net.createmod.ponder.api.scene.PonderStoryBoard; 6 | import net.createmod.ponder.foundation.PonderStoryBoardEntry; 7 | import net.createmod.ponder.foundation.registration.PonderSceneRegistry; 8 | import net.minecraft.resources.ResourceLocation; 9 | 10 | import java.util.Set; 11 | 12 | public class PonderBuilderJS { 13 | public static final ResourceLocation BASIC_STRUCTURE = ResourceLocation.parse("ponderjs:basic"); 14 | private final Set itemIds; 15 | private final PonderSceneRegistry sceneRegistry; 16 | 17 | public PonderBuilderJS(Set itemIds, PonderSceneRegistry sceneRegistry) { 18 | this.itemIds = itemIds; 19 | this.sceneRegistry = sceneRegistry; 20 | } 21 | 22 | public PonderBuilderJS scene(String name, String title, PonderStoryBoard scene) { 23 | return scene(name, title, BASIC_STRUCTURE, scene); 24 | } 25 | 26 | public PonderBuilderJS scene(String name, String title, ResourceLocation structureName, PonderStoryBoard storyBoard, ResourceLocation... tags) { 27 | ResourceLocation id = PonderJS.appendKubeToId(name); 28 | PonderJS.NAMESPACES.add(id.getNamespace()); 29 | 30 | PonderStoryBoard wrapper = (scene, util) -> { 31 | scene.title(id.getPath(), title); 32 | try { 33 | storyBoard.program(scene, util); 34 | } catch (Exception e) { 35 | PonderErrorHelper.yeet(e); 36 | } 37 | }; 38 | 39 | for (var itemId : itemIds) { 40 | var storyBoardEntry = new PonderStoryBoardEntry(wrapper, id.getNamespace(), structureName, itemId); 41 | sceneRegistry.addStoryBoard(storyBoardEntry); 42 | } 43 | 44 | return this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderEvents.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import dev.latvian.mods.kubejs.event.EventGroup; 4 | import dev.latvian.mods.kubejs.event.EventHandler; 5 | 6 | public interface PonderEvents { 7 | EventGroup GROUP = EventGroup.of("Ponder"); 8 | EventHandler REGISTRY = GROUP.client("registry", () -> PonderRegistryEventJS.class); 9 | EventHandler TAGS = GROUP.client("tags", () -> PonderItemTagEventJS.class); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderItemTagEventJS.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import com.google.common.base.Preconditions; 4 | import dev.latvian.mods.kubejs.event.KubeEvent; 5 | import dev.latvian.mods.kubejs.script.ConsoleJS; 6 | import net.createmod.ponder.api.registration.PonderTagRegistrationHelper; 7 | import net.createmod.ponder.foundation.PonderTag; 8 | import net.minecraft.core.registries.BuiltInRegistries; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.world.item.Item; 11 | import net.minecraft.world.item.ItemStack; 12 | import net.minecraft.world.item.Items; 13 | import net.minecraft.world.item.crafting.Ingredient; 14 | 15 | import javax.annotation.Nullable; 16 | import java.util.Arrays; 17 | import java.util.LinkedHashSet; 18 | import java.util.Set; 19 | import java.util.function.Consumer; 20 | import java.util.stream.Collectors; 21 | 22 | public class PonderItemTagEventJS implements KubeEvent { 23 | 24 | private final PonderTagRegistrationHelper helper; 25 | 26 | public PonderItemTagEventJS(PonderTagRegistrationHelper helper) { 27 | this.helper = helper; 28 | } 29 | 30 | public void createTag(String id, Consumer onCreate) { 31 | var idWithNameSpace = PonderJS.appendKubeToId(id); 32 | PonderJS.NAMESPACES.add(idWithNameSpace.getNamespace()); 33 | 34 | var builder = new Builder(idWithNameSpace); 35 | onCreate.accept(builder); 36 | builder.fin(helper); 37 | } 38 | 39 | public void createTag(String id, Item displayItem, String title, String description, @Nullable Ingredient ingredient) { 40 | createTag(id, builder -> { 41 | builder.icon(displayItem); 42 | builder.title(title); 43 | builder.description(description); 44 | if (ingredient != null) builder.items(ingredient); 45 | }); 46 | } 47 | 48 | public void createTag(String id, Item displayItem, String title, String description) { 49 | createTag(id, displayItem, title, description, null); 50 | } 51 | 52 | public void add(PonderTag tag, Ingredient ingredient) { 53 | if (ingredient.isEmpty()) return; 54 | 55 | var tagBuilder = helper.addToTag(tag.getId()); 56 | for (ItemStack item : ingredient.getItems()) { 57 | var id = BuiltInRegistries.ITEM.getKey(item.getItem()); 58 | tagBuilder.add(id); 59 | } 60 | } 61 | 62 | public void removeTag(PonderTag... tagsToRemove) { 63 | if (tagsToRemove.length == 0) return; 64 | 65 | var reg = PonderJS.getTagRegistryAccessor(); 66 | for (var tag : tagsToRemove) { 67 | if (tag.equals(reg.getMissing())) continue; 68 | 69 | reg.getRegisteredTags().remove(tag.getId()); 70 | reg.getListedTags().remove(tag); 71 | remove(tag, PonderJS.getTagRegistry().getItems(tag)); 72 | } 73 | } 74 | 75 | public void remove(PonderTag tag, Ingredient ingredient) { 76 | if (ingredient.isEmpty()) return; 77 | Set ids = Arrays.stream(ingredient.getItems()) 78 | .map(ItemStack::getItem) 79 | .map(BuiltInRegistries.ITEM::getKey) 80 | .collect(Collectors.toSet()); 81 | remove(tag, ids); 82 | } 83 | 84 | private void remove(PonderTag tag, Set items) { 85 | var reg = PonderJS.getTagRegistryAccessor(); 86 | 87 | for (ResourceLocation item : items) { 88 | if (reg.getComponentTagMap().get(item).remove(tag.getId())) { 89 | ConsoleJS.CLIENT.info("Removed ponder tag " + tag.getId() + " from item " + item); 90 | } 91 | } 92 | } 93 | 94 | @SuppressWarnings("UnusedReturnValue") 95 | public static class Builder { 96 | 97 | private final LinkedHashSet itemIds = new LinkedHashSet<>(); 98 | private final ResourceLocation id; 99 | @Nullable 100 | private String title; 101 | @Nullable 102 | private String description; 103 | private Item itemIcon = Items.BARRIER; 104 | private boolean noIndex = false; 105 | private boolean addItemIconToItems = false; 106 | 107 | private Builder(ResourceLocation id) { 108 | this.id = id; 109 | } 110 | 111 | public Builder title(String title) { 112 | this.title = title; 113 | return this; 114 | } 115 | 116 | public Builder description(String description) { 117 | this.description = description; 118 | return this; 119 | } 120 | 121 | public Builder icon(Item item) { 122 | this.itemIcon = item; 123 | return this; 124 | } 125 | 126 | public Builder noIndex() { 127 | this.noIndex = true; 128 | return this; 129 | } 130 | 131 | public Builder addIconToItems() { 132 | addItemIconToItems = true; 133 | return this; 134 | } 135 | 136 | public Builder items(Ingredient ingredient) { 137 | for (ItemStack item : ingredient.getItems()) { 138 | var itemId = BuiltInRegistries.ITEM.getKey(item.getItem()); 139 | itemIds.add(itemId); 140 | } 141 | 142 | return this; 143 | } 144 | 145 | private void fin(PonderTagRegistrationHelper helper) { 146 | Preconditions.checkNotNull(title, "Title cannot be null for tag " + id); 147 | Preconditions.checkNotNull(description, "Description cannot be null for tag " + id); 148 | 149 | var tagBuilder = helper.registerTag(id).title(title).description(description); 150 | if (!noIndex) tagBuilder.addToIndex(); 151 | tagBuilder.item(itemIcon, true, addItemIconToItems); 152 | 153 | tagBuilder.register(); 154 | 155 | for (var itemId : itemIds) { 156 | helper.addTagToComponent(itemId, id); 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderJS.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import com.almostreliable.ponderjs.mixin.PonderIndexAccessor; 4 | import com.almostreliable.ponderjs.mixin.PonderTagRegistryAccessor; 5 | import dev.latvian.mods.kubejs.KubeJS; 6 | import net.createmod.ponder.foundation.PonderTag; 7 | import net.createmod.ponder.foundation.registration.PonderTagRegistry; 8 | import net.minecraft.locale.Language; 9 | import net.minecraft.resources.ResourceLocation; 10 | import org.apache.logging.log4j.LogManager; 11 | import org.apache.logging.log4j.Logger; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.HashSet; 15 | import java.util.Optional; 16 | import java.util.Set; 17 | 18 | public class PonderJS { 19 | public static final PonderJSPlugin PLUGIN = new PonderJSPlugin(); 20 | public static final Logger LOGGER = LogManager.getLogger(BuildConfig.MOD_ID); 21 | @Nullable public static final String TAG_EVENT = "ponder.tag"; 22 | public static final String REGISTRY_EVENT = "ponder.registry"; 23 | public static final Set NAMESPACES = new HashSet<>(); 24 | // public static final HashMap CACHED_ICONS = new HashMap<>(); 25 | public static final PonderStoriesManager STORIES_MANAGER = new PonderStoriesManager(); 26 | @Nullable public static Language DEFAULT_LANGUAGE; 27 | public static boolean ON_RELOAD = false; 28 | 29 | public static Optional getTagByName(ResourceLocation res) { 30 | return getTagRegistryAccessor().getListedTags().stream().filter(tag -> tag.getId().equals(res)).findFirst(); 31 | } 32 | 33 | public static PonderTagRegistryAccessor getTagRegistryAccessor() { 34 | return (PonderTagRegistryAccessor) (PonderIndexAccessor.getTags()); 35 | } 36 | 37 | public static PonderTagRegistry getTagRegistry() { 38 | return PonderIndexAccessor.getTags(); 39 | } 40 | 41 | public static ResourceLocation appendKubeToId(String id) { 42 | if (!id.contains(":")) id = KubeJS.MOD_ID + ":" + id; 43 | return ResourceLocation.parse(id); 44 | } 45 | 46 | public static Optional getTagByName(String tag) { 47 | var rl = ResourceLocation.tryParse(tag); 48 | if (rl == null) { 49 | throw new IllegalArgumentException("Given tag is not a valid resource location: " + tag); 50 | } 51 | 52 | return getTagByName(rl); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderJSMod.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | 4 | import com.almostreliable.ponderjs.commands.GenerateKubeJSLangCommand; 5 | import com.mojang.brigadier.CommandDispatcher; 6 | import com.mojang.brigadier.arguments.StringArgumentType; 7 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 8 | import net.createmod.ponder.foundation.PonderIndex; 9 | import net.minecraft.commands.CommandSourceStack; 10 | import net.minecraft.commands.Commands; 11 | import net.neoforged.bus.api.IEventBus; 12 | import net.neoforged.fml.common.Mod; 13 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 14 | import net.neoforged.neoforge.common.NeoForge; 15 | import net.neoforged.neoforge.event.RegisterCommandsEvent; 16 | 17 | import static com.almostreliable.ponderjs.PonderJS.PLUGIN; 18 | 19 | @Mod(BuildConfig.MOD_ID) 20 | public class PonderJSMod { 21 | 22 | public PonderJSMod(IEventBus bus) { 23 | // I have no clue for what this existed lol 24 | // ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, 25 | // () -> new IExtensionPoint.DisplayTest(() -> "ANY", (a, b) -> true)); 26 | 27 | NeoForge.EVENT_BUS.addListener(this::registerCommands); 28 | bus.addListener(this::onClient); 29 | } 30 | 31 | private void onClient(FMLClientSetupEvent event) { 32 | PonderIndex.addPlugin(PLUGIN); 33 | } 34 | 35 | private void registerCommands(RegisterCommandsEvent event) { 36 | CommandDispatcher dis = event.getDispatcher(); 37 | LiteralArgumentBuilder b = Commands.literal(BuildConfig.MOD_ID); 38 | b.then(Commands.literal("generate_lang_template") 39 | .then(Commands.argument("lang", StringArgumentType.word()) 40 | .requires((source) -> source.getServer().isSingleplayer()) 41 | .executes(new GenerateKubeJSLangCommand()))); 42 | dis.register(b); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderJSPlugin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import net.createmod.ponder.api.registration.PonderPlugin; 4 | 5 | public class PonderJSPlugin implements PonderPlugin { 6 | 7 | @Override 8 | public String getModId() { 9 | return BuildConfig.MOD_ID; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderLang.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import com.almostreliable.ponderjs.mixin.PonderIndexAccessor; 4 | import com.almostreliable.ponderjs.util.PonderErrorHelper; 5 | import com.google.gson.Gson; 6 | import com.google.gson.GsonBuilder; 7 | import com.google.gson.JsonObject; 8 | import net.createmod.ponder.foundation.PonderIndex; 9 | import net.minecraft.client.Minecraft; 10 | import org.apache.commons.io.FileUtils; 11 | 12 | import javax.annotation.Nullable; 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.nio.charset.StandardCharsets; 16 | 17 | import static com.almostreliable.ponderjs.PonderJS.PLUGIN; 18 | 19 | public class PonderLang { 20 | public static final String PATH = "kubejs/assets/ponderjs_generated/lang/%lang%.json"; 21 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 22 | public static boolean GENERATING_LANG = false; 23 | 24 | public static void initLanguage(boolean ignoreSharedText) { 25 | if (!PonderIndexAccessor.getPlugins().contains(PLUGIN)) { 26 | return; 27 | } 28 | 29 | GENERATING_LANG = true; 30 | 31 | try { 32 | if (generate("en_us")) { 33 | try { 34 | Minecraft.getInstance().reloadResourcePacks(); 35 | } catch (Exception e) { 36 | throw new RuntimeException( 37 | "Something went wrong while reloading resources after PonderJS init. You have to manually reload the resources for the changes to take effect.", 38 | e); 39 | } 40 | } 41 | } catch (Exception e) { 42 | PonderErrorHelper.yeet(e); 43 | } 44 | 45 | GENERATING_LANG = false; 46 | } 47 | 48 | /** 49 | * @param langName as String 50 | * @return true if a new lang file was created 51 | */ 52 | public static boolean generate(String langName) { 53 | File file = new File(PATH.replace("%lang%", langName)); 54 | 55 | JsonObject existingLang = read(file); 56 | JsonObject currentLang = createFromLocalization(); 57 | 58 | if (currentLang.equals(existingLang)) { 59 | return false; 60 | } 61 | 62 | PonderJS.LOGGER.info( 63 | "PonderJS - New lang file differ from existing lang file, generating new lang file.\n Old Lang size: {} \n\n New lang size: {}", 64 | existingLang == null ? 0 : existingLang.size(), 65 | currentLang.size()); 66 | 67 | return write(file, currentLang); 68 | } 69 | 70 | private static boolean write(File file, JsonObject currentLang) { 71 | try { 72 | String output = GSON.toJson(currentLang); 73 | FileUtils.writeStringToFile(file, output, StandardCharsets.UTF_8); 74 | return true; 75 | } catch (IOException e) { 76 | PonderJS.LOGGER.error(e); 77 | } 78 | 79 | return false; 80 | } 81 | 82 | @Nullable 83 | protected static JsonObject read(File file) { 84 | if (file.exists()) { 85 | try { 86 | String s = FileUtils.readFileToString(file, StandardCharsets.UTF_8); 87 | return GSON.fromJson(s, JsonObject.class); 88 | } catch (IOException e) { 89 | PonderJS.LOGGER.error(e); 90 | } 91 | } 92 | return null; 93 | } 94 | 95 | public static JsonObject createFromLocalization() { 96 | JsonObject object = new JsonObject(); 97 | for (String namespace : PonderJS.NAMESPACES) { 98 | PonderIndex.getLangAccess().provideLang(namespace, object::addProperty); 99 | } 100 | 101 | return object; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderRegistryEventJS.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | import dev.latvian.mods.kubejs.event.KubeEvent; 4 | import dev.latvian.mods.kubejs.script.ConsoleJS; 5 | import net.createmod.ponder.foundation.registration.PonderSceneRegistry; 6 | import net.minecraft.core.particles.SimpleParticleType; 7 | import net.minecraft.core.registries.BuiltInRegistries; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraft.world.item.ItemStack; 10 | import net.minecraft.world.item.crafting.Ingredient; 11 | 12 | import java.util.Arrays; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | 16 | public class PonderRegistryEventJS implements KubeEvent { 17 | 18 | private final PonderSceneRegistry sceneRegistry; 19 | 20 | public PonderRegistryEventJS(PonderSceneRegistry sceneRegistry) { 21 | this.sceneRegistry = sceneRegistry; 22 | } 23 | 24 | public PonderBuilderJS create(Ingredient ingredient) { 25 | if (ingredient.isEmpty()) { 26 | throw new IllegalArgumentException("Provided items must not be empty!"); 27 | } 28 | 29 | Set itemIds = Arrays 30 | .stream(ingredient.getItems()) 31 | .map(ItemStack::getItem) 32 | .map(BuiltInRegistries.ITEM::getKey) 33 | .collect(Collectors.toSet()); 34 | return new PonderBuilderJS(itemIds, sceneRegistry); 35 | } 36 | 37 | @SuppressWarnings("DataFlowIssue") 38 | public void printParticleNames() { 39 | StringBuilder sb = new StringBuilder(); 40 | sb.append("\n").append("### Particles ###").append("\n"); 41 | BuiltInRegistries.PARTICLE_TYPE.stream() 42 | .filter(SimpleParticleType.class::isInstance) 43 | .map(BuiltInRegistries.PARTICLE_TYPE::getKey) 44 | .sorted() 45 | .forEach(id -> sb.append(" - ").append(id).append("\n")); 46 | ConsoleJS.CLIENT.info(sb.toString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/PonderStoriesManager.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs; 2 | 3 | public class PonderStoriesManager { 4 | 5 | 6 | // public void compileLang() { 7 | // stories.values() 8 | // .stream() 9 | // .flatMap(Collection::stream) 10 | // .forEach(entry -> PonderRegistry.compileScene(0, entry, null)); 11 | // } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/CustomPonderOverlayElement.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.api; 2 | 3 | 4 | import net.createmod.ponder.foundation.PonderScene; 5 | import net.createmod.ponder.foundation.element.AnimatedOverlayElementBase; 6 | import net.createmod.ponder.foundation.ui.PonderUI; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | 9 | public class CustomPonderOverlayElement extends AnimatedOverlayElementBase { 10 | protected OnRenderOverlay onRender = (ctx) -> {}; 11 | protected OnElementAction onWhileSkipping = (ctx) -> {}; 12 | protected OnElementAction onTick = (ctx) -> {}; 13 | protected OnElementAction onReset = (ctx) -> {}; 14 | private int currentTick = 0; 15 | 16 | public int getCurrentTick() { 17 | return currentTick; 18 | } 19 | 20 | public CustomPonderOverlayElement onSkipping(OnElementAction onWhileSkipping) { 21 | this.onWhileSkipping = onWhileSkipping; 22 | return this; 23 | } 24 | 25 | public CustomPonderOverlayElement onTick(OnElementAction onTick) { 26 | this.onTick = onTick; 27 | return this; 28 | } 29 | 30 | public CustomPonderOverlayElement onReset(OnElementAction onReset) { 31 | this.onReset = onReset; 32 | return this; 33 | } 34 | 35 | public CustomPonderOverlayElement onRender(OnRenderOverlay onRender) { 36 | this.onRender = onRender; 37 | return this; 38 | } 39 | 40 | @Override 41 | public void whileSkipping(PonderScene scene) { 42 | super.whileSkipping(scene); 43 | onWhileSkipping.accept(new OnElementAction.Context(this, scene)); 44 | } 45 | 46 | @Override 47 | public void tick(PonderScene scene) { 48 | super.tick(scene); 49 | currentTick++; 50 | onTick.accept(new OnElementAction.Context(this, scene)); 51 | } 52 | 53 | @Override 54 | public void reset(PonderScene scene) { 55 | super.reset(scene); 56 | currentTick = 0; 57 | onReset.accept(new OnElementAction.Context(this, scene)); 58 | } 59 | 60 | @Override 61 | public void render(PonderScene scene, PonderUI screen, GuiGraphics graphics, float partialTicks, float fade) { 62 | var ctx = new OnRenderOverlay.RenderContext(this, scene, screen, graphics, partialTicks, fade); 63 | onRender.render(ctx); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/CustomPonderSceneElement.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.api; 2 | 3 | import dev.latvian.mods.rhino.util.HideFromJS; 4 | import net.createmod.ponder.api.level.PonderLevel; 5 | import net.createmod.ponder.foundation.PonderScene; 6 | import net.createmod.ponder.foundation.element.AnimatedSceneElementBase; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | import net.minecraft.client.renderer.MultiBufferSource; 9 | import net.minecraft.client.renderer.RenderType; 10 | 11 | public class CustomPonderSceneElement extends AnimatedSceneElementBase { 12 | protected OnRenderWorld onRenderFirst = (ctx) -> {}; 13 | protected OnRenderWorld.Layer onRenderWorldLayer = (ctx) -> {}; 14 | protected OnRenderWorld onRenderLast = (ctx) -> {}; 15 | protected OnElementAction onWhileSkipping = (ctx) -> {}; 16 | protected OnElementAction onTick = (ctx) -> {}; 17 | protected OnElementAction onReset = (ctx) -> {}; 18 | private int currentTick = 0; 19 | 20 | public int getCurrentTick() { 21 | return currentTick; 22 | } 23 | 24 | public CustomPonderSceneElement onSkipping(OnElementAction onWhileSkipping) { 25 | this.onWhileSkipping = onWhileSkipping; 26 | return this; 27 | } 28 | 29 | public CustomPonderSceneElement onTick(OnElementAction onTick) { 30 | this.onTick = onTick; 31 | return this; 32 | } 33 | 34 | public CustomPonderSceneElement onReset(OnElementAction onReset) { 35 | this.onReset = onReset; 36 | return this; 37 | } 38 | 39 | public CustomPonderSceneElement onRenderFirst(OnRenderWorld onRenderWorld) { 40 | this.onRenderFirst = onRenderWorld; 41 | return this; 42 | } 43 | 44 | public CustomPonderSceneElement onRender(OnRenderWorld.Layer onRenderWorldLayer) { 45 | this.onRenderWorldLayer = onRenderWorldLayer; 46 | return this; 47 | } 48 | 49 | public CustomPonderSceneElement onRenderLast(OnRenderWorld onRenderWorld) { 50 | this.onRenderLast = onRenderWorld; 51 | return this; 52 | } 53 | 54 | @Override 55 | public void whileSkipping(PonderScene scene) { 56 | super.whileSkipping(scene); 57 | onWhileSkipping.accept(new OnElementAction.Context(this, scene)); 58 | } 59 | 60 | @Override 61 | public void tick(PonderScene scene) { 62 | super.tick(scene); 63 | currentTick++; 64 | onTick.accept(new OnElementAction.Context(this, scene)); 65 | } 66 | 67 | @Override 68 | public void reset(PonderScene scene) { 69 | super.reset(scene); 70 | currentTick = 0; 71 | onReset.accept(new OnElementAction.Context(this, scene)); 72 | } 73 | 74 | 75 | @HideFromJS 76 | @Override 77 | public void renderFirst(PonderLevel world, MultiBufferSource buffer, GuiGraphics graphics, float fade, float pt) { 78 | super.renderFirst(world, buffer, graphics, fade, pt); 79 | var ctx = new OnRenderWorld.RenderContext(this, world, buffer, graphics, pt, fade); 80 | onRenderFirst.renderWorld(ctx); 81 | } 82 | 83 | @HideFromJS 84 | @Override 85 | public void renderLayer(PonderLevel world, MultiBufferSource buffer, RenderType type, GuiGraphics graphics, float fade, float pt) { 86 | super.renderLayer(world, buffer, type, graphics, fade, pt); 87 | var ctx = new OnRenderWorld.Layer.RenderContext(this, world, buffer, type, graphics, pt, fade); 88 | onRenderWorldLayer.renderLayer(ctx); 89 | } 90 | 91 | @HideFromJS 92 | @Override 93 | public void renderLast(PonderLevel world, MultiBufferSource buffer, GuiGraphics graphics, float fade, float pt) { 94 | super.renderLast(world, buffer, graphics, fade, pt); 95 | var ctx = new OnRenderWorld.RenderContext(this, world, buffer, graphics, pt, fade); 96 | onRenderLast.renderWorld(ctx); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/OnElementAction.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.api; 2 | 3 | import net.createmod.ponder.api.element.PonderElement; 4 | import net.createmod.ponder.foundation.PonderScene; 5 | 6 | @FunctionalInterface 7 | public interface OnElementAction { 8 | 9 | void accept(Context context); 10 | 11 | record Context(PonderElement getElement, PonderScene getScene) {} 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/OnRenderOverlay.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.api; 2 | 3 | import net.createmod.ponder.api.element.PonderOverlayElement; 4 | import net.createmod.ponder.foundation.PonderScene; 5 | import net.createmod.ponder.foundation.ui.PonderUI; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | 8 | @FunctionalInterface 9 | public interface OnRenderOverlay { 10 | 11 | void render(RenderContext context); 12 | 13 | record RenderContext(PonderOverlayElement getElement, PonderScene getScene, PonderUI getScreen, 14 | GuiGraphics getGraphics, float getPartialTicks, float getFade) {} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/OnRenderWorld.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.api; 2 | 3 | import net.createmod.ponder.api.element.PonderElement; 4 | import net.createmod.ponder.api.level.PonderLevel; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | import net.minecraft.client.renderer.MultiBufferSource; 7 | import net.minecraft.client.renderer.RenderType; 8 | 9 | @FunctionalInterface 10 | public interface OnRenderWorld { 11 | 12 | void renderWorld(RenderContext context); 13 | 14 | @FunctionalInterface 15 | interface Layer { 16 | void renderLayer(RenderContext context); 17 | 18 | record RenderContext(PonderElement getElement, PonderLevel getWorld, MultiBufferSource getBuffer, 19 | RenderType getType, GuiGraphics getGraphics, float getPartialTicks, float getFade) {} 20 | } 21 | 22 | 23 | record RenderContext(PonderElement getElement, PonderLevel getWorld, MultiBufferSource getBuffer, 24 | GuiGraphics getGraphics, float getPartialTicks, float getFade) {} 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/api/package-info.java: -------------------------------------------------------------------------------- 1 | @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault 2 | package com.almostreliable.ponderjs.api; 3 | 4 | import net.minecraft.MethodsReturnNonnullByDefault; 5 | 6 | import javax.annotation.ParametersAreNonnullByDefault; 7 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/commands/GenerateKubeJSLangCommand.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.commands; 2 | 3 | import com.almostreliable.ponderjs.PonderLang; 4 | import com.mojang.brigadier.Command; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import net.minecraft.commands.CommandSourceStack; 7 | import net.minecraft.network.chat.Component; 8 | 9 | public class GenerateKubeJSLangCommand implements Command { 10 | @Override 11 | public int run(CommandContext context) { 12 | String lang = context.getArgument("lang", String.class); 13 | 14 | CommandSourceStack source = context.getSource(); 15 | if (PonderLang.generate(lang)) { 16 | source.sendSuccess(() -> Component.literal("Changes detected - New lang file created."), false); 17 | } else { 18 | source.sendSuccess(() -> Component.literal("Lang file the same. Nothing created."), false); 19 | } 20 | 21 | return SINGLE_SUCCESS; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/extension/OverlayInstructionExtension.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.extension; 2 | 3 | import com.almostreliable.ponderjs.api.CustomPonderOverlayElement; 4 | import dev.latvian.mods.rhino.util.HideFromJS; 5 | import dev.latvian.mods.rhino.util.RemapPrefixForJS; 6 | import net.createmod.ponder.foundation.PonderScene; 7 | import net.createmod.ponder.foundation.PonderSceneBuilder; 8 | import net.createmod.ponder.foundation.instruction.TickingInstruction; 9 | 10 | @RemapPrefixForJS("ponderjs$") 11 | public interface OverlayInstructionExtension { 12 | 13 | @HideFromJS 14 | PonderSceneBuilder ponderjs$builder(); 15 | 16 | default CustomPonderOverlayElement ponderjs$addElement(int ticks) { 17 | var element = new CustomPonderOverlayElement(); 18 | ponderjs$builder().addInstruction(new TickingInstruction(false, ticks) { 19 | @Override 20 | protected void firstTick(PonderScene scene) { 21 | super.firstTick(scene); 22 | scene.addElement(element); 23 | } 24 | }); 25 | 26 | return element; 27 | } 28 | 29 | default CustomPonderOverlayElement ponderjs$addElement() { 30 | var element = new CustomPonderOverlayElement(); 31 | ponderjs$builder().addInstruction(ponderScene -> { 32 | ponderScene.addElement(element); 33 | }); 34 | 35 | return element; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/extension/SceneBuilderExtension.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.extension; 2 | 3 | import com.almostreliable.ponderjs.particles.ParticleInstructions; 4 | import com.google.common.base.Preconditions; 5 | import dev.latvian.mods.rhino.util.HideFromJS; 6 | import dev.latvian.mods.rhino.util.RemapPrefixForJS; 7 | import net.createmod.catnip.math.Pointing; 8 | import net.createmod.ponder.api.PonderPalette; 9 | import net.createmod.ponder.api.element.InputElementBuilder; 10 | import net.createmod.ponder.api.element.TextElementBuilder; 11 | import net.createmod.ponder.api.scene.SceneBuilder; 12 | import net.createmod.ponder.foundation.PonderScene; 13 | import net.minecraft.client.Minecraft; 14 | import net.minecraft.client.resources.sounds.SimpleSoundInstance; 15 | import net.minecraft.client.resources.sounds.SoundInstance; 16 | import net.minecraft.core.BlockPos; 17 | import net.minecraft.core.Direction; 18 | import net.minecraft.resources.ResourceLocation; 19 | import net.minecraft.sounds.SoundEvent; 20 | import net.minecraft.sounds.SoundSource; 21 | import net.minecraft.world.phys.Vec3; 22 | 23 | @RemapPrefixForJS("ponderjs$") 24 | public interface SceneBuilderExtension { 25 | 26 | @HideFromJS 27 | SceneBuilder ponderjs$self(); 28 | 29 | @HideFromJS 30 | PonderScene ponderjs$getScene(); 31 | 32 | ParticleInstructions ponderjs$getParticles(); 33 | 34 | default void ponderjs$showStructure() { 35 | ponderjs$showStructure(ponderjs$getScene().getBasePlateSize() * 2); 36 | } 37 | 38 | default void ponderjs$showStructure(int height) { 39 | var start = new BlockPos(ponderjs$getScene().getBasePlateOffsetX(), 40 | 0, 41 | ponderjs$getScene().getBasePlateOffsetZ()); 42 | var size = start.offset(ponderjs$getScene().getBasePlateSize() - 1, 43 | height, 44 | ponderjs$getScene().getBasePlateSize() - 1); 45 | var selection = ponderjs$getScene().getSceneBuildingUtil().select().cuboid(start, size); 46 | ponderjs$self().world().showSection(selection, Direction.UP); 47 | } 48 | 49 | default void ponderjs$encapsulateBounds(BlockPos size) { 50 | ponderjs$self().addInstruction(ps -> { 51 | ps.getWorld().getBounds().encapsulate(size); 52 | }); 53 | } 54 | 55 | @SuppressWarnings("ConstantValue") 56 | default void ponderjs$playSound(SoundEvent soundEvent, SoundSource soundSource, float volume, float pitch) { 57 | Preconditions.checkArgument(soundEvent != null, "Given sound does not exist"); 58 | 59 | ponderjs$self().addInstruction(ps -> { 60 | if (Minecraft.getInstance().player == null) { 61 | return; 62 | } 63 | 64 | var sound = new SimpleSoundInstance(soundEvent, 65 | soundSource, 66 | volume, 67 | pitch, 68 | SoundInstance.createUnseededRandom(), 69 | Minecraft.getInstance().player.blockPosition()); 70 | Minecraft.getInstance().getSoundManager().play(sound); 71 | }); 72 | } 73 | 74 | default void ponderjs$playSound(SoundEvent soundEvent, float volume) { 75 | ponderjs$playSound(soundEvent, SoundSource.MASTER, volume, 1); 76 | } 77 | 78 | default void ponderjs$playSound(SoundEvent soundEvent) { 79 | ponderjs$playSound(soundEvent, SoundSource.MASTER, 1, 1); 80 | } 81 | 82 | default TextElementBuilder ponderjs$text(int duration, String text) { 83 | return ponderjs$self().overlay().showText(duration).text(text); 84 | } 85 | 86 | default TextElementBuilder ponderjs$text(int duration, String text, Vec3 position) { 87 | return ponderjs$self().overlay().showText(duration).text(text).pointAt(position); 88 | } 89 | 90 | default TextElementBuilder ponderjs$sharedText(int duration, ResourceLocation key) { 91 | return ponderjs$self().overlay().showText(duration).sharedText(key); 92 | } 93 | 94 | default TextElementBuilder ponderjs$sharedText(int duration, ResourceLocation key, Vec3 position) { 95 | return ponderjs$self() 96 | .overlay() 97 | .showText(duration) 98 | .sharedText(key) 99 | .pointAt(position) 100 | .colored(PonderPalette.BLUE); 101 | } 102 | 103 | default InputElementBuilder ponderjs$showControls(int duration, Vec3 pos, Pointing pointing) { 104 | return ponderjs$self().overlay().showControls(pos, pointing, duration); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/extension/WorldInstructionExtension.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.extension; 2 | 3 | import com.almostreliable.ponderjs.api.CustomPonderSceneElement; 4 | import com.almostreliable.ponderjs.util.BlockStateFunction; 5 | import dev.latvian.mods.rhino.util.HideFromJS; 6 | import dev.latvian.mods.rhino.util.RemapPrefixForJS; 7 | import net.createmod.ponder.api.element.ElementLink; 8 | import net.createmod.ponder.api.element.EntityElement; 9 | import net.createmod.ponder.api.scene.Selection; 10 | import net.createmod.ponder.api.scene.WorldInstructions; 11 | import net.createmod.ponder.foundation.PonderScene; 12 | import net.createmod.ponder.foundation.PonderSceneBuilder; 13 | import net.createmod.ponder.foundation.instruction.FadeInOutInstruction; 14 | import net.minecraft.commands.arguments.EntityAnchorArgument; 15 | import net.minecraft.core.BlockPos; 16 | import net.minecraft.core.registries.BuiltInRegistries; 17 | import net.minecraft.nbt.CompoundTag; 18 | import net.minecraft.world.entity.Entity; 19 | import net.minecraft.world.entity.EntityType; 20 | import net.minecraft.world.level.block.entity.BlockEntity; 21 | import net.minecraft.world.level.block.state.BlockState; 22 | import net.minecraft.world.phys.Vec3; 23 | 24 | import java.util.Objects; 25 | import java.util.function.Consumer; 26 | import java.util.function.UnaryOperator; 27 | 28 | @RemapPrefixForJS("ponderjs$") 29 | public interface WorldInstructionExtension { 30 | 31 | @HideFromJS 32 | PonderSceneBuilder ponderjs$builder(); 33 | 34 | default CustomPonderSceneElement ponderjs$addElement(int ticks) { 35 | var element = new CustomPonderSceneElement(); 36 | element.setVisible(false); 37 | ponderjs$builder().addInstruction(new FadeInOutInstruction(ticks) { 38 | @Override 39 | protected void show(PonderScene scene) { 40 | scene.addElement(element); 41 | element.setVisible(true); 42 | } 43 | 44 | @Override 45 | protected void hide(PonderScene scene) { 46 | element.setVisible(false); 47 | } 48 | 49 | @Override 50 | protected void applyFade(PonderScene scene, float fade) { 51 | element.setFade(fade); 52 | } 53 | }); 54 | 55 | return element; 56 | } 57 | 58 | default CustomPonderSceneElement ponderjs$addElement() { 59 | var element = new CustomPonderSceneElement(); 60 | ponderjs$builder().addInstruction(ponderScene -> { 61 | ponderScene.addElement(element); 62 | element.setVisible(true); 63 | }); 64 | 65 | return element; 66 | } 67 | 68 | /** 69 | * Create a new entity with some default behavior. The entity will be rotated to face north. 70 | * 71 | * @param entityType The type of entity to create. 72 | * @param position The position to create the entity at. 73 | * @param consumer Callback to modify the entity. 74 | * @return An entity link which can be used later on. 75 | */ 76 | default ElementLink ponderjs$createEntity(EntityType entityType, Vec3 position, Consumer consumer) { 77 | return ponderjs$builder().world().createEntity(level -> { 78 | Entity entity = entityType.create(level); 79 | if (entity == null) { 80 | throw new IllegalArgumentException("Could not create entity of type " + 81 | BuiltInRegistries.ENTITY_TYPE.getKey(entityType)); 82 | } 83 | 84 | entity.setPosRaw(position.x, position.y, position.z); 85 | entity.setOldPosAndRot(); 86 | entity.lookAt(EntityAnchorArgument.Anchor.FEET, position.add(0, 0, -1)); 87 | consumer.accept(entity); 88 | return entity; 89 | }); 90 | } 91 | 92 | default ElementLink ponderjs$createEntity(EntityType entityType, Vec3 position) { 93 | return ponderjs$createEntity(entityType, position, entity -> { 94 | }); 95 | } 96 | 97 | /** 98 | * Short version for modify blocks with default spawn particles. 99 | * 100 | * @param pos the position to modify 101 | * @param function the function to apply 102 | */ 103 | default void ponderjs$modifyBlocks(Selection pos, BlockStateFunction function) { 104 | ponderjs$modifyBlocks(pos, true, function); 105 | } 106 | 107 | /** 108 | * Wrapper for {@link WorldInstructions#modifyBlock(BlockPos, UnaryOperator, boolean)} 109 | *

110 | * NOTE: Will probably be removed in the future, exist earlier for backwards compatibility 111 | */ 112 | default void ponderjs$modifyBlocks(Selection selection, boolean spawnParticles, BlockStateFunction function) { 113 | ponderjs$builder().world().modifyBlocks(selection, BlockStateFunction.from(function), spawnParticles); 114 | } 115 | 116 | /** 117 | * Wrapper for {@link WorldInstructions#modifyBlock(BlockPos, UnaryOperator, boolean)} with TypeWrapper for {@link UnaryOperator< BlockState >} 118 | * 119 | * @param selection selection 120 | * @param function Wrapper function for BlockState 121 | * @param spawnParticles spawn particles 122 | */ 123 | default void ponderjs$modifyBlocks(Selection selection, BlockStateFunction function, boolean spawnParticles) { 124 | ponderjs$builder().world().modifyBlocks(selection, BlockStateFunction.from(function), spawnParticles); 125 | } 126 | 127 | /** 128 | * Wrapper for {@link WorldInstructions#modifyBlock(BlockPos, UnaryOperator, boolean)} with TypeWrapper for {@link UnaryOperator} 129 | * 130 | * @param pos position 131 | * @param function Wrapper function for BlockState 132 | * @param spawnParticles spawn particles 133 | */ 134 | default void ponderjs$modifyBlock(BlockPos pos, BlockStateFunction function, boolean spawnParticles) { 135 | ponderjs$builder().world().modifyBlock(pos, BlockStateFunction.from(function), spawnParticles); 136 | } 137 | 138 | /** 139 | * Set blocks with default particle spawning 140 | * 141 | * @param selection selection 142 | * @param blockState block state 143 | */ 144 | default void ponderjs$setBlocks(Selection selection, BlockState blockState) { 145 | ponderjs$setBlocks(selection, true, blockState); 146 | } 147 | 148 | /** 149 | * Wrapper for {@link WorldInstructions#setBlocks(Selection, BlockState, boolean)} 150 | *

151 | * NOTE: Will probably be removed in the future, exist earlier for backwards compatibility 152 | */ 153 | default void ponderjs$setBlocks(Selection selection, boolean spawnParticles, BlockState blockState) { 154 | ponderjs$builder().world().setBlocks(selection, blockState, spawnParticles); 155 | } 156 | 157 | 158 | default void ponderjs$modifyBlockEntityNBT(Selection selection, Consumer consumer) { 159 | ponderjs$modifyBlockEntityNBT(selection, false, consumer); 160 | } 161 | 162 | default void ponderjs$modifyBlockEntityNBT(Selection selection, boolean reDrawBlocks, Consumer consumer) { 163 | ponderjs$builder().world().modifyBlockEntityNBT(selection, BlockEntity.class, consumer, reDrawBlocks); 164 | } 165 | 166 | default void ponderjs$removeEntity(ElementLink link) { 167 | ponderjs$builder().addInstruction(scene -> { 168 | var resolve = scene.resolve(link); 169 | if (resolve != null) { 170 | resolve.ifPresent(Entity::discard); 171 | } 172 | }); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/extension/package-info.java: -------------------------------------------------------------------------------- 1 | @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault 2 | package com.almostreliable.ponderjs.extension; 3 | 4 | import net.minecraft.MethodsReturnNonnullByDefault; 5 | 6 | import javax.annotation.ParametersAreNonnullByDefault; 7 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/KubeJSClientMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import dev.latvian.mods.kubejs.client.KubeJSClient; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | @Mixin(KubeJSClient.class) 10 | public class KubeJSClientMixin { 11 | 12 | @Inject(method = "reloadClientScripts", at = @At("RETURN"), remap = false) 13 | private static void reloadClientScripts(CallbackInfo ci) { 14 | // if (PonderJS.isInitialized()) { 15 | // PonderJS.reload(); 16 | // String msg = "Ponder tags event is currently not reloadable. Only scenes were reloaded."; 17 | // if (KubeJS.PROXY.getClientPlayer() != null) { 18 | // KubeJS.PROXY.getClientPlayer().sendSystemMessage(Component.literal(msg)); 19 | // } 20 | // ConsoleJS.CLIENT.info(msg); 21 | // } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/ParticleAccessor.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import net.minecraft.client.particle.Particle; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(Particle.class) 8 | public interface ParticleAccessor { 9 | 10 | @Accessor("hasPhysics") 11 | void ponderjs$setHasPhysics(boolean hasPhysics); 12 | 13 | @Accessor("gravity") 14 | void ponderjs$setGravity(float gravity); 15 | 16 | @Accessor("stoppedByCollision") 17 | void ponderjs$setStoppedByCollision(boolean stoppedByCollision); 18 | 19 | @Accessor("roll") 20 | void ponderjs$setRoll(float roll); 21 | 22 | @Accessor("friction") 23 | void ponderjs$setFriction(float friction); 24 | 25 | @Accessor("alpha") 26 | void ponderjs$setAlpha(float alpha); 27 | 28 | @Accessor("lifetime") 29 | void ponderjs$setLifetime(int lifetime); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderClientMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.PonderLang; 4 | import net.createmod.ponder.PonderClient; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(PonderClient.class) 11 | public class PonderClientMixin { 12 | 13 | @Inject(method = "modLoadCompleted", at = @At("RETURN"), remap = false) 14 | private static void ponderjs$injectLanguage(CallbackInfo ci) { 15 | PonderLang.initLanguage(false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderIndexAccessor.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import net.createmod.ponder.api.registration.PonderPlugin; 4 | import net.createmod.ponder.foundation.PonderIndex; 5 | import net.createmod.ponder.foundation.registration.PonderTagRegistry; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | import org.spongepowered.asm.mixin.throwables.MixinException; 9 | 10 | import java.util.Set; 11 | 12 | @Mixin(PonderIndex.class) 13 | public interface PonderIndexAccessor { 14 | 15 | @Accessor(value = "TAGS", remap = false) 16 | static PonderTagRegistry getTags() { 17 | throw new MixinException("Cannot access PonderIndex.TAGS directly!"); 18 | } 19 | 20 | @Accessor(value = "plugins", remap = false) 21 | static Set getPlugins() { 22 | throw new MixinException("Cannot access PonderIndex.plugins directly!"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderIndexMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.*; 4 | import net.createmod.ponder.foundation.PonderIndex; 5 | import net.createmod.ponder.foundation.registration.*; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import static com.almostreliable.ponderjs.PonderJS.PLUGIN; 14 | 15 | @Mixin(PonderIndex.class) 16 | public class PonderIndexMixin { 17 | 18 | @Shadow(remap = false) @Final private static PonderSceneRegistry SCENES; 19 | 20 | @Shadow(remap = false) @Final private static PonderTagRegistry TAGS; 21 | 22 | @Shadow(remap = false) @Final private static PonderLocalization LOCALIZATION; 23 | 24 | @Inject(method = "reload", at = @At("RETURN"), remap = false) 25 | private static void ponderjs$injectLanguage(CallbackInfo ci) { 26 | PonderJS.ON_RELOAD = true; 27 | PonderLang.initLanguage(true); 28 | PonderJS.ON_RELOAD = false; 29 | } 30 | 31 | @Inject(method = "registerAll", at = @At("HEAD"), remap = false, cancellable = true) 32 | private static void ponderjs$blockRegistering(CallbackInfo ci) { 33 | if (PonderLang.GENERATING_LANG) ci.cancel(); 34 | } 35 | 36 | @Inject(method = "gatherSharedText", at = @At("HEAD"), remap = false, cancellable = true) 37 | private static void ponderjs$blockSharedText(CallbackInfo ci) { 38 | if (PonderJS.ON_RELOAD) ci.cancel(); 39 | } 40 | 41 | @Inject(method = "registerAll", at = @At("RETURN"), remap = false) 42 | private static void ponderjs$invokeEvents(CallbackInfo ci) { 43 | PonderJS.NAMESPACES.clear(); 44 | PonderEvents.REGISTRY.post(new PonderRegistryEventJS(SCENES)); 45 | var tagRegHelper = new DefaultPonderTagRegistrationHelper(PLUGIN.getModId(), TAGS, LOCALIZATION); 46 | PonderEvents.TAGS.post(new PonderItemTagEventJS(tagRegHelper)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderInstructionMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.util.PonderErrorHelper; 4 | import dev.latvian.mods.rhino.RhinoException; 5 | import net.createmod.ponder.foundation.PonderScene; 6 | import net.minecraft.client.Minecraft; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import java.util.function.Consumer; 14 | 15 | /** 16 | * Mixin into the simple PonderInstruction to catch Rhino Exceptions, so we can delegate them to the user. 17 | */ 18 | @Mixin(targets = "net.createmod.ponder.foundation.instruction.PonderInstruction$Simple") 19 | public class PonderInstructionMixin { 20 | 21 | @Shadow(remap = false) 22 | private Consumer callback; 23 | 24 | @Inject(method = "", at = @At("RETURN"), remap = false) 25 | private void init(Consumer argCallback, CallbackInfo ci) { 26 | callback = ponderScene -> { 27 | try { 28 | argCallback.accept(ponderScene); 29 | } catch (RhinoException e) { 30 | PonderErrorHelper.yeet(e); 31 | if (Minecraft.getInstance() != null) { 32 | Minecraft.getInstance().setScreen(null); 33 | } 34 | } 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderLocalizationMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.PonderJS; 4 | import com.almostreliable.ponderjs.PonderLang; 5 | import net.createmod.ponder.api.level.PonderLevel; 6 | import net.createmod.ponder.foundation.PonderIndex; 7 | import net.createmod.ponder.foundation.registration.PonderLocalization; 8 | import net.createmod.ponder.foundation.registration.PonderSceneRegistry; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.core.BlockPos; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(PonderLocalization.class) 17 | public class PonderLocalizationMixin { 18 | 19 | @Inject(method = "generateSceneLang", at = @At("HEAD"), remap = false, cancellable = true) 20 | public void ponderjs$overrideGenerateSceneLang(CallbackInfo ci) { 21 | if (!PonderLang.GENERATING_LANG) { 22 | return; 23 | } 24 | 25 | var localization = (PonderLocalization) (Object) this; 26 | PonderIndex 27 | .getSceneAccess() 28 | .getRegisteredEntries() 29 | .stream() 30 | .filter(scene -> PonderJS.NAMESPACES.contains(scene.getKey().getNamespace())) 31 | .forEach( 32 | entry -> { 33 | assert Minecraft.getInstance().level != null; 34 | PonderSceneRegistry.compileScene(localization, 35 | entry.getValue(), 36 | new PonderLevel(BlockPos.ZERO, Minecraft.getInstance().level)); 37 | } 38 | ); 39 | 40 | ci.cancel(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderOverlayInstructionsMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.extension.OverlayInstructionExtension; 4 | import net.createmod.ponder.foundation.PonderSceneBuilder; 5 | import org.spongepowered.asm.mixin.Final; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | 9 | @Mixin(PonderSceneBuilder.PonderOverlayInstructions.class) 10 | public class PonderOverlayInstructionsMixin implements OverlayInstructionExtension { 11 | 12 | @Shadow(remap = false) @Final PonderSceneBuilder this$0; 13 | 14 | @Override 15 | public PonderSceneBuilder ponderjs$builder() { 16 | return this$0; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderSceneBuilderMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.extension.SceneBuilderExtension; 4 | import com.almostreliable.ponderjs.particles.ParticleInstructions; 5 | import dev.latvian.mods.rhino.util.RemapForJS; 6 | import net.createmod.ponder.api.scene.*; 7 | import net.createmod.ponder.foundation.PonderScene; 8 | import net.createmod.ponder.foundation.PonderSceneBuilder; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.Unique; 13 | 14 | @Mixin(PonderSceneBuilder.class) 15 | public abstract class PonderSceneBuilderMixin implements SceneBuilderExtension { 16 | 17 | @Unique 18 | private final ParticleInstructions ponderjs$particles = new ParticleInstructions((SceneBuilder) (Object) this); 19 | 20 | @Shadow(remap = false) @Final protected PonderScene scene; 21 | 22 | @RemapForJS("getWorld") 23 | @Shadow(remap = false) 24 | public abstract WorldInstructions world(); 25 | 26 | @RemapForJS("getDebug") 27 | @Shadow(remap = false) 28 | public abstract DebugInstructions debug(); 29 | 30 | @RemapForJS("getOverlay") 31 | @Shadow(remap = false) 32 | public abstract OverlayInstructions overlay(); 33 | 34 | @RemapForJS("getEffects") 35 | @Shadow(remap = false) 36 | public abstract EffectInstructions effects(); 37 | 38 | @RemapForJS("getSpecial") 39 | @Shadow(remap = false) 40 | public abstract SpecialInstructions special(); 41 | 42 | @Override 43 | public PonderScene ponderjs$getScene() { 44 | return scene; 45 | } 46 | 47 | @Override 48 | public ParticleInstructions ponderjs$getParticles() { 49 | return ponderjs$particles; 50 | } 51 | 52 | @Override 53 | public SceneBuilder ponderjs$self() { 54 | return (SceneBuilder) (Object) this; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderSceneRegistryMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.PonderJS; 4 | import net.createmod.ponder.api.level.PonderLevel; 5 | import net.createmod.ponder.foundation.registration.PonderSceneRegistry; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.core.BlockPos; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | @Mixin(PonderSceneRegistry.class) 15 | public class PonderSceneRegistryMixin { 16 | 17 | // TODO check if still needed. 18 | @ModifyVariable(method = "compileScene", at = @At("HEAD"), ordinal = 0, argsOnly = true, remap = false) 19 | private static @Nullable PonderLevel ponderjs$createLevelIfNotExist(@Nullable PonderLevel level) { 20 | if (!PonderJS.ON_RELOAD) { 21 | return level; 22 | } 23 | 24 | if (level != null) { 25 | return level; 26 | } 27 | 28 | try { 29 | //noinspection DataFlowIssue 30 | return new PonderLevel(BlockPos.ZERO, Minecraft.getInstance().level); 31 | } catch (Exception e) { 32 | PonderJS.LOGGER.error("Couldn't reload ponderjs", e); 33 | return level; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderSpecialInstructionsMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import dev.latvian.mods.rhino.util.HideFromJS; 4 | import net.createmod.ponder.foundation.PonderSceneBuilder; 5 | import net.minecraft.core.BlockPos; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | 9 | @Mixin(PonderSceneBuilder.PonderSpecialInstructions.class) 10 | public abstract class PonderSpecialInstructionsMixin { 11 | 12 | @Shadow(remap = false) 13 | @HideFromJS 14 | public abstract void movePointOfInterest(BlockPos location); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderTagRegistryAccessor.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.google.common.collect.Multimap; 4 | import net.createmod.ponder.foundation.PonderTag; 5 | import net.createmod.ponder.foundation.registration.PonderLocalization; 6 | import net.createmod.ponder.foundation.registration.PonderTagRegistry; 7 | import net.minecraft.resources.ResourceLocation; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.gen.Accessor; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | @Mixin(PonderTagRegistry.class) 15 | public interface PonderTagRegistryAccessor { 16 | 17 | @Accessor(value = "MISSING", remap = false) 18 | PonderTag getMissing(); 19 | 20 | @Accessor(value = "localization", remap = false) 21 | PonderLocalization getLocalization(); 22 | 23 | @Accessor(value = "componentTagMap", remap = false) 24 | Multimap getComponentTagMap(); 25 | 26 | @Accessor(value = "registeredTags", remap = false) 27 | Map getRegisteredTags(); 28 | 29 | @Accessor(value = "listedTags", remap = false) 30 | List getListedTags(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderWorldAccessor.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import net.createmod.ponder.api.level.PonderLevel; 4 | import net.minecraft.client.particle.Particle; 5 | import net.minecraft.core.particles.ParticleOptions; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(PonderLevel.class) 10 | public interface PonderWorldAccessor { 11 | 12 | @Invoker(value = "makeParticle", remap = false) 13 | Particle ponderjs$makeParticle(T data, double x, double y, double z, double mx, double my, double mz); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/PonderWorldInstructionMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import com.almostreliable.ponderjs.extension.WorldInstructionExtension; 4 | import dev.latvian.mods.rhino.util.HideFromJS; 5 | import net.createmod.ponder.api.scene.Selection; 6 | import net.createmod.ponder.foundation.PonderSceneBuilder; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | 13 | import java.util.function.UnaryOperator; 14 | 15 | @Mixin(PonderSceneBuilder.PonderWorldInstructions.class) 16 | public abstract class PonderWorldInstructionMixin implements WorldInstructionExtension { 17 | 18 | @Shadow(remap = false) @Final PonderSceneBuilder this$0; 19 | 20 | @HideFromJS 21 | @Shadow(remap = false) 22 | public abstract void modifyBlocks(Selection selection, UnaryOperator stateFunc, boolean spawnParticles); 23 | 24 | @HideFromJS 25 | @Shadow(remap = false) 26 | public abstract void modifyBlock(BlockPos pos, UnaryOperator stateFunc, boolean spawnParticles); 27 | 28 | @Override 29 | public PonderSceneBuilder ponderjs$builder() { 30 | return this$0; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/SceneBuildingUtilMixin.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.mixin; 2 | 3 | import dev.latvian.mods.rhino.util.RemapForJS; 4 | import net.createmod.ponder.api.scene.PositionUtil; 5 | import net.createmod.ponder.api.scene.SelectionUtil; 6 | import net.createmod.ponder.api.scene.VectorUtil; 7 | import net.createmod.ponder.foundation.PonderSceneBuildingUtil; 8 | import net.minecraft.world.level.block.Block; 9 | import net.minecraft.world.level.block.state.BlockState; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.Unique; 13 | 14 | @Mixin(PonderSceneBuildingUtil.class) 15 | public abstract class SceneBuildingUtilMixin { 16 | 17 | @Shadow(remap = false) 18 | @RemapForJS("getGrid") 19 | public abstract PositionUtil grid(); 20 | 21 | @Shadow(remap = false) 22 | @RemapForJS("getSelect") 23 | public abstract SelectionUtil select(); 24 | 25 | @Shadow(remap = false) 26 | @RemapForJS("getVector") 27 | public abstract VectorUtil vector(); 28 | 29 | @Unique 30 | @RemapForJS("getDefaultState") 31 | public BlockState ponderjs$getDefaultState(Block block) { 32 | return block.defaultBlockState(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/mixin/package-info.java: -------------------------------------------------------------------------------- 1 | @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault 2 | package com.almostreliable.ponderjs.mixin; 3 | 4 | import net.minecraft.MethodsReturnNonnullByDefault; 5 | 6 | import javax.annotation.ParametersAreNonnullByDefault; 7 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/package-info.java: -------------------------------------------------------------------------------- 1 | @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault 2 | package com.almostreliable.ponderjs; 3 | 4 | import net.minecraft.MethodsReturnNonnullByDefault; 5 | 6 | import javax.annotation.ParametersAreNonnullByDefault; 7 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/particles/ParticleDataBuilder.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.particles; 2 | 3 | import dev.latvian.mods.kubejs.color.KubeColor; 4 | import net.createmod.ponder.Ponder; 5 | import net.minecraft.core.particles.DustColorTransitionOptions; 6 | import net.minecraft.core.particles.DustParticleOptions; 7 | import net.minecraft.core.particles.ParticleOptions; 8 | import net.minecraft.core.particles.ScalableParticleOptionsBase; 9 | import net.minecraft.world.phys.Vec3; 10 | 11 | import javax.annotation.Nullable; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public abstract class ParticleDataBuilder, PO extends ParticleOptions> { 16 | final List transformations = new ArrayList<>(); 17 | int density = 1; 18 | @Nullable Float gravity = null; 19 | @Nullable Boolean physics = null; 20 | @Nullable Boolean collision = null; 21 | @Nullable KubeColor color = null; 22 | @Nullable Float roll = null; 23 | @Nullable Float friction = null; 24 | @Nullable Float scale = null; 25 | @Nullable Integer lifetime = null; 26 | 27 | public O density(int density) { 28 | this.density = density; 29 | return getSelf(); 30 | } 31 | 32 | public O gravity(float gravity) { 33 | this.gravity = gravity; 34 | return getSelf(); 35 | } 36 | 37 | public O physics(boolean physics) { 38 | this.physics = physics; 39 | return getSelf(); 40 | } 41 | 42 | public O collision(boolean collision) { 43 | this.collision = collision; 44 | return getSelf(); 45 | } 46 | 47 | public O color(KubeColor color) { 48 | this.color = color; 49 | return getSelf(); 50 | } 51 | 52 | public O roll(float roll) { 53 | this.roll = roll; 54 | return getSelf(); 55 | } 56 | 57 | public O friction(float friction) { 58 | this.friction = friction; 59 | return getSelf(); 60 | } 61 | 62 | public O scale(float scale) { 63 | this.scale = scale; 64 | return getSelf(); 65 | } 66 | 67 | public O lifetime(int lifetime) { 68 | this.lifetime = lifetime; 69 | return getSelf(); 70 | } 71 | 72 | public O motion(Vec3 motion) { 73 | return transformMotion((partialTicks, m) -> motion); 74 | } 75 | 76 | public O speed(Vec3 speed) { 77 | return transformMotion((partialTick, motion) -> new Vec3( 78 | Ponder.RANDOM.nextGaussian() * speed.x, 79 | Ponder.RANDOM.nextGaussian() * speed.y, 80 | Ponder.RANDOM.nextGaussian() * speed.z 81 | )); 82 | } 83 | 84 | public O withinBlockSpace() { 85 | return transformPosition((partialTicks, position) -> new Vec3( 86 | Math.floor(position.x) + Ponder.RANDOM.nextFloat(), 87 | Math.floor(position.y) + Ponder.RANDOM.nextFloat(), 88 | Math.floor(position.z) + Ponder.RANDOM.nextFloat() 89 | )); 90 | } 91 | 92 | public O area(Vec3 area) { 93 | return transformPosition((partialTicks, position) -> new Vec3( 94 | position.x + (Ponder.RANDOM.nextFloat() * (area.x - position.x)), 95 | position.y + (Ponder.RANDOM.nextFloat() * (area.y - position.y)), 96 | position.z + (Ponder.RANDOM.nextFloat() * (area.z - position.z)) 97 | )); 98 | } 99 | 100 | public O delta(Vec3 delta) { 101 | return transformPosition((partialTicks, position) -> new Vec3( 102 | position.x + (Ponder.RANDOM.nextGaussian() * (delta.x)), 103 | position.y + (Ponder.RANDOM.nextGaussian() * (delta.y)), 104 | position.z + (Ponder.RANDOM.nextGaussian() * (delta.z)) 105 | )); 106 | } 107 | 108 | public O transform(ParticleTransformation transformer) { 109 | transformations.add(transformer); 110 | return getSelf(); 111 | } 112 | 113 | public O transformPosition(ParticleTransformation.Simple transformer) { 114 | return transform(ParticleTransformation.onlyPosition(transformer)); 115 | } 116 | 117 | public O transformMotion(ParticleTransformation.Simple transformer) { 118 | return transform(ParticleTransformation.onlyMotion(transformer)); 119 | } 120 | 121 | abstract PO createOptions(); 122 | 123 | @SuppressWarnings("unchecked") 124 | protected O getSelf() { 125 | return (O) this; 126 | } 127 | 128 | public static class Static extends ParticleDataBuilder { 129 | private final ParticleOptions type; 130 | 131 | public Static(ParticleOptions type) { 132 | this.type = type; 133 | } 134 | 135 | @Override 136 | ParticleOptions createOptions() { 137 | return type; 138 | } 139 | } 140 | 141 | public static class DustParticleDataBuilder 142 | extends ParticleDataBuilder { 143 | final KubeColor fromColor; 144 | @Nullable final KubeColor toColor; 145 | 146 | public DustParticleDataBuilder(KubeColor fromColor, @Nullable KubeColor toColor) { 147 | this.fromColor = fromColor; 148 | this.toColor = toColor; 149 | } 150 | 151 | @Override 152 | public DustParticleDataBuilder color(KubeColor color) { 153 | // color is defined through constructor 154 | return this; 155 | } 156 | 157 | @Override 158 | ScalableParticleOptionsBase createOptions() { 159 | float s = scale == null ? 1.0f : scale; 160 | var fC = new net.createmod.catnip.theme.Color(fromColor.kjs$getRGB()).asVectorF(); 161 | 162 | if (toColor == null) { 163 | return new DustParticleOptions(fC, s); 164 | } 165 | 166 | var toC = new net.createmod.catnip.theme.Color(toColor.kjs$getRGB()).asVectorF(); 167 | return new DustColorTransitionOptions(fC, toC, s); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/particles/ParticleInstructions.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.particles; 2 | 3 | import com.almostreliable.ponderjs.mixin.ParticleAccessor; 4 | import com.almostreliable.ponderjs.mixin.PonderWorldAccessor; 5 | import com.almostreliable.ponderjs.util.PonderErrorHelper; 6 | import dev.latvian.mods.kubejs.color.KubeColor; 7 | import net.createmod.ponder.api.scene.SceneBuilder; 8 | import net.createmod.ponder.foundation.PonderScene; 9 | import net.createmod.ponder.foundation.instruction.TickingInstruction; 10 | import net.minecraft.client.particle.Particle; 11 | import net.minecraft.core.particles.*; 12 | import net.minecraft.core.registries.BuiltInRegistries; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.level.block.state.BlockState; 15 | import net.minecraft.world.phys.Vec3; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class ParticleInstructions { 21 | private final SceneBuilder scene; 22 | 23 | public ParticleInstructions(SceneBuilder scene) { 24 | this.scene = scene; 25 | } 26 | 27 | public ParticleDataBuilder simple(int ticks, ParticleType type, Vec3 pos) { 28 | if (type instanceof SimpleParticleType simple) { 29 | return create(ticks, pos, new ParticleDataBuilder.Static(simple)); 30 | } 31 | 32 | throw new IllegalArgumentException( 33 | "Particle type " + (type == null ? "INVALID" : BuiltInRegistries.PARTICLE_TYPE.getKey(type)) + 34 | " is null or not simple."); 35 | } 36 | 37 | public ParticleDataBuilder.DustParticleDataBuilder dust(int ticks, KubeColor color, Vec3 pos) { 38 | return create(ticks, pos, new ParticleDataBuilder.DustParticleDataBuilder(color, null).color(color)); 39 | } 40 | 41 | public ParticleDataBuilder.DustParticleDataBuilder dust(int ticks, KubeColor fromColor, KubeColor toColor, Vec3 pos) { 42 | return create(ticks, pos, new ParticleDataBuilder.DustParticleDataBuilder(fromColor, toColor).color(fromColor)); 43 | } 44 | 45 | public ParticleDataBuilder.Static item(int ticks, ItemStack item, Vec3 pos) { 46 | ItemParticleOption options = new ItemParticleOption(ParticleTypes.ITEM, item); 47 | return create(ticks, pos, new ParticleDataBuilder.Static(options)); 48 | } 49 | 50 | public ParticleDataBuilder.Static block(int ticks, BlockState blockState, Vec3 pos) { 51 | BlockParticleOption options = new BlockParticleOption(ParticleTypes.BLOCK, blockState); 52 | return create(ticks, pos, new ParticleDataBuilder.Static(options)); 53 | } 54 | 55 | private > O create(int ticks, Vec3 origin, O options) { 56 | scene.addInstruction(new ParticleInstruction(ticks, origin, options)); 57 | return options; 58 | } 59 | 60 | public static class ParticleInstruction extends TickingInstruction { 61 | private final ParticleDataBuilder builder; 62 | private final Vec3 origin; 63 | private final List transformations = new ArrayList<>(); 64 | private ParticleOptions cachedOptions; 65 | 66 | public ParticleInstruction(int ticks, Vec3 origin, ParticleDataBuilder builder) { 67 | super(false, ticks); 68 | this.origin = origin; 69 | this.builder = builder; 70 | } 71 | 72 | @Override 73 | protected void firstTick(PonderScene scene) { 74 | cachedOptions = builder.createOptions(); 75 | transformations.clear(); 76 | transformations.addAll(builder.transformations); 77 | } 78 | 79 | @Override 80 | public void tick(PonderScene scene) { 81 | try { 82 | super.tick(scene); 83 | doTick(scene); 84 | } catch (Exception e) { 85 | PonderErrorHelper.yeet(e); 86 | remainingTicks = 0; 87 | } 88 | } 89 | 90 | private void doTick(PonderScene scene) { 91 | int currentTick = totalTicks - remainingTicks; 92 | for (int i = 0; i < builder.density; i++) { 93 | var data = new ParticleTransformation.Data(origin, Vec3.ZERO); 94 | for (ParticleTransformation transformation : transformations) { 95 | float partialTicks = currentTick + ((float) i / builder.density); 96 | data = transformation.apply(partialTicks, data.position(), data.motion()); 97 | } 98 | 99 | Vec3 pos = data.position(); 100 | Vec3 motion = data.motion(); 101 | Particle particle = ((PonderWorldAccessor) scene.getWorld()).ponderjs$makeParticle(cachedOptions, 102 | pos.x, 103 | pos.y, 104 | pos.z, 105 | motion.x, 106 | motion.y, 107 | motion.z); 108 | 109 | if (particle != null) { 110 | applyParticleData(particle); 111 | scene.getWorld().addParticle(particle); 112 | } 113 | } 114 | } 115 | 116 | private void applyParticleData(Particle particle) { 117 | if (particle instanceof ParticleAccessor accessor) { 118 | if (builder.color != null) { 119 | long argb = builder.color.kjs$getARGB(); 120 | float a = (argb >> 24 & 255) / 255.0F; 121 | float r = (argb >> 16 & 255) / 255.0F; 122 | float g = (argb >> 8 & 255) / 255.0F; 123 | float b = (argb & 255) / 255.0F; 124 | 125 | particle.setColor(r, g, b); 126 | accessor.ponderjs$setAlpha(a); 127 | } 128 | 129 | if (builder.scale != null) { 130 | particle.scale(builder.scale); 131 | } 132 | 133 | if (builder.roll != null) { 134 | accessor.ponderjs$setRoll(builder.roll); 135 | } 136 | 137 | if (builder.friction != null) { 138 | accessor.ponderjs$setFriction(builder.friction); 139 | } 140 | 141 | if (builder.gravity != null) { 142 | accessor.ponderjs$setGravity(builder.gravity); 143 | } 144 | 145 | if (builder.physics != null) { 146 | accessor.ponderjs$setHasPhysics(builder.physics); 147 | } 148 | 149 | if (builder.collision != null) { 150 | accessor.ponderjs$setStoppedByCollision(builder.collision); 151 | } 152 | 153 | if (builder.lifetime != null) { 154 | accessor.ponderjs$setLifetime(builder.lifetime); 155 | } 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/particles/ParticleTransformation.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.particles; 2 | 3 | import com.almostreliable.ponderjs.util.PonderErrorHelper; 4 | import com.almostreliable.ponderjs.util.Util; 5 | import dev.latvian.mods.kubejs.util.UtilsJS; 6 | import dev.latvian.mods.rhino.Context; 7 | import net.minecraft.world.phys.Vec3; 8 | 9 | import javax.annotation.Nullable; 10 | import java.util.List; 11 | 12 | @FunctionalInterface 13 | public interface ParticleTransformation { 14 | static ParticleTransformation onlyPosition(Simple transformation) { 15 | return (partialTick, position, motion) -> new Data(transformation.apply(partialTick, position), motion); 16 | } 17 | 18 | static ParticleTransformation onlyMotion(Simple transformation) { 19 | return (partialTick, position, motion) -> new Data(position, transformation.apply(partialTick, motion)); 20 | } 21 | 22 | Data apply(float partialTick, Vec3 position, Vec3 motion); 23 | 24 | @FunctionalInterface 25 | interface Simple { 26 | Vec3 apply(float partialTick, Vec3 vec); 27 | } 28 | 29 | record Data(Vec3 position, Vec3 motion) { 30 | public static Data of(Context ctx, @Nullable Object o) { 31 | if (o instanceof List list && list.size() >= 2) { 32 | Vec3 pos = (Vec3) ctx.jsToJava(list.get(0), Util.VEC_TYPE); 33 | Vec3 motion = (Vec3) ctx.jsToJava(list.get(1), Util.VEC_TYPE); 34 | return new Data(pos, motion); 35 | } 36 | 37 | IllegalArgumentException e = new IllegalArgumentException( 38 | "Invalid format for particle transformation data. Please use [position, motion] or [[x, y, z], [mx, my, mz]]"); 39 | PonderErrorHelper.yeet(e); 40 | return new Data(Vec3.ZERO, Vec3.ZERO); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/util/BlockStateFunction.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.util; 2 | 3 | import dev.latvian.mods.kubejs.block.predicate.BlockIDPredicate; 4 | import dev.latvian.mods.kubejs.script.ScriptManager; 5 | import dev.latvian.mods.kubejs.script.ScriptType; 6 | import dev.latvian.mods.rhino.BaseFunction; 7 | import dev.latvian.mods.rhino.Context; 8 | import dev.latvian.mods.rhino.NativeJavaObject; 9 | import dev.latvian.mods.rhino.type.TypeInfo; 10 | import net.minecraft.world.level.block.Block; 11 | import net.minecraft.world.level.block.state.BlockState; 12 | 13 | import javax.annotation.Nullable; 14 | import java.util.function.Function; 15 | import java.util.function.UnaryOperator; 16 | 17 | public interface BlockStateFunction extends Function { 18 | 19 | TypeInfo FUNCTION_TYPE = TypeInfo.of(Function.class); 20 | TypeInfo BLOCK_STATE_TYPE = TypeInfo.of(BlockState.class); 21 | 22 | static BlockStateFunction of(Context ctx, @Nullable Object o) { 23 | if (o instanceof BaseFunction function) { 24 | //noinspection rawtypes 25 | Function f = (Function) ctx.createInterfaceAdapter(FUNCTION_TYPE, function); 26 | return blockIDPredicate -> { 27 | //noinspection unchecked 28 | Object result = f.apply(blockIDPredicate); 29 | return BlockStateFunction.of(ctx, result).apply(blockIDPredicate); 30 | }; 31 | } 32 | 33 | BlockState blockState = (BlockState) ctx.jsToJava(o, BLOCK_STATE_TYPE); 34 | return ($) -> blockState; 35 | } 36 | 37 | static UnaryOperator from(BlockStateFunction function) { 38 | return blockState -> { 39 | BlockIDPredicate predicate = Util.createBlockID(blockState); 40 | return function.apply(predicate); 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/util/DyeColorWrapper.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.util; 2 | 3 | import net.minecraft.world.item.DyeColor; 4 | 5 | public class DyeColorWrapper { 6 | public final DyeColor mcColor; 7 | 8 | public DyeColorWrapper(DyeColor color) { 9 | this.mcColor = color; 10 | } 11 | 12 | public static DyeColorWrapper get(String name) { 13 | return new DyeColorWrapper(DyeColor.byName(name, null)); 14 | } 15 | 16 | public static DyeColorWrapper byId(int id) { 17 | return new DyeColorWrapper(DyeColor.byId(id)); 18 | } 19 | 20 | public int getId() { 21 | return mcColor.getId(); 22 | } 23 | 24 | public String getName() { 25 | return mcColor.getName(); 26 | } 27 | 28 | public String getSerializedName() { 29 | return mcColor.getSerializedName(); 30 | } 31 | 32 | public int getColorValue() { 33 | return mcColor.getTextColor(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/util/PonderErrorHelper.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.util; 2 | 3 | import com.almostreliable.ponderjs.PonderJS; 4 | import dev.latvian.mods.kubejs.KubeJS; 5 | import dev.latvian.mods.kubejs.script.ConsoleJS; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.network.chat.Component; 8 | import net.minecraft.network.chat.MutableComponent; 9 | import net.minecraft.world.entity.player.Player; 10 | 11 | public class PonderErrorHelper { 12 | 13 | public static void yeet(Exception e) { 14 | ConsoleJS.CLIENT.error(e); 15 | PonderJS.LOGGER.error(e.getMessage(), e); 16 | Player clientPlayer = KubeJS.PROXY.getClientPlayer(); 17 | if (clientPlayer != null) { 18 | MutableComponent first = Component.literal("[PonderJS ERROR] ").withStyle(ChatFormatting.DARK_RED); 19 | MutableComponent second = Component.literal(e.getMessage()).withStyle(ChatFormatting.RED); 20 | clientPlayer.sendSystemMessage(first.append(second)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/almostreliable/ponderjs/util/Util.java: -------------------------------------------------------------------------------- 1 | package com.almostreliable.ponderjs.util; 2 | 3 | import com.almostreliable.ponderjs.PonderJS; 4 | import dev.latvian.mods.kubejs.block.predicate.BlockIDPredicate; 5 | import dev.latvian.mods.kubejs.script.ConsoleJS; 6 | import dev.latvian.mods.kubejs.util.UtilsJS; 7 | import dev.latvian.mods.rhino.Context; 8 | import dev.latvian.mods.rhino.type.TypeInfo; 9 | import net.createmod.ponder.api.scene.Selection; 10 | import net.createmod.ponder.foundation.PonderTag; 11 | import net.createmod.ponder.foundation.SelectionImpl; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.core.registries.BuiltInRegistries; 14 | import net.minecraft.resources.ResourceLocation; 15 | import net.minecraft.world.level.block.Block; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.block.state.BlockState; 18 | import net.minecraft.world.level.levelgen.structure.BoundingBox; 19 | import net.minecraft.world.phys.Vec3; 20 | 21 | import javax.annotation.Nullable; 22 | import java.util.List; 23 | import java.util.Objects; 24 | 25 | public class Util { 26 | public static final TypeInfo VEC_TYPE = TypeInfo.of(Vec3.class); 27 | 28 | public static Selection selectionOf(Context ctx, @Nullable Object o) { 29 | if (o instanceof Selection s) return s; 30 | if (o instanceof BoundingBox box) { 31 | return SelectionImpl.of(box); 32 | } 33 | 34 | if (o instanceof BlockPos b) { 35 | return SelectionImpl.of(new BoundingBox(b)); 36 | } 37 | 38 | if (o instanceof List l) { 39 | if (l.stream().anyMatch(Objects::isNull)) { 40 | ConsoleJS.CLIENT.warn( 41 | "Selection was provided as list with invalid values. This may happen if a comma is missing. Please check your code."); 42 | } 43 | 44 | if (l.size() == 2) { 45 | // TODO Change to direct typewrapper if kube adds them 46 | Vec3 from = (Vec3) ctx.jsToJava(l.get(0), VEC_TYPE); 47 | Vec3 to = (Vec3) ctx.jsToJava(l.get(1), VEC_TYPE); 48 | return SelectionImpl.of(new BoundingBox((int) from.x, 49 | (int) from.y, 50 | (int) from.z, 51 | (int) to.x, 52 | (int) to.y, 53 | (int) to.z)); 54 | } 55 | 56 | Integer[] values = l.stream().map(entry -> UtilsJS.parseInt(entry, 0)).toArray(Integer[]::new); 57 | if (values.length == 6) { 58 | return SelectionImpl.of(new BoundingBox(values[0], 59 | values[1], 60 | values[2], 61 | values[3], 62 | values[4], 63 | values[5])); 64 | } 65 | if (values.length == 3) { 66 | return SelectionImpl.of(new BoundingBox(values[0], 67 | values[1], 68 | values[2], 69 | values[0], 70 | values[1], 71 | values[2])); 72 | } 73 | } 74 | 75 | Vec3 v = (Vec3) ctx.jsToJava(o, VEC_TYPE); 76 | return SelectionImpl.of(new BoundingBox(new BlockPos((int) v.x, (int) v.y, (int) v.z))); 77 | } 78 | 79 | // public static AllIcons allIconsOf(@Nullable Object o) { 80 | // if (o instanceof AllIcons) return (AllIcons) o; 81 | // if (o == null) { 82 | // return AllIcons.I_ACTIVE; 83 | // } 84 | // return PonderJS.getIconByName(o.toString()); 85 | // } 86 | 87 | public static PonderTag ponderTagOf(@Nullable Object o) { 88 | Objects.requireNonNull(o); 89 | PonderTag ponderTag = PonderJS.getTagByName(o.toString()).orElse(null); 90 | if (ponderTag == null) { 91 | IllegalArgumentException e = new IllegalArgumentException("Invalid PonderTag: " + o); 92 | PonderErrorHelper.yeet(e); 93 | throw e; 94 | } 95 | 96 | return ponderTag; 97 | } 98 | 99 | public static BlockIDPredicate createBlockID(BlockState state) { 100 | BlockIDPredicate predicate = new BlockIDPredicate(BuiltInRegistries.BLOCK.getKey(state.getBlock())); 101 | for (var entry : state.getValues().entrySet()) { 102 | predicate.with(entry.getKey().getName(), entry.getValue().toString()); 103 | } 104 | return predicate; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "[2,)" 3 | issueTrackerURL = "https://github.com/${githubUser}/${githubRepo}/issues" 4 | license = "${license}" 5 | 6 | [[mods]] 7 | modId = "${modId}" 8 | version = "${version}" 9 | displayName = "${modName}" 10 | credits = "${modCredits}" 11 | authors = "${modAuthor}" 12 | description = '''${modDescription}''' 13 | 14 | [[dependencies.ponderjs]] 15 | modId = "neoforge" 16 | mandatory = true 17 | versionRange = "[${neoforgeVersion},)" 18 | ordering = "NONE" 19 | side = "BOTH" 20 | 21 | [[dependencies.ponderjs]] 22 | modId = "minecraft" 23 | mandatory = true 24 | versionRange = "[1.20.1,)" 25 | ordering = "NONE" 26 | side = "BOTH" 27 | 28 | [[dependencies.ponderjs]] 29 | modId = "kubejs" 30 | mandatory = true 31 | versionRange = "[${kubejsVersion},)" 32 | ordering = "AFTER" 33 | side = "BOTH" 34 | 35 | [[mixins]] 36 | config = "ponderjs.mixins.json" 37 | -------------------------------------------------------------------------------- /src/main/resources/assets/ponderjs/ponder/basic.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlmostReliable/ponderjs/5ecb4d103d54c53dd50a516261ea8220ae6255c4/src/main/resources/assets/ponderjs/ponder/basic.nbt -------------------------------------------------------------------------------- /src/main/resources/assets/ponderjs/ponder/block_entity_tutorial.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlmostReliable/ponderjs/5ecb4d103d54c53dd50a516261ea8220ae6255c4/src/main/resources/assets/ponderjs/ponder/block_entity_tutorial.nbt -------------------------------------------------------------------------------- /src/main/resources/assets/ponderjs/ponder/the_cake_is_a_lie.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlmostReliable/ponderjs/5ecb4d103d54c53dd50a516261ea8220ae6255c4/src/main/resources/assets/ponderjs/ponder/the_cake_is_a_lie.nbt -------------------------------------------------------------------------------- /src/main/resources/kubejs.plugins.txt: -------------------------------------------------------------------------------- 1 | com.almostreliable.ponderjs.KubePlugin 2 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "${modId} resources", 4 | "pack_format": 9 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/ponderjs.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.almostreliable.ponderjs.mixin", 4 | "compatibilityLevel": "JAVA_21", 5 | "mixins": [ 6 | "KubeJSClientMixin", 7 | "PonderClientMixin", 8 | "PonderIndexAccessor", 9 | "PonderIndexMixin", 10 | "PonderInstructionMixin", 11 | "PonderLocalizationMixin", 12 | "PonderOverlayInstructionsMixin", 13 | "PonderSceneBuilderMixin", 14 | "PonderSceneRegistryMixin", 15 | "PonderSpecialInstructionsMixin", 16 | "PonderTagRegistryAccessor", 17 | "PonderWorldAccessor", 18 | "PonderWorldInstructionMixin", 19 | "SceneBuildingUtilMixin" 20 | ], 21 | "client": [ 22 | "ParticleAccessor" 23 | ], 24 | "injectors": { 25 | "defaultRequire": 1 26 | }, 27 | "minVersion": "0.8.4" 28 | } 29 | --------------------------------------------------------------------------------