1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +02:00

generate propname mapping

This commit is contained in:
Robin Appelman 2022-04-09 18:14:13 +02:00
commit 5976b43d56
4 changed files with 134 additions and 4 deletions

25
codegen/Cargo.lock generated
View file

@ -275,6 +275,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a" checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a"
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.4.1" version = "2.4.1"
@ -526,6 +535,15 @@ dependencies = [
"regex-syntax", "regex-syntax",
] ]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax",
]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.25" version = "0.6.25"
@ -719,7 +737,7 @@ dependencies = [
[[package]] [[package]]
name = "tf-demo-parser" name = "tf-demo-parser"
version = "0.3.3" version = "0.4.0"
dependencies = [ dependencies = [
"bitbuffer", "bitbuffer",
"enumflags2", "enumflags2",
@ -746,6 +764,7 @@ dependencies = [
"better-panic", "better-panic",
"fnv", "fnv",
"lazy_static", "lazy_static",
"main_error",
"prettyplease", "prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -842,9 +861,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d81bfa81424cc98cb034b837c985b7a290f592e5b4322f353f94a0ab0f9f594" checksum = "5d81bfa81424cc98cb034b837c985b7a290f592e5b4322f353f94a0ab0f9f594"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"lazy_static",
"matchers",
"regex",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
] ]

View file

@ -18,4 +18,5 @@ proc-macro2 = "1"
tempfile = "3" tempfile = "3"
lazy_static = "1" lazy_static = "1"
fnv = "1" fnv = "1"
prettyplease = "0.1" prettyplease = "0.1"
main_error = "0.1.2"

View file

@ -1,4 +1,6 @@
use crate::gameevent::generate_game_events; use crate::gameevent::generate_game_events;
use crate::propnames::generate_prop_names;
use main_error::MainError;
use prettyplease::unparse; use prettyplease::unparse;
use std::env; use std::env;
use std::fs; use std::fs;
@ -6,8 +8,9 @@ use syn::{parse2, File};
use tf_demo_parser::Demo; use tf_demo_parser::Demo;
mod gameevent; mod gameevent;
mod propnames;
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> { fn main() -> std::result::Result<(), MainError> {
better_panic::install(); better_panic::install();
let args: Vec<_> = env::args().collect(); let args: Vec<_> = env::args().collect();
@ -18,7 +21,11 @@ fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let path = args[1].clone(); let path = args[1].clone();
let file = fs::read(path).expect("Unable to read file"); let file = fs::read(path).expect("Unable to read file");
let demo = Demo::new(&file); let demo = Demo::new(&file);
let tokens = generate_game_events(demo); let tokens = match args.get(2).map(|s| s.as_str()) {
None | Some("events") => generate_game_events(demo),
Some("props") => generate_prop_names(demo),
_ => panic!("unsupported"),
};
let file = parse2::<File>(tokens)?; let file = parse2::<File>(tokens)?;
let code = unparse(&file); let code = unparse(&file);
println!("{}", code); println!("{}", code);

99
codegen/src/propnames.rs Normal file
View file

@ -0,0 +1,99 @@
use fnv::{FnvHashMap, FnvHashSet};
use proc_macro2::TokenStream;
use quote::quote;
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::packet::datatable::{ParseSendTable, SendTableName, ServerClass};
use tf_demo_parser::demo::parser::MessageHandler;
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropName};
use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState};
struct PropInfo {
identifier: SendPropIdentifier,
table_name: String,
prop_name: String,
}
#[derive(Default)]
struct PropAnalyzer {
props: FnvHashSet<SendPropIdentifier>,
prop_names: FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
}
impl MessageHandler for PropAnalyzer {
type Output = Vec<PropInfo>;
fn does_handle(message_type: MessageType) -> bool {
matches!(message_type, MessageType::PacketEntities)
}
fn handle_message(&mut self, message: &Message, _tick: u32) {
if let Message::PacketEntities(message) = message {
for entity in &message.entities {
for prop in &entity.props {
self.props.insert(prop.identifier);
}
}
}
}
fn handle_data_tables(
&mut self,
parse_tables: &[ParseSendTable],
_server_classes: &[ServerClass],
) {
for table in parse_tables {
for prop_def in &table.props {
self.prop_names.insert(
prop_def.identifier(),
(table.name.clone(), prop_def.name.clone()),
);
}
}
}
fn into_output(self, _state: &ParserState) -> Self::Output {
let mut props: Vec<_> = self
.prop_names
.into_iter()
.map(|(identifier, (table_name, prop_name))| PropInfo {
identifier,
table_name: table_name.to_string(),
prop_name: prop_name.to_string(),
})
.collect();
props.sort_by(|a, b| a.identifier.cmp(&b.identifier));
props
}
}
pub fn generate_prop_names(demo: Demo) -> TokenStream {
let (_, props) = DemoParser::new_with_analyser(demo.get_stream(), PropAnalyzer::default())
.parse()
.unwrap();
let imports = quote!(
use tf_demo_parser::demo::packet::datatable::SendTableName;
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropName};
);
let matches = props.into_iter().map(|prop| {
let identifier: u64 = prop.identifier.into();
let table_name = prop.table_name;
let prop_name = prop.prop_name;
quote! {
#identifier => Some((#table_name, #prop_name))
}
});
quote!(
#imports
pub fn get_prop_names(identifier: SendPropIdentifier) -> Option<(&'static str, &'static str)> {
let identifier: u64 = identifier.into();
match identifier {
#(#matches,)*
_ => None,
}
}
)
}