diff --git a/CHANGELOG.md b/CHANGELOG.md index b42e196162..cc582d70a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed wild roaming cyclop loot table to not drop the quarry key - Dungeons now have an outer wall, preventing them from intersecting with caves or leaving holes in sides of mountains. +- Location names are displayed in character selection dialog ## [0.15.0] - 2023-07-01 diff --git a/common/src/character.rs b/common/src/character.rs index 5b8bdd9501..112c1b67b7 100644 --- a/common/src/character.rs +++ b/common/src/character.rs @@ -25,4 +25,6 @@ pub struct CharacterItem { pub character: Character, pub body: comp::Body, pub inventory: Inventory, + // this string changes between database representation and human readable name in server.tick + pub location: Option, } diff --git a/server/src/lib.rs b/server/src/lib.rs index 4b19c3af17..d5aa548cea 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -894,10 +894,29 @@ impl Server { CharacterUpdaterMessage::CharacterScreenResponse(response) => { match response.response_kind { CharacterScreenResponseKind::CharacterList(result) => match result { - Ok(character_list_data) => self.notify_client( - response.target_entity, - ServerGeneral::CharacterListUpdate(character_list_data), - ), + Ok(mut character_list_data) => { + character_list_data.iter_mut().for_each(|c| { + let name = c + .location + .as_ref() + .and_then(|s| { + persistence::parse_waypoint(s).ok().and_then( + |(waypoint, _)| waypoint.map(|w| w.get_pos()), + ) + }) + .and_then(|wpos| { + self.world.get_location_name( + self.index.as_index_ref(), + wpos.xy().as_::(), + ) + }); + c.location = name; + }); + self.notify_client( + response.target_entity, + ServerGeneral::CharacterListUpdate(character_list_data), + ) + }, Err(error) => self.notify_client( response.target_entity, ServerGeneral::CharacterActionError(error.to_string()), diff --git a/server/src/persistence/character.rs b/server/src/persistence/character.rs index 2aa84ab530..3758dbd7dc 100644 --- a/server/src/persistence/character.rs +++ b/server/src/persistence/character.rs @@ -41,6 +41,8 @@ mod conversions; pub(crate) type EntityId = i64; +pub(crate) use conversions::convert_waypoint_from_database_json as parse_waypoint; + const CHARACTER_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.character"; const INVENTORY_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.inventory"; const LOADOUT_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.loadout"; @@ -297,7 +299,8 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara let mut stmt = connection.prepare_cached( " SELECT character_id, - alias + alias, + waypoint FROM character WHERE player_uuid = ?1 ORDER BY character_id", @@ -309,7 +312,7 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara character_id: row.get(0)?, alias: row.get(1)?, player_uuid: player_uuid_.to_owned(), - waypoint: None, // Not used for character select + waypoint: row.get(2)?, }) })? .map(|x| x.unwrap()) @@ -355,6 +358,7 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara character: char, body: char_body, inventory: Inventory::with_loadout(loadout, char_body), + location: character_data.waypoint.as_ref().cloned(), }) }) .collect() diff --git a/server/src/persistence/mod.rs b/server/src/persistence/mod.rs index 9d57370209..9b0e8f5e02 100644 --- a/server/src/persistence/mod.rs +++ b/server/src/persistence/mod.rs @@ -21,6 +21,9 @@ use std::{ }; use tracing::info; +// re-export waypoint parser for use to look up location names in character list +pub(crate) use character::parse_waypoint; + /// A struct of the components that are persisted to the DB for each character #[derive(Debug)] pub struct PersistedComponents { diff --git a/voxygen/src/menu/char_selection/ui/mod.rs b/voxygen/src/menu/char_selection/ui/mod.rs index 9bef967643..b11bf86690 100644 --- a/voxygen/src/menu/char_selection/ui/mod.rs +++ b/voxygen/src/menu/char_selection/ui/mod.rs @@ -623,10 +623,15 @@ impl Controls { Text::new(&character.character.alias) .size(fonts.cyri.scale(26)) .into(), - Text::new( - // TODO: Add actual location here - i18n.get_msg("char_selection-uncanny_valley"), - ) + Text::new(character.location.as_ref().map_or_else( + || { + i18n.get_msg( + "char_selection-uncanny_valley", + ) + .to_string() + }, + |s| s.clone(), + )) .into(), ]), ) diff --git a/world/src/lib.rs b/world/src/lib.rs index 9053045193..ffed2503f9 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -51,7 +51,8 @@ use common::{ resources::TimeOfDay, rtsim::ChunkResource, terrain::{ - Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid, + Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunk, TerrainChunkMeta, + TerrainChunkSize, TerrainGrid, }, vol::{ReadVol, RectVolSize, WriteVol}, }; @@ -685,4 +686,21 @@ impl World { lod::Zone { objects } } + + // determine waypoint name + pub fn get_location_name(&self, index: IndexRef, wpos2d: Vec2) -> Option { + let chunk_pos = wpos2d.wpos_to_cpos(); + let sim_chunk = self.sim.get(chunk_pos)?; + // TODO: Move this into SimChunk for reuse with above? + sim_chunk + .sites + .iter() + .filter(|id| { + index.sites[**id].get_origin().distance_squared(wpos2d) as f32 + <= index.sites[**id].radius().powi(2) + }) + .min_by_key(|id| index.sites[**id].get_origin().distance_squared(wpos2d)) + .map(|id| index.sites[*id].name().to_string()) + .or_else(|| sim_chunk.poi.map(|poi| self.civs.pois[poi].name.clone())) + } }