From 473161674fcf6a5bb6c770005194225fa9963b6d Mon Sep 17 00:00:00 2001 From: Rusty Striker Date: Sat, 12 Oct 2024 15:07:07 +0300 Subject: [PATCH] add AccessLevel stuff to charactersheet trait --- src/game/character_sheet.rs | 20 +++++++--- src/game/mod.rs | 7 +++- src/lib.rs | 3 +- src/pathfinder2r_impl/mod.rs | 2 + tavern_macros/src/lib.rs | 77 +++++++++++++++++++++++++----------- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/game/character_sheet.rs b/src/game/character_sheet.rs index 58e7414..84170a0 100644 --- a/src/game/character_sheet.rs +++ b/src/game/character_sheet.rs @@ -17,15 +17,25 @@ pub trait Character : CharacterSheet { pub trait CharacterSheet : Default { /// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength - fn inputs(&self) -> Vec<(String, EntryType)>; - /// All fields in the character sheet + fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>; + /// All fields in the character sheet, maybe change it to only a vec of strings? fn fields(&self) -> Vec<(String, EntryType)>; /// Character sheet to display, ordered. `None`s can be used to convey a seperator (of any sort) - fn display(&self) -> Vec>; + fn display(&self, access: AccessLevel) -> Vec>; /// Gets a character sheet entry value - fn get(&self, entry: &str) -> Option; + fn get(&self, entry: &str, access: AccessLevel) -> Option; /// Sets a cahrater sheet entry value - fn set(&mut self, entry: &str, value: EntryType); + fn set(&mut self, entry: &str, value: EntryType, access: AccessLevel); +} + +#[derive(Debug, Copy, Clone)] +pub enum AccessLevel { + Admin = 0, Owner = 1, PartyMember = 2, World = 3, +} +impl AccessLevel { + pub fn has_access(self, other: Self) -> bool { + (self as u8) <= (other as u8) + } } #[derive(Debug)] diff --git a/src/game/mod.rs b/src/game/mod.rs index 5826638..984ae7b 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -9,8 +9,10 @@ pub mod chat_message; pub mod entry; pub trait GameImpl + Serialize, A: entry::GameEntry + Serialize> { + /// Creates a new game fn new() -> Self; - fn create_character(&mut self); + /// Creates a new character, returning the character id + fn create_character(&mut self) -> usize; } pub struct Game + Serialize, A: entry::GameEntry + Serialize> { @@ -27,7 +29,8 @@ impl + Serialize, A: entry::GameEntry + Serialize> GameImpl usize { self.characters.push(C::default()); + self.characters.len() - 1 } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fa70b4f..7d46bd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ impl GameServer { .with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1)) .with_roll(DiceRoll::new("Fire".to_string(), 4, 2)) ) - .with_action(ActionDefinition::new("Attack +3".to_string())) + .with_action(ActionDefinition::new("Attack +3".to_string()).with_roll(DiceRoll::new("Base".to_string(), 20, 1))) .with_action(ActionDefinition::new("Attack -1".to_string())) ) ], @@ -48,6 +48,7 @@ impl GameServer { println!("Got message from {}: {:?}", &id, &req); match req { + // ignore errors and re-login requests api::Request::Error => {} api::Request::Login(_) => {} api::Request::Message(mut msg) => { diff --git a/src/pathfinder2r_impl/mod.rs b/src/pathfinder2r_impl/mod.rs index acae6d6..3a54241 100644 --- a/src/pathfinder2r_impl/mod.rs +++ b/src/pathfinder2r_impl/mod.rs @@ -9,6 +9,7 @@ use entry::{Entry, Weapon}; pub struct Pathfinder2rCharacterSheet { // Genral stuff #[Input("Name")] + #[Access(World)] name: String, #[Input("Weapons")] #[InputExpr(set_items, get_items)] @@ -30,6 +31,7 @@ pub struct Pathfinder2rCharacterSheet { // Skills #[Seperator] #[Field("Acrobatics")] + #[Access(PartyMember)] #[FieldExpr(self.dex + self.acrobatics_prof * 2)] _acro: i32, #[Input("Acrobatics Prof")] diff --git a/tavern_macros/src/lib.rs b/tavern_macros/src/lib.rs index c982021..cd99f81 100644 --- a/tavern_macros/src/lib.rs +++ b/tavern_macros/src/lib.rs @@ -1,8 +1,8 @@ use proc_macro2::{Delimiter, Group, Span, TokenStream}; use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{parse_macro_input, DeriveInput, Ident}; +use syn::{parse_macro_input, Attribute, DeriveInput, Ident}; -#[proc_macro_derive(CharacterSheet, attributes(Input, InputExpr, Field, FieldExpr, Seperator))] +#[proc_macro_derive(CharacterSheet, attributes(Input, InputExpr, Field, FieldExpr, Seperator, Access, AccessSet))] pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput); let mut output = quote! { @@ -49,13 +49,21 @@ fn get_type_ident_set(ty: &syn::Type) -> Option { _ => panic!("Invalid data type"), } } +fn get_access_level(attrs: &Vec, ident: &str) -> Ident { + attrs.iter() + .find(|a| a.path.is_ident(ident)) + .map(|a| a.parse_args().unwrap_or(None)) + .flatten() + .unwrap_or(Ident::new(&"Owner", Span::call_site())) +} fn impl_inputs(data: &syn::Data) -> TokenStream { let mut output = TokenStream::new(); output.extend(quote! { - fn inputs(&self) -> Vec<(String, EntryType)> + fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)> }); let mut items = TokenStream::new(); + let mut count = 0_usize; if let syn::Data::Struct(ds) = data { if let syn::Fields::Named(fs) = &ds.fields { for f in &fs.named { @@ -64,13 +72,17 @@ fn impl_inputs(data: &syn::Data) -> TokenStream { if let Some(attr) = attr { let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); let exp: Option<&syn::Attribute> = f.attrs.iter().find(|a| a.path.is_ident("InputExpr")); + let access = get_access_level(&f.attrs, "AccessSet"); + count += 1; if let Some(attr) = exp { let exp: syn::Meta = attr.parse_meta().expect("Failed to parse MetaList!"); if let syn::Meta::List(l) = exp { let from_input = &l.nested[1]; items.extend(quote! { - (#arg.to_string(), self.#from_input()), - }) + if AccessLevel::#access.has_access(access) { + v.push((#arg.to_string(), self.#from_input())); + } + }); } else { panic!("Failed parsing InputExpr attribute, expected `(&mut self, EntryType), (&self) -> EntryType`"); @@ -79,15 +91,18 @@ fn impl_inputs(data: &syn::Data) -> TokenStream { else { let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); items.extend(quote! { - (#arg.to_string(), EntryType::#t(self.#name.clone())), + if AccessLevel::#access.has_access(access) { + v.push((#arg.to_string(), EntryType::#t(self.#name.clone()))); + } }); } } } } } - let mut vec = quote! { Vec::from }; - vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream())); + let mut vec = quote! { let mut v = Vec::with_capacity(#count); }; + vec.extend(items); + vec.extend(quote! { v }); output.append(Group::new(Delimiter::Brace, vec)); output @@ -159,13 +174,14 @@ fn impl_fields(data: &syn::Data) -> TokenStream { fn impl_get(data: &syn::Data) -> TokenStream { let mut output = TokenStream::new(); output.extend(quote! { - fn get(&self, entry: &str) -> Option + fn get(&self, entry: &str, access: AccessLevel) -> Option }); let mut match_hands = TokenStream::new(); if let syn::Data::Struct(ds) = data { if let syn::Fields::Named(fs) = &ds.fields { for f in &fs.named { let name = f.ident.clone().unwrap(); + let access = get_access_level(&f.attrs, "Access"); let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input")); if let Some(attr) = input_attr { let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); @@ -175,7 +191,7 @@ fn impl_get(data: &syn::Data) -> TokenStream { if let syn::Meta::List(l) = exp { let from_input = &l.nested[1]; match_hands.extend(quote! { - #arg => Some(self.#from_input()), + #arg => if AccessLevel::#access.has_access(access) { Some(self.#from_input()) } else { None }, }); } else { @@ -185,7 +201,7 @@ fn impl_get(data: &syn::Data) -> TokenStream { else { let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); match_hands.extend(quote! { - #arg => Some(EntryType::#t(self.#name.clone())), + #arg => if AccessLevel::#access.has_access(access) { Some(EntryType::#t(self.#name.clone())) } else { None }, }); } } @@ -197,13 +213,13 @@ fn impl_get(data: &syn::Data) -> TokenStream { if let Some(exp) = field_expr { let exp: syn::Expr = exp.parse_args().expect("Invalid expression"); match_hands.extend(quote! { - #arg => Some(EntryType::Number(#exp)), + #arg => if AccessLevel::#access.has_access(access) { Some(EntryType::Number(#exp)) } else { None }, }) } else { // No expression, guess we just push this and nothing special (should prob be an input but mehhh) match_hands.extend(quote! { - #arg => Some(EntryType::#t(self.#name.clone())), + #arg => if AccessLevel::#access.has_access(access) { Some(EntryType::#t(self.#name.clone())) } else { None }, }); } } @@ -221,7 +237,7 @@ fn impl_get(data: &syn::Data) -> TokenStream { fn impl_set(data: &syn::Data) -> TokenStream { let mut output = TokenStream::new(); output.extend(quote! { - fn set(&mut self, entry: &str, value: EntryType) + fn set(&mut self, entry: &str, value: EntryType, access: AccessLevel) }); let mut match_hands = TokenStream::new(); @@ -230,6 +246,7 @@ fn impl_set(data: &syn::Data) -> TokenStream { for f in &fs.named { let name = f.ident.clone().unwrap(); let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input")); + let access = get_access_level(&f.attrs, "AccessSet"); if let Some(attr) = input_attr { let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); let exp = f.attrs.iter().find(|a| a.path.is_ident("InputExpr")); @@ -238,7 +255,7 @@ fn impl_set(data: &syn::Data) -> TokenStream { if let syn::Meta::List(l) = exp { let to_input = &l.nested[0]; match_hands.extend(quote! { - #arg => self.#to_input(value), + #arg => if AccessLevel::#access.has_access(access) { self.#to_input(value) }, }); } else { @@ -248,7 +265,7 @@ fn impl_set(data: &syn::Data) -> TokenStream { else { let t = get_type_ident_set(&f.ty).expect(&format!("Invalid type for input: {}", name)); match_hands.extend(quote! { - #arg => self.#name = value.#t(), + #arg => if AccessLevel::#access.has_access(access) { self.#name = value.#t() }, }); } } @@ -266,17 +283,20 @@ fn impl_set(data: &syn::Data) -> TokenStream { fn impl_display(data: &syn::Data) -> TokenStream { let mut output = TokenStream::new(); output.extend(quote! { - fn display(&self) -> Vec> + fn display(&self, access: AccessLevel) -> Vec> }); let mut items = TokenStream::new(); + let mut count = 0_usize; if let syn::Data::Struct(ds) = data { if let syn::Fields::Named(fs) = &ds.fields { for f in &fs.named { let name = f.ident.clone().unwrap(); if f.attrs.iter().any(|a| a.path.is_ident("Seperator")) { - items.extend(quote! { None, }) + items.extend(quote! { v.push(None); }) } + let access = get_access_level(&f.attrs, "Access"); + count += 1; let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input")); if let Some(attr) = input_attr { let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); @@ -286,7 +306,9 @@ fn impl_display(data: &syn::Data) -> TokenStream { if let syn::Meta::List(l) = exp { let from_input = &l.nested[1]; items.extend(quote! { - Some((#arg.to_string(), self.#from_input())), + if AccessLevel::#access.has_access(access) { + v.push(Some((#arg.to_string(), self.#from_input()))); + } }) } else { @@ -296,7 +318,9 @@ fn impl_display(data: &syn::Data) -> TokenStream { else { let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); items.extend(quote! { - Some((#arg.to_string(), EntryType::#t(self.#name.clone()))), + if AccessLevel::#access.has_access(access) { + Some((#arg.to_string(), EntryType::#t(self.#name.clone()))); + } }); } } @@ -308,13 +332,17 @@ fn impl_display(data: &syn::Data) -> TokenStream { if let Some(exp) = field_expr { let exp: syn::Expr = exp.parse_args().expect("Invalid expression"); items.extend(quote! { - Some((#arg.to_string(), EntryType::Number(#exp))), + if AccessLevel::#access.has_access(access) { + Some((#arg.to_string(), EntryType::Number(#exp))); + } }) } else { // No expression, guess we just push this and nothing special (should prob be an input but mehhh) items.extend(quote! { - Some((#arg.to_string(), EntryType::#t(self.#name.clone()))), + if AccessLevel::#access.has_access(access) { + Some((#arg.to_string(), EntryType::#t(self.#name.clone()))); + } }); } @@ -322,8 +350,9 @@ fn impl_display(data: &syn::Data) -> TokenStream { } } } - let mut vec = quote! { Vec::from }; - vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream())); + let mut vec = quote! { let mut v = Vec::with_capacity(#count); }; + vec.extend( items); + vec.extend(quote! { v }); output.append(Group::new(Delimiter::Brace, vec)); output