Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems showing Chunks with mods like Sodium or Starlight enabled(Anvil Example) #481

Open
FloGamerMC opened this issue Aug 19, 2023 · 3 comments
Labels
bug Something isn't working triage Bug has not been confirmed as real issue yet

Comments

@FloGamerMC
Copy link

Valence Version

e83c264

What You Did

I run and slightly modified version of the anvil_loading example. I changed the spawn not to be at 0 0, but it was not far from 0 0.

Playground
#![allow(clippy::type_complexity)]

use std::path::PathBuf;

use clap::Parser;
use valence::abilities::{FlyingSpeed, FovModifier, PlayerAbilitiesFlags};
use valence::message::SendMessage;
use valence::prelude::*;
use valence_anvil::{AnvilLevel, ChunkLoadEvent, ChunkLoadStatus};

const SPAWN_POS: DVec3 = DVec3::new(88.5, 87.5, -29.5);

#[derive(Parser, Resource)]
#[clap(author, version, about)]
struct Cli {
    /// The path to a Minecraft world save containing a `region` subdirectory.
    path: PathBuf,
}

pub fn main() {
    let cli = Cli::parse();

    if !cli.path.exists() {
        eprintln!(
            "Directory `{}` does not exist. Exiting.",
            cli.path.display()
        );
        return;
    }

    if !cli.path.is_dir() {
        eprintln!("`{}` is not a directory. Exiting.", cli.path.display());
        return;
    }

    App::new()
        .add_plugins(DefaultPlugins)
        .insert_resource(cli)
        .add_systems(Startup, setup)
        .add_systems(
            Update,
            (
                despawn_disconnected_clients,
                (init_clients, handle_chunk_loads).chain(),
                display_loaded_chunk_count,
            ),
        )
        .run();
}

fn setup(
    mut commands: Commands,
    dimensions: Res<DimensionTypeRegistry>,
    biomes: Res<BiomeRegistry>,
    server: Res<Server>,
    cli: Res<Cli>,
) {
    let layer = LayerBundle::new(ident!("overworld"), &dimensions, &biomes, &server);
    let mut level = AnvilLevel::new(&cli.path, &biomes);

    // Force a 16x16 area of chunks around the origin to be loaded at all times.
    // This is similar to "spawn chunks" in vanilla. This isn't necessary for the
    // example to function, but it's done to demonstrate that it's possible.
    for z in -8..8 {
        for x in -8..8 {
            let pos = ChunkPos::new(x, z);

            level.ignored_chunks.insert(pos);
            level.force_chunk_load(pos);
        }
    }

    commands.spawn((layer, level));
}

fn init_clients(
    mut clients: Query<
        (
            &mut EntityLayerId,
            &mut VisibleChunkLayer,
            &mut VisibleEntityLayers,
            &mut Position,
            &mut GameMode,
            &mut PlayerAbilitiesFlags,
            &mut FlyingSpeed,
            &mut FovModifier,
        ),
        Added<Client>,
    >,
    layers: Query<Entity, With<ChunkLayer>>,
) {
    for (
        mut layer_id,
        mut visible_chunk_layer,
        mut visible_entity_layers,
        mut pos,
        mut game_mode,
        mut abilities,
        mut flying_speed,
        mut fov_modifier,
    ) in &mut clients
    {
        let layer = layers.single();

        layer_id.0 = layer;
        visible_chunk_layer.0 = layer;
        visible_entity_layers.0.insert(layer);
        pos.set(SPAWN_POS);
        *game_mode = GameMode::Adventure;
        abilities.set_allow_flying(true);
        flying_speed.0 = 0.1;
        fov_modifier.0 = 0.05;
    }
}

fn handle_chunk_loads(
    mut events: EventReader<ChunkLoadEvent>,
    mut layers: Query<&mut ChunkLayer, With<AnvilLevel>>,
) {
    let mut layer = layers.single_mut();

    for event in events.iter() {
        match &event.status {
            ChunkLoadStatus::Success { .. } => {
                // The chunk was inserted into the world. Nothing for us to do.
            }
            ChunkLoadStatus::Empty => {
                // There's no chunk here so let's insert an empty chunk. If we were doing
                // terrain generation we would prepare that here.
                layer.insert_chunk(event.pos, UnloadedChunk::new());
            }
            ChunkLoadStatus::Failed(e) => {
                // Something went wrong.
                let errmsg = format!(
                    "failed to load chunk at ({}, {}): {e:#}",
                    event.pos.x, event.pos.z
                );

                eprintln!("{errmsg}");
                layer.send_chat_message(errmsg.color(Color::RED));

                layer.insert_chunk(event.pos, UnloadedChunk::new());
            }
        }
    }
}

// Display the number of loaded chunks in the action bar of all clients.
fn display_loaded_chunk_count(mut layers: Query<&mut ChunkLayer>, mut last_count: Local<usize>) {
    let mut layer = layers.single_mut();

    let cnt = layer.chunks().count();

    if *last_count != cnt {
        *last_count = cnt;
        layer.send_action_bar_message("Chunk Count: ".into_text() + cnt.color(Color::LIGHT_PURPLE));
    }
}

What Went Wrong

On clients with sodium or starlight or both installed, the chunks didn't shown up correctly and the client was long stuck at the "Loading terrain..." screen. I also tried this with different maps, so I can say for sure that this isn't a problem of this map.

I disused this problem on the discord server, a other user can reproduce this problem.

This Issue only occur on clients with sodium or starlight installed. On a vanilla client it works fine.

Additional Information

Link to the discord thread

My screenshot where you can see no chunks showing up
image

Screenshot of the other user in the discord thread
image

@FloGamerMC FloGamerMC added bug Something isn't working triage Bug has not been confirmed as real issue yet labels Aug 19, 2023
@Mac898
Copy link
Contributor

Mac898 commented Sep 21, 2023

This is also happening with me for a completely vanilla 1.20.1 client when loading an Anvil world.
I will try to do some investigating when I can, but I can re-confirm it occurs whenever the spawn position is set away from 0,0 for me.

Spawning the player in at more than +- 80-96 blocks in either direction seems to be when the issue occurs. This is exactly 5/6 chunks away.

As for the client log, that's quite interesting since there is a lot of:

[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -6, -6
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -6, -7
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -7, -6
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -5, -6
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -6, -5
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -7, -7
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -5, -7
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -7, -5
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -6, -8
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -8, -6
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -4, -6
[00:26:43] [Render thread/WARN]: Ignoring chunk since it's not in the view range: -6, -4

Update:
I've got a packet capture setup, and I can see that the valence server tends to send a lot more chunk packets than the vanilla one:

| Level Chunk With Light     | 1024 (98.75%) | 64104 (80.57%) |

vs

| Level Chunk With Light         |  453 ( 7.80%) | 2386807 (95.27%) |

However, this is the same as in the cases where the world does load properly:

| Level Chunk With Light     | 1024 (98.75%) | 4622204 (99.67%) |

vs

| Level Chunk With Light         |  453 (19.56%) | 2385156 (96.66%) |

All the measurements were taken in the same world at positions -80, surface, 0 (working) and -96, surface, 0 (not working).
Here's a link to the raw logs incase that helps anyone: https://gist.github.com/Mac898/6284cd75ee4029c4b226d90af3697d74

I'm curious if it's the order of the chunks that are making the big difference considering that the number of chunks sent by valence in the working vs non-working configuration are the same.

The hypothesis I will be testing is that valence is over-filling a cache, causing the minecraft client to forget the chunks that are actually needed, therefore causing the world holes.

Update:
The high number of chunks was caused by me force-loading a lot of the chunks. Here's an example with only -4 to 4 forcibly loaded.
https://gist.github.com/Mac898/f240afd3c9af23c5f2ac8b8debd88c48

@Mac898
Copy link
Contributor

Mac898 commented Sep 26, 2023

I found out that the difference in ordering of the player position and default spawn position packets in relation to the chunks was due to me using a encrypted/authenticated server in one case, and not in the other.

I've got new logs which have much more detail:
https://gist.github.com/Mac898/700a91d6dec5b78e5571aa6f0dfd2a74

However, looking over the diff carefully I see one main difference: "Set Chunk Cache Center"
https://wiki.vg/Protocol#Set_Center_Chunk
It's sent immediately after the default spawn position by the vanilla server.

My guess: Since we haven't initialized the buffer here the client isn't expecting the correct chunks and it ends up failing in some way. So i'm going to try and send this packet as the next debugging step.

We also send "Set Chunk Cache Radius", which according to the wiki is only sent by the integrated server:
https://wiki.vg/Protocol#Set_Render_Distance
That's another thing to check.

@Mac898
Copy link
Contributor

Mac898 commented Sep 26, 2023

I'm not sure that this in the right place, but I have a working diff:

index 776ecbc..f86ade4 100644
--- a/crates/valence_server/src/client.rs
+++ b/crates/valence_server/src/client.rs
@@ -600,10 +600,21 @@ pub fn despawn_disconnected_clients(
 }

 fn update_chunk_load_dist(
-    mut clients: Query<(&mut Client, &ViewDistance, &OldViewDistance), Changed<ViewDistance>>,
+    mut clients: Query<
+        (&mut Client, &ViewDistance, &OldViewDistance, &Position),
+        Changed<ViewDistance>,
+    >,
 ) {
-    for (mut client, dist, old_dist) in &mut clients {
+    for (mut client, dist, old_dist, pos) in &mut clients {
         if client.is_added() {
+            // TODO: Locate to a better place.
+            // Set Chunk Cache Center On First Load.
+            let chunk_pos = ChunkPos::from(pos.0);
+            client.write_packet(&ChunkRenderDistanceCenterS2c {
+                chunk_x: VarInt(chunk_pos.x),
+                chunk_z: VarInt(chunk_pos.z),
+            });
+
             // Join game packet includes the view distance.
             continue;
         }

Seems to solve the issue in Vanilla, and with Sodium/Iris modded client.
Note although that lighting is still broken for me with Sodium/Iris installed.

I'll happily PR this, but maybe someone with more experience could direct me on the appropriate place to put this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Bug has not been confirmed as real issue yet
Projects
None yet
Development

No branches or pull requests

2 participants