@@ -39,7 +39,7 @@ use crate::app::{
3939 AppState , BASE_SENSITIVITY_RAD_PER_PIXEL , Game , GameMode , PreloadState , RemotePlayerState ,
4040} ;
4141use crate :: camera:: CameraMode ;
42- use crate :: chunk_loader:: affected_chunks;
42+ use crate :: chunk_loader:: { affected_chunks, chunk_pos_of } ;
4343use crate :: input:: InputState ;
4444use crate :: mesh_jobs:: { MeshPriority , MeshRunStats } ;
4545use crate :: prediction:: {
@@ -1355,6 +1355,23 @@ fn render_connecting_frame(app: &Rc<RefCell<App>>, cw: u32, ch: u32) -> Result<(
13551355 renderer,
13561356 ) ;
13571357 drop ( server_mut) ;
1358+ } else if game. entity_id != 0 {
1359+ let mut server_mut = game. server . borrow_mut ( ) ;
1360+ let requests = game. chunk_loader . update_remote (
1361+ voxweb_server:: DEFAULT_SPAWN ,
1362+ & mut server_mut,
1363+ & mut game. mesh_jobs ,
1364+ renderer,
1365+ ) ;
1366+ drop ( server_mut) ;
1367+ if !requests. is_empty ( ) {
1368+ log:: debug!( "[remote] request {} spawn preload chunks" , requests. len( ) ) ;
1369+ game. net . send_client_message ( ClientMessage :: ChunkRequest {
1370+ center : chunk_pos_of ( voxweb_server:: DEFAULT_SPAWN ) ,
1371+ render_distance : game. chunk_loader . render_distance . max ( 0 ) as u32 ,
1372+ chunks : requests,
1373+ } ) ;
1374+ }
13581375 }
13591376
13601377 // 运行网格化(预载期间用 16ms 预算,比正常 4ms 更大)
@@ -1365,6 +1382,7 @@ fn render_connecting_frame(app: &Rc<RefCell<App>>, cw: u32, ch: u32) -> Result<(
13651382 // 统计已接收和已网格化的区块数
13661383 let spawn_center = crate :: chunk_loader:: chunk_pos_of ( voxweb_server:: DEFAULT_SPAWN ) ;
13671384 let r = game. chunk_loader . render_distance ;
1385+ preload. total = ( ( 2 * r + 1 ) * ( 2 * r + 1 ) ) as usize ;
13681386 let mut received = 0usize ;
13691387 let mut meshed = 0usize ;
13701388 for dx in -r..=r {
@@ -1744,7 +1762,7 @@ fn apply_room_event(app: &Rc<RefCell<App>>, ev: RoomEvent) {
17441762 // 网络连接完成,启动区块预载(不再直接进 InGame)
17451763 if a. state == AppState :: Connecting {
17461764 if let Some ( ref game) = a. game {
1747- let rd = game. settings . render_distance as i32 ;
1765+ let rd = game. chunk_loader . render_distance ;
17481766 let total = ( ( 2 * rd + 1 ) * ( 2 * rd + 1 ) ) as usize ;
17491767 a. preload_state = Some ( PreloadState {
17501768 total,
@@ -2032,8 +2050,9 @@ fn render_game_frame(
20322050 )
20332051 } ;
20342052
2035- // —— 5. ChunkLoader 滚动(仅 Local / Host;Remote 由 ChunkSnapshot / BlockUpdate 驱动) ——
2036- if mode != GameMode :: Remote {
2053+ // —— 5. ChunkLoader 滚动 ——
2054+ // Local/Host 直接生成;Remote 只请求缺失 chunk,由 Host 回 ChunkSnapshot。
2055+ {
20372056 let mut a = app. borrow_mut ( ) ;
20382057 let App {
20392058 ref mut renderer,
@@ -2044,8 +2063,28 @@ fn render_game_frame(
20442063 return Ok ( ( ) ) ;
20452064 } ;
20462065 let mut server_mut = game. server . borrow_mut ( ) ;
2047- game. chunk_loader
2048- . update ( camera_pos, & mut server_mut, & mut game. mesh_jobs , renderer) ;
2066+ if mode == GameMode :: Remote {
2067+ if game. entity_id != 0 {
2068+ let requests = game. chunk_loader . update_remote (
2069+ camera_pos,
2070+ & mut server_mut,
2071+ & mut game. mesh_jobs ,
2072+ renderer,
2073+ ) ;
2074+ drop ( server_mut) ;
2075+ if !requests. is_empty ( ) {
2076+ log:: debug!( "[remote] request {} chunks near camera" , requests. len( ) ) ;
2077+ game. net . send_client_message ( ClientMessage :: ChunkRequest {
2078+ center : chunk_pos_of ( camera_pos) ,
2079+ render_distance : game. chunk_loader . render_distance . max ( 0 ) as u32 ,
2080+ chunks : requests,
2081+ } ) ;
2082+ }
2083+ }
2084+ } else {
2085+ game. chunk_loader
2086+ . update ( camera_pos, & mut server_mut, & mut game. mesh_jobs , renderer) ;
2087+ }
20492088 }
20502089
20512090 // —— 6. mesh_jobs run_until_budget ——
@@ -2659,19 +2698,37 @@ fn ingest_server_clock_sample(game: &mut Game, estimated_offset_ms: f64, alpha:
26592698 game. server_clock_offset_ms = game. server_clock_offset_ms * ( 1.0 - a) + estimated_offset_ms * a;
26602699}
26612700
2701+ fn apply_host_render_distance ( game : & mut Game , host_render_distance : u32 ) {
2702+ let capped = host_render_distance. max ( 1 ) ;
2703+ let before = game. chunk_loader . render_distance ;
2704+ game. host_render_distance = capped;
2705+ game. apply_settings ( ) ;
2706+ let after = game. chunk_loader . render_distance ;
2707+ if game. mode == GameMode :: Remote && before != after {
2708+ log:: info!(
2709+ "[remote] effective render distance capped by host: requested={} host={} effective={}" ,
2710+ game. settings. render_distance,
2711+ capped,
2712+ after
2713+ ) ;
2714+ }
2715+ }
2716+
26622717fn apply_server_message ( game : & mut Game , msg : ServerMessage ) {
26632718 match msg {
26642719 ServerMessage :: Welcome {
26652720 entity_id,
26662721 world_seed,
26672722 host_entity_id,
2723+ host_render_distance,
26682724 players,
26692725 ..
26702726 } => {
26712727 game. entity_id = entity_id;
26722728 game. host_entity_id = host_entity_id;
2729+ apply_host_render_distance ( game, host_render_distance) ;
26732730 log:: info!(
2674- "Welcome v2 : entity_id={entity_id}, seed={world_seed}, host={host_entity_id}, roster_size={}" ,
2731+ "Welcome v3 : entity_id={entity_id}, seed={world_seed}, host={host_entity_id}, host_rd={host_render_distance }, roster_size={}" ,
26752732 players. len( )
26762733 ) ;
26772734 // 写入 roster:除自己以外的玩家进入 remote_players
@@ -2693,6 +2750,9 @@ fn apply_server_message(game: &mut Game, msg: ServerMessage) {
26932750 game. server . borrow_mut ( ) . world . chunks . clear ( ) ;
26942751 }
26952752 }
2753+ ServerMessage :: HostSettings { render_distance } => {
2754+ apply_host_render_distance ( game, render_distance) ;
2755+ }
26962756 ServerMessage :: ChunkSnapshot {
26972757 pos,
26982758 frag_index,
@@ -2707,6 +2767,7 @@ fn apply_server_message(game: &mut Game, msg: ServerMessage) {
27072767 Ok ( blocks) => {
27082768 let chunk = voxweb_core:: chunk:: Chunk { blocks } ;
27092769 game. server . borrow_mut ( ) . world . chunks . insert ( pos, chunk) ;
2770+ game. chunk_loader . mark_loaded ( pos) ;
27102771 // 自己 + 相邻 8 个 chunk 都重 mesh
27112772 for dz in -1 ..=1i32 {
27122773 for dx in -1 ..=1i32 {
0 commit comments