mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 10:14:10 +02:00
pov
This commit is contained in:
parent
9c1b246e7c
commit
cb395c87a4
4 changed files with 40 additions and 7 deletions
|
|
@ -29,7 +29,7 @@ pub fn map_coords<C: Into<[f32; 3]>>(vec: C) -> [f32; 3] {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 hammer unit is ~1.905cm
|
// 1 hammer unit is ~1.905cm
|
||||||
const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
|
pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
|
||||||
|
|
||||||
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
|
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
|
||||||
let positions: Vec<f32> = model
|
let positions: Vec<f32> = model
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,6 @@ impl Control for DemoCamera {
|
||||||
if text == "p" {
|
if text == "p" {
|
||||||
change = true;
|
change = true;
|
||||||
self.playing = !self.playing;
|
self.playing = !self.playing;
|
||||||
dbg!(self.playing);
|
|
||||||
if self.playing {
|
if self.playing {
|
||||||
self.playback_start_time = accumulated_time;
|
self.playback_start_time = accumulated_time;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
40
src/demo.rs
40
src/demo.rs
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::bsp::map_coords;
|
use crate::bsp::{map_coords, UNIT_SCALE};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tf_demo_parser::demo::data::UserInfo;
|
use tf_demo_parser::demo::data::UserInfo;
|
||||||
|
use tf_demo_parser::demo::header::Header;
|
||||||
use tf_demo_parser::demo::message::packetentities::EntityId;
|
use tf_demo_parser::demo::message::packetentities::EntityId;
|
||||||
use tf_demo_parser::demo::message::Message;
|
use tf_demo_parser::demo::message::Message;
|
||||||
|
use tf_demo_parser::demo::packet::message::MessagePacketMeta;
|
||||||
use tf_demo_parser::demo::packet::stringtable::StringTableEntry;
|
use tf_demo_parser::demo::packet::stringtable::StringTableEntry;
|
||||||
use tf_demo_parser::demo::parser::MessageHandler;
|
use tf_demo_parser::demo::parser::MessageHandler;
|
||||||
use tf_demo_parser::demo::sendprop::SendPropIdentifier;
|
use tf_demo_parser::demo::sendprop::SendPropIdentifier;
|
||||||
|
|
@ -39,11 +41,14 @@ impl DemoInfo {
|
||||||
struct PovAnalyzer {
|
struct PovAnalyzer {
|
||||||
last_position: Vector,
|
last_position: Vector,
|
||||||
last_angles: [f32; 2],
|
last_angles: [f32; 2],
|
||||||
|
view_offset: f32,
|
||||||
positions: Vec<(Vec3, [f32; 2])>,
|
positions: Vec<(Vec3, [f32; 2])>,
|
||||||
name: String,
|
name: String,
|
||||||
player: Option<EntityId>,
|
player: Option<EntityId>,
|
||||||
start_tick: u32,
|
start_tick: u32,
|
||||||
last_tick: u32,
|
last_tick: u32,
|
||||||
|
pov_name: String,
|
||||||
|
is_pov: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageHandler for PovAnalyzer {
|
impl MessageHandler for PovAnalyzer {
|
||||||
|
|
@ -53,6 +58,23 @@ impl MessageHandler for PovAnalyzer {
|
||||||
matches!(message_type, MessageType::PacketEntities)
|
matches!(message_type, MessageType::PacketEntities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_header(&mut self, header: &Header) {
|
||||||
|
self.pov_name = header.nick.clone();
|
||||||
|
if self.name.is_empty() {
|
||||||
|
self.name = self.pov_name.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_packet_meta(&mut self, meta: &MessagePacketMeta) {
|
||||||
|
if self.is_pov {
|
||||||
|
self.last_angles = [
|
||||||
|
meta.view_angles.local_angles.1.x,
|
||||||
|
meta.view_angles.local_angles.1.y,
|
||||||
|
];
|
||||||
|
self.last_position = meta.view_angles.origin.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_message(&mut self, message: &Message, tick: u32) {
|
fn handle_message(&mut self, message: &Message, tick: u32) {
|
||||||
const LOCAL_ORIGIN: SendPropIdentifier =
|
const LOCAL_ORIGIN: SendPropIdentifier =
|
||||||
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_vecOrigin");
|
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_vecOrigin");
|
||||||
|
|
@ -70,6 +92,8 @@ impl MessageHandler for PovAnalyzer {
|
||||||
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_angEyeAngles[0]");
|
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_angEyeAngles[0]");
|
||||||
const NON_LOCAL_PITCH_ANGLES: SendPropIdentifier =
|
const NON_LOCAL_PITCH_ANGLES: SendPropIdentifier =
|
||||||
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[0]");
|
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[0]");
|
||||||
|
const VIEW_OFFSET: SendPropIdentifier =
|
||||||
|
SendPropIdentifier::new("DT_LocalPlayerExclusive", "m_vecViewOffset[2]");
|
||||||
|
|
||||||
if let (Message::PacketEntities(message), Some(player_id)) = (message, self.player) {
|
if let (Message::PacketEntities(message), Some(player_id)) = (message, self.player) {
|
||||||
if self.start_tick == 0 {
|
if self.start_tick == 0 {
|
||||||
|
|
@ -94,6 +118,10 @@ impl MessageHandler for PovAnalyzer {
|
||||||
LOCAL_PITCH_ANGLES | NON_LOCAL_PITCH_ANGLES => {
|
LOCAL_PITCH_ANGLES | NON_LOCAL_PITCH_ANGLES => {
|
||||||
self.last_angles[0] = f32::try_from(&prop.value).unwrap_or_default()
|
self.last_angles[0] = f32::try_from(&prop.value).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
VIEW_OFFSET => {
|
||||||
|
self.view_offset =
|
||||||
|
f32::try_from(&prop.value).unwrap_or_default() * UNIT_SCALE;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,8 +132,10 @@ impl MessageHandler for PovAnalyzer {
|
||||||
if tick > self.last_tick {
|
if tick > self.last_tick {
|
||||||
self.last_tick = tick;
|
self.last_tick = tick;
|
||||||
let pos = map_coords(self.last_position);
|
let pos = map_coords(self.last_position);
|
||||||
self.positions
|
self.positions.push((
|
||||||
.push((vec3(pos[0], pos[1], pos[2]), self.last_angles));
|
vec3(pos[0], pos[1] + self.view_offset, pos[2]),
|
||||||
|
self.last_angles,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,11 +162,14 @@ impl PovAnalyzer {
|
||||||
PovAnalyzer {
|
PovAnalyzer {
|
||||||
last_position: Vector::default(),
|
last_position: Vector::default(),
|
||||||
last_angles: [0.0, 0.0],
|
last_angles: [0.0, 0.0],
|
||||||
|
view_offset: 0.0,
|
||||||
positions: vec![],
|
positions: vec![],
|
||||||
name,
|
name,
|
||||||
player: None,
|
player: None,
|
||||||
start_tick: 0,
|
start_tick: 0,
|
||||||
last_tick: 0,
|
last_tick: 0,
|
||||||
|
pov_name: String::new(),
|
||||||
|
is_pov: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,6 +181,7 @@ impl PovAnalyzer {
|
||||||
.to_ascii_lowercase()
|
.to_ascii_lowercase()
|
||||||
.contains(&self.name)
|
.contains(&self.name)
|
||||||
{
|
{
|
||||||
|
self.is_pov = user_info.player_info.name == self.pov_name;
|
||||||
self.player = Some(user_info.entity_id);
|
self.player = Some(user_info.entity_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ struct Args {
|
||||||
/// Path of the demo or map file
|
/// Path of the demo or map file
|
||||||
path: String,
|
path: String,
|
||||||
/// Name of the player to follow
|
/// Name of the player to follow
|
||||||
player: String,
|
player: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
@ -79,7 +79,7 @@ fn main() -> Result<(), Error> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if args.path.ends_with(".dem") {
|
if args.path.ends_with(".dem") {
|
||||||
let demo = DemoInfo::new(args.path, &args.player)?;
|
let demo = DemoInfo::new(args.path, &args.player.unwrap_or_default())?;
|
||||||
let mut loader = Loader::new()?;
|
let mut loader = Loader::new()?;
|
||||||
let map = loader.load(&format!("maps/{}.bsp", demo.map))?;
|
let map = loader.load(&format!("maps/{}.bsp", demo.map))?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue