From fa4d298c148343d18d6fc9f546b10320d0d94d93 Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Tue, 28 Jan 2025 15:43:18 +0100 Subject: [PATCH 1/7] Start Environment Check Framework --- .../score_on_non_player_entity.mcfunction | 10 +++++++++ .../assign_score.mcfunction | 12 +++++++++++ base/data/gm4/function/load.mcfunction | 1 + base/data/gm4/function/log.mcfunction | 1 + base/data/gm4/function/post_load.mcfunction | 1 + gm4/plugins/versioning.py | 21 +++++++++++++++++++ gm4_animi_shamir/beet.yaml | 1 + 7 files changed, 47 insertions(+) create mode 100644 base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction create mode 100644 base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction new file mode 100644 index 0000000000..0916f0f0c2 --- /dev/null +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction @@ -0,0 +1,10 @@ +# Tests if non-player entities can hold scores. Default-config Spigot fails this test. +# @s = unspecified +# at unspecified +# run from modules which require this environment check + +# if there is no recent echeck result, re-run echeck +execute unless score $score_on_non_player_entity gm4.environment_check_results matches 0.. summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score + +# return result +return run scoreboard players get $score_on_non_player_entity gm4.environment_check_results diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction new file mode 100644 index 0000000000..776bf30cf3 --- /dev/null +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction @@ -0,0 +1,12 @@ +# Assigns a score to this marker and reads it back. Kills the marker afterwards +# @s = test marker, just summoned +# at @s +# run from gm4:environment_check/score_on_non_player_entity + +# set up marker +scoreboard players set @s gm4.environment_check_results 1 +scoreboard players operation $score_on_non_player_entity gm4.environment_check_results = @s gm4.environment_check_results + +# clean up marker +scoreboard players reset @s gm4.environment_check_results +kill @s diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index 34e6f1b303..9ebbd7f204 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -3,6 +3,7 @@ data modify storage gm4:log queue append value {type:"text",message:'{"text":"[G scoreboard objectives add gm4_modules dummy scoreboard objectives add gm4_data dummy +scoreboard objectives add gm4.environment_check_results dummy function gm4:upgrade_paths/load # Counts the number of consecutive reloads the player has not been seen in creative diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index 37194dc37c..6dd076f6f0 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,6 +4,7 @@ execute if data storage gm4:log log{type:"install"} run tellraw @a[tag=gm4_show_ execute if data storage gm4:log log{type:"missing"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because ","color":"red"},{"nbt":"log.require","storage":"gm4:log","color":"red"},{"text":" is not installed."}] execute if data storage gm4:log log{type:"outdated"} run function gm4:outdated_logs/outdated_start execute if data storage gm4:log log{type:"version_conflict"} run function gm4:conflict_logs/version_conflict_start +execute if data storage gm4:log log{type:"environment_check_failed"} run tellraw @a[tag=gm4_show_log] [{"text":"Cancelled installation of ","color":"red"},{"nbt":"log.module","storage":"gm4:log"},{"text":" as the required environment check '","color":"red"},{"nbt":"log.environment_check","storage":"gm4:log"},{"text":"' failed!","color":"red"}] data remove storage gm4:log queue[0] execute store result score #log_size gm4_data run data get storage gm4:log queue diff --git a/base/data/gm4/function/post_load.mcfunction b/base/data/gm4/function/post_load.mcfunction index 750958366a..f9f681ec88 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -1,3 +1,4 @@ +scoreboard players reset * gm4.environment_check_results execute unless data storage gm4:log queue[{type:"install"}] run data modify storage gm4:log queue append value {type:"text",message:'{"text":"[GM4]: No updates found.","color":"#4AA0C7"}'} execute if data storage gm4:log queue[{type:"install"}] run data modify storage gm4:log queue append value {type:"text",message:'{"text":"[GM4]: Updates completed.","color":"#4AA0C7"}'} diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 38c43904df..9e8f233160 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -11,6 +11,7 @@ class VersionInjectionConfig(PluginOptions): advancements: list[str] = [] class VersioningConfig(PluginOptions, extra=Extra.ignore): + environment_checks: list[str] = [] schedule_loops: list[str] = [] required: dict[str, str] = {} extra_version_injections: VersionInjectionConfig = Field(default=VersionInjectionConfig()) @@ -56,6 +57,26 @@ def modules(ctx: Context, opts: VersioningConfig): lines.append(f"execute if score {dep_id} load.status matches 1.. unless score {dep_id} load.status matches {dep_ver.major} run data modify storage gm4:log queue append value {log_data}") lines.append(f"execute if score {dep_id} load.status matches {dep_ver.major} unless score {dep_id}_minor load.status matches {dep_ver.minor}.. run data modify storage gm4:log queue append value {log_data}") + # add required environment checks + for namespaced_environment_check in opts.environment_checks: + base_namespace = None + match namespaced_environment_check.split(":"): + case [check]: + namespace = ctx.project_id + case ["gm4", check]: + namespace = "gm4" + base_version = Version(base_ver) + base_namespace = f"gm4-{base_version.major}.{base_version.minor}" # NOTE this is a bit sketch. Does only base need this treatment? How do I know which namespaces need to be versioned for function calls? Or for scoreboards? + case [namespace, check]: + pass + case _: + raise ValueError(f"{namespaced_environment_check} is not a valid environment check name") + + lines[0] += f"if function {namespace if not base_namespace else base_namespace}:environment_check/{check} " + lines[1] += f"if function {namespace if not base_namespace else base_namespace}:environment_check/{check} " + log_data = f"{{type:\"environment_check_failed\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",environment_check:\"{namespace}:{check}\"}}" + lines.append(f"execute if score ${check} {namespace}.environment_check_results matches 0 run data modify storage gm4:log queue append value {log_data}") + # finalize startup check module_ver = Version(ctx.project_version) lines[1] = lines[0] + f"run scoreboard players set {ctx.project_id}_minor load.status {module_ver.minor}" diff --git a/gm4_animi_shamir/beet.yaml b/gm4_animi_shamir/beet.yaml index 730882ceb9..94bd4b0fd8 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,6 +20,7 @@ meta: required: gm4_metallurgy: 1.4.0 lib_player_death: 1.2.0 + environment_checks: [gm4:score_on_non_player_entity] schedule_loops: [main] model_data: - reference: shamir/animi From c5d16271f47f35376879c3b59ad6d152e1815bf3 Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Tue, 28 Jan 2025 21:51:14 +0100 Subject: [PATCH 2/7] Place gm4: EnvChecks in Folder & Leave Structure for Custom EnvChecks up to Implementer --- .../score_on_non_player_entity/assign_score.mcfunction | 2 +- .../run.mcfunction} | 0 base/data/gm4/function/log.mcfunction | 2 +- gm4/plugins/versioning.py | 10 +++++----- 4 files changed, 7 insertions(+), 7 deletions(-) rename base/data/gm4/function/environment_check/{score_on_non_player_entity.mcfunction => score_on_non_player_entity/run.mcfunction} (100%) diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction index 776bf30cf3..d41f41804b 100644 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction @@ -1,7 +1,7 @@ # Assigns a score to this marker and reads it back. Kills the marker afterwards # @s = test marker, just summoned # at @s -# run from gm4:environment_check/score_on_non_player_entity +# run from gm4:environment_check/score_on_non_player_entity/run # set up marker scoreboard players set @s gm4.environment_check_results 1 diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction similarity index 100% rename from base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction rename to base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index 6dd076f6f0..01c693fb51 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,7 +4,7 @@ execute if data storage gm4:log log{type:"install"} run tellraw @a[tag=gm4_show_ execute if data storage gm4:log log{type:"missing"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because ","color":"red"},{"nbt":"log.require","storage":"gm4:log","color":"red"},{"text":" is not installed."}] execute if data storage gm4:log log{type:"outdated"} run function gm4:outdated_logs/outdated_start execute if data storage gm4:log log{type:"version_conflict"} run function gm4:conflict_logs/version_conflict_start -execute if data storage gm4:log log{type:"environment_check_failed"} run tellraw @a[tag=gm4_show_log] [{"text":"Cancelled installation of ","color":"red"},{"nbt":"log.module","storage":"gm4:log"},{"text":" as the required environment check '","color":"red"},{"nbt":"log.environment_check","storage":"gm4:log"},{"text":"' failed!","color":"red"}] +execute if data storage gm4:log log{type:"environment_check_failed"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because the required environment check '","color":"red"},{"nbt":"log.environment_check","storage":"gm4:log","color":"red"},{"text":"' failed!","color":"red"}] data remove storage gm4:log queue[0] execute store result score #log_size gm4_data run data get storage gm4:log queue diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 9e8f233160..408be63138 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -59,21 +59,21 @@ def modules(ctx: Context, opts: VersioningConfig): # add required environment checks for namespaced_environment_check in opts.environment_checks: - base_namespace = None match namespaced_environment_check.split(":"): case [check]: namespace = ctx.project_id + line = f"if function {namespace}:{check} " case ["gm4", check]: namespace = "gm4" base_version = Version(base_ver) - base_namespace = f"gm4-{base_version.major}.{base_version.minor}" # NOTE this is a bit sketch. Does only base need this treatment? How do I know which namespaces need to be versioned for function calls? Or for scoreboards? + line = f"if function {namespace}-{base_version.major}.{base_version.minor}:environment_check/{check}/run " # NOTE this is a bit sketch. Does only base need this treatment? How do I know which namespaces need to be versioned for function calls? Or for scoreboards? case [namespace, check]: - pass + line = f"if function {namespace}:{check} " case _: raise ValueError(f"{namespaced_environment_check} is not a valid environment check name") - lines[0] += f"if function {namespace if not base_namespace else base_namespace}:environment_check/{check} " - lines[1] += f"if function {namespace if not base_namespace else base_namespace}:environment_check/{check} " + lines[0] += line + lines[1] += line log_data = f"{{type:\"environment_check_failed\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",environment_check:\"{namespace}:{check}\"}}" lines.append(f"execute if score ${check} {namespace}.environment_check_results matches 0 run data modify storage gm4:log queue append value {log_data}") From 94b38a6dba53054a50de4c3b4e7a1d0cf36168b6 Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Sun, 9 Feb 2025 16:28:25 +0100 Subject: [PATCH 3/7] Use Storage Instead of Score This allows echecks to provide a helpful "probable_cause" message --- .../score_on_non_player_entity.mcfunction | 10 ++++++++++ .../assign_score.mcfunction | 15 ++++++++++----- .../score_on_non_player_entity/run.mcfunction | 10 ---------- base/data/gm4/function/load.mcfunction | 1 - base/data/gm4/function/log.mcfunction | 2 +- base/data/gm4/function/post_load.mcfunction | 4 +++- gm4/plugins/versioning.py | 18 +++++++++--------- 7 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction delete mode 100644 base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction new file mode 100644 index 0000000000..94763d00a0 --- /dev/null +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction @@ -0,0 +1,10 @@ +# Tests if non-player entities can hold scores. Default-config Spigot fails this test. +# @s = unspecified +# at unspecified +# run from modules which require this environment check + +# if there is no recent echeck result, re-run echeck +execute unless data storage gm4:environment_checks result.score_on_non_player_entity summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score + +# return result +return run data get storage gm4:environment_checks result.score_on_non_player_entity.passed diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction index d41f41804b..c6f55c7164 100644 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction @@ -1,12 +1,17 @@ # Assigns a score to this marker and reads it back. Kills the marker afterwards # @s = test marker, just summoned # at @s -# run from gm4:environment_check/score_on_non_player_entity/run +# run from gm4:environment_check/score_on_non_player_entity -# set up marker -scoreboard players set @s gm4.environment_check_results 1 -scoreboard players operation $score_on_non_player_entity gm4.environment_check_results = @s gm4.environment_check_results +# set up marker & run test +scoreboard players set @s gm4_data 1 + +# if the score is present, mark the check as passed +execute if score @s gm4_data matches 1 run data modify storage gm4:environment_checks result set value {score_on_non_player_entity: {passed: 1b}} + +# (optional) if no score is present, provide a probible cause message to the user +execute unless score @s gm4_data matches 1 run data modify storage gm4:environment_checks result set value {score_on_non_player_entity: {"probable_cause": "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=true'."}} # clean up marker -scoreboard players reset @s gm4.environment_check_results +scoreboard players reset @s gm4_data kill @s diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction deleted file mode 100644 index 0916f0f0c2..0000000000 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity/run.mcfunction +++ /dev/null @@ -1,10 +0,0 @@ -# Tests if non-player entities can hold scores. Default-config Spigot fails this test. -# @s = unspecified -# at unspecified -# run from modules which require this environment check - -# if there is no recent echeck result, re-run echeck -execute unless score $score_on_non_player_entity gm4.environment_check_results matches 0.. summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score - -# return result -return run scoreboard players get $score_on_non_player_entity gm4.environment_check_results diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index 9ebbd7f204..34e6f1b303 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -3,7 +3,6 @@ data modify storage gm4:log queue append value {type:"text",message:'{"text":"[G scoreboard objectives add gm4_modules dummy scoreboard objectives add gm4_data dummy -scoreboard objectives add gm4.environment_check_results dummy function gm4:upgrade_paths/load # Counts the number of consecutive reloads the player has not been seen in creative diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index 01c693fb51..3ec3e90268 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,7 +4,7 @@ execute if data storage gm4:log log{type:"install"} run tellraw @a[tag=gm4_show_ execute if data storage gm4:log log{type:"missing"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because ","color":"red"},{"nbt":"log.require","storage":"gm4:log","color":"red"},{"text":" is not installed."}] execute if data storage gm4:log log{type:"outdated"} run function gm4:outdated_logs/outdated_start execute if data storage gm4:log log{type:"version_conflict"} run function gm4:conflict_logs/version_conflict_start -execute if data storage gm4:log log{type:"environment_check_failed"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because the required environment check '","color":"red"},{"nbt":"log.environment_check","storage":"gm4:log","color":"red"},{"text":"' failed!","color":"red"}] +execute if data storage gm4:log log{type:"environment_check_failed"} run tellraw @a[tag=gm4_show_log] [{"nbt":"log.module","storage":"gm4:log","color":"red"},{"text":" is disabled because the required environment check '","color":"red"},{"nbt":"log.environment_check","storage":"gm4:log","color":"red"},{"text":"' failed! ","color":"red"}, {"nbt":"log.probable_cause","storage":"gm4:log","color":"red", "interpret": true}] data remove storage gm4:log queue[0] execute store result score #log_size gm4_data run data get storage gm4:log queue diff --git a/base/data/gm4/function/post_load.mcfunction b/base/data/gm4/function/post_load.mcfunction index f9f681ec88..2a96d25527 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -1,5 +1,7 @@ -scoreboard players reset * gm4.environment_check_results execute unless data storage gm4:log queue[{type:"install"}] run data modify storage gm4:log queue append value {type:"text",message:'{"text":"[GM4]: No updates found.","color":"#4AA0C7"}'} execute if data storage gm4:log queue[{type:"install"}] run data modify storage gm4:log queue append value {type:"text",message:'{"text":"[GM4]: Updates completed.","color":"#4AA0C7"}'} function gm4:log_wait + +# discard environment check test results (done post-load so players can overwrite echecks pre-load) +data remove storage gm4:environment_checks result diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 408be63138..96d43eed56 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -60,22 +60,22 @@ def modules(ctx: Context, opts: VersioningConfig): # add required environment checks for namespaced_environment_check in opts.environment_checks: match namespaced_environment_check.split(":"): - case [check]: + case [check]: # if no namespace is given, assume current project's namespace namespace = ctx.project_id - line = f"if function {namespace}:{check} " - case ["gm4", check]: - namespace = "gm4" - base_version = Version(base_ver) - line = f"if function {namespace}-{base_version.major}.{base_version.minor}:environment_check/{check}/run " # NOTE this is a bit sketch. Does only base need this treatment? How do I know which namespaces need to be versioned for function calls? Or for scoreboards? case [namespace, check]: - line = f"if function {namespace}:{check} " + pass case _: raise ValueError(f"{namespaced_environment_check} is not a valid environment check name") + if namespace == "gm4" or namespace.startswith("lib_"): # base and libraries need versioned namespaces + parsed_version = Version(dependencies[namespace]) + line = f"if function {namespace}-{parsed_version.major}.{parsed_version.minor}:environment_check/{check} " + else: + line = f"if function {namespace}:environment_check/{check} " lines[0] += line lines[1] += line - log_data = f"{{type:\"environment_check_failed\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",environment_check:\"{namespace}:{check}\"}}" - lines.append(f"execute if score ${check} {namespace}.environment_check_results matches 0 run data modify storage gm4:log queue append value {log_data}") + log_data = f"{{type:\"environment_check_failed\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",environment_check:\"{namespace}:{check}\",probable_cause:{{\"nbt\":\"result.{check}.probable_cause\",\"storage\":\"{namespace}:environment_checks\"}}}}" + lines.append(f"execute unless data storage {namespace}:environment_checks result.{check}.passed run data modify storage gm4:log queue append value {log_data}") # finalize startup check module_ver = Version(ctx.project_version) From da96da3ef93bd29f127460afd3c79a9412cebdaf Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Sun, 9 Feb 2025 16:37:38 +0100 Subject: [PATCH 4/7] Move Test Check --- gm4_animi_shamir/beet.yaml | 1 - gm4_double_doors/beet.yaml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gm4_animi_shamir/beet.yaml b/gm4_animi_shamir/beet.yaml index 94bd4b0fd8..730882ceb9 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,7 +20,6 @@ meta: required: gm4_metallurgy: 1.4.0 lib_player_death: 1.2.0 - environment_checks: [gm4:score_on_non_player_entity] schedule_loops: [main] model_data: - reference: shamir/animi diff --git a/gm4_double_doors/beet.yaml b/gm4_double_doors/beet.yaml index 85afc6e5d0..b5a3536690 100644 --- a/gm4_double_doors/beet.yaml +++ b/gm4_double_doors/beet.yaml @@ -16,6 +16,7 @@ meta: gm4: versioning: schedule_loops: [] + environment_checks: [gm4:score_on_non_player_entity] website: description: Tired of clicking twice to open a double door? Annoyed by the fact that doors are only two blocks tall? This data pack automatically opens adjacent doors, making double doors fully functional! Additionally, bottom trapdoors of matching wood type placed above a door are opened alongside the door when it is opened by a player. recommended: [] From 7cb54068dde00fda131fe170ddc3cd690791175e Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:11:51 +0200 Subject: [PATCH 5/7] Fix Typos --- .../score_on_non_player_entity/assign_score.mcfunction | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction index c6f55c7164..3eba964f04 100644 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction @@ -9,8 +9,8 @@ scoreboard players set @s gm4_data 1 # if the score is present, mark the check as passed execute if score @s gm4_data matches 1 run data modify storage gm4:environment_checks result set value {score_on_non_player_entity: {passed: 1b}} -# (optional) if no score is present, provide a probible cause message to the user -execute unless score @s gm4_data matches 1 run data modify storage gm4:environment_checks result set value {score_on_non_player_entity: {"probable_cause": "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=true'."}} +# (optional) if no score is present, provide a probable cause message to the user +execute unless score @s gm4_data matches 1 run data modify storage gm4:environment_checks result set value {score_on_non_player_entity: {probable_cause: "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."}} # clean up marker scoreboard players reset @s gm4_data From 747eeaa67f855a305c9526d2f435e3df76f73462 Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:12:08 +0200 Subject: [PATCH 6/7] Add More Documentation --- docs/making-a-module.md | 3 + docs/utilities.md | 139 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 docs/utilities.md diff --git a/docs/making-a-module.md b/docs/making-a-module.md index 124cfcee2f..aee45c6239 100644 --- a/docs/making-a-module.md +++ b/docs/making-a-module.md @@ -68,6 +68,9 @@ meta: - main # namespace assumed to be the module id - gm4_bat_grenades:tick # but one can be manually specified + # A list of checks to run when installing the module. May be omitted if not needed + environment_checks: [gm4:score_on_non_player_entity] + website: # A description. This should be a good summary of what this module adds or achieves, to get someone interested in this module description: Break apart gold and iron tools and weapons for materials. Attach this to a mobfarm to finally make use of those extra armour sets! diff --git a/docs/utilities.md b/docs/utilities.md new file mode 100644 index 0000000000..6cd9710ef3 --- /dev/null +++ b/docs/utilities.md @@ -0,0 +1,139 @@ +# Utilities +Chances are, the tough problem you are trying to tackle has been solved by someone else working on Gamemode 4 long before you did. +This document will give you an overview of utilities and tools that have been developed over the years and which may help you when making a module. + +## Table of contents +* [Common Tags](#common-tags) + * [Blocks Tags](#block-tags) + * [Entity Tags](#entity-tags) +* [Environment Checks]() + * [Base Checks]() + * [Other Notable Checks]() + * [Creating New Checks]() +* [Upgrade Paths]() + +## Common Tags +Selecting blocks or entities with common properties is an error prone task, and subsequent updates often miss module-specific, hardcoded tags. +As such, `base` provides various tags that are maintained through updates and which should be prioritized over module-specific solutions. + +### Block Tags +Gamemode 4's default block tags are located at `base/data/gm4/tags/block/`. + +| Tag Name | Source | Description | +|---------------------|---------------------|------------------------------------------------------------------------------------------------------| +| #gm4:air | air.json | All air types. | +| #gm4:foliage | foliage.json | Naturally generating decoration on surfaces, which are easily broken, i.e. are washed away by water. | +| #gm4:full_collision | full_collision.json | All blocks that have a full-block collision box. | +| #gm4:no_collision | no_collision.json | All blocks without any collision, including air. | +| #gm4:replaceable | replaceable.json | Blocks that can be replaced by placing another block inside it, including air. | +| #gm4:water | water.json | Blocks that act as a water source. | +| #gm4:waterloggable | waterloggable.json | Blocks which can be water-logged. | + +### Entity Tags +Gamemode 4's default entity tags are located at `base/data/gm4/tags/block/`. + +| Tag Name | Source | Description | +|----------------------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------| +| #gm4:boats | boats.json | All boat variations, including rafts. | +| #gm4:boss | boss.json | Bosses, namely the Ender Dragon and the Wither. | +| #gm4:chest_boats | chest_boats.json | All boat variations with a chest. | +| #gm4:hostile | hostile.json | Living entities that are hostile towards player by default. | +| #gm4:minecarts | minecarts.json | All minecart variations. | +| #gm4:neutral_hostile | neutral_hostile.json | Hostile living entities that may be, given the right conditions, neutral towards the player by default but turn hostile if provoked. | +| #gm4:neutral_passive | neutral_passive.json | Entities that are normally neutral, but turn hostile if provoked. | +| #gm4:neutral | neutral.json | Entities that may be neutral given the right conditions. | +| #gm4:non-living | non-living.json | Entities that are not considered living. | +| #gm4:passive | passive.json | Entities that are normally friendly and do not turn hostile, even if provoked. | + +## Environment Checks +The environment a data pack is installed into can affect its performance. +Servers may have command blocks disabled, or mods may change the way the game reacts to changes made by commands. +Not all users are aware of this, which can lead to rather frustrating debugging experiences. +To counteract this, modules can include environment checks which warn the user and block installation of the data pack if certain conditions are not met. + +Environment checks are included by specifying them by name (including namespace) inside a module's `beet.yaml`, e.g. +```yaml +id: gm4_double_doors +name: Double Doors +version: 1.2.X + +data_pack: + load: . + +require: + - bolt + +pipeline: + - gm4_double_doors.generate + - gm4.plugins.extend.module + +meta: + gm4: + versioning: + schedule_loops: [] + + # List of environment checks to include + environment_checks: [gm4:score_on_non_player_entity] + website: + description: Tired of clicking twice to open a double door? Annoyed by the fact that doors are only two blocks tall? This data pack automatically opens adjacent doors, making double doors fully functional! Additionally, bottom trapdoors of matching wood type placed above a door are opened alongside the door when it is opened by a player. + recommended: [] + notes: [] + modrinth: + project_id: Vx4zJ1Np + smithed: + pack_id: gm4_double_doors + video: null + wiki: https://wiki.gm4.co/wiki/Double_Doors + credits: + Creator: + - Bloo + Icon Design: + - venomousbirds +``` + +Multiple checks may be included and are executed in-order: +```yaml +environment_checks: [gm4:score_on_non_player_entity, gm4_double_doors:bloo_is_not_online, lib_forceload:command_blocks_enabled] +``` + +As shown above, environment checks are namespaced. If the namespace is omitted, the namespace of the parent module is used. + +Environment checks are run on every reload, with each check only running once per reload even if multiple modules require it. +For testing purposes, environment checks may be bypassed by setting a positive test result before reloading data packs. +To do this run +```mcfunction +/data modify storage {namespace}:environment_checks result.{check name}.passed set value 1b +``` +and run `/reload`. +This has to be repeated before each reload. + +### Base Environment Checks +`base` comes with some fundamental environment checks that can be referenced by the `gm4:` namespace. + +| Check Name | Description | +|--------------------------------|--------------------------------------------------------------------------------------------------------------------------| +| gm4:score_on_non_player_entity | Checks if non-player entities can be added to a scoreboard. Fails if a test marker's score can not be set and read back. | + +### Other Notable Environment Checks +Some libraries also implement checks, which are inherited by all modules requiring said libraries, as a failed library install will prevent the dependent module from installing. +Hence, you probably don't need to add these checks to your module if you already depend on the library. + +| Library | Check Name | Description | +|---------------|----------------------------|---------------------------------------------------------------------------------------------------------------------| +| lib_forceload | gm4:command_blocks_enabled | Checks if command blocks are enabled. Fails if the command block in the forceloaded chunk can not execute commands. | + +### Creating New Environment Checks +Modules may also introduce their own environment checks. +Any functions contained directly within the `function/environment_check/` folder of a module are treated as environment checks and may be mentioned within 'beet.yaml`. +Functions in subfolders within `function/environment_check/` are ignored and can therefore be used as helper functions. + +To indicate a successful environment check include +```mcfunction +data modify storage :environment_checks result set value {: {passed: 1b}} +``` +within your check, replacing `` and `` with the module's namespace and the new check's name (identical to the file name without the `.mcfunction` suffix) respectively. +Optionally, a failed environment check can display a message to the user by including +```mcfunction +data modify storage :environment_checks result set value {: {probable_cause: "This may be caused by the programmer not expecting you to run this on a potato."}} +``` +within your check, once again replacing the `` and `` with the module's and the new check's name respectively, as well as adding a more adequate message. From 908771240fa91e401b16aad114aba3612210dc52 Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:19:38 +0200 Subject: [PATCH 7/7] Even More Documentation --- docs/utilities.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/utilities.md b/docs/utilities.md index 6cd9710ef3..cc0e42f319 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -137,3 +137,13 @@ Optionally, a failed environment check can display a message to the user by incl data modify storage :environment_checks result set value {: {probable_cause: "This may be caused by the programmer not expecting you to run this on a potato."}} ``` within your check, once again replacing the `` and `` with the module's and the new check's name respectively, as well as adding a more adequate message. + +Multiple modules may require the same environment check during a single reload. +To cut down on lag, you should ensure your environment check tries to use a previous test result -- from the same `/reload` period -- before deciding to re-run the test. +This can be done using +```mcfunction +execute unless data storage :environment_checks result. +``` +You **must also clear all check results** in post-load. + +For a textbook example of an environment check, inspect `gm4:score_on_non_player_entity` in `base`.