mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Merge pull request #11706 from Bioneisme/fix/damage-type-command-ids
🤖 Agent: /damage ids now come from the world's damage catalog and are replaced on each world open, so a pack's type doesn't leak into the next world (union of 74 heads on main: fmt, clippy -D warnings, tests green).
This commit is contained in:
2 files changed
+148
No files matched your search
@@ -275,6 +275,25 @@ impl Registries {
|
||||
.clone_from(&e.advancement_criteria);
|
||||
}
|
||||
}
|
||||
/// Add the damage catalog's types ([`Self::damage_types`]: content mods'
|
||||
/// and the world's packs' with vanilla's) to the commands'
|
||||
/// `minecraft:damage_type` ids, which the export lists for vanilla alone.
|
||||
/// `ResourceArgument` looks a type up in the server's registries, so
|
||||
/// `/damage` takes every type the world has. The export's tags stay. The
|
||||
/// ids are replaced, not extended: `by_registry` outlives a world, and a
|
||||
/// pack's type must not stay accepted in the next world opened.
|
||||
pub fn sync_damage_type_ids(&mut self) {
|
||||
if self.damage_types.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut ids = self.damage_types.clone();
|
||||
ids.sort();
|
||||
ids.dedup();
|
||||
self.by_registry
|
||||
.entry("minecraft:damage_type".into())
|
||||
.or_default()
|
||||
.ids = ids;
|
||||
}
|
||||
/// The element ids of a registry (sorted).
|
||||
pub fn ids(&self, registry: &str) -> &[String] {
|
||||
if let Some(r) = self.by_registry.get(registry) {
|
||||
@@ -312,3 +331,49 @@ impl Registries {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Registries;
|
||||
|
||||
/// A content mod's damage type joins vanilla's in the commands' ids, the
|
||||
/// export's tags stay, and a second world open lists each type once.
|
||||
#[test]
|
||||
fn damage_type_ids_take_the_catalogs_types() {
|
||||
let export = Registries::from_export(&serde_json::json!({
|
||||
"by_registry": {"minecraft:damage_type": {
|
||||
"ids": ["minecraft:fall", "minecraft:magic"],
|
||||
"tags": ["minecraft:is_fall"],
|
||||
}},
|
||||
}));
|
||||
let mut reg = Registries {
|
||||
damage_types: vec![
|
||||
"minecraft:magic".into(),
|
||||
"example:test".into(),
|
||||
"minecraft:fall".into(),
|
||||
],
|
||||
..Registries::default()
|
||||
};
|
||||
reg.fill_from_exported(&export);
|
||||
assert_eq!(
|
||||
reg.ids("minecraft:damage_type"),
|
||||
["minecraft:fall", "minecraft:magic"],
|
||||
"the export alone lists vanilla's types"
|
||||
);
|
||||
for _ in 0..2 {
|
||||
reg.sync_damage_type_ids();
|
||||
assert_eq!(
|
||||
reg.ids("minecraft:damage_type"),
|
||||
["example:test", "minecraft:fall", "minecraft:magic"]
|
||||
);
|
||||
assert_eq!(reg.tags("minecraft:damage_type"), ["minecraft:is_fall"]);
|
||||
}
|
||||
// The next world, without the pack: its type is no longer accepted.
|
||||
reg.damage_types = vec!["minecraft:fall".into(), "minecraft:magic".into()];
|
||||
reg.sync_damage_type_ids();
|
||||
assert_eq!(
|
||||
reg.ids("minecraft:damage_type"),
|
||||
["minecraft:fall", "minecraft:magic"]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -684,6 +684,8 @@ impl Game<'_> {
|
||||
.map(|(k, _)| k.clone())
|
||||
.collect();
|
||||
self.sync_enchantment_registries();
|
||||
// After the export, which keys the registry with vanilla's tags.
|
||||
self.ui.registries.sync_damage_type_ids();
|
||||
}
|
||||
/// The block the player is looking at, for coordinate suggestions, and
|
||||
/// the entity, for entity arguments (ClientSuggestionProvider).
|
||||
@@ -2308,3 +2310,84 @@ mod enchantment_snapshot_tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod damage_type_registry_tests {
|
||||
use crate::game::{Audio, Game, Options, Progress, Settings, load_resources};
|
||||
|
||||
/// A world pack's damage type is a `/damage` type once the world opens,
|
||||
/// beside vanilla's, and the registry keeps vanilla's tags.
|
||||
#[test]
|
||||
#[ignore = "needs prepared resources in HORIZON_TEST_RESOURCES"]
|
||||
fn a_world_packs_damage_type_parses_in_damage() {
|
||||
let root = std::path::PathBuf::from(std::env::var_os("HORIZON_TEST_RESOURCES").unwrap());
|
||||
let settings = Settings::default();
|
||||
let loaded = load_resources(
|
||||
root.clone(),
|
||||
None,
|
||||
&root,
|
||||
&settings,
|
||||
std::time::Instant::now(),
|
||||
false,
|
||||
true,
|
||||
&Progress::new(),
|
||||
&mut |_, _| unreachable!(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut options = Options::parse(std::iter::empty()).unwrap().unwrap();
|
||||
options.resources = root.clone();
|
||||
options.execution_role = crate::game::execution_role::ExecutionRole::IntegratedServer;
|
||||
let mut game = Game::new(
|
||||
&loaded.resources,
|
||||
loaded.pack,
|
||||
loaded.gui.unwrap(),
|
||||
options,
|
||||
settings,
|
||||
Audio::silent(&root),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dir = std::path::PathBuf::from(std::env::var_os("HORIZON_HOME").unwrap())
|
||||
.join("damage-type-ids");
|
||||
let pack = dir.join("datapacks/model");
|
||||
let types = pack.join("data/example/damage_type");
|
||||
std::fs::create_dir_all(&types).unwrap();
|
||||
std::fs::write(pack.join("pack.mcmeta"), "{}").unwrap();
|
||||
std::fs::write(
|
||||
types.join("test.json"),
|
||||
r#"{"message_id":"example.test","scaling":"never","exhaustion":0.0}"#,
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(
|
||||
dir.join("datapacks.json"),
|
||||
r#"{"enabled":["file/model"],"disabled":[]}"#,
|
||||
)
|
||||
.unwrap();
|
||||
game.world_root = dir;
|
||||
(game.world_tables, game.health_resources) = game.build_world_tables(false, &[]).unwrap();
|
||||
game.level.allow_commands = Some(true);
|
||||
game.build_registries();
|
||||
|
||||
let reg = &game.ui.registries;
|
||||
assert!(
|
||||
reg.damage_types.contains(&"example:test".to_owned()),
|
||||
"the damage catalog holds the pack's type"
|
||||
);
|
||||
let parse = |input: &str| {
|
||||
horizon_client::command::vanilla::dispatcher()
|
||||
.parse(input, reg)
|
||||
.executable()
|
||||
.map(|_| ())
|
||||
.map_err(|e| format!("{e:?}"))
|
||||
};
|
||||
assert_eq!(parse("damage @s 1 example:test"), Ok(()));
|
||||
assert_eq!(parse("damage @s 1 minecraft:magic"), Ok(()));
|
||||
assert!(parse("damage @s 1 example:missing").is_err());
|
||||
assert!(
|
||||
reg.tags("minecraft:damage_type")
|
||||
.contains(&"minecraft:is_fire".to_owned()),
|
||||
"vanilla's damage type tags stay"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user