Add basic nameplates to players
This commit is contained in:
parent
ea23219993
commit
548c98edf8
|
@ -5,7 +5,7 @@ use shared::{Direction, Position};
|
||||||
use world;
|
use world;
|
||||||
use world::block::Block;
|
use world::block::Block;
|
||||||
use render;
|
use render;
|
||||||
use render::model;
|
use render::model::{self, FormatState};
|
||||||
|
|
||||||
pub fn add_systems(m: &mut ecs::Manager) {
|
pub fn add_systems(m: &mut ecs::Manager) {
|
||||||
let sys = SignRenderer::new(m);
|
let sys = SignRenderer::new(m);
|
||||||
|
@ -139,18 +139,22 @@ impl ecs::System for SignRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, line) in info.lines.iter().enumerate() {
|
for (i, line) in info.lines.iter().enumerate() {
|
||||||
|
const Y_SCALE: f32 = (6.0 / 16.0) / 4.0;
|
||||||
|
const X_SCALE: f32 = Y_SCALE / 16.0;
|
||||||
let mut state = FormatState {
|
let mut state = FormatState {
|
||||||
line: i as f32,
|
|
||||||
width: 0.0,
|
width: 0.0,
|
||||||
offset: 0.0,
|
offset: 0.0,
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
|
y_scale: Y_SCALE,
|
||||||
|
x_scale: X_SCALE,
|
||||||
};
|
};
|
||||||
state.build(line, format::Color::Black);
|
state.build(line, format::Color::Black);
|
||||||
let width = state.width;
|
let width = state.width;
|
||||||
// Center align text
|
// Center align text
|
||||||
for vert in &mut state.text {
|
for vert in &mut state.text {
|
||||||
vert.x += width * 0.5;
|
vert.x += width * 0.5;
|
||||||
|
vert.y -= (Y_SCALE + 0.4/16.0) * (i as f32);
|
||||||
}
|
}
|
||||||
verts.extend_from_slice(&state.text);
|
verts.extend_from_slice(&state.text);
|
||||||
}
|
}
|
||||||
|
@ -184,67 +188,3 @@ impl ecs::System for SignRenderer {
|
||||||
info.model = None;
|
info.model = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FormatState<'a> {
|
|
||||||
line: f32,
|
|
||||||
offset: f32,
|
|
||||||
width: f32,
|
|
||||||
text: Vec<model::Vertex>,
|
|
||||||
renderer: &'a mut render::Renderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> FormatState<'a> {
|
|
||||||
fn build(&mut self, c: &Component, color: format::Color) {
|
|
||||||
match c {
|
|
||||||
&format::Component::Text(ref txt) => {
|
|
||||||
let col = FormatState::get_color(&txt.modifier, color);
|
|
||||||
self.append_text(&txt.text, col);
|
|
||||||
let modi = &txt.modifier;
|
|
||||||
if let Some(ref extra) = modi.extra {
|
|
||||||
for e in extra {
|
|
||||||
self.build(e, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_text(&mut self, txt: &str, color: format::Color) {
|
|
||||||
const Y_SCALE: f32 = (6.0 / 16.0) / 4.0;
|
|
||||||
const X_SCALE: f32 = Y_SCALE / 16.0;
|
|
||||||
|
|
||||||
let (rr, gg, bb) = color.to_rgb();
|
|
||||||
for ch in txt.chars() {
|
|
||||||
if ch == ' ' {
|
|
||||||
self.offset += 6.0 * X_SCALE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let texture = self.renderer.ui.character_texture(ch);
|
|
||||||
let w = self.renderer.ui.size_of_char(ch) as f32;
|
|
||||||
|
|
||||||
for vert in ::model::BlockVertex::face_by_direction(Direction::North) {
|
|
||||||
self.text.push(model::Vertex {
|
|
||||||
x: vert.x * X_SCALE * w - (self.offset + w * X_SCALE),
|
|
||||||
y: vert.y * Y_SCALE - (Y_SCALE + 0.4/16.0) * self.line + 2.1 / 16.0,
|
|
||||||
z: -0.6 / 16.0,
|
|
||||||
texture: texture.clone(),
|
|
||||||
texture_x: vert.toffsetx as f64,
|
|
||||||
texture_y: vert.toffsety as f64,
|
|
||||||
r: rr,
|
|
||||||
g: gg,
|
|
||||||
b: bb,
|
|
||||||
a: 255,
|
|
||||||
id: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.offset += (w + 2.0) * X_SCALE;
|
|
||||||
}
|
|
||||||
if self.offset > self.width {
|
|
||||||
self.width = self.offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
|
|
||||||
modi.color.unwrap_or(color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use world;
|
use world;
|
||||||
use render;
|
use render;
|
||||||
use render::model;
|
use render::model::{self, FormatState};
|
||||||
use types::Gamemode;
|
use types::Gamemode;
|
||||||
use collision::{Aabb, Aabb3};
|
use collision::{Aabb, Aabb3};
|
||||||
use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Angle, Quaternion};
|
use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Angle, Quaternion};
|
||||||
|
@ -21,6 +21,7 @@ use std::hash::BuildHasherDefault;
|
||||||
use types::hash::FNVHash;
|
use types::hash::FNVHash;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use shared::Position as BPosition;
|
use shared::Position as BPosition;
|
||||||
|
use format;
|
||||||
|
|
||||||
pub fn add_systems(m: &mut ecs::Manager) {
|
pub fn add_systems(m: &mut ecs::Manager) {
|
||||||
// Not actually rendering related but the faster
|
// Not actually rendering related but the faster
|
||||||
|
@ -43,11 +44,11 @@ pub fn create_local(m: &mut ecs::Manager) -> ecs::Entity {
|
||||||
Point3::new(-0.3, 0.0, -0.3),
|
Point3::new(-0.3, 0.0, -0.3),
|
||||||
Point3::new(0.3, 1.8, 0.3)
|
Point3::new(0.3, 1.8, 0.3)
|
||||||
)));
|
)));
|
||||||
m.add_component_direct(entity, PlayerModel::new(false, false, true));
|
m.add_component_direct(entity, PlayerModel::new("", false, false, true));
|
||||||
entity
|
entity
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_remote(m: &mut ecs::Manager) -> ecs::Entity {
|
pub fn create_remote(m: &mut ecs::Manager, name: &str) -> ecs::Entity {
|
||||||
let entity = m.create_entity();
|
let entity = m.create_entity();
|
||||||
m.add_component_direct(entity, Position::new(0.0, 0.0, 0.0));
|
m.add_component_direct(entity, Position::new(0.0, 0.0, 0.0));
|
||||||
m.add_component_direct(entity, TargetPosition::new(0.0, 0.0, 0.0));
|
m.add_component_direct(entity, TargetPosition::new(0.0, 0.0, 0.0));
|
||||||
|
@ -58,7 +59,7 @@ pub fn create_remote(m: &mut ecs::Manager) -> ecs::Entity {
|
||||||
Point3::new(-0.3, 0.0, -0.3),
|
Point3::new(-0.3, 0.0, -0.3),
|
||||||
Point3::new(0.3, 1.8, 0.3)
|
Point3::new(0.3, 1.8, 0.3)
|
||||||
)));
|
)));
|
||||||
m.add_component_direct(entity, PlayerModel::new(true, true, false));
|
m.add_component_direct(entity, PlayerModel::new(name, true, true, false));
|
||||||
entity
|
entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ pub struct PlayerModel {
|
||||||
model: Option<model::ModelKey>,
|
model: Option<model::ModelKey>,
|
||||||
skin_url: Option<String>,
|
skin_url: Option<String>,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
|
name: String,
|
||||||
|
|
||||||
has_head: bool,
|
has_head: bool,
|
||||||
has_name_tag: bool,
|
has_name_tag: bool,
|
||||||
|
@ -80,11 +82,12 @@ pub struct PlayerModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerModel {
|
impl PlayerModel {
|
||||||
pub fn new(has_head: bool, has_name_tag: bool, first_person: bool) -> PlayerModel {
|
pub fn new(name: &str, has_head: bool, has_name_tag: bool, first_person: bool) -> PlayerModel {
|
||||||
PlayerModel {
|
PlayerModel {
|
||||||
model: None,
|
model: None,
|
||||||
skin_url: None,
|
skin_url: None,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
name: name.to_owned(),
|
||||||
|
|
||||||
has_head: has_head,
|
has_head: has_head,
|
||||||
has_name_tag: has_name_tag,
|
has_name_tag: has_name_tag,
|
||||||
|
@ -137,8 +140,8 @@ enum PlayerModelPart {
|
||||||
LegRight = 3,
|
LegRight = 3,
|
||||||
ArmLeft = 4,
|
ArmLeft = 4,
|
||||||
ArmRight = 5,
|
ArmRight = 5,
|
||||||
Cape = 6,
|
NameTag = 6,
|
||||||
NameTag = 7
|
Cape = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Setup culling
|
// TODO: Setup culling
|
||||||
|
@ -186,6 +189,16 @@ impl ecs::System for PlayerRenderer {
|
||||||
disp: offset,
|
disp: offset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO This sucks
|
||||||
|
if player_model.has_name_tag {
|
||||||
|
let ang = (position.position.x - renderer.camera.pos.x).atan2(position.position.z - renderer.camera.pos.z) as f32;
|
||||||
|
mdl.matrix[PlayerModelPart::NameTag as usize] = Matrix4::from(Decomposed {
|
||||||
|
scale: 1.0,
|
||||||
|
rot: Quaternion::from_angle_y(Rad::new(ang)),
|
||||||
|
disp: offset + Vector3::new(0.0, (-24.0/16.0) - 0.6, 0.0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix * Matrix4::from(Decomposed {
|
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix * Matrix4::from(Decomposed {
|
||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
rot: Quaternion::from_angle_x(Rad::new(-rotation.pitch as f32)),
|
rot: Quaternion::from_angle_x(Rad::new(-rotation.pitch as f32)),
|
||||||
|
@ -354,6 +367,39 @@ impl ecs::System for PlayerRenderer {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut name_verts = vec![];
|
||||||
|
if player_model.has_name_tag {
|
||||||
|
let mut state = FormatState {
|
||||||
|
width: 0.0,
|
||||||
|
offset: 0.0,
|
||||||
|
text: Vec::new(),
|
||||||
|
renderer: renderer,
|
||||||
|
y_scale: 0.16,
|
||||||
|
x_scale: 0.01,
|
||||||
|
};
|
||||||
|
let mut name = format::Component::Text(format::TextComponent::new(&player_model.name));
|
||||||
|
format::convert_legacy(&mut name);
|
||||||
|
state.build(&name, format::Color::Black);
|
||||||
|
let width = state.width;
|
||||||
|
// Center align text
|
||||||
|
for vert in &mut state.text {
|
||||||
|
vert.x += width * 0.5;
|
||||||
|
vert.r = 64;
|
||||||
|
vert.g = 64;
|
||||||
|
vert.b = 64;
|
||||||
|
}
|
||||||
|
name_verts.extend_from_slice(&state.text);
|
||||||
|
for vert in &mut state.text {
|
||||||
|
vert.x -= 0.01;
|
||||||
|
vert.y -= 0.01;
|
||||||
|
vert.z -= 0.05;
|
||||||
|
vert.r = 255;
|
||||||
|
vert.g = 255;
|
||||||
|
vert.b = 255;
|
||||||
|
}
|
||||||
|
name_verts.extend_from_slice(&state.text);
|
||||||
|
}
|
||||||
|
|
||||||
player_model.model = Some(renderer.model.create_model(
|
player_model.model = Some(renderer.model.create_model(
|
||||||
model::DEFAULT,
|
model::DEFAULT,
|
||||||
vec![
|
vec![
|
||||||
|
@ -363,6 +409,7 @@ impl ecs::System for PlayerRenderer {
|
||||||
part_verts[1].clone(),
|
part_verts[1].clone(),
|
||||||
part_verts[2].clone(),
|
part_verts[2].clone(),
|
||||||
part_verts[3].clone(),
|
part_verts[3].clone(),
|
||||||
|
name_verts
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use types::hash::FNVHash;
|
||||||
use shared::Direction;
|
use shared::Direction;
|
||||||
use byteorder::{WriteBytesExt, NativeEndian};
|
use byteorder::{WriteBytesExt, NativeEndian};
|
||||||
use model::BlockVertex;
|
use model::BlockVertex;
|
||||||
|
use format::{self, Component};
|
||||||
|
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
collections: Vec<Collection>,
|
collections: Vec<Collection>,
|
||||||
|
@ -369,3 +370,65 @@ pub fn append_box_texture_scale(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FormatState<'a> {
|
||||||
|
pub offset: f32,
|
||||||
|
pub width: f32,
|
||||||
|
pub text: Vec<Vertex>,
|
||||||
|
pub renderer: &'a mut super::Renderer,
|
||||||
|
pub y_scale: f32,
|
||||||
|
pub x_scale: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> FormatState<'a> {
|
||||||
|
pub fn build(&mut self, c: &Component, color: format::Color) {
|
||||||
|
match c {
|
||||||
|
&format::Component::Text(ref txt) => {
|
||||||
|
let col = FormatState::get_color(&txt.modifier, color);
|
||||||
|
self.append_text(&txt.text, col);
|
||||||
|
let modi = &txt.modifier;
|
||||||
|
if let Some(ref extra) = modi.extra {
|
||||||
|
for e in extra {
|
||||||
|
self.build(e, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_text(&mut self, txt: &str, color: format::Color) {
|
||||||
|
let (rr, gg, bb) = color.to_rgb();
|
||||||
|
for ch in txt.chars() {
|
||||||
|
if ch == ' ' {
|
||||||
|
self.offset += 6.0 * self.x_scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let texture = self.renderer.ui.character_texture(ch);
|
||||||
|
let w = self.renderer.ui.size_of_char(ch) as f32;
|
||||||
|
|
||||||
|
for vert in ::model::BlockVertex::face_by_direction(Direction::North) {
|
||||||
|
self.text.push(Vertex {
|
||||||
|
x: vert.x * self.x_scale * w - (self.offset + w * self.x_scale),
|
||||||
|
y: vert.y * self.y_scale + 2.1 / 16.0,
|
||||||
|
z: -0.6 / 16.0,
|
||||||
|
texture: texture.clone(),
|
||||||
|
texture_x: vert.toffsetx as f64,
|
||||||
|
texture_y: vert.toffsety as f64,
|
||||||
|
r: rr,
|
||||||
|
g: gg,
|
||||||
|
b: bb,
|
||||||
|
a: 255,
|
||||||
|
id: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.offset += (w + 2.0) * self.x_scale;
|
||||||
|
}
|
||||||
|
if self.offset > self.width {
|
||||||
|
self.width = self.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
|
||||||
|
modi.color.unwrap_or(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -601,7 +601,7 @@ impl Server {
|
||||||
if let Some(entity) = self.entity_map.remove(&spawn.entity_id.0) {
|
if let Some(entity) = self.entity_map.remove(&spawn.entity_id.0) {
|
||||||
self.entities.remove_entity(entity);
|
self.entities.remove_entity(entity);
|
||||||
}
|
}
|
||||||
let entity = entity::player::create_remote(&mut self.entities);
|
let entity = entity::player::create_remote(&mut self.entities, self.players.get(&spawn.uuid).map_or("MISSING", |v| &v.name));
|
||||||
let position = self.entities.get_component_mut(entity, self.position).unwrap();
|
let position = self.entities.get_component_mut(entity, self.position).unwrap();
|
||||||
let target_position = self.entities.get_component_mut(entity, self.target_position).unwrap();
|
let target_position = self.entities.get_component_mut(entity, self.target_position).unwrap();
|
||||||
let rotation = self.entities.get_component_mut(entity, self.rotation).unwrap();
|
let rotation = self.entities.get_component_mut(entity, self.rotation).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue