Leaf culling: account for active server packs

Include server resource-pack overlays in leaf and entity culling safety checks, and restore the selected leaf mode when a server pack is removed.

Co-Authored-By: Codex <[email protected]>
This commit is contained in:
ElyTheCatandCodex committed 2026-11-01 18:51:01 +03:30
1 parent 5c8a4156ff
commit cf2c59e1bd
4 files changed
+69 -12

No files matched your search

@@ -409,6 +409,19 @@ impl Graphics {
pub fn vanilla_models(&self, resource_packs: &[String]) -> bool {
resource_packs.iter().all(|id| id == "vanilla")
}
/// The same check including packs overlaid by the connected server.
/// Their ids are namespaced as `server/...`, so an active server pack
/// disables model-dependent occlusion assumptions.
pub fn vanilla_models_with_server_packs<'a>(
&self,
resource_packs: impl IntoIterator<Item = &'a str>,
server_packs: impl IntoIterator<Item = &'a str>,
) -> bool {
resource_packs
.into_iter()
.chain(server_packs)
.all(|id| id == "vanilla")
}
/// The leaf culling the mesher may apply. A pack that can replace leaf
/// models falls back to `Off`, which draws exactly vanilla's leaves.
pub fn leaf_culling_effective(&self, resource_packs: &[String]) -> LeafCullingMode {
@@ -418,6 +431,18 @@ impl Graphics {
LeafCullingMode::Off
}
}
/// The effective mode when local and server resource packs are active.
pub fn leaf_culling_effective_with_server_packs<'a>(
&self,
resource_packs: impl IntoIterator<Item = &'a str>,
server_packs: impl IntoIterator<Item = &'a str>,
) -> LeafCullingMode {
if self.vanilla_models_with_server_packs(resource_packs, server_packs) {
self.leaf_culling
} else {
LeafCullingMode::Off
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Graphics {
@@ -921,6 +946,30 @@ mod tests {
assert_eq!(g.leaf_culling_effective(&[]), LeafCullingMode::Hollow);
}
#[test]
fn server_pack_apply_disables_leaf_culling_and_removal_restores_it() {
let g = Graphics {
leaf_culling: LeafCullingMode::Solid,
..Graphics::default()
};
let selected = ["vanilla"];
let applied_server_pack = ["server/0123456789abcdef/model-pack.zip"];
assert_eq!(
g.leaf_culling_effective_with_server_packs(selected, applied_server_pack),
LeafCullingMode::Off,
"an applied server pack can replace block models"
);
assert!(!g.vanilla_models_with_server_packs(selected, applied_server_pack));
assert_eq!(
g.leaf_culling_effective_with_server_packs(selected, []),
LeafCullingMode::Solid,
"removing the server pack restores the selected local mode"
);
assert!(g.vanilla_models_with_server_packs(selected, []));
}
#[test]
fn integrated_gpus_other_than_apple_cap_the_lod_distance() {
let adapter = |name: &str, device_type| wgpu::AdapterInfo {
+1 -4
View File
@@ -13269,10 +13269,7 @@ impl Game<'_> {
self.streaming.radius = self.settings.render_distance;
// Options.biomeBlendRadius, ambientOcclusion, cutoutLeaves and the
// leaf-culling mode: LevelExtractor.allChanged when they change.
let leaf_culling = self
.settings
.horizon
.leaf_culling_effective(&self.settings.resource_packs);
let leaf_culling = self.effective_leaf_culling();
let (s, st) = (&self.settings, &self.streaming);
let remesh = (
s.biome_blend,
@@ -25,10 +25,7 @@ impl Game<'_> {
let at = camera.to_array().map(|v| v.floor() as i32);
self.entity_culler = (self.settings.horizon.entity_culling
// Packs can replace an opaque block's model or texture.
&& self
.settings
.horizon
.vanilla_models(&self.settings.resource_packs)
&& self.model_packs_are_vanilla()
&& self.player.is_some()
&& !self.spectator()
&& !opaque(self.res.facts().get(self.world.block(at[0], at[1], at[2]))))
+18 -4
View File
@@ -148,6 +148,23 @@ impl Game<'_> {
self.ui.vanilla_root.clone()
}
}
/// Whether all active packs preserve vanilla's block models. The server
/// overlay sits above the local selection and must be included too.
pub(super) fn model_packs_are_vanilla(&self) -> bool {
self.settings.horizon.vanilla_models_with_server_packs(
self.settings.resource_packs.iter().map(String::as_str),
self.server_packs.active.iter().map(|pack| pack.id.as_str()),
)
}
/// The leaf mode that is safe for the current local and server packs.
pub(super) fn effective_leaf_culling(&self) -> horizon_client::graphics::LeafCullingMode {
self.settings
.horizon
.leaf_culling_effective_with_server_packs(
self.settings.resource_packs.iter().map(String::as_str),
self.server_packs.active.iter().map(|pack| pack.id.as_str()),
)
}
/// The packs the pack screen offers and the current selection
/// (`PackSelectionScreen` makes its `PackSelectionModel` from them).
pub(super) fn refresh_pack_lists(&mut self) {
@@ -353,10 +370,7 @@ impl Game<'_> {
self.clear_lod();
// A pack that may replace leaf models falls back to `Off` before the
// reload marks every section dirty.
self.streaming.leaf_culling = self
.settings
.horizon
.leaf_culling_effective(&self.settings.resource_packs);
self.streaming.leaf_culling = self.effective_leaf_culling();
self.streaming.reload_resources(&mut self.world, context);
self.pending_uploads.clear();
// New GPU textures: a renderer built from the reloaded resources; the