mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
fixes
This commit is contained in:
parent
1b1878a77b
commit
deb3375ac7
11 changed files with 97 additions and 32 deletions
45
Cargo.lock
generated
45
Cargo.lock
generated
|
|
@ -52,6 +52,11 @@ dependencies = [
|
||||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
@ -91,6 +96,39 @@ dependencies = [
|
||||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "snap"
|
name = "snap"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
|
@ -138,6 +176,8 @@ dependencies = [
|
||||||
"enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"snap 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"snap 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -157,12 +197,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b90e520ec62c1864c8c78d637acbfe8baf5f63240f2fb8165b8325c07812dd"
|
"checksum enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b90e520ec62c1864c8c78d637acbfe8baf5f63240f2fb8165b8325c07812dd"
|
||||||
"checksum enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "801303a673e02d2110a196d70e4a807f0ff0a68ce1060eebc1e6a0d598db65e8"
|
"checksum enumflags2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "801303a673e02d2110a196d70e4a807f0ff0a68ce1060eebc1e6a0d598db65e8"
|
||||||
"checksum enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e015b3dfedc096cb55cdc5d022d6b4e6b94547212fb94ad2d9ece20bcd88fe3"
|
"checksum enumflags2_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e015b3dfedc096cb55cdc5d022d6b4e6b94547212fb94ad2d9ece20bcd88fe3"
|
||||||
|
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||||
|
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||||
|
"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560"
|
||||||
|
"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c"
|
||||||
|
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
|
||||||
"checksum snap 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "95d697d63d44ad8b78b8d235bf85b34022a78af292c8918527c5f0cffdde7f43"
|
"checksum snap 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "95d697d63d44ad8b78b8d235bf85b34022a78af292c8918527c5f0cffdde7f43"
|
||||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||||
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||||
name = "tf_demo_parser"
|
name = "tf_demo_parser"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "test"
|
name = "test_demo"
|
||||||
path = "src/bin/main.rs"
|
path = "src/bin/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
@ -19,3 +19,5 @@ enumflags2 = "0.5"
|
||||||
enumflags2_derive = "0.5"
|
enumflags2_derive = "0.5"
|
||||||
arraydeque = "0.4"
|
arraydeque = "0.4"
|
||||||
snap = "0.2"
|
snap = "0.2"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
@ -10,7 +10,10 @@ fn main() -> std::result::Result<(), Box<ParseError>> {
|
||||||
let stream: Stream = demo.get_stream();
|
let stream: Stream = demo.get_stream();
|
||||||
let mut parser = DemoParser::new(stream);
|
let mut parser = DemoParser::new(stream);
|
||||||
let (header, state) = parser.parse_demo()?;
|
let (header, state) = parser.parse_demo()?;
|
||||||
dbg!(header);
|
//dbg!(header);
|
||||||
dbg!(state);
|
//dbg!(state.deaths);
|
||||||
|
//let json = serde_json::to_string(&state.deaths).unwrap_or("err".to_string());
|
||||||
|
//std::thread::sleep(std::time::Duration::from_secs(5));
|
||||||
|
//println!("{}", json);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ pub struct EntityMessage {
|
||||||
pub class_id: u16,
|
pub class_id: u16,
|
||||||
#[size = 11]
|
#[size = 11]
|
||||||
pub length: u16,
|
pub length: u16,
|
||||||
#[size = "length * 8"]
|
#[size = "length"]
|
||||||
pub data: Stream,
|
pub data: Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
|
use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
|
||||||
use enum_primitive_derive::Primitive;
|
use enum_primitive_derive::Primitive;
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::demo::message::usermessage::UserMessage::SayText2;
|
use crate::demo::message::usermessage::UserMessage::SayText2;
|
||||||
use crate::{ReadResult, Stream};
|
use crate::{ReadResult, Stream};
|
||||||
|
|
@ -87,7 +88,7 @@ impl BitRead<LittleEndian> for UserMessage {
|
||||||
let mut data = stream.read_bits(length)?;
|
let mut data = stream.read_bits(length)?;
|
||||||
let message = match message_type {
|
let message = match message_type {
|
||||||
UserMessageType::SayText2 => UserMessage::SayText2(data.read()?),
|
UserMessageType::SayText2 => UserMessage::SayText2(data.read()?),
|
||||||
UserMessageType::TextMsg => UserMessage::Text(data.read()?),
|
//UserMessageType::TextMsg => UserMessage::Text(data.read()?),
|
||||||
UserMessageType::ResetHUD => UserMessage::ResetHUD(data.read()?),
|
UserMessageType::ResetHUD => UserMessage::ResetHUD(data.read()?),
|
||||||
UserMessageType::Train => UserMessage::Train(data.read()?),
|
UserMessageType::Train => UserMessage::Train(data.read()?),
|
||||||
UserMessageType::VoiceSubtitle => UserMessage::VoiceSubtitle(data.read()?),
|
UserMessageType::VoiceSubtitle => UserMessage::VoiceSubtitle(data.read()?),
|
||||||
|
|
@ -98,7 +99,7 @@ impl BitRead<LittleEndian> for UserMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum SayText2Kind {
|
pub enum SayText2Kind {
|
||||||
ChatAll,
|
ChatAll,
|
||||||
ChatTeam,
|
ChatTeam,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ impl BitRead<LittleEndian> for ConsoleCmdPacket {
|
||||||
let tick = stream.read_int(32)?;
|
let tick = stream.read_int(32)?;
|
||||||
let len = stream.read_int::<usize>(32)?;
|
let len = stream.read_int::<usize>(32)?;
|
||||||
let mut packet_data = stream.read_bits(len * 8)?;
|
let mut packet_data = stream.read_bits(len * 8)?;
|
||||||
let command = packet_data.read_string(None)?;
|
let command = packet_data.read_string(Some(len))?;
|
||||||
Ok(ConsoleCmdPacket { tick, command })
|
Ok(ConsoleCmdPacket { tick, command })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ pub struct ExtraData {
|
||||||
pub data: Stream,
|
pub data: Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitRead, Clone)]
|
#[derive(BitRead, Clone, Default)]
|
||||||
#[endianness = "LittleEndian"]
|
#[endianness = "LittleEndian"]
|
||||||
pub struct StringTableEntry {
|
pub struct StringTableEntry {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent};
|
use crate::demo::gameevent_gen::{GameEvent, PlayerDeathEvent};
|
||||||
use crate::demo::message::Message;
|
use crate::demo::message::Message;
|
||||||
use crate::demo::message::usermessage::{SayText2Kind, UserMessage};
|
use crate::demo::message::usermessage::{SayText2Kind, UserMessage};
|
||||||
use crate::demo::vector::Vector;
|
use crate::demo::vector::Vector;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct ChatMassage {
|
pub struct ChatMassage {
|
||||||
pub kind: SayText2Kind,
|
pub kind: SayText2Kind,
|
||||||
pub from: String,
|
pub from: String,
|
||||||
|
|
@ -11,7 +13,7 @@ pub struct ChatMassage {
|
||||||
pub tick: u32,
|
pub tick: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct UserEntityInfo {
|
pub struct UserEntityInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub user_id: u8,
|
pub user_id: u8,
|
||||||
|
|
@ -19,13 +21,13 @@ pub struct UserEntityInfo {
|
||||||
pub entity_id: u32,
|
pub entity_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct UserInfo {
|
pub struct UserInfo {
|
||||||
pub team: String,
|
pub team: String,
|
||||||
pub entity_info: UserEntityInfo,
|
pub entity_info: UserEntityInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Death {
|
pub struct Death {
|
||||||
pub weapon: String,
|
pub weapon: String,
|
||||||
pub victim: u8,
|
pub victim: u8,
|
||||||
|
|
@ -34,26 +36,26 @@ pub struct Death {
|
||||||
pub tick: u32,
|
pub tick: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Round {
|
pub struct Round {
|
||||||
winner: String,
|
winner: String,
|
||||||
length: f32,
|
length: f32,
|
||||||
end_tick: u32,
|
end_tick: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Serialize)]
|
||||||
pub struct World {
|
pub struct World {
|
||||||
boundary_min: Vector,
|
boundary_min: Vector,
|
||||||
boundary_max: Vector,
|
boundary_max: Vector,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Serialize)]
|
||||||
pub struct Analyser {
|
pub struct Analyser {
|
||||||
chat: Vec<ChatMassage>,
|
pub chat: Vec<ChatMassage>,
|
||||||
users: Vec<UserInfo>,
|
pub users: Vec<UserInfo>,
|
||||||
deaths: Vec<Death>,
|
pub deaths: Vec<Death>,
|
||||||
rounds: Vec<Round>,
|
pub rounds: Vec<Round>,
|
||||||
world: World,
|
pub world: World,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyser {
|
impl Analyser {
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ impl DemoParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn read<T: Parse>(&mut self) -> Result<T> {
|
pub fn read<T: Parse>(&mut self) -> Result<T> {
|
||||||
T::parse(&mut self.stream, &self.state)
|
T::parse(&mut self.stream, &self.state)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,9 @@ impl ParserState {
|
||||||
pub fn handle_packet(&mut self, packet: Packet) -> Vec<Message> {
|
pub fn handle_packet(&mut self, packet: Packet) -> Vec<Message> {
|
||||||
match packet {
|
match packet {
|
||||||
Packet::Message(packet) | Packet::Sigon(packet) => {
|
Packet::Message(packet) | Packet::Sigon(packet) => {
|
||||||
let mut unhandled_messages = Vec::with_capacity(packet.messages.len());
|
return packet.messages.into_iter()
|
||||||
for message in packet.messages {
|
.filter_map(|message| self.handle_message(message))
|
||||||
match self.handle_message(message) {
|
.collect();
|
||||||
Some(message) => unhandled_messages.push(message),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return unhandled_messages;
|
|
||||||
}
|
}
|
||||||
Packet::DataTables(packet) => {
|
Packet::DataTables(packet) => {
|
||||||
if self.send_tables.len() > 0 {
|
if self.send_tables.len() > 0 {
|
||||||
|
|
@ -97,6 +92,9 @@ impl ParserState {
|
||||||
match table {
|
match table {
|
||||||
Some(table) => {
|
Some(table) => {
|
||||||
for (index, entry) in entries {
|
for (index, entry) in entries {
|
||||||
|
if index as usize > table.entries.len() {
|
||||||
|
table.entries.resize(index as usize, StringTableEntry::default());
|
||||||
|
}
|
||||||
table.entries.insert(index as usize, entry);
|
table.entries.insert(index as usize, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,26 @@
|
||||||
use bitstream_reader::BitRead;
|
use bitstream_reader::{BitRead, LittleEndian};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(BitRead, Debug, Clone, Copy, Default)]
|
use crate::{ReadResult, Stream};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, Serialize)]
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
pub z: f32,
|
pub z: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitRead, Debug, Clone, Copy, Default)]
|
impl BitRead<LittleEndian> for Vector {
|
||||||
|
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||||
|
Ok(Vector {
|
||||||
|
x: stream.read()?,
|
||||||
|
y: stream.read()?,
|
||||||
|
z: stream.read()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitRead, Debug, Clone, Copy, Default, Serialize)]
|
||||||
pub struct VectorXY {
|
pub struct VectorXY {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue