mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'isse/shared-waypoints' into 'master'
Shared and persistent waypoints See merge request veloren/veloren!3162
This commit is contained in:
commit
df7cd2da1a
@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Convert giant trees to site2
|
||||
- Add new upgraded travelers
|
||||
- Wallrunning
|
||||
- Waypoints saved between sessions and shared with group members.
|
||||
|
||||
### Changed
|
||||
|
||||
|
BIN
assets/voxygen/element/ui/map/buttons/location_marker_group.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/ui/map/buttons/location_marker_group.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -32,6 +32,7 @@
|
||||
"hud.map.toggle_minimap_voxel": "Toggle Minimap Voxel View",
|
||||
"hud.map.zoom_minimap_explanation": "Zoom in the Minimap to see\nthe area around you in higher detail",
|
||||
"hud.map.gnarling": "Gnarling Fortification",
|
||||
"hud.map.placed_by": "Placed by {name}",
|
||||
},
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ use common::{
|
||||
slot::{EquipSlot, InvSlotId, Slot},
|
||||
CharacterState, ChatMode, ControlAction, ControlEvent, Controller, ControllerInputs,
|
||||
GroupManip, InputKind, InventoryAction, InventoryEvent, InventoryUpdateEvent,
|
||||
UtteranceKind,
|
||||
MapMarkerChange, UtteranceKind,
|
||||
},
|
||||
event::{EventBus, LocalEvent},
|
||||
grid::Grid,
|
||||
@ -112,6 +112,7 @@ pub enum Event {
|
||||
CharacterCreated(CharacterId),
|
||||
CharacterEdited(CharacterId),
|
||||
CharacterError(String),
|
||||
MapMarker(comp::MapMarkerUpdate),
|
||||
}
|
||||
|
||||
pub struct WorldData {
|
||||
@ -759,7 +760,8 @@ impl Client {
|
||||
| ClientGeneral::UnlockSkillGroup(_)
|
||||
| ClientGeneral::RequestPlayerPhysics { .. }
|
||||
| ClientGeneral::RequestLossyTerrainCompression { .. }
|
||||
| ClientGeneral::AcknowledgePersistenceLoadError => {
|
||||
| ClientGeneral::AcknowledgePersistenceLoadError
|
||||
| ClientGeneral::UpdateMapMarker(_) => {
|
||||
#[cfg(feature = "tracy")]
|
||||
{
|
||||
ingame = 1.0;
|
||||
@ -1190,6 +1192,10 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_marker_event(&mut self, event: MapMarkerChange) {
|
||||
self.send_msg(ClientGeneral::UpdateMapMarker(event));
|
||||
}
|
||||
|
||||
/// Checks whether a player can swap their weapon+ability `Loadout` settings
|
||||
/// and sends the `ControlAction` event that signals to do the swap.
|
||||
pub fn swap_loadout(&mut self) { self.control_action(ControlAction::SwapEquippedWeapons) }
|
||||
@ -1909,6 +1915,9 @@ impl Client {
|
||||
self.personalize_alias(uid, player_info.player_alias.clone())
|
||||
)),
|
||||
));
|
||||
frontend_events.push(Event::MapMarker(
|
||||
comp::MapMarkerUpdate::GroupMember(uid, MapMarkerChange::Remove),
|
||||
));
|
||||
}
|
||||
if self.group_members.remove(&uid).is_none() {
|
||||
warn!(
|
||||
@ -1931,10 +1940,12 @@ impl Client {
|
||||
if let Some(uid) = self.uid() {
|
||||
self.group_members.remove(&uid);
|
||||
}
|
||||
frontend_events.push(Event::MapMarker(comp::MapMarkerUpdate::ClearGroup));
|
||||
},
|
||||
NoGroup => {
|
||||
self.group_leader = None;
|
||||
self.group_members = HashMap::new();
|
||||
frontend_events.push(Event::MapMarker(comp::MapMarkerUpdate::ClearGroup));
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -2032,6 +2043,9 @@ impl Client {
|
||||
rich.economy = Some(economy);
|
||||
}
|
||||
},
|
||||
ServerGeneral::MapMarker(event) => {
|
||||
frontend_events.push(Event::MapMarker(event));
|
||||
},
|
||||
_ => unreachable!("Not a in_game message"),
|
||||
}
|
||||
Ok(())
|
||||
|
@ -78,6 +78,7 @@ pub enum ClientGeneral {
|
||||
UnlockSkill(Skill),
|
||||
UnlockSkillGroup(SkillGroupKind),
|
||||
RequestSiteInfo(SiteId),
|
||||
UpdateMapMarker(comp::MapMarkerChange),
|
||||
//Only in Game, via terrain stream
|
||||
TerrainChunkRequest {
|
||||
key: Vec2<i32>,
|
||||
@ -132,7 +133,8 @@ impl ClientMsg {
|
||||
| ClientGeneral::UnlockSkillGroup(_)
|
||||
| ClientGeneral::RequestPlayerPhysics { .. }
|
||||
| ClientGeneral::RequestLossyTerrainCompression { .. }
|
||||
| ClientGeneral::AcknowledgePersistenceLoadError => {
|
||||
| ClientGeneral::AcknowledgePersistenceLoadError
|
||||
| ClientGeneral::UpdateMapMarker(_) => {
|
||||
c_type == ClientType::Game && presence.is_some()
|
||||
},
|
||||
//Always possible
|
||||
|
@ -189,6 +189,7 @@ pub enum ServerGeneral {
|
||||
FinishedTrade(TradeResult),
|
||||
/// Economic information about sites
|
||||
SiteEconomy(EconomyInfo),
|
||||
MapMarker(comp::MapMarkerUpdate),
|
||||
}
|
||||
|
||||
impl ServerGeneral {
|
||||
@ -298,7 +299,8 @@ impl ServerMsg {
|
||||
| ServerGeneral::Knockback(_)
|
||||
| ServerGeneral::UpdatePendingTrade(_, _, _)
|
||||
| ServerGeneral::FinishedTrade(_)
|
||||
| ServerGeneral::SiteEconomy(_) => {
|
||||
| ServerGeneral::SiteEconomy(_)
|
||||
| ServerGeneral::MapMarker(_) => {
|
||||
c_type == ClientType::Game && presence.is_some()
|
||||
},
|
||||
// Always possible
|
||||
|
@ -62,9 +62,9 @@ pub enum ChangeNotification<E> {
|
||||
// Also note when the same notification is sent to multiple destinations the
|
||||
// mapping might be duplicated effort
|
||||
impl<E> ChangeNotification<E> {
|
||||
pub fn try_map<T>(self, f: impl Fn(E) -> Option<T>) -> Option<ChangeNotification<T>> {
|
||||
pub fn try_map_ref<T>(&self, f: impl Fn(&E) -> Option<T>) -> Option<ChangeNotification<T>> {
|
||||
match self {
|
||||
Self::Added(e, r) => f(e).map(|t| ChangeNotification::Added(t, r)),
|
||||
Self::Added(e, r) => f(e).map(|t| ChangeNotification::Added(t, *r)),
|
||||
Self::Removed(e) => f(e).map(ChangeNotification::Removed),
|
||||
Self::NewLeader(e) => f(e).map(ChangeNotification::NewLeader),
|
||||
// Note just discards members that fail map
|
||||
@ -72,8 +72,8 @@ impl<E> ChangeNotification<E> {
|
||||
f(leader).map(|leader| ChangeNotification::NewGroup {
|
||||
leader,
|
||||
members: members
|
||||
.into_iter()
|
||||
.filter_map(|(e, r)| f(e).map(|t| (t, r)))
|
||||
.iter()
|
||||
.filter_map(|(e, r)| f(e).map(|t| (t, *r)))
|
||||
.collect(),
|
||||
})
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::resources::Time;
|
||||
use crate::{resources::Time, uid::Uid};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::Component;
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -45,3 +45,25 @@ impl Component for WaypointArea {
|
||||
impl Default for WaypointArea {
|
||||
fn default() -> Self { Self(5.0) }
|
||||
}
|
||||
|
||||
/// Marker on the map, used for sharing waypoint with group and
|
||||
/// persisting it server side.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MapMarker(pub Vec2<i32>);
|
||||
|
||||
impl Component for MapMarker {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum MapMarkerChange {
|
||||
Update(Vec2<i32>),
|
||||
Remove,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum MapMarkerUpdate {
|
||||
Owned(MapMarkerChange),
|
||||
GroupMember(Uid, MapMarkerChange),
|
||||
ClearGroup,
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ pub use self::{
|
||||
slot, Inventory, InventoryUpdate, InventoryUpdateEvent,
|
||||
},
|
||||
last::Last,
|
||||
location::{Waypoint, WaypointArea},
|
||||
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
|
||||
melee::{Melee, MeleeConstructor},
|
||||
misc::Object,
|
||||
ori::Ori,
|
||||
|
@ -115,6 +115,7 @@ pub enum ServerEvent {
|
||||
Option<comp::Waypoint>,
|
||||
Vec<(comp::Pet, comp::Body, comp::Stats)>,
|
||||
comp::ActiveAbilities,
|
||||
Option<comp::MapMarker>,
|
||||
),
|
||||
},
|
||||
ExitIngame {
|
||||
@ -209,6 +210,10 @@ pub enum ServerEvent {
|
||||
auxiliary_key: comp::ability::AuxiliaryKey,
|
||||
new_ability: comp::ability::AuxiliaryAbility,
|
||||
},
|
||||
UpdateMapMarker {
|
||||
entity: EcsEntity,
|
||||
update: comp::MapMarkerChange,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -191,6 +191,7 @@ impl State {
|
||||
ecs.register::<comp::InventoryUpdate>();
|
||||
ecs.register::<comp::Admin>();
|
||||
ecs.register::<comp::Waypoint>();
|
||||
ecs.register::<comp::MapMarker>();
|
||||
ecs.register::<comp::Projectile>();
|
||||
ecs.register::<comp::Melee>();
|
||||
ecs.register::<comp::ItemDrop>();
|
||||
|
@ -64,6 +64,7 @@ pub fn create_character(
|
||||
.expect("Inventory has at least 1 slot left!");
|
||||
|
||||
let waypoint = None;
|
||||
let map_marker = None;
|
||||
|
||||
character_updater.create_character(entity, player_uuid, character_alias, PersistedComponents {
|
||||
body,
|
||||
@ -73,6 +74,7 @@ pub fn create_character(
|
||||
waypoint,
|
||||
pets: Vec::new(),
|
||||
active_abilities: Default::default(),
|
||||
map_marker,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
@ -185,7 +185,8 @@ impl Client {
|
||||
| ServerGeneral::Knockback(_)
|
||||
| ServerGeneral::SiteEconomy(_)
|
||||
| ServerGeneral::UpdatePendingTrade(_, _, _)
|
||||
| ServerGeneral::FinishedTrade(_) => {
|
||||
| ServerGeneral::FinishedTrade(_)
|
||||
| ServerGeneral::MapMarker(_) => {
|
||||
PreparedMsg::new(2, &g, &self.in_game_stream_params)
|
||||
},
|
||||
//Ingame related, terrain
|
||||
|
@ -22,6 +22,8 @@ use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use std::time::Duration;
|
||||
use vek::{Rgb, Vec3};
|
||||
|
||||
use super::group_manip::update_map_markers;
|
||||
|
||||
pub fn handle_initialize_character(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
@ -35,6 +37,14 @@ pub fn handle_loaded_character_data(
|
||||
entity: EcsEntity,
|
||||
loaded_components: PersistedComponents,
|
||||
) {
|
||||
if let Some(marker) = loaded_components.map_marker {
|
||||
server.notify_client(
|
||||
entity,
|
||||
ServerGeneral::MapMarker(comp::MapMarkerUpdate::Owned(comp::MapMarkerChange::Update(
|
||||
marker.0,
|
||||
))),
|
||||
);
|
||||
}
|
||||
server
|
||||
.state
|
||||
.update_character_data(entity, loaded_components);
|
||||
@ -103,6 +113,7 @@ pub fn handle_create_npc(
|
||||
let uids = state.ecs().read_storage::<Uid>();
|
||||
let mut group_manager = state.ecs().write_resource::<comp::group::GroupManager>();
|
||||
if let Some(owner) = state.ecs().entity_from_uid(owner_uid.into()) {
|
||||
let map_markers = state.ecs().read_storage::<comp::MapMarker>();
|
||||
group_manager.new_pet(
|
||||
new_entity,
|
||||
owner,
|
||||
@ -115,10 +126,13 @@ pub fn handle_create_npc(
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| {
|
||||
// Might be unneccessary, but maybe pets can somehow have map
|
||||
// markers in the future
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
|
@ -1267,3 +1267,41 @@ pub fn handle_change_ability(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_update_map_marker(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
update: comp::MapMarkerChange,
|
||||
) {
|
||||
use comp::{MapMarker, MapMarkerChange::*};
|
||||
match update {
|
||||
Update(waypoint) => {
|
||||
server
|
||||
.state
|
||||
.write_component_ignore_entity_dead(entity, MapMarker(waypoint));
|
||||
},
|
||||
Remove => {
|
||||
server.state.delete_component::<MapMarker>(entity);
|
||||
},
|
||||
}
|
||||
let ecs = server.state.ecs_mut();
|
||||
// Send updated waypoint to group members
|
||||
let groups = ecs.read_storage();
|
||||
let uids = ecs.read_storage();
|
||||
if let Some((group_id, uid)) = groups.get(entity).zip(uids.get(entity)) {
|
||||
let clients = ecs.read_storage::<Client>();
|
||||
for client in comp::group::members(
|
||||
*group_id,
|
||||
&groups,
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage(),
|
||||
&uids,
|
||||
)
|
||||
.filter_map(|(e, _)| if e != entity { clients.get(e) } else { None })
|
||||
{
|
||||
client.send_fallible(ServerGeneral::MapMarker(
|
||||
comp::MapMarkerUpdate::GroupMember(*uid, update),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::{client::Client, Server};
|
||||
use common::{
|
||||
comp::{
|
||||
self,
|
||||
group::{self, Group, GroupManager},
|
||||
group::{self, ChangeNotification, Group, GroupManager},
|
||||
invite::{InviteKind, PendingInvites},
|
||||
ChatType, GroupManip,
|
||||
},
|
||||
@ -81,6 +81,37 @@ pub fn can_invite(
|
||||
true
|
||||
}
|
||||
|
||||
pub fn update_map_markers<'a>(
|
||||
map_markers: &ReadStorage<'a, comp::MapMarker>,
|
||||
uids: &ReadStorage<'a, Uid>,
|
||||
client: &Client,
|
||||
change: &ChangeNotification<Entity>,
|
||||
) {
|
||||
use comp::group::ChangeNotification::*;
|
||||
let send_update = |entity| {
|
||||
if let (Some(map_marker), Some(uid)) = (map_markers.get(entity), uids.get(entity)) {
|
||||
client.send_fallible(ServerGeneral::MapMarker(
|
||||
comp::MapMarkerUpdate::GroupMember(
|
||||
*uid,
|
||||
comp::MapMarkerChange::Update(map_marker.0),
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
match change {
|
||||
&Added(entity, _) => {
|
||||
send_update(entity);
|
||||
},
|
||||
NewGroup { leader: _, members } => {
|
||||
for (entity, _) in members {
|
||||
send_update(*entity);
|
||||
}
|
||||
},
|
||||
// Removed and NoGroup can be inferred by the client, NewLeader does not affect map markers
|
||||
Removed(_) | NoGroup | NewLeader(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: turn chat messages into enums
|
||||
pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupManip) {
|
||||
match manip {
|
||||
@ -89,6 +120,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
let clients = state.ecs().read_storage::<Client>();
|
||||
let uids = state.ecs().read_storage::<Uid>();
|
||||
let mut group_manager = state.ecs().write_resource::<GroupManager>();
|
||||
let map_markers = state.ecs().read_storage::<comp::MapMarker>();
|
||||
group_manager.leave_group(
|
||||
entity,
|
||||
&mut state.ecs().write_storage(),
|
||||
@ -100,10 +132,13 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -151,6 +186,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
|
||||
let mut groups = state.ecs().write_storage::<group::Group>();
|
||||
let mut group_manager = state.ecs().write_resource::<GroupManager>();
|
||||
let map_markers = state.ecs().read_storage::<comp::MapMarker>();
|
||||
// Make sure kicker is the group leader
|
||||
match groups
|
||||
.get(target)
|
||||
@ -169,10 +205,13 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@ -230,6 +269,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
};
|
||||
let groups = state.ecs().read_storage::<group::Group>();
|
||||
let mut group_manager = state.ecs().write_resource::<GroupManager>();
|
||||
let map_markers = state.ecs().read_storage::<comp::MapMarker>();
|
||||
// Make sure assigner is the group leader
|
||||
match groups
|
||||
.get(target)
|
||||
@ -248,10 +288,13 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
// Tell them they are the leader
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::group_manip;
|
||||
use super::group_manip::{self, update_map_markers};
|
||||
use crate::{client::Client, Server};
|
||||
use common::{
|
||||
comp::{
|
||||
@ -202,6 +202,7 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
|
||||
|
||||
match kind {
|
||||
InviteKind::Group => {
|
||||
let map_markers = state.ecs().read_storage::<comp::MapMarker>();
|
||||
let mut group_manager = state.ecs().write_resource::<GroupManager>();
|
||||
group_manager.add_group_member(
|
||||
inviter,
|
||||
@ -215,10 +216,13 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
|
@ -12,7 +12,7 @@ use entity_manipulation::{
|
||||
handle_aura, handle_bonk, handle_buff, handle_change_ability, handle_combo_change,
|
||||
handle_delete, handle_destroy, handle_energy_change, handle_entity_attacked_hook,
|
||||
handle_explosion, handle_health_change, handle_knockback, handle_land_on_ground, handle_parry,
|
||||
handle_poise, handle_respawn, handle_teleport_to,
|
||||
handle_poise, handle_respawn, handle_teleport_to, handle_update_map_marker,
|
||||
};
|
||||
use group_manip::handle_group;
|
||||
use information::handle_site_info;
|
||||
@ -26,6 +26,8 @@ use player::{handle_client_disconnect, handle_exit_ingame};
|
||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use trade::{cancel_trade_for, handle_process_trade_action};
|
||||
|
||||
pub use group_manip::update_map_markers;
|
||||
|
||||
mod entity_creation;
|
||||
mod entity_manipulation;
|
||||
mod group_manip;
|
||||
@ -132,8 +134,16 @@ impl Server {
|
||||
character_id,
|
||||
} => handle_initialize_character(self, entity, character_id),
|
||||
ServerEvent::UpdateCharacterData { entity, components } => {
|
||||
let (body, stats, skill_set, inventory, waypoint, pets, active_abilities) =
|
||||
components;
|
||||
let (
|
||||
body,
|
||||
stats,
|
||||
skill_set,
|
||||
inventory,
|
||||
waypoint,
|
||||
pets,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
) = components;
|
||||
let components = PersistedComponents {
|
||||
body,
|
||||
stats,
|
||||
@ -142,6 +152,7 @@ impl Server {
|
||||
waypoint,
|
||||
pets,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
};
|
||||
handle_loaded_character_data(self, entity, components);
|
||||
},
|
||||
@ -253,6 +264,9 @@ impl Server {
|
||||
auxiliary_key,
|
||||
new_ability,
|
||||
} => handle_change_ability(self, entity, slot, auxiliary_key, new_ability),
|
||||
ServerEvent::UpdateMapMarker { entity, update } => {
|
||||
handle_update_map_marker(self, entity, update)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,11 @@ fn persist_entity(state: &mut State, entity: EcsEntity) -> EcsEntity {
|
||||
.read_storage::<common::comp::Waypoint>()
|
||||
.get(entity)
|
||||
.cloned();
|
||||
let map_marker = state
|
||||
.ecs()
|
||||
.read_storage::<common::comp::MapMarker>()
|
||||
.get(entity)
|
||||
.cloned();
|
||||
// Store last battle mode change
|
||||
if let Some(change) = player_info.last_battlemode_change {
|
||||
let mode = player_info.battle_mode;
|
||||
@ -261,6 +266,7 @@ fn persist_entity(state: &mut State, entity: EcsEntity) -> EcsEntity {
|
||||
pets,
|
||||
waypoint,
|
||||
active_abilities.clone(),
|
||||
map_marker,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -887,6 +887,7 @@ impl Server {
|
||||
waypoint,
|
||||
pets,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
} = character_data;
|
||||
let character_data = (
|
||||
body,
|
||||
@ -896,6 +897,7 @@ impl Server {
|
||||
waypoint,
|
||||
pets,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
);
|
||||
ServerEvent::UpdateCharacterData {
|
||||
entity: query_result.entity,
|
||||
|
@ -148,19 +148,22 @@ pub fn load_character_data(
|
||||
},
|
||||
)?;
|
||||
|
||||
let char_waypoint = character_data.waypoint.as_ref().and_then(|x| {
|
||||
match convert_waypoint_from_database_json(x) {
|
||||
Ok(w) => Some(w),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Error reading waypoint from database for character ID
|
||||
let (char_waypoint, char_map_marker) = match character_data
|
||||
.waypoint
|
||||
.as_ref()
|
||||
.map(|x| convert_waypoint_from_database_json(x))
|
||||
{
|
||||
Some(Ok(w)) => w,
|
||||
Some(Err(e)) => {
|
||||
warn!(
|
||||
"Error reading waypoint from database for character ID
|
||||
{}, error: {}",
|
||||
char_id, e
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
});
|
||||
char_id, e
|
||||
);
|
||||
(None, None)
|
||||
},
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
let mut stmt = connection.prepare_cached(
|
||||
"
|
||||
@ -261,6 +264,7 @@ pub fn load_character_data(
|
||||
waypoint: char_waypoint,
|
||||
pets,
|
||||
active_abilities: convert_active_abilities_from_database(&ability_set_data),
|
||||
map_marker: char_map_marker,
|
||||
})
|
||||
}
|
||||
|
||||
@ -354,6 +358,7 @@ pub fn create_character(
|
||||
waypoint,
|
||||
pets: _,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
} = persisted_components;
|
||||
|
||||
// Fetch new entity IDs for character, inventory and loadout
|
||||
@ -438,7 +443,7 @@ pub fn create_character(
|
||||
&character_id as &dyn ToSql,
|
||||
&uuid,
|
||||
&character_alias,
|
||||
&convert_waypoint_to_database_json(waypoint),
|
||||
&convert_waypoint_to_database_json(waypoint, map_marker),
|
||||
])?;
|
||||
drop(stmt);
|
||||
|
||||
@ -935,6 +940,8 @@ fn delete_pets(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn update(
|
||||
char_id: CharacterId,
|
||||
char_skill_set: comp::SkillSet,
|
||||
@ -942,6 +949,7 @@ pub fn update(
|
||||
pets: Vec<PetPersistenceData>,
|
||||
char_waypoint: Option<comp::Waypoint>,
|
||||
active_abilities: comp::ability::ActiveAbilities,
|
||||
map_marker: Option<comp::MapMarker>,
|
||||
transaction: &mut Transaction,
|
||||
) -> Result<(), PersistenceError> {
|
||||
// Run pet persistence
|
||||
@ -1066,7 +1074,7 @@ pub fn update(
|
||||
])?;
|
||||
}
|
||||
|
||||
let db_waypoint = convert_waypoint_to_database_json(char_waypoint);
|
||||
let db_waypoint = convert_waypoint_to_database_json(char_waypoint, map_marker);
|
||||
|
||||
let mut stmt = transaction.prepare_cached(
|
||||
"
|
||||
@ -1103,7 +1111,7 @@ pub fn update(
|
||||
if ability_sets_count != 1 {
|
||||
return Err(PersistenceError::OtherError(format!(
|
||||
"Error updating ability_set table for char_id {}",
|
||||
char_id
|
||||
char_id,
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -217,28 +217,30 @@ pub fn convert_body_to_database_json(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn convert_waypoint_to_database_json(waypoint: Option<Waypoint>) -> Option<String> {
|
||||
match waypoint {
|
||||
Some(w) => {
|
||||
let charpos = CharacterPosition {
|
||||
waypoint: w.get_pos(),
|
||||
};
|
||||
Some(
|
||||
serde_json::to_string(&charpos)
|
||||
.map_err(|err| {
|
||||
PersistenceError::ConversionError(format!(
|
||||
"Error encoding waypoint: {:?}",
|
||||
err
|
||||
))
|
||||
})
|
||||
.ok()?,
|
||||
)
|
||||
},
|
||||
None => None,
|
||||
pub fn convert_waypoint_to_database_json(
|
||||
waypoint: Option<Waypoint>,
|
||||
map_marker: Option<MapMarker>,
|
||||
) -> Option<String> {
|
||||
if waypoint.is_some() || map_marker.is_some() {
|
||||
let charpos = CharacterPosition {
|
||||
waypoint: waypoint.map(|w| w.get_pos()),
|
||||
map_marker: map_marker.map(|m| m.0),
|
||||
};
|
||||
Some(
|
||||
serde_json::to_string(&charpos)
|
||||
.map_err(|err| {
|
||||
PersistenceError::ConversionError(format!("Error encoding waypoint: {:?}", err))
|
||||
})
|
||||
.ok()?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_waypoint_from_database_json(position: &str) -> Result<Waypoint, PersistenceError> {
|
||||
pub fn convert_waypoint_from_database_json(
|
||||
position: &str,
|
||||
) -> Result<(Option<Waypoint>, Option<MapMarker>), PersistenceError> {
|
||||
let character_position =
|
||||
serde_json::de::from_str::<CharacterPosition>(position).map_err(|err| {
|
||||
PersistenceError::ConversionError(format!(
|
||||
@ -246,7 +248,12 @@ pub fn convert_waypoint_from_database_json(position: &str) -> Result<Waypoint, P
|
||||
position, err
|
||||
))
|
||||
})?;
|
||||
Ok(Waypoint::new(character_position.waypoint, Time(0.0)))
|
||||
Ok((
|
||||
character_position
|
||||
.waypoint
|
||||
.map(|pos| Waypoint::new(pos, Time(0.0))),
|
||||
character_position.map_marker.map(MapMarker),
|
||||
))
|
||||
}
|
||||
|
||||
/// Properly-recursive items (currently modular weapons) occupy the same
|
||||
|
@ -25,6 +25,7 @@ pub type CharacterUpdateData = (
|
||||
Vec<PetPersistenceData>,
|
||||
Option<comp::Waypoint>,
|
||||
comp::ability::ActiveAbilities,
|
||||
Option<comp::MapMarker>,
|
||||
);
|
||||
|
||||
pub type PetPersistenceData = (comp::Pet, comp::Body, comp::Stats);
|
||||
@ -332,12 +333,21 @@ impl CharacterUpdater {
|
||||
Vec<PetPersistenceData>,
|
||||
Option<&'a comp::Waypoint>,
|
||||
&'a comp::ability::ActiveAbilities,
|
||||
Option<&'a comp::MapMarker>,
|
||||
),
|
||||
>,
|
||||
) {
|
||||
let updates = updates
|
||||
.map(
|
||||
|(character_id, skill_set, inventory, pets, waypoint, active_abilities)| {
|
||||
|(
|
||||
character_id,
|
||||
skill_set,
|
||||
inventory,
|
||||
pets,
|
||||
waypoint,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
)| {
|
||||
(
|
||||
character_id,
|
||||
(
|
||||
@ -346,6 +356,7 @@ impl CharacterUpdater {
|
||||
pets,
|
||||
waypoint.cloned(),
|
||||
active_abilities.clone(),
|
||||
map_marker.cloned(),
|
||||
),
|
||||
)
|
||||
},
|
||||
@ -388,7 +399,7 @@ fn execute_batch_update(
|
||||
transaction.set_drop_behavior(DropBehavior::Rollback);
|
||||
trace!("Transaction started for character batch update");
|
||||
updates.into_iter().try_for_each(
|
||||
|(character_id, (stats, inventory, pets, waypoint, active_abilities))| {
|
||||
|(character_id, (stats, inventory, pets, waypoint, active_abilities, map_marker))| {
|
||||
super::character::update(
|
||||
character_id,
|
||||
stats,
|
||||
@ -396,6 +407,7 @@ fn execute_batch_update(
|
||||
pets,
|
||||
waypoint,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
&mut transaction,
|
||||
)
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ use common_base::dev_panic;
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::string::ToString;
|
||||
use vek::Vec3;
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct HumanoidBody {
|
||||
@ -62,7 +62,8 @@ generic_body_from_impl!(comp::quadruped_small::Body);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CharacterPosition {
|
||||
pub waypoint: Vec3<f32>,
|
||||
pub waypoint: Option<Vec3<f32>>,
|
||||
pub map_marker: Option<Vec2<i32>>,
|
||||
}
|
||||
|
||||
pub fn skill_group_to_db_string(skill_group: comp::skillset::SkillGroupKind) -> String {
|
||||
|
@ -31,6 +31,7 @@ pub struct PersistedComponents {
|
||||
pub waypoint: Option<comp::Waypoint>,
|
||||
pub pets: Vec<PetPersistenceData>,
|
||||
pub active_abilities: comp::ActiveAbilities,
|
||||
pub map_marker: Option<comp::MapMarker>,
|
||||
}
|
||||
|
||||
pub type EditableComponents = (comp::Body,);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::client::Client;
|
||||
use crate::{client::Client, events::update_map_markers};
|
||||
use common::{
|
||||
comp::{anchor::Anchor, group::GroupManager, Agent, Alignment, Pet},
|
||||
comp::{self, anchor::Anchor, group::GroupManager, Agent, Alignment, Pet},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::msg::ServerGeneral;
|
||||
@ -59,6 +59,7 @@ fn tame_pet_internal(ecs: &specs::World, pet_entity: Entity, owner: Entity, pet:
|
||||
// Add to group system
|
||||
let clients = ecs.read_storage::<Client>();
|
||||
let mut group_manager = ecs.write_resource::<GroupManager>();
|
||||
let map_markers = ecs.read_storage::<comp::MapMarker>();
|
||||
group_manager.new_pet(
|
||||
pet_entity,
|
||||
owner,
|
||||
@ -71,10 +72,15 @@ fn tame_pet_internal(ecs: &specs::World, pet_entity: Entity, owner: Entity, pet:
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send_fallible(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
// Might be unneccessary, but maybe pets can somehow have map
|
||||
// markers in the future
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
client::Client,
|
||||
events::update_map_markers,
|
||||
persistence::PersistedComponents,
|
||||
pet::restore_pet,
|
||||
presence::{Presence, RepositionOnChunkLoad},
|
||||
@ -526,6 +527,7 @@ impl StateExt for State {
|
||||
waypoint,
|
||||
pets,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
} = components;
|
||||
|
||||
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
|
||||
@ -572,6 +574,10 @@ impl StateExt for State {
|
||||
self.write_component_ignore_entity_dead(entity, comp::ForceUpdate);
|
||||
}
|
||||
|
||||
if let Some(map_marker) = map_marker {
|
||||
self.write_component_ignore_entity_dead(entity, map_marker);
|
||||
}
|
||||
|
||||
let player_pos = self.ecs().read_storage::<comp::Pos>().get(entity).copied();
|
||||
if let Some(player_pos) = player_pos {
|
||||
trace!(
|
||||
@ -885,6 +891,7 @@ impl StateExt for State {
|
||||
let clients = self.ecs().read_storage::<Client>();
|
||||
let uids = self.ecs().read_storage::<Uid>();
|
||||
let mut group_manager = self.ecs().write_resource::<comp::group::GroupManager>();
|
||||
let map_markers = self.ecs().read_storage::<comp::MapMarker>();
|
||||
group_manager.entity_deleted(
|
||||
entity,
|
||||
&mut self.ecs().write_storage(),
|
||||
@ -896,10 +903,13 @@ impl StateExt for State {
|
||||
.get(entity)
|
||||
.and_then(|c| {
|
||||
group_change
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.try_map_ref(|e| uids.get(*e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g)));
|
||||
.map(|(g, c)| {
|
||||
update_map_markers(&map_markers, &uids, c, &group_change);
|
||||
c.send_fallible(ServerGeneral::GroupUpdate(g));
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -285,6 +285,9 @@ impl Sys {
|
||||
.get_mut(entity)
|
||||
.map(|mut skill_set| skill_set.persistence_load_error = None);
|
||||
},
|
||||
ClientGeneral::UpdateMapMarker(update) => {
|
||||
server_emitter.emit(ServerEvent::UpdateMapMarker { entity, update });
|
||||
},
|
||||
ClientGeneral::RequestCharacterList
|
||||
| ClientGeneral::CreateCharacter { .. }
|
||||
| ClientGeneral::EditCharacter { .. }
|
||||
|
@ -2,7 +2,7 @@ use crate::{persistence::character_updater, presence::Presence, sys::SysSchedule
|
||||
use common::{
|
||||
comp::{
|
||||
pet::{is_tameable, Pet},
|
||||
ActiveAbilities, Alignment, Body, Inventory, SkillSet, Stats, Waypoint,
|
||||
ActiveAbilities, Alignment, Body, Inventory, MapMarker, SkillSet, Stats, Waypoint,
|
||||
},
|
||||
uid::Uid,
|
||||
};
|
||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Inventory>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Waypoint>,
|
||||
ReadStorage<'a, MapMarker>,
|
||||
ReadStorage<'a, Pet>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, ActiveAbilities>,
|
||||
@ -43,6 +44,7 @@ impl<'a> System<'a> for Sys {
|
||||
player_inventories,
|
||||
uids,
|
||||
player_waypoints,
|
||||
map_markers,
|
||||
pets,
|
||||
stats,
|
||||
active_abilities,
|
||||
@ -59,6 +61,7 @@ impl<'a> System<'a> for Sys {
|
||||
&uids,
|
||||
player_waypoints.maybe(),
|
||||
&active_abilities,
|
||||
map_markers.maybe(),
|
||||
)
|
||||
.join()
|
||||
.filter_map(
|
||||
@ -69,6 +72,7 @@ impl<'a> System<'a> for Sys {
|
||||
player_uid,
|
||||
waypoint,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
)| match presence.kind {
|
||||
PresenceKind::Character(id) => {
|
||||
let pets = (&alignments, &bodies, &stats, &pets)
|
||||
@ -86,7 +90,15 @@ impl<'a> System<'a> for Sys {
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some((id, skill_set, inventory, pets, waypoint, active_abilities))
|
||||
Some((
|
||||
id,
|
||||
skill_set,
|
||||
inventory,
|
||||
pets,
|
||||
waypoint,
|
||||
active_abilities,
|
||||
map_marker,
|
||||
))
|
||||
},
|
||||
PresenceKind::Spectator => None,
|
||||
},
|
||||
|
@ -368,6 +368,7 @@ image_ids! {
|
||||
indicator_group_up: "voxygen.element.ui.map.buttons.group_indicator_arrow_up",
|
||||
indicator_group_down: "voxygen.element.ui.map.buttons.group_indicator_arrow_down",
|
||||
location_marker: "voxygen.element.ui.map.buttons.location_marker",
|
||||
location_marker_group: "voxygen.element.ui.map.buttons.location_marker_group",
|
||||
map_mode_overlay: "voxygen.element.ui.map.buttons.map_modes",
|
||||
minimap_mode_overlay: "voxygen.element.ui.map.buttons.minimap_modes",
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Show, QUALITY_COMMON, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE, TEXT_BG,
|
||||
MapMarkers, QUALITY_COMMON, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE, TEXT_BG,
|
||||
TEXT_BLUE_COLOR, TEXT_COLOR, TEXT_GRAY_COLOR, TEXT_VELORITE, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
@ -51,6 +51,7 @@ widget_ids! {
|
||||
member_indicators[],
|
||||
member_height_indicators[],
|
||||
location_marker,
|
||||
location_marker_group[],
|
||||
map_settings_align,
|
||||
show_towns_img,
|
||||
show_towns_box,
|
||||
@ -98,7 +99,6 @@ const SHOW_ECONOMY: bool = false; // turn this display off (for 0.9) until we ha
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Map<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
world_map: &'a (Vec<img_ids::Rotations>, Vec2<u32>),
|
||||
imgs: &'a Imgs,
|
||||
@ -110,12 +110,11 @@ pub struct Map<'a> {
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
location_marker: Option<Vec2<f32>>,
|
||||
location_markers: &'a MapMarkers,
|
||||
map_drag: Vec2<f64>,
|
||||
}
|
||||
impl<'a> Map<'a> {
|
||||
pub fn new(
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
@ -125,11 +124,10 @@ impl<'a> Map<'a> {
|
||||
localized_strings: &'a Localization,
|
||||
global_state: &'a GlobalState,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
location_marker: Option<Vec2<f32>>,
|
||||
location_markers: &'a MapMarkers,
|
||||
map_drag: Vec2<f64>,
|
||||
) -> Self {
|
||||
Self {
|
||||
show,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
world_map,
|
||||
@ -140,7 +138,7 @@ impl<'a> Map<'a> {
|
||||
localized_strings,
|
||||
global_state,
|
||||
tooltip_manager,
|
||||
location_marker,
|
||||
location_markers,
|
||||
map_drag,
|
||||
}
|
||||
}
|
||||
@ -154,9 +152,9 @@ pub enum Event {
|
||||
SettingsChange(InterfaceChange),
|
||||
Close,
|
||||
RequestSiteInfo(SiteId),
|
||||
SetLocationMarker(Vec2<f32>),
|
||||
SetLocationMarker(Vec2<i32>),
|
||||
MapDrag(Vec2<f64>),
|
||||
ToggleMarker,
|
||||
RemoveMarker,
|
||||
}
|
||||
|
||||
fn get_site_economy(site_rich: &SiteInfoRich) -> String {
|
||||
@ -370,16 +368,15 @@ impl<'a> Widget for Map<'a> {
|
||||
.next()
|
||||
{
|
||||
match wpos {
|
||||
Some(ref wpos) => events.push(Event::SetLocationMarker(*wpos)),
|
||||
Some(ref wpos) => events.push(Event::SetLocationMarker(wpos.as_())),
|
||||
None => {
|
||||
let tmp: Vec2<f64> = Vec2::<f64>::from(click.xy) / zoom - drag;
|
||||
let wpos = tmp
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e as f32 * sz as f32)
|
||||
+ player_pos;
|
||||
events.push(Event::SetLocationMarker(wpos));
|
||||
events.push(Event::SetLocationMarker(wpos.as_()));
|
||||
},
|
||||
}
|
||||
events.push(Event::ToggleMarker);
|
||||
}
|
||||
|
||||
// Handle zooming with the mousewheel
|
||||
@ -1220,18 +1217,36 @@ impl<'a> Widget for Map<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Location marker
|
||||
if self.show.map_marker {
|
||||
let factor = 1.4;
|
||||
let side_length = 20.0 * factor;
|
||||
if let Some((lm, (rpos, fade))) = self.location_marker.and_then(|lm| {
|
||||
Some(lm).zip(wpos_to_rpos_fade(
|
||||
lm,
|
||||
Vec2::from(side_length / 2.0),
|
||||
side_length / 2.0,
|
||||
))
|
||||
}) {
|
||||
if Button::image(self.imgs.location_marker)
|
||||
let factor = 1.4;
|
||||
let side_length = 20.0 * factor;
|
||||
// Groups location markers
|
||||
if state.ids.location_marker_group.len() < self.location_markers.group.len() {
|
||||
state.update(|s| {
|
||||
s.ids.location_marker_group.resize(
|
||||
self.location_markers.group.len(),
|
||||
&mut ui.widget_id_generator(),
|
||||
)
|
||||
})
|
||||
};
|
||||
for (i, (&uid, &rpos)) in self.location_markers.group.iter().enumerate() {
|
||||
let lm = rpos.as_();
|
||||
if let Some((rpos, fade)) =
|
||||
wpos_to_rpos_fade(lm, Vec2::from(side_length / 2.0), side_length / 2.0)
|
||||
{
|
||||
let name = self
|
||||
.client
|
||||
.player_list()
|
||||
.get(&uid)
|
||||
.map(|info| info.player_alias.as_str())
|
||||
.or_else(|| {
|
||||
uid_allocator
|
||||
.retrieve_entity_internal(uid.into())
|
||||
.and_then(|entity| stats.get(entity))
|
||||
.map(|stats| stats.name.as_str())
|
||||
})
|
||||
.unwrap_or("");
|
||||
|
||||
Button::image(self.imgs.location_marker_group)
|
||||
.x_y_position_relative_to(
|
||||
state.ids.map_layers[0],
|
||||
position::Relative::Scalar(rpos.x as f64),
|
||||
@ -1247,26 +1262,58 @@ impl<'a> Widget for Map<'a> {
|
||||
"X: {}, Y: {}\n\n{}",
|
||||
lm.x as i32,
|
||||
lm.y as i32,
|
||||
i18n.get("hud.map.marked_location_remove")
|
||||
i18n.get("hud.map.placed_by").replace("{name}", name),
|
||||
),
|
||||
&site_tooltip,
|
||||
TEXT_VELORITE,
|
||||
)
|
||||
.set(state.ids.location_marker, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::ToggleMarker);
|
||||
}
|
||||
|
||||
handle_widget_mouse_events(
|
||||
state.ids.location_marker,
|
||||
Some(Vec2::new(0.0, 0.0)),
|
||||
ui,
|
||||
&mut events,
|
||||
state.ids.map_layers[0],
|
||||
);
|
||||
.set(state.ids.location_marker_group[i], ui);
|
||||
}
|
||||
}
|
||||
// Location marker
|
||||
if let Some((lm, (rpos, fade))) = self.location_markers.owned.and_then(|lm| {
|
||||
let lm = lm.as_();
|
||||
Some(lm).zip(wpos_to_rpos_fade(
|
||||
lm,
|
||||
Vec2::from(side_length / 2.0),
|
||||
side_length / 2.0,
|
||||
))
|
||||
}) {
|
||||
if Button::image(self.imgs.location_marker)
|
||||
.x_y_position_relative_to(
|
||||
state.ids.map_layers[0],
|
||||
position::Relative::Scalar(rpos.x as f64),
|
||||
position::Relative::Scalar(rpos.y as f64 + 10.0 * factor as f64),
|
||||
)
|
||||
.w_h(side_length as f64, side_length as f64)
|
||||
.image_color(Color::Rgba(1.0, 1.0, 1.0, fade))
|
||||
.floating(true)
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
i18n.get("hud.map.marked_location"),
|
||||
&format!(
|
||||
"X: {}, Y: {}\n\n{}",
|
||||
lm.x as i32,
|
||||
lm.y as i32,
|
||||
i18n.get("hud.map.marked_location_remove")
|
||||
),
|
||||
&site_tooltip,
|
||||
TEXT_VELORITE,
|
||||
)
|
||||
.set(state.ids.location_marker, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::RemoveMarker);
|
||||
}
|
||||
|
||||
handle_widget_mouse_events(
|
||||
state.ids.location_marker,
|
||||
Some(Vec2::new(0.0, 0.0)),
|
||||
ui,
|
||||
&mut events,
|
||||
state.ids.map_layers[0],
|
||||
);
|
||||
}
|
||||
|
||||
// Cursor pos relative to playerpos and widget size
|
||||
// Cursor stops moving on an axis as soon as it's position exceeds the maximum
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Show, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
|
||||
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
MapMarkers, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW,
|
||||
QUALITY_MODERATE, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
hud::{Graphic, Ui},
|
||||
@ -375,7 +375,6 @@ widget_ids! {
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct MiniMap<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
@ -385,13 +384,12 @@ pub struct MiniMap<'a> {
|
||||
common: widget::CommonBuilder,
|
||||
ori: Vec3<f32>,
|
||||
global_state: &'a GlobalState,
|
||||
location_marker: Option<Vec2<f32>>,
|
||||
location_markers: &'a MapMarkers,
|
||||
voxel_minimap: &'a VoxelMinimap,
|
||||
}
|
||||
|
||||
impl<'a> MiniMap<'a> {
|
||||
pub fn new(
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
@ -399,11 +397,10 @@ impl<'a> MiniMap<'a> {
|
||||
fonts: &'a Fonts,
|
||||
ori: Vec3<f32>,
|
||||
global_state: &'a GlobalState,
|
||||
location_marker: Option<Vec2<f32>>,
|
||||
location_markers: &'a MapMarkers,
|
||||
voxel_minimap: &'a VoxelMinimap,
|
||||
) -> Self {
|
||||
Self {
|
||||
show,
|
||||
client,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
@ -412,7 +409,7 @@ impl<'a> MiniMap<'a> {
|
||||
common: widget::CommonBuilder::default(),
|
||||
ori,
|
||||
global_state,
|
||||
location_marker,
|
||||
location_markers,
|
||||
voxel_minimap,
|
||||
}
|
||||
}
|
||||
@ -792,11 +789,14 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
}
|
||||
|
||||
// Location marker
|
||||
if self.show.map_marker {
|
||||
if let Some(rpos) = self.location_marker.and_then(|lm| wpos_to_rpos(lm, true)) {
|
||||
let factor = 1.2;
|
||||
if let Some(rpos) = self
|
||||
.location_markers
|
||||
.owned
|
||||
.and_then(|lm| wpos_to_rpos(lm.as_(), true))
|
||||
{
|
||||
let factor = 1.2;
|
||||
|
||||
Button::image(self.imgs.location_marker)
|
||||
Button::image(self.imgs.location_marker)
|
||||
.x_y_position_relative_to(
|
||||
state.ids.map_layers[0],
|
||||
position::Relative::Scalar(rpos.x as f64),
|
||||
@ -806,7 +806,6 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
//.image_color(Color::Rgba(1.0, 1.0, 1.0, 1.0))
|
||||
.floating(true)
|
||||
.set(state.ids.location_marker, ui);
|
||||
}
|
||||
}
|
||||
// Indicator
|
||||
let ind_scale = 0.4;
|
||||
|
@ -83,7 +83,7 @@ use common::{
|
||||
inventory::{slot::InvSlotId, trade_pricing::TradePricing},
|
||||
item::{tool::ToolKind, ItemDesc, MaterialStatManifest, Quality},
|
||||
skillset::{skills::Skill, SkillGroupKind},
|
||||
BuffData, BuffKind, Item,
|
||||
BuffData, BuffKind, Item, MapMarkerChange,
|
||||
},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
link::Is,
|
||||
@ -546,6 +546,7 @@ pub enum Event {
|
||||
|
||||
SettingsChange(SettingsChange),
|
||||
AcknowledgePersistenceLoadError,
|
||||
MapMarkerEvent(MapMarkerChange),
|
||||
}
|
||||
|
||||
// TODO: Are these the possible layouts we want?
|
||||
@ -638,6 +639,12 @@ impl PressBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct MapMarkers {
|
||||
owned: Option<Vec2<i32>>,
|
||||
group: HashMap<Uid, Vec2<i32>>,
|
||||
}
|
||||
|
||||
pub struct Show {
|
||||
ui: bool,
|
||||
intro: bool,
|
||||
@ -667,8 +674,7 @@ pub struct Show {
|
||||
auto_walk: bool,
|
||||
camera_clamp: bool,
|
||||
prompt_dialog: Option<PromptDialogSettings>,
|
||||
location_marker: Option<Vec2<f32>>,
|
||||
map_marker: bool,
|
||||
location_markers: MapMarkers,
|
||||
salvage: bool,
|
||||
}
|
||||
impl Show {
|
||||
@ -889,6 +895,26 @@ impl Show {
|
||||
global_state.window.center_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_map_markers(&mut self, event: comp::MapMarkerUpdate) {
|
||||
match event {
|
||||
comp::MapMarkerUpdate::Owned(event) => match event {
|
||||
MapMarkerChange::Update(waypoint) => self.location_markers.owned = Some(waypoint),
|
||||
MapMarkerChange::Remove => self.location_markers.owned = None,
|
||||
},
|
||||
comp::MapMarkerUpdate::GroupMember(user, event) => match event {
|
||||
MapMarkerChange::Update(waypoint) => {
|
||||
self.location_markers.group.insert(user, waypoint);
|
||||
},
|
||||
MapMarkerChange::Remove => {
|
||||
self.location_markers.group.remove(&user);
|
||||
},
|
||||
},
|
||||
comp::MapMarkerUpdate::ClearGroup => {
|
||||
self.location_markers.group.clear();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PromptDialogSettings {
|
||||
@ -1060,8 +1086,7 @@ impl Hud {
|
||||
auto_walk: false,
|
||||
camera_clamp: false,
|
||||
prompt_dialog: None,
|
||||
location_marker: None,
|
||||
map_marker: false,
|
||||
location_markers: MapMarkers::default(),
|
||||
salvage: false,
|
||||
},
|
||||
to_focus: None,
|
||||
@ -2756,7 +2781,6 @@ impl Hud {
|
||||
|
||||
// MiniMap
|
||||
for event in MiniMap::new(
|
||||
&self.show,
|
||||
client,
|
||||
&self.imgs,
|
||||
&self.rot_imgs,
|
||||
@ -2764,7 +2788,7 @@ impl Hud {
|
||||
&self.fonts,
|
||||
camera.get_orientation(),
|
||||
global_state,
|
||||
self.show.location_marker,
|
||||
&self.show.location_markers,
|
||||
&self.voxel_minimap,
|
||||
)
|
||||
.set(self.ids.minimap, ui_widgets)
|
||||
@ -3272,7 +3296,6 @@ impl Hud {
|
||||
// Map
|
||||
if self.show.map {
|
||||
for event in Map::new(
|
||||
&self.show,
|
||||
client,
|
||||
&self.imgs,
|
||||
&self.rot_imgs,
|
||||
@ -3282,7 +3305,7 @@ impl Hud {
|
||||
i18n,
|
||||
global_state,
|
||||
tooltip_manager,
|
||||
self.show.location_marker,
|
||||
&self.show.location_markers,
|
||||
self.map_drag,
|
||||
)
|
||||
.set(self.ids.map, ui_widgets)
|
||||
@ -3300,13 +3323,15 @@ impl Hud {
|
||||
events.push(Event::RequestSiteInfo(id));
|
||||
},
|
||||
map::Event::SetLocationMarker(pos) => {
|
||||
self.show.location_marker = Some(pos);
|
||||
events.push(Event::MapMarkerEvent(MapMarkerChange::Update(pos)));
|
||||
self.show.location_markers.owned = Some(pos);
|
||||
},
|
||||
map::Event::MapDrag(new_drag) => {
|
||||
self.map_drag = new_drag;
|
||||
},
|
||||
map::Event::ToggleMarker => {
|
||||
self.show.map_marker = !self.show.map_marker;
|
||||
map::Event::RemoveMarker => {
|
||||
self.show.location_markers.owned = None;
|
||||
events.push(Event::MapMarkerEvent(MapMarkerChange::Remove));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -308,6 +308,9 @@ impl SessionState {
|
||||
client::Event::CharacterError(error) => {
|
||||
global_state.client_error = Some(error);
|
||||
},
|
||||
client::Event::MapMarker(event) => {
|
||||
self.hud.show.update_map_markers(event);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1446,6 +1449,9 @@ impl PlayState for SessionState {
|
||||
.borrow_mut()
|
||||
.acknolwedge_persistence_load_error();
|
||||
},
|
||||
HudEvent::MapMarkerEvent(event) => {
|
||||
self.client.borrow_mut().map_marker_event(event);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user