From 42e3278719dac104f19c12a5386968fbb426cae8 Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Tue, 28 Jan 2025 15:43:18 +0100 Subject: [PATCH 01/17] 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 215ba36011..17ddac1eea 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":"[GM 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 1012328392..6dacaff992 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 89dd053fe2..77e3c3a012 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="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 5265aa0b02..e5762fc9d7 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,6 +20,7 @@ meta: required: gm4_metallurgy: 1.5.0 lib_player_death: 1.3.0 + environment_checks: [gm4:score_on_non_player_entity] schedule_loops: [main] model_data: - reference: shamir/animi From 789f736c433d96ae7e732776f5a7ffccc79f56c5 Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Tue, 28 Jan 2025 21:51:14 +0100 Subject: [PATCH 02/17] 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 77e3c3a012..fdcf19f91b 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 aa913a2f49c749f2a821ba787f36dea89402f58d Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Sun, 9 Feb 2025 16:28:25 +0100 Subject: [PATCH 03/17] 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 | 3 +++ gm4/plugins/versioning.py | 18 +++++++++--------- 7 files changed, 33 insertions(+), 26 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 17ddac1eea..215ba36011 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":"[GM 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 6dacaff992..7226b89a63 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -3,3 +3,6 @@ execute unless data storage gm4:log queue[{type:"install"}] run data modify stor 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 fdcf19f91b..20d4f6f81b 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 2c9fdcab4c5e2cfdb79da5bd83f0b0254610b64d Mon Sep 17 00:00:00 2001 From: Bloo-dev Date: Sun, 9 Feb 2025 16:37:38 +0100 Subject: [PATCH 04/17] Move Test Check --- gm4_double_doors/beet.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/gm4_double_doors/beet.yaml b/gm4_double_doors/beet.yaml index d0162212a2..7e2a4ec0e8 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 150fc11b6236bf04ee7d26a5498e2a90253d182e Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:11:51 +0200 Subject: [PATCH 05/17] 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 aead8079b2d43a5c000f1e9d8b35edc3f72cc1e2 Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:12:08 +0200 Subject: [PATCH 06/17] 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 44dfad1c68..5313ac73d7 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 fbe6524412b6d1eae7bb794dca4ce490f9e5480d Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 10 May 2025 23:19:38 +0200 Subject: [PATCH 07/17] 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`. From 4c6f346cb9792abf5264c449619412b8d982bedd Mon Sep 17 00:00:00 2001 From: Bloo Date: Sun, 22 Feb 2026 19:51:03 +0100 Subject: [PATCH 08/17] Non-Blocking Environment Checks --- base/beet.yaml | 2 + ...await_environment_check_results.mcfunction | 6 + .../score_on_non_player_entity.mcfunction | 5 +- .../assign_score.mcfunction | 6 +- base/data/gm4/function/load.mcfunction | 1 + base/data/gm4/function/post_load.mcfunction | 4 +- .../function/evaluate_environment_checks.json | 5 + gm4/plugins/versioning.py | 146 ++++++++++++------ gm4/skin_cache.json | 10 -- 9 files changed, 123 insertions(+), 62 deletions(-) create mode 100644 base/data/gm4/function/await_environment_check_results.mcfunction create mode 100644 base/data/gm4/tags/function/evaluate_environment_checks.json diff --git a/base/beet.yaml b/base/beet.yaml index d6f042a321..2880a197ca 100644 --- a/base/beet.yaml +++ b/base/beet.yaml @@ -24,6 +24,8 @@ meta: extra_version_injections: advancements: - 'gm4:intro_song/play_song' + functions: + - 'gm4:environment_check/score_on_non_player_entity' model_data: - item: command_block reference: gm4:gui/advancement/root diff --git a/base/data/gm4/function/await_environment_check_results.mcfunction b/base/data/gm4/function/await_environment_check_results.mcfunction new file mode 100644 index 0000000000..b2c3bb9235 --- /dev/null +++ b/base/data/gm4/function/await_environment_check_results.mcfunction @@ -0,0 +1,6 @@ +# Waits until all environment checks have returned their results +# run from post_load + + +# TODO wait for all checks to complete (check for the result object in each check) +# TODO print out probable_cause from each echeck (in result.probable cause) 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 index 94763d00a0..61859562b5 100644 --- 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 @@ -4,7 +4,4 @@ # 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 +execute unless data storage gm4:log environment_checks."gm4:score_on_non_player_entity".result summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score 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 3eba964f04..1f20c4a983 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 @@ -6,11 +6,13 @@ # set up marker & run test scoreboard players set @s gm4_data 1 +# depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. + # 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}} +execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks."gm4:score_on_non_player_entity".result set value {passed: 1b, probable_cause: ""} # (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'."}} +execute unless score @s gm4_data matches 1 run data modify storage gm4:log environment_checks."gm4:score_on_non_player_entity".result set value {passed: 0b, 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 diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index 215ba36011..4c04975a17 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -1,4 +1,5 @@ data merge storage gm4:log {queue:[],versions:[]} +data modify storage gm4:log environment_checks set value {} data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: Checking for updates...","color":"#4AA0C7"}} scoreboard objectives add gm4_modules dummy diff --git a/base/data/gm4/function/post_load.mcfunction b/base/data/gm4/function/post_load.mcfunction index 7226b89a63..97ed658f77 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -4,5 +4,5 @@ execute if data storage gm4:log queue[{type:"install"}] run data modify storage 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 +function #gm4:evaluate_environment_checks +schedule function gm4:await_environment_check_results 1t diff --git a/base/data/gm4/tags/function/evaluate_environment_checks.json b/base/data/gm4/tags/function/evaluate_environment_checks.json new file mode 100644 index 0000000000..5d872448bb --- /dev/null +++ b/base/data/gm4/tags/function/evaluate_environment_checks.json @@ -0,0 +1,5 @@ +{ + "values": [ + "gm4:environment_check/score_on_non_player_entity" + ] +} diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 20d4f6f81b..527bd58602 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -1,3 +1,5 @@ +from typing import List + from beet import Context, Function, FunctionTag, PluginOptions, configurable from beet.contrib.rename_files import rename_files from beet.contrib.find_replace import find_replace @@ -21,11 +23,14 @@ def modules(ctx: Context, opts: VersioningConfig): """Assembles version-functions for modules from dependency information: - load:{module_name}.json - {module_name}:load.mcfunction - - load:load.json""" + - {module_name}:environment_checks.mcfunction + - load:load.json + """ ctx.cache["currently_building"].json = {"name": ctx.project_name, "id": ctx.project_id, "added_libs": []} # cache module's project id for access within library pipelines dependencies = opts.required manifest = gm4.plugins.manifest.ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json) - lines = ["execute ", ""] + dependency_check_command = "execute " + log_message_commands: List[str] = [] # {{module_name}}.json tag load_tag = dependency_load_tags(ctx, dependencies) @@ -48,53 +53,62 @@ def modules(ctx: Context, opts: VersioningConfig): dep_id = manifest.libraries.get(dep_id, NoneAttribute()).id # append to startup check - lines[0] += f"if score {dep_id} load.status matches {dep_ver.major} if score {dep_id}_minor load.status matches {dep_ver.minor}.. " + dependency_check_command += f"if score {dep_id} load.status matches {dep_ver.major} if score {dep_id}_minor load.status matches {dep_ver.minor}.. " # failure logs - lines.append(f"execute unless score {dep_id} load.status matches 1.. run data modify storage gm4:log queue append value {{type:\"missing\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",require:\"{dep_name}\",require_id:\"{dep_id}\"}}") + log_message_commands.append(f"execute unless score {dep_id} load.status matches 1.. run data modify storage gm4:log queue append value {{type:\"missing\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",require:\"{dep_name}\",require_id:\"{dep_id}\"}}") log_data = f"{{type:\"version_conflict\",module:\"{ctx.project_name}\",id:\"{ctx.project_id}\",require:\"{dep_name}\",require_id:\"{dep_id}\",require_ver:\"{dep_ver}\"}}" - 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}") + log_message_commands.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}") + log_message_commands.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 + # add environment check requests + environment_check_requests: List[str] = [] for namespaced_environment_check in opts.environment_checks: match namespaced_environment_check.split(":"): - case [check]: # if no namespace is given, assume current project's namespace + case [ + check + ]: # if no namespace is given, assume current project's namespace namespace = ctx.project_id case [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} " + raise ValueError(f"{namespaced_environment_check} is not a valid environment check name!") + environment_check_requests.append(f"data modify storage gm4:log environment_checks.\"{namespace}:{check}\".required_by append value \"{ctx.project_id}\"") - 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}\",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}") + if 0 < len(environment_check_requests): # append an empty line to envcheck command list if there is at least one envcheck + environment_check_requests.append("") - # finalize startup check + # parse module version module_ver = Version(ctx.project_version) - lines[1] = lines[0] + f"run scoreboard players set {ctx.project_id}_minor load.status {module_ver.minor}" - lines[0] += f"run scoreboard players set {ctx.project_id} load.status {module_ver.major}" # otherwise, log failed startup with -1 load.status - lines.append(f"execute unless score {ctx.project_id} load.status matches 1.. run scoreboard players set {ctx.project_id} load.status -1") + log_message_commands.append(f"execute unless score {ctx.project_id} load.status matches 1.. run scoreboard players set {ctx.project_id} load.status -1") - lines.append('') + log_message_commands.append('') # start module clocks - lines.append(f"execute if score {ctx.project_id} load.status matches {module_ver.major} run function {ctx.project_id}:init") + log_message_commands.append(f"execute if score {ctx.project_id} load.status matches {module_ver.major} run function {ctx.project_id}:init") # unschedule clocks for function in opts.schedule_loops: namespaced_function = f"{ctx.project_id}:{function}" if ":" not in function else function - lines.append(f"execute unless score {ctx.project_id} load.status matches {module_ver.major} run schedule clear {namespaced_function}") + log_message_commands.append(f"execute unless score {ctx.project_id} load.status matches {module_ver.major} run schedule clear {namespaced_function}") + + # populate function + ctx.data.functions[f"{ctx.project_id}:load"] = Function( + [ + dependency_check_command + + f"run scoreboard players set {ctx.project_id} load.status {module_ver.major}", + dependency_check_command + + f"run scoreboard players set {ctx.project_id}_minor load.status {module_ver.minor}", + "", + *environment_check_requests, + *log_message_commands, + ] + ) - ctx.data.functions[f"{ctx.project_id}:load"] = Function(lines) + # environment_checks.mcfunction if this data pack defines environment checks + index_environment_checks(ctx, module_ver) # load.json tag ctx.data.function_tags["load:load"] = FunctionTag({ @@ -104,18 +118,20 @@ def modules(ctx: Context, opts: VersioningConfig): }) # inject module load success checks (load.status 1..) into technical and display advancements - # advancements get score checks injected into every criteria + # advancements get score checks injected into every criteria versioned_advancements(ctx, Version("X.X.X"), [a for a in ctx.data.advancements.keys() if not a=="gm4:root"], False) @configurable("gm4.versioning", validator=VersioningConfig) def libraries(ctx: Context, opts: VersioningConfig): """Assembles version-functions for libraries from dependency information: - - {lib_name}:enumerate.mcfunction - - {lib_name}:resolve_load.mcfunction - - load:{lib_name}.json - - load:{lib_name}/enumerate.json - - load:{lib_name}/resolve_load.json - - load:{lib_name}/dependencies.json""" + - {lib_name}:enumerate.mcfunction + - {lib_name}:resolve_load.mcfunction + - {lib_name}:environment_checks.mcfunction + - load:{lib_name}.json + - load:{lib_name}/enumerate.json + - load:{lib_name}/resolve_load.json + - load:{lib_name}/dependencies.json + """ dependencies = opts.required manifest = gm4.plugins.manifest.ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json) lib_ver = Version(ctx.project_version) @@ -152,6 +168,9 @@ def libraries(ctx: Context, opts: VersioningConfig): ctx.data.functions[f"{ctx.project_id}:resolve_load"] = Function(lines) + # environment_checks.mcfunction if this data pack defines environment checks + index_environment_checks(ctx, lib_ver) + # load/tags {{ lib name }}.json ctx.data.function_tags[f"load:{ctx.project_id}"] = FunctionTag({ "values": [ @@ -186,16 +205,9 @@ def libraries(ctx: Context, opts: VersioningConfig): # additional version injections # NOTE functions get version checks replaced onto `load.status` checks - ctx.require(find_replace(data_pack={"match": { - "functions": [f if ':' in f else f"{ctx.project_id}:{f}" for f in opts.extra_version_injections.functions]} - }, - substitute={ - "find": f"{ctx.project_id} load\\.status matches \\d(?: if score {ctx.project_id}_minor load\\.status matches \\d)?", - "replace": f"{ctx.project_id} load.status matches {lib_ver.major} if score {ctx.project_id}_minor load.status matches {lib_ver.minor}" - } - )) + versioned_functions(ctx, lib_ver, opts.extra_version_injections.functions) - # stamp version number and module bring packaged into into load.mcfunction + # stamp version number and module bring packaged into into load.mcfunction handle = ctx.data.functions[f"{ctx.project_id}:load"] handle.append([ "\n", @@ -230,10 +242,16 @@ def base(ctx: Context, opts: VersioningConfig): lines = f"execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} run function gm4:post_load" ctx.data.functions[f"gm4:resolve_post_load"] = Function(lines) + # index env checks + index_environment_checks(ctx, ver) + versioned_advancements(ctx, ver, opts.extra_version_injections.advancements, strict=True) #type:ignore + versioned_functions(ctx, ver, opts.extra_version_injections.functions) + versioned_namespace(ctx, ver) + def versioned_namespace(ctx: Context, version: Version): """Puts the project version into the namespace, and renames all references to match Used for libraries that may have multiple versions exist in a world at once without @@ -246,7 +264,7 @@ def versioned_namespace(ctx: Context, version: Version): "replace": f"{versioned_namespace}:\\1" })) ctx.require(find_replace(data_pack={"match": "*"}, substitute={ - "find": f"(? index_environment_checks. Injects active-version checks into environment check entry points.",] + for entry_point in ctx.data.function_tags['gm4:evaluate_environment_checks'].data["values"]: + lines.append(f"execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} unless data storage gm4:log environment_checks.\"{entry_point}\" run function {entry_point}") + print(entry_point) + ctx.data.functions[f"{ctx.project_id}:environment_checks"] = Function(lines) + + # point function tag to environment_checks.mcfunction + ctx.data.function_tags["gm4:evaluate_environment_checks"] = FunctionTag( + {"values": [f"{ctx.project_id}:environment_checks"]} + ) + + def warn_on_future_version(ctx: Context, dep_id: str, ver: Version): - """Issues a console warning if the dependancy version a module requires is greater than the current version of that dependancy""" + """Issues a console warning if the dependency version a module requires is greater than the current version of that dependency""" if dep_id == "gm4": return # the base version is not in the manifest, tis a special case if "lib" in dep_id: diff --git a/gm4/skin_cache.json b/gm4/skin_cache.json index e0ff0678cf..c2d7fcb211 100644 --- a/gm4/skin_cache.json +++ b/gm4/skin_cache.json @@ -1093,7 +1093,6 @@ "gm4_potion_liquids:liquids/harming", "gm4_potion_liquids:liquids/healing", "gm4_potion_liquids:liquids/leaping", - "gm4_potion_liquids:liquids/harming", "gm4_potion_liquids:liquids/poison", "gm4_potion_liquids:liquids/regeneration", "gm4_potion_liquids:liquids/strength", @@ -1104,15 +1103,6 @@ ], "gm4_auto_crafting": [ "gm4_custom_crafters:custom_crafter" - ], - "gm4_zauber_liquids": [ - "gm4_potion_liquids:liquids/harming", - "gm4_potion_liquids:liquids/healing", - "gm4_potion_liquids:liquids/leaping", - "gm4_potion_liquids:liquids/poison", - "gm4_potion_liquids:liquids/regeneration", - "gm4_potion_liquids:liquids/strength", - "gm4_potion_liquids:liquids/swiftness" ] } } From 52a3dd5d63a833a1a55acad1f2c7870d699ca740 Mon Sep 17 00:00:00 2001 From: Bloo Date: Sun, 22 Feb 2026 23:19:39 +0100 Subject: [PATCH 09/17] Switch to List-of-Objects for Environment Check Storage This makes it easier to keep track of pending checks --- ...await_environment_check_results.mcfunction | 4 ++- .../score_on_non_player_entity.mcfunction | 5 ++-- .../assign_score.mcfunction | 4 +-- base/data/gm4/function/load.mcfunction | 2 +- base/data/gm4/function/post_load.mcfunction | 1 + gm4/plugins/versioning.py | 29 +++++++++++++++---- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/base/data/gm4/function/await_environment_check_results.mcfunction b/base/data/gm4/function/await_environment_check_results.mcfunction index b2c3bb9235..717c8347ef 100644 --- a/base/data/gm4/function/await_environment_check_results.mcfunction +++ b/base/data/gm4/function/await_environment_check_results.mcfunction @@ -1,6 +1,8 @@ # Waits until all environment checks have returned their results # run from post_load +# Peek if any environment checks are still pending (passed:-1), if so, continue waiting +execute if data storage gm4:log environment_checks[{result:{passed:-1}}] run return run schedule function gm4:await_environment_check_results 1t -# TODO wait for all checks to complete (check for the result object in each check) # TODO print out probable_cause from each echeck (in result.probable cause) +say all checks complete! 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 index 61859562b5..2f1ed00c4c 100644 --- 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 @@ -3,5 +3,6 @@ # 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:log environment_checks."gm4:score_on_non_player_entity".result summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score +say non player score +# start environment check as marker +execute summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score 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 1f20c4a983..70dedafcbf 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,10 +9,10 @@ scoreboard players set @s gm4_data 1 # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. # if the score is present, mark the check as passed -execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks."gm4:score_on_non_player_entity".result set value {passed: 1b, probable_cause: ""} +execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 1b, probable_cause: ""} # (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:log environment_checks."gm4:score_on_non_player_entity".result set value {passed: 0b, probable_cause: "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +execute unless score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 0b, 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 diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index 4c04975a17..b9ba05fcce 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -1,5 +1,5 @@ data merge storage gm4:log {queue:[],versions:[]} -data modify storage gm4:log environment_checks set value {} +data modify storage gm4:log environment_checks set value [] data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: Checking for updates...","color":"#4AA0C7"}} scoreboard objectives add gm4_modules dummy diff --git a/base/data/gm4/function/post_load.mcfunction b/base/data/gm4/function/post_load.mcfunction index 97ed658f77..3c69273bad 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -4,5 +4,6 @@ execute if data storage gm4:log queue[{type:"install"}] run data modify storage function gm4:log_wait +say post load function #gm4:evaluate_environment_checks schedule function gm4:await_environment_check_results 1t diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 527bd58602..b199687df2 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -74,7 +74,8 @@ def modules(ctx: Context, opts: VersioningConfig): pass case _: raise ValueError(f"{namespaced_environment_check} is not a valid environment check name!") - environment_check_requests.append(f"data modify storage gm4:log environment_checks.\"{namespace}:{check}\".required_by append value \"{ctx.project_id}\"") + environment_check_requests.append(f"execute unless data storage gm4:log environment_checks[{{ecid:\"{namespace}:{check}\"}}] run data modify storage gm4:log environment_checks append value {{ecid:\"{namespace}:{check}\",required_by:[],result:{{passed:-1}}}}") + environment_check_requests.append(f"data modify storage gm4:log environment_checks[{{ecid:\"{namespace}:{check}\"}}].required_by append value \"{ctx.project_id}\"") if 0 < len(environment_check_requests): # append an empty line to envcheck command list if there is at least one envcheck environment_check_requests.append("") @@ -264,7 +265,7 @@ def versioned_namespace(ctx: Context, version: Version): "replace": f"{versioned_namespace}:\\1" })) ctx.require(find_replace(data_pack={"match": "*"}, substitute={ - "find": f"(? index_environment_checks. Injects active-version checks into environment check entry points.",] for entry_point in ctx.data.function_tags['gm4:evaluate_environment_checks'].data["values"]: - lines.append(f"execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} unless data storage gm4:log environment_checks.\"{entry_point}\" run function {entry_point}") - print(entry_point) + + # if default directory for environment checks is given, remove it from id + entry_point: str + check_id = entry_point + namespace_separator_index = check_id.find(":") + if check_id[namespace_separator_index:].startswith(":environment_check/"): + check_id = check_id[:namespace_separator_index + 1] + check_id[namespace_separator_index + 19:] + + # append conditional environment check entry point + # only run check if: + # - the active version of the library/base matches the version this check was written in (in case this is a versioned library or base) + # - the environment check has been requested by a module/library/base + # - the environment check has not yet been evaluated this reload (in-built caching) + lines.append( + f"""execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} \\ + if data storage gm4:log environment_checks.[{{ecid:"{check_id}"}}] \\ + if data storage gm4:log environment_checks.[{{ecid:"{check_id}",result:{{passed:-1}}}}] \\ + run function {entry_point}""" + ) + print(f"{ctx.project_id} defines envcheck at {entry_point}") ctx.data.functions[f"{ctx.project_id}:environment_checks"] = Function(lines) - + # point function tag to environment_checks.mcfunction ctx.data.function_tags["gm4:evaluate_environment_checks"] = FunctionTag( {"values": [f"{ctx.project_id}:environment_checks"]} From 220ec348503f2c421156215ef9b389d2cde2a2e1 Mon Sep 17 00:00:00 2001 From: Bloo Date: Mon, 23 Feb 2026 22:21:53 +0100 Subject: [PATCH 10/17] Announce Fails and Time Outs to Chat --- ...nnounce_environment_check_results.mcfunction | 17 +++++++++++++++++ .../await_environment_check_results.mcfunction | 8 ++++++-- .../score_on_non_player_entity.mcfunction | 1 - .../assign_score.mcfunction | 8 ++++---- base/data/gm4/function/log.mcfunction | 3 ++- base/data/gm4/function/post_load.mcfunction | 2 +- 6 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 base/data/gm4/function/announce_environment_check_results.mcfunction diff --git a/base/data/gm4/function/announce_environment_check_results.mcfunction b/base/data/gm4/function/announce_environment_check_results.mcfunction new file mode 100644 index 0000000000..358623ce2a --- /dev/null +++ b/base/data/gm4/function/announce_environment_check_results.mcfunction @@ -0,0 +1,17 @@ +# Copies the results of environment checks into the log queue to prepare for printing to chat +# @s = none +# at unspecified +# run from await_environment_check_results + +# if no check failed, no need to print +execute unless data storage gm4:log environment_checks[{result:{passed:0b}}] unless data storage gm4:log environment_checks[{result:{passed:-1b}}] run return 0 + +# copy results into queue, KEEP VERSION IN environment_checks, SO WE CAN INSPECT IT FOR DEBUGGING +data modify storage gm4:log queue set from storage gm4:log environment_checks + +# add extra text around warnings +data modify storage gm4:log queue prepend value {type:"text",message:{"text":"[GM4]: Some environment have not succeeded:","color":"#4AA0C7"}} +data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: This may lead to unintended behavior.","color":"#4AA0C7"}} + +# start announcing +function gm4:log_start diff --git a/base/data/gm4/function/await_environment_check_results.mcfunction b/base/data/gm4/function/await_environment_check_results.mcfunction index 717c8347ef..f497c3f0ed 100644 --- a/base/data/gm4/function/await_environment_check_results.mcfunction +++ b/base/data/gm4/function/await_environment_check_results.mcfunction @@ -1,8 +1,12 @@ # Waits until all environment checks have returned their results # run from post_load +# maintain timeout timer +scoreboard players remove $environment_check_timeout gm4_data 1 +execute if score $environment_check_timeout gm4_data matches ..0 run return run function gm4:announce_environment_check_results + # Peek if any environment checks are still pending (passed:-1), if so, continue waiting execute if data storage gm4:log environment_checks[{result:{passed:-1}}] run return run schedule function gm4:await_environment_check_results 1t -# TODO print out probable_cause from each echeck (in result.probable cause) -say all checks complete! +# all test have returned, print to chat +function gm4:announce_environment_check_results 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 index 2f1ed00c4c..10930a79c4 100644 --- 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 @@ -3,6 +3,5 @@ # at unspecified # run from modules which require this environment check -say non player score # start environment check as marker execute summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score 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 70dedafcbf..d4700bf718 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 @@ -8,11 +8,11 @@ scoreboard players set @s gm4_data 1 # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. -# if the score is present, mark the check as passed -execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 1b, probable_cause: ""} +# if the score is present, mark the check as passed by removing it from storage +execute unless score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 1b, probable_cause: ""} -# (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:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 0b, probable_cause: "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +# if no score is present, provide a probable cause message to the user +execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 0b, 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 diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index 3ec3e90268..ba04401c42 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,7 +4,8 @@ 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"}, {"nbt":"log.probable_cause","storage":"gm4:log","color":"red", "interpret": true}] +execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:-1b} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has timed out!","color":"white"}] +execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:0b} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has failed! ","color":"white"},{"nbt":"log.result.probable_cause","storage":"gm4:log","interpret":true,"color":"white"}] 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 3c69273bad..3d82102426 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -4,6 +4,6 @@ execute if data storage gm4:log queue[{type:"install"}] run data modify storage function gm4:log_wait -say post load function #gm4:evaluate_environment_checks +scoreboard players set $environment_check_timeout gm4_data 600 schedule function gm4:await_environment_check_results 1t From 6fd28f6fa42b69813a0d447b5e3c721f32f1c250 Mon Sep 17 00:00:00 2001 From: Bloo Date: Wed, 25 Feb 2026 19:26:51 +0100 Subject: [PATCH 11/17] Don't Mangle Environment Check Name --- .../score_on_non_player_entity.mcfunction | 2 +- .../assign_score.mcfunction | 2 +- .../tags/function/evaluate_environment_checks.json | 2 +- gm4/plugins/versioning.py | 11 ++--------- gm4_animi_shamir/beet.yaml | 2 +- 5 files changed, 6 insertions(+), 13 deletions(-) rename base/data/gm4/function/{environment_check => echeck}/score_on_non_player_entity.mcfunction (69%) rename base/data/gm4/function/{environment_check => echeck}/score_on_non_player_entity/assign_score.mcfunction (94%) diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction b/base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction similarity index 69% rename from base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction rename to base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction index 10930a79c4..2a459faa4a 100644 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity.mcfunction +++ b/base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction @@ -4,4 +4,4 @@ # run from modules which require this environment check # start environment check as marker -execute summon marker run function gm4:environment_check/score_on_non_player_entity/assign_score +execute summon marker run function gm4:echeck/score_on_non_player_entity/assign_score diff --git a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction similarity index 94% rename from base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction rename to base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction index d4700bf718..75a5fd7d39 100644 --- a/base/data/gm4/function/environment_check/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/echeck/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:echeck/score_on_non_player_entity # set up marker & run test scoreboard players set @s gm4_data 1 diff --git a/base/data/gm4/tags/function/evaluate_environment_checks.json b/base/data/gm4/tags/function/evaluate_environment_checks.json index 5d872448bb..c244cbc393 100644 --- a/base/data/gm4/tags/function/evaluate_environment_checks.json +++ b/base/data/gm4/tags/function/evaluate_environment_checks.json @@ -1,5 +1,5 @@ { "values": [ - "gm4:environment_check/score_on_non_player_entity" + "gm4:echeck/score_on_non_player_entity" ] } diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index b199687df2..963d5952d5 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -350,13 +350,6 @@ def index_environment_checks(ctx: Context, ver: Version): lines = ["# Auto-generated by gm4/plugins/versioning.py -> index_environment_checks. Injects active-version checks into environment check entry points.",] for entry_point in ctx.data.function_tags['gm4:evaluate_environment_checks'].data["values"]: - # if default directory for environment checks is given, remove it from id - entry_point: str - check_id = entry_point - namespace_separator_index = check_id.find(":") - if check_id[namespace_separator_index:].startswith(":environment_check/"): - check_id = check_id[:namespace_separator_index + 1] + check_id[namespace_separator_index + 19:] - # append conditional environment check entry point # only run check if: # - the active version of the library/base matches the version this check was written in (in case this is a versioned library or base) @@ -364,8 +357,8 @@ def index_environment_checks(ctx: Context, ver: Version): # - the environment check has not yet been evaluated this reload (in-built caching) lines.append( f"""execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} \\ - if data storage gm4:log environment_checks.[{{ecid:"{check_id}"}}] \\ - if data storage gm4:log environment_checks.[{{ecid:"{check_id}",result:{{passed:-1}}}}] \\ + if data storage gm4:log environment_checks.[{{ecid:"{entry_point}"}}] \\ + if data storage gm4:log environment_checks.[{{ecid:"{entry_point}",result:{{passed:-1}}}}] \\ run function {entry_point}""" ) print(f"{ctx.project_id} defines envcheck at {entry_point}") diff --git a/gm4_animi_shamir/beet.yaml b/gm4_animi_shamir/beet.yaml index e5762fc9d7..b887bb047a 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,7 +20,7 @@ meta: required: gm4_metallurgy: 1.5.0 lib_player_death: 1.3.0 - environment_checks: [gm4:score_on_non_player_entity] + environment_checks: [gm4:echeck/score_on_non_player_entity] schedule_loops: [main] model_data: - reference: shamir/animi From 6b7610d441f8b153ecdb3fe326fd0ddae6f8106f Mon Sep 17 00:00:00 2001 From: Bloo Date: Wed, 25 Feb 2026 19:47:30 +0100 Subject: [PATCH 12/17] Clean Up & Remove Debug Statements --- .../function/announce_environment_check_results.mcfunction | 4 ++-- .../score_on_non_player_entity/assign_score.mcfunction | 6 ++---- base/data/gm4/function/load.mcfunction | 1 + base/data/gm4/function/log.mcfunction | 4 ++-- gm4/plugins/versioning.py | 1 - 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/base/data/gm4/function/announce_environment_check_results.mcfunction b/base/data/gm4/function/announce_environment_check_results.mcfunction index 358623ce2a..8e5faf0a71 100644 --- a/base/data/gm4/function/announce_environment_check_results.mcfunction +++ b/base/data/gm4/function/announce_environment_check_results.mcfunction @@ -4,13 +4,13 @@ # run from await_environment_check_results # if no check failed, no need to print -execute unless data storage gm4:log environment_checks[{result:{passed:0b}}] unless data storage gm4:log environment_checks[{result:{passed:-1b}}] run return 0 +execute unless data storage gm4:log environment_checks[{result:{passed:0}}] unless data storage gm4:log environment_checks[{result:{passed:-1}}] run return 0 # copy results into queue, KEEP VERSION IN environment_checks, SO WE CAN INSPECT IT FOR DEBUGGING data modify storage gm4:log queue set from storage gm4:log environment_checks # add extra text around warnings -data modify storage gm4:log queue prepend value {type:"text",message:{"text":"[GM4]: Some environment have not succeeded:","color":"#4AA0C7"}} +data modify storage gm4:log queue prepend value {type:"text",message:{"text":"[GM4]: Some environment checks have not succeeded:","color":"#4AA0C7"}} data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: This may lead to unintended behavior.","color":"#4AA0C7"}} # start announcing diff --git a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction index 75a5fd7d39..452fc0f280 100644 --- a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction @@ -2,17 +2,15 @@ # @s = test marker, just summoned # at @s # run from gm4:echeck/score_on_non_player_entity - # set up marker & run test scoreboard players set @s gm4_data 1 - # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. # if the score is present, mark the check as passed by removing it from storage -execute unless score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 1b, probable_cause: ""} +execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} # if no score is present, provide a probable cause message to the user -execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:score_on_non_player_entity"}].result set value {passed: 0b, probable_cause: "This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +execute unless score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,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 diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index b9ba05fcce..69dc62f05e 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -1,5 +1,6 @@ data merge storage gm4:log {queue:[],versions:[]} data modify storage gm4:log environment_checks set value [] +schedule clear gm4:await_environment_check_results data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: Checking for updates...","color":"#4AA0C7"}} scoreboard objectives add gm4_modules dummy diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index ba04401c42..0373fff36c 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,8 +4,8 @@ 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.ecid if data storage gm4:log log.result{passed:-1b} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has timed out!","color":"white"}] -execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:0b} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has failed! ","color":"white"},{"nbt":"log.result.probable_cause","storage":"gm4:log","interpret":true,"color":"white"}] +execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:-1} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has timed out!","color":"white"}] +execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:0} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has failed! ","color":"white"},{"nbt":"log.result.probable_cause","storage":"gm4:log","interpret":true,"color":"white"}] 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 963d5952d5..48843263c9 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -361,7 +361,6 @@ def index_environment_checks(ctx: Context, ver: Version): if data storage gm4:log environment_checks.[{{ecid:"{entry_point}",result:{{passed:-1}}}}] \\ run function {entry_point}""" ) - print(f"{ctx.project_id} defines envcheck at {entry_point}") ctx.data.functions[f"{ctx.project_id}:environment_checks"] = Function(lines) # point function tag to environment_checks.mcfunction From f0a2d53a211f2a2bf33a667ce95191b1526918d3 Mon Sep 17 00:00:00 2001 From: Bloo Date: Wed, 25 Feb 2026 19:56:26 +0100 Subject: [PATCH 13/17] Use 'echeck' instead of the lengthy 'environment_checks' --- base/beet.yaml | 2 - ...ion => announce_echeck_results.mcfunction} | 8 +-- .../function/await_echeck_results.mcfunction | 12 ++++ ...await_environment_check_results.mcfunction | 12 ---- .../assign_score.mcfunction | 4 +- base/data/gm4/function/load.mcfunction | 4 +- base/data/gm4/function/log.mcfunction | 4 +- base/data/gm4/function/post_load.mcfunction | 8 +-- ...ment_checks.json => evaluate_echecks.json} | 0 docs/making-a-module.md | 2 +- docs/utilities.md | 16 ++--- gm4/plugins/versioning.py | 62 +++++++++---------- gm4_animi_shamir/beet.yaml | 2 +- gm4_double_doors/beet.yaml | 2 +- 14 files changed, 68 insertions(+), 70 deletions(-) rename base/data/gm4/function/{announce_environment_check_results.mcfunction => announce_echeck_results.mcfunction} (58%) create mode 100644 base/data/gm4/function/await_echeck_results.mcfunction delete mode 100644 base/data/gm4/function/await_environment_check_results.mcfunction rename base/data/gm4/tags/function/{evaluate_environment_checks.json => evaluate_echecks.json} (100%) diff --git a/base/beet.yaml b/base/beet.yaml index 2880a197ca..d6f042a321 100644 --- a/base/beet.yaml +++ b/base/beet.yaml @@ -24,8 +24,6 @@ meta: extra_version_injections: advancements: - 'gm4:intro_song/play_song' - functions: - - 'gm4:environment_check/score_on_non_player_entity' model_data: - item: command_block reference: gm4:gui/advancement/root diff --git a/base/data/gm4/function/announce_environment_check_results.mcfunction b/base/data/gm4/function/announce_echeck_results.mcfunction similarity index 58% rename from base/data/gm4/function/announce_environment_check_results.mcfunction rename to base/data/gm4/function/announce_echeck_results.mcfunction index 8e5faf0a71..306b2ff201 100644 --- a/base/data/gm4/function/announce_environment_check_results.mcfunction +++ b/base/data/gm4/function/announce_echeck_results.mcfunction @@ -1,13 +1,13 @@ # Copies the results of environment checks into the log queue to prepare for printing to chat # @s = none # at unspecified -# run from await_environment_check_results +# run from await_echeck_results # if no check failed, no need to print -execute unless data storage gm4:log environment_checks[{result:{passed:0}}] unless data storage gm4:log environment_checks[{result:{passed:-1}}] run return 0 +execute unless data storage gm4:log echecks[{result:{passed:0}}] unless data storage gm4:log echecks[{result:{passed:-1}}] run return 0 -# copy results into queue, KEEP VERSION IN environment_checks, SO WE CAN INSPECT IT FOR DEBUGGING -data modify storage gm4:log queue set from storage gm4:log environment_checks +# copy results into queue, KEEP VERSION IN echecks, SO WE CAN INSPECT IT FOR DEBUGGING +data modify storage gm4:log queue set from storage gm4:log echecks # add extra text around warnings data modify storage gm4:log queue prepend value {type:"text",message:{"text":"[GM4]: Some environment checks have not succeeded:","color":"#4AA0C7"}} diff --git a/base/data/gm4/function/await_echeck_results.mcfunction b/base/data/gm4/function/await_echeck_results.mcfunction new file mode 100644 index 0000000000..6ea4837570 --- /dev/null +++ b/base/data/gm4/function/await_echeck_results.mcfunction @@ -0,0 +1,12 @@ +# Waits until all environment checks have returned their results +# run from post_load + +# maintain timeout timer +scoreboard players remove $echeck_timeout gm4_data 1 +execute if score $echeck_timeout gm4_data matches ..0 run return run function gm4:announce_echeck_results + +# Peek if any environment checks are still pending (passed:-1), if so, continue waiting +execute if data storage gm4:log echecks[{result:{passed:-1}}] run return run schedule function gm4:await_echeck_results 1t + +# all test have returned, print to chat +function gm4:announce_echeck_results diff --git a/base/data/gm4/function/await_environment_check_results.mcfunction b/base/data/gm4/function/await_environment_check_results.mcfunction deleted file mode 100644 index f497c3f0ed..0000000000 --- a/base/data/gm4/function/await_environment_check_results.mcfunction +++ /dev/null @@ -1,12 +0,0 @@ -# Waits until all environment checks have returned their results -# run from post_load - -# maintain timeout timer -scoreboard players remove $environment_check_timeout gm4_data 1 -execute if score $environment_check_timeout gm4_data matches ..0 run return run function gm4:announce_environment_check_results - -# Peek if any environment checks are still pending (passed:-1), if so, continue waiting -execute if data storage gm4:log environment_checks[{result:{passed:-1}}] run return run schedule function gm4:await_environment_check_results 1t - -# all test have returned, print to chat -function gm4:announce_environment_check_results diff --git a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction index 452fc0f280..f56c1a077a 100644 --- a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction @@ -7,10 +7,10 @@ scoreboard players set @s gm4_data 1 # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. # if the score is present, mark the check as passed by removing it from storage -execute if score @s gm4_data matches 1 run data modify storage gm4:log environment_checks[{ecid:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} +execute if score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} # 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:log environment_checks[{ecid:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +execute unless score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,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 diff --git a/base/data/gm4/function/load.mcfunction b/base/data/gm4/function/load.mcfunction index 69dc62f05e..3aa804ccd6 100644 --- a/base/data/gm4/function/load.mcfunction +++ b/base/data/gm4/function/load.mcfunction @@ -1,6 +1,6 @@ data merge storage gm4:log {queue:[],versions:[]} -data modify storage gm4:log environment_checks set value [] -schedule clear gm4:await_environment_check_results +data modify storage gm4:log echecks set value [] +schedule clear gm4:await_echeck_results data modify storage gm4:log queue append value {type:"text",message:{"text":"[GM4]: Checking for updates...","color":"#4AA0C7"}} scoreboard objectives add gm4_modules dummy diff --git a/base/data/gm4/function/log.mcfunction b/base/data/gm4/function/log.mcfunction index 0373fff36c..873b6ee891 100644 --- a/base/data/gm4/function/log.mcfunction +++ b/base/data/gm4/function/log.mcfunction @@ -4,8 +4,8 @@ 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.ecid if data storage gm4:log log.result{passed:-1} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has timed out!","color":"white"}] -execute if data storage gm4:log log.ecid if data storage gm4:log log.result{passed:0} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.ecid","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has failed! ","color":"white"},{"nbt":"log.result.probable_cause","storage":"gm4:log","interpret":true,"color":"white"}] +execute if data storage gm4:log log.echeck_id if data storage gm4:log log.result{passed:-1} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.echeck_id","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has timed out!","color":"white"}] +execute if data storage gm4:log log.echeck_id if data storage gm4:log log.result{passed:0} run tellraw @a[tag=gm4_show_log] [{"text":"-","color":"white"},{"nbt":"log.echeck_id","storage":"gm4:log","interpret":true, "color": "yellow"},{"text":" has failed! ","color":"white"},{"nbt":"log.result.probable_cause","storage":"gm4:log","interpret":true,"color":"white"}] 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 3d82102426..7dd809d2bb 100644 --- a/base/data/gm4/function/post_load.mcfunction +++ b/base/data/gm4/function/post_load.mcfunction @@ -1,9 +1,9 @@ -scoreboard players reset * gm4.environment_check_results +scoreboard players reset * gm4.echeck_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 -function #gm4:evaluate_environment_checks -scoreboard players set $environment_check_timeout gm4_data 600 -schedule function gm4:await_environment_check_results 1t +function #gm4:evaluate_echecks +scoreboard players set $echeck_timeout gm4_data 600 +schedule function gm4:await_echeck_results 1t diff --git a/base/data/gm4/tags/function/evaluate_environment_checks.json b/base/data/gm4/tags/function/evaluate_echecks.json similarity index 100% rename from base/data/gm4/tags/function/evaluate_environment_checks.json rename to base/data/gm4/tags/function/evaluate_echecks.json diff --git a/docs/making-a-module.md b/docs/making-a-module.md index 5313ac73d7..f057c0eefb 100644 --- a/docs/making-a-module.md +++ b/docs/making-a-module.md @@ -69,7 +69,7 @@ meta: - 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] + echecks: [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 diff --git a/docs/utilities.md b/docs/utilities.md index cc0e42f319..4e3f05a0e3 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -73,7 +73,7 @@ meta: schedule_loops: [] # List of environment checks to include - environment_checks: [gm4:score_on_non_player_entity] + echecks: [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: [] @@ -93,7 +93,7 @@ meta: 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] +echecks: [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. @@ -102,7 +102,7 @@ Environment checks are run on every reload, with each check only running once pe 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 +/data modify storage {namespace}:echecks result.{check name}.passed set value 1b ``` and run `/reload`. This has to be repeated before each reload. @@ -124,17 +124,17 @@ Hence, you probably don't need to add these checks to your module if you already ### 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. +Any functions contained directly within the `function/echeck/` folder of a module are treated as environment checks and may be mentioned within 'beet.yaml`. +Functions in subfolders within `function/echeck/` 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}} +data modify storage :echecks 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."}} +data modify storage :echecks 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. @@ -142,7 +142,7 @@ 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. +execute unless data storage :echecks result. ``` You **must also clear all check results** in post-load. diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 48843263c9..2f58accd6f 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -13,7 +13,7 @@ class VersionInjectionConfig(PluginOptions): advancements: list[str] = [] class VersioningConfig(PluginOptions, extra="ignore"): - environment_checks: list[str] = [] + echecks: list[str] = [] schedule_loops: list[str] = [] required: dict[str, str] = {} extra_version_injections: VersionInjectionConfig = Field(default=VersionInjectionConfig()) @@ -23,7 +23,7 @@ def modules(ctx: Context, opts: VersioningConfig): """Assembles version-functions for modules from dependency information: - load:{module_name}.json - {module_name}:load.mcfunction - - {module_name}:environment_checks.mcfunction + - {module_name}:echecks.mcfunction - load:load.json """ ctx.cache["currently_building"].json = {"name": ctx.project_name, "id": ctx.project_id, "added_libs": []} # cache module's project id for access within library pipelines @@ -63,9 +63,9 @@ def modules(ctx: Context, opts: VersioningConfig): log_message_commands.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 environment check requests - environment_check_requests: List[str] = [] - for namespaced_environment_check in opts.environment_checks: - match namespaced_environment_check.split(":"): + echeck_requests: List[str] = [] + for namespaced_echeck in opts.echecks: + match namespaced_echeck.split(":"): case [ check ]: # if no namespace is given, assume current project's namespace @@ -73,12 +73,12 @@ def modules(ctx: Context, opts: VersioningConfig): case [namespace, check]: pass case _: - raise ValueError(f"{namespaced_environment_check} is not a valid environment check name!") - environment_check_requests.append(f"execute unless data storage gm4:log environment_checks[{{ecid:\"{namespace}:{check}\"}}] run data modify storage gm4:log environment_checks append value {{ecid:\"{namespace}:{check}\",required_by:[],result:{{passed:-1}}}}") - environment_check_requests.append(f"data modify storage gm4:log environment_checks[{{ecid:\"{namespace}:{check}\"}}].required_by append value \"{ctx.project_id}\"") + raise ValueError(f"{namespaced_echeck} is not a valid environment check name!") + echeck_requests.append(f"execute unless data storage gm4:log echecks[{{echeck_id:\"{namespace}:{check}\"}}] run data modify storage gm4:log echecks append value {{echeck_id:\"{namespace}:{check}\",required_by:[],result:{{passed:-1}}}}") + echeck_requests.append(f"data modify storage gm4:log echecks[{{echeck_id:\"{namespace}:{check}\"}}].required_by append value \"{ctx.project_id}\"") - if 0 < len(environment_check_requests): # append an empty line to envcheck command list if there is at least one envcheck - environment_check_requests.append("") + if 0 < len(echeck_requests): # append an empty line to envcheck command list if there is at least one envcheck + echeck_requests.append("") # parse module version module_ver = Version(ctx.project_version) @@ -103,13 +103,13 @@ def modules(ctx: Context, opts: VersioningConfig): dependency_check_command + f"run scoreboard players set {ctx.project_id}_minor load.status {module_ver.minor}", "", - *environment_check_requests, + *echeck_requests, *log_message_commands, ] ) - # environment_checks.mcfunction if this data pack defines environment checks - index_environment_checks(ctx, module_ver) + # echecks.mcfunction if this data pack defines environment checks + index_echecks(ctx, module_ver) # load.json tag ctx.data.function_tags["load:load"] = FunctionTag({ @@ -127,7 +127,7 @@ def libraries(ctx: Context, opts: VersioningConfig): """Assembles version-functions for libraries from dependency information: - {lib_name}:enumerate.mcfunction - {lib_name}:resolve_load.mcfunction - - {lib_name}:environment_checks.mcfunction + - {lib_name}:echecks.mcfunction - load:{lib_name}.json - load:{lib_name}/enumerate.json - load:{lib_name}/resolve_load.json @@ -169,8 +169,8 @@ def libraries(ctx: Context, opts: VersioningConfig): ctx.data.functions[f"{ctx.project_id}:resolve_load"] = Function(lines) - # environment_checks.mcfunction if this data pack defines environment checks - index_environment_checks(ctx, lib_ver) + # echecks.mcfunction if this data pack defines environment checks + index_echecks(ctx, lib_ver) # load/tags {{ lib name }}.json ctx.data.function_tags[f"load:{ctx.project_id}"] = FunctionTag({ @@ -244,7 +244,7 @@ def base(ctx: Context, opts: VersioningConfig): ctx.data.functions[f"gm4:resolve_post_load"] = Function(lines) # index env checks - index_environment_checks(ctx, ver) + index_echecks(ctx, ver) versioned_advancements(ctx, ver, opts.extra_version_injections.advancements, strict=True) #type:ignore @@ -265,7 +265,7 @@ def versioned_namespace(ctx: Context, version: Version): "replace": f"{versioned_namespace}:\\1" })) ctx.require(find_replace(data_pack={"match": "*"}, substitute={ - "find": f"(? index_environment_checks. Injects active-version checks into environment check entry points.",] - for entry_point in ctx.data.function_tags['gm4:evaluate_environment_checks'].data["values"]: + # read out defined environment checks and build echecks.mcfunction (introduces active-version checking) + lines = ["# Auto-generated by gm4/plugins/versioning.py -> index_echecks. Injects active-version checks into environment check entry points.",] + for entry_point in ctx.data.function_tags['gm4:evaluate_echecks'].data["values"]: # append conditional environment check entry point # only run check if: @@ -357,15 +357,15 @@ def index_environment_checks(ctx: Context, ver: Version): # - the environment check has not yet been evaluated this reload (in-built caching) lines.append( f"""execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} \\ - if data storage gm4:log environment_checks.[{{ecid:"{entry_point}"}}] \\ - if data storage gm4:log environment_checks.[{{ecid:"{entry_point}",result:{{passed:-1}}}}] \\ + if data storage gm4:log echecks.[{{echeck_id:"{entry_point}"}}] \\ + if data storage gm4:log echecks.[{{echeck_id:"{entry_point}",result:{{passed:-1}}}}] \\ run function {entry_point}""" ) - ctx.data.functions[f"{ctx.project_id}:environment_checks"] = Function(lines) + ctx.data.functions[f"{ctx.project_id}:echecks"] = Function(lines) - # point function tag to environment_checks.mcfunction - ctx.data.function_tags["gm4:evaluate_environment_checks"] = FunctionTag( - {"values": [f"{ctx.project_id}:environment_checks"]} + # point function tag to echecks.mcfunction + ctx.data.function_tags["gm4:evaluate_echecks"] = FunctionTag( + {"values": [f"{ctx.project_id}:echecks"]} ) diff --git a/gm4_animi_shamir/beet.yaml b/gm4_animi_shamir/beet.yaml index b887bb047a..7fd8536692 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,7 +20,7 @@ meta: required: gm4_metallurgy: 1.5.0 lib_player_death: 1.3.0 - environment_checks: [gm4:echeck/score_on_non_player_entity] + echecks: [gm4:echeck/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 7e2a4ec0e8..ab4634fec6 100644 --- a/gm4_double_doors/beet.yaml +++ b/gm4_double_doors/beet.yaml @@ -16,7 +16,7 @@ meta: gm4: versioning: schedule_loops: [] - environment_checks: [gm4:score_on_non_player_entity] + echecks: [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 b4e796d85d7fd992334cdacc0a485cc020738d2c Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 28 Feb 2026 10:33:01 +0100 Subject: [PATCH 14/17] Fix Hardcoded Namespace in Version Check --- gm4/plugins/versioning.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 2f58accd6f..6e2665d20d 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -350,16 +350,34 @@ def index_echecks(ctx: Context, ver: Version): lines = ["# Auto-generated by gm4/plugins/versioning.py -> index_echecks. Injects active-version checks into environment check entry points.",] for entry_point in ctx.data.function_tags['gm4:evaluate_echecks'].data["values"]: + # parse function tag entry + # entry point may be a dict instead of a string (e.g. {"required":false, "id":<...>}) + # if that is the case, find the id field and extract the string-form namespace resource locator + if isinstance(entry_point, dict): + if ("id" not in entry_point) or (not isinstance(entry_point["id"], str)): + raise ValueError(f"Failed to parse echeck entry point from 'gm4:evaluate_echecks' entry '{entry_point}'.") + entry_point = entry_point["id"] + + # strings should be a namespaced resource locator + if isinstance(entry_point, str): + if ":" not in entry_point: + raise ValueError(f"Failed to parse echeck entry point from 'gm4:evaluate_echecks' entry '{entry_point}'.") + namespace, path = entry_point.split(":", maxsplit=1) + + # unknown type + else: + raise ValueError(f"Failed to parse echeck entry point from from 'gm4:evaluate_echecks' entry '{entry_point}' (type '{type(entry_point)}').") + # append conditional environment check entry point # only run check if: # - the active version of the library/base matches the version this check was written in (in case this is a versioned library or base) # - the environment check has been requested by a module/library/base # - the environment check has not yet been evaluated this reload (in-built caching) lines.append( - f"""execute if score gm4 load.status matches {ver.major} if score gm4_minor load.status matches {ver.minor} \\ - if data storage gm4:log echecks.[{{echeck_id:"{entry_point}"}}] \\ - if data storage gm4:log echecks.[{{echeck_id:"{entry_point}",result:{{passed:-1}}}}] \\ - run function {entry_point}""" + f"""execute if score {namespace} load.status matches {ver.major} if score {namespace}_minor load.status matches {ver.minor} \\ + if data storage gm4:log echecks.[{{echeck_id:"{namespace}:{path}"}}] \\ + if data storage gm4:log echecks.[{{echeck_id:"{namespace}:{path}",result:{{passed:-1}}}}] \\ + run function {namespace}:{path}""" ) ctx.data.functions[f"{ctx.project_id}:echecks"] = Function(lines) From c56f0f115c5b0cdb2c23746741a023c10631deee Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 28 Feb 2026 10:50:11 +0100 Subject: [PATCH 15/17] Update Documentation --- docs/utilities.md | 53 +++++++++++++-------------------------- gm4/plugins/versioning.py | 2 +- 2 files changed, 18 insertions(+), 37 deletions(-) diff --git a/docs/utilities.md b/docs/utilities.md index 4e3f05a0e3..ee7ff220f0 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -46,10 +46,10 @@ Gamemode 4's default entity tags are located at `base/data/gm4/tags/block/`. | #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. +The environment a data pack is installed into may 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. +To counteract this, modules may include environment checks which warn the user 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 @@ -91,21 +91,16 @@ meta: - venomousbirds ``` -Multiple checks may be included and are executed in-order: +Multiple checks may be included, however, the order they will be executed in is arbitrary: ```yaml echecks: [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. +On reload, `base` obtains a list of environment checks requested by all installed modules and libraries. During `post_load` this list is then executed. +Announcements of the test results are only made if at least one test did not succeed and may not be instantaneous, as environment checks are allowed 30s of runtime. +If any check does not return after 30s it is marked as "timed-out" and will be announced as such. -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}:echecks result.{check name}.passed set value 1b -``` -and run `/reload`. -This has to be repeated before each reload. +For debug purposes, you may inspect the contents of storage `gm4:log echecks` to see the results of the latest environment checks. This storage is only cleared before new checks are executed. ### Base Environment Checks `base` comes with some fundamental environment checks that can be referenced by the `gm4:` namespace. @@ -114,36 +109,22 @@ This has to be repeated before each reload. |--------------------------------|--------------------------------------------------------------------------------------------------------------------------| | 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/echeck/` folder of a module are treated as environment checks and may be mentioned within 'beet.yaml`. -Functions in subfolders within `function/echeck/` are ignored and can therefore be used as helper functions. +Modules may also introduce their own environment checks. Environment checks are defined as a single `.mcfunction` entry point, but may call other `.mcfunction` files, predicates, etc. from their entry point. +Caching of environment check results is provided automatically, you do not have to implement caching. -To indicate a successful environment check include +When introducing an environment check, the corresponding module must add the environment check's entry point to the `#gm4:evaluate_echecks` function tag. +Upon completion of the test (failure or success), the environment check needs to add a `result` object to its entry in the `gm4:log echeck` storage. + +For example, the test with entry point located at `gm4:echeck/score_on_non_player_entity` may indicate a test failure as follows ```mcfunction -data modify storage :echecks result set value {: {passed: 1b}} +data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} ``` -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 +Or a test success as ```mcfunction -data modify storage :echecks result set value {: {probable_cause: "This may be caused by the programmer not expecting you to run this on a potato."}} +data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} ``` -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 :echecks result. -``` -You **must also clear all check results** in post-load. +The `result.probable_cause` is shown to the user in chat in case the test fails. For a textbook example of an environment check, inspect `gm4:score_on_non_player_entity` in `base`. diff --git a/gm4/plugins/versioning.py b/gm4/plugins/versioning.py index 6e2665d20d..bef52659f1 100644 --- a/gm4/plugins/versioning.py +++ b/gm4/plugins/versioning.py @@ -361,7 +361,7 @@ def index_echecks(ctx: Context, ver: Version): # strings should be a namespaced resource locator if isinstance(entry_point, str): if ":" not in entry_point: - raise ValueError(f"Failed to parse echeck entry point from 'gm4:evaluate_echecks' entry '{entry_point}'.") + raise ValueError(f"Failed to parse echeck entry point from 'gm4:evaluate_echecks' entry '{entry_point}'. Missing namespace!") namespace, path = entry_point.split(":", maxsplit=1) # unknown type From 11fdc5c314301042f2c4aec24a2080e6a370a205 Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 28 Feb 2026 12:47:11 +0100 Subject: [PATCH 16/17] Separate Score and Team Checks --- .../assign_score.mcfunction | 6 +++--- .../gm4/function/echeck/join_team.mcfunction | 19 +++++++++++++++++++ .../non_player_entity_has_score.mcfunction | 7 +++++++ .../non_player_entity_on_team.mcfunction | 7 +++++++ .../score_on_non_player_entity.mcfunction | 7 ------- .../gm4/tags/function/evaluate_echecks.json | 2 +- docs/making-a-module.md | 4 ++-- docs/utilities.md | 14 +++++++------- gm4_animi_shamir/beet.yaml | 2 +- gm4_double_doors/beet.yaml | 2 +- gm4_monsters_unbound/beet.yaml | 1 + 11 files changed, 49 insertions(+), 22 deletions(-) rename base/data/gm4/function/echeck/{score_on_non_player_entity => }/assign_score.mcfunction (62%) create mode 100644 base/data/gm4/function/echeck/join_team.mcfunction create mode 100644 base/data/gm4/function/echeck/non_player_entity_has_score.mcfunction create mode 100644 base/data/gm4/function/echeck/non_player_entity_on_team.mcfunction delete mode 100644 base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction diff --git a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction b/base/data/gm4/function/echeck/assign_score.mcfunction similarity index 62% rename from base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction rename to base/data/gm4/function/echeck/assign_score.mcfunction index f56c1a077a..feeffaa030 100644 --- a/base/data/gm4/function/echeck/score_on_non_player_entity/assign_score.mcfunction +++ b/base/data/gm4/function/echeck/assign_score.mcfunction @@ -1,16 +1,16 @@ # Assigns a score to this marker and reads it back. Kills the marker afterwards # @s = test marker, just summoned # at @s -# run from gm4:echeck/score_on_non_player_entity +# run from gm4:echeck/non_player_entity_has_score # set up marker & run test scoreboard players set @s gm4_data 1 # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. # if the score is present, mark the check as passed by removing it from storage -execute if score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} +execute if score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:1,probable_cause:""} # 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:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +execute unless score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,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 diff --git a/base/data/gm4/function/echeck/join_team.mcfunction b/base/data/gm4/function/echeck/join_team.mcfunction new file mode 100644 index 0000000000..a5ed0961c4 --- /dev/null +++ b/base/data/gm4/function/echeck/join_team.mcfunction @@ -0,0 +1,19 @@ +# Assigns a score to this marker and reads it back. Kills the marker afterwards +# @s = test marker, just summoned +# at @s +# run from gm4:echeck/non_player_entity_has_score +# set up marker & run test +team add gm4_echeck_non_player_entity_on_team_temp +team join gm4_echeck_non_player_entity_on_team_temp @s + +# depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. + +# if the score is present, mark the check as passed by removing it from storage +execute if entity @s[team=gm4_echeck_non_player_entity_on_team_temp] run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:1,probable_cause:""} + +# if no score is present, provide a probable cause message to the user +execute unless entity @s[team=gm4_echeck_non_player_entity_on_team_temp] run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} + +# clean up +team remove gm4_echeck_non_player_entity_on_team_temp +kill @s diff --git a/base/data/gm4/function/echeck/non_player_entity_has_score.mcfunction b/base/data/gm4/function/echeck/non_player_entity_has_score.mcfunction new file mode 100644 index 0000000000..b0ebaa886d --- /dev/null +++ b/base/data/gm4/function/echeck/non_player_entity_has_score.mcfunction @@ -0,0 +1,7 @@ +# Tests if non-player entities can hold scores. We think spigot might have done this at some point, but are not sure. +# @s = unspecified +# at unspecified +# run from modules which require this environment check + +# start environment check as marker +execute summon marker run function gm4:echeck/assign_score diff --git a/base/data/gm4/function/echeck/non_player_entity_on_team.mcfunction b/base/data/gm4/function/echeck/non_player_entity_on_team.mcfunction new file mode 100644 index 0000000000..9c2ac24891 --- /dev/null +++ b/base/data/gm4/function/echeck/non_player_entity_on_team.mcfunction @@ -0,0 +1,7 @@ +# Tests if non-player entities can be on teams. Spigot prevents non-players on teams if the config is changed. +# @s = unspecified +# at unspecified +# run from modules which require this environment check + +# start environment check as marker +execute summon marker run function gm4:echeck/join_team diff --git a/base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction b/base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction deleted file mode 100644 index 2a459faa4a..0000000000 --- a/base/data/gm4/function/echeck/score_on_non_player_entity.mcfunction +++ /dev/null @@ -1,7 +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 - -# start environment check as marker -execute summon marker run function gm4:echeck/score_on_non_player_entity/assign_score diff --git a/base/data/gm4/tags/function/evaluate_echecks.json b/base/data/gm4/tags/function/evaluate_echecks.json index c244cbc393..c7be2aa97c 100644 --- a/base/data/gm4/tags/function/evaluate_echecks.json +++ b/base/data/gm4/tags/function/evaluate_echecks.json @@ -1,5 +1,5 @@ { "values": [ - "gm4:echeck/score_on_non_player_entity" + "gm4:echeck/non_player_entity_has_score" ] } diff --git a/docs/making-a-module.md b/docs/making-a-module.md index f057c0eefb..85fcabea30 100644 --- a/docs/making-a-module.md +++ b/docs/making-a-module.md @@ -68,8 +68,8 @@ 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 - echecks: [gm4:score_on_non_player_entity] + # A list of checks to run on reload while the module is installed. May be omitted. + echecks: [gm4:non_player_entity_has_score] website: # A description. This should be a good summary of what this module adds or achieves, to get someone interested in this module diff --git a/docs/utilities.md b/docs/utilities.md index ee7ff220f0..6b9ae7e823 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -73,7 +73,7 @@ meta: schedule_loops: [] # List of environment checks to include - echecks: [gm4:score_on_non_player_entity] + echecks: [gm4:non_player_entity_has_score] 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: [] @@ -93,7 +93,7 @@ meta: Multiple checks may be included, however, the order they will be executed in is arbitrary: ```yaml -echecks: [gm4:score_on_non_player_entity, gm4_double_doors:bloo_is_not_online, lib_forceload:command_blocks_enabled] +echecks: [gm4:non_player_entity_has_score, gm4_double_doors:bloo_is_not_online, lib_forceload:command_blocks_enabled] ``` On reload, `base` obtains a list of environment checks requested by all installed modules and libraries. During `post_load` this list is then executed. @@ -107,7 +107,7 @@ For debug purposes, you may inspect the contents of storage `gm4:log echecks` to | 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. | +| gm4:non_player_entity_has_score | 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. | ### Creating New Environment Checks Modules may also introduce their own environment checks. Environment checks are defined as a single `.mcfunction` entry point, but may call other `.mcfunction` files, predicates, etc. from their entry point. @@ -116,15 +116,15 @@ Caching of environment check results is provided automatically, you do not have When introducing an environment check, the corresponding module must add the environment check's entry point to the `#gm4:evaluate_echecks` function tag. Upon completion of the test (failure or success), the environment check needs to add a `result` object to its entry in the `gm4:log echeck` storage. -For example, the test with entry point located at `gm4:echeck/score_on_non_player_entity` may indicate a test failure as follows +For example, the test with entry point located at `gm4:echeck/non_player_entity_has_score` may indicate a test failure as follows ```mcfunction -data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} ``` Or a test success as ```mcfunction -data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/score_on_non_player_entity"}].result set value {passed:1,probable_cause:""} +data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:1,probable_cause:""} ``` The `result.probable_cause` is shown to the user in chat in case the test fails. -For a textbook example of an environment check, inspect `gm4:score_on_non_player_entity` in `base`. +For a textbook example of an environment check, inspect `gm4:non_player_entity_has_score` in `base`. diff --git a/gm4_animi_shamir/beet.yaml b/gm4_animi_shamir/beet.yaml index 7fd8536692..47409fc1b6 100644 --- a/gm4_animi_shamir/beet.yaml +++ b/gm4_animi_shamir/beet.yaml @@ -20,7 +20,7 @@ meta: required: gm4_metallurgy: 1.5.0 lib_player_death: 1.3.0 - echecks: [gm4:echeck/score_on_non_player_entity] + echecks: [gm4:echeck/non_player_entity_has_score] schedule_loops: [main] model_data: - reference: shamir/animi diff --git a/gm4_double_doors/beet.yaml b/gm4_double_doors/beet.yaml index ab4634fec6..b4842278a2 100644 --- a/gm4_double_doors/beet.yaml +++ b/gm4_double_doors/beet.yaml @@ -16,7 +16,7 @@ meta: gm4: versioning: schedule_loops: [] - echecks: [gm4:score_on_non_player_entity] + echecks: [gm4:non_player_entity_has_score] 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: [] diff --git a/gm4_monsters_unbound/beet.yaml b/gm4_monsters_unbound/beet.yaml index 2c068ad40c..1383cf69d5 100644 --- a/gm4_monsters_unbound/beet.yaml +++ b/gm4_monsters_unbound/beet.yaml @@ -23,6 +23,7 @@ meta: - tick - main - slow_clock + echecks: [gm4:echeck/non_player_entity_on_team] website: description: Mobs gain special effects based on their biome. recommended: From fb74ace0e1491ead6478b8f6b01b255462bdd0af Mon Sep 17 00:00:00 2001 From: Bloo Date: Sat, 28 Feb 2026 12:50:57 +0100 Subject: [PATCH 17/17] Update Comments & Remove Probable Cause on Score ECheck --- base/data/gm4/function/echeck/assign_score.mcfunction | 4 ++-- base/data/gm4/function/echeck/join_team.mcfunction | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/base/data/gm4/function/echeck/assign_score.mcfunction b/base/data/gm4/function/echeck/assign_score.mcfunction index feeffaa030..69bf592911 100644 --- a/base/data/gm4/function/echeck/assign_score.mcfunction +++ b/base/data/gm4/function/echeck/assign_score.mcfunction @@ -9,8 +9,8 @@ scoreboard players set @s gm4_data 1 # if the score is present, mark the check as passed by removing it from storage execute if score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:1,probable_cause:""} -# 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:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} +# if no score is present, we don't know why this would happen. Good luck. +execute unless score @s gm4_data matches 1 run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,probable_cause:""} # clean up marker scoreboard players reset @s gm4_data diff --git a/base/data/gm4/function/echeck/join_team.mcfunction b/base/data/gm4/function/echeck/join_team.mcfunction index a5ed0961c4..8792840a0f 100644 --- a/base/data/gm4/function/echeck/join_team.mcfunction +++ b/base/data/gm4/function/echeck/join_team.mcfunction @@ -8,10 +8,10 @@ team join gm4_echeck_non_player_entity_on_team_temp @s # depending on test outcome, set the 'result' object in storage. Base uses this to test if the check has completed. -# if the score is present, mark the check as passed by removing it from storage +# if the marker is now on the team, mark the check as passed by removing it from storage execute if entity @s[team=gm4_echeck_non_player_entity_on_team_temp] run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:1,probable_cause:""} -# if no score is present, provide a probable cause message to the user +# if the marker is not on the team, provide a probable cause message to the user execute unless entity @s[team=gm4_echeck_non_player_entity_on_team_temp] run data modify storage gm4:log echecks[{echeck_id:"gm4:echeck/non_player_entity_has_score"}].result set value {passed:0,probable_cause:"This may be caused by the Paper/Spigot setting 'scoreboards.allow-non-player-entities-on-scoreboards=false'."} # clean up