add AccessLevel stuff to charactersheet trait
This commit is contained in:
parent
0eaffc9a8f
commit
473161674f
5 changed files with 77 additions and 32 deletions
|
@ -17,15 +17,25 @@ pub trait Character<E: GameEntry> : 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<Option<(String, EntryType)>>;
|
||||
fn display(&self, access: AccessLevel) -> Vec<Option<(String, EntryType)>>;
|
||||
/// Gets a character sheet entry value
|
||||
fn get(&self, entry: &str) -> Option<EntryType>;
|
||||
fn get(&self, entry: &str, access: AccessLevel) -> Option<EntryType>;
|
||||
/// 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)]
|
||||
|
|
|
@ -9,8 +9,10 @@ pub mod chat_message;
|
|||
pub mod entry;
|
||||
|
||||
pub trait GameImpl<C: Character<A> + 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<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> {
|
||||
|
@ -27,7 +29,8 @@ impl<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> GameImpl<C, A
|
|||
}
|
||||
}
|
||||
|
||||
fn create_character(&mut self) {
|
||||
fn create_character(&mut self) -> usize {
|
||||
self.characters.push(C::default());
|
||||
self.characters.len() - 1
|
||||
}
|
||||
}
|
|
@ -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) => {
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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<Ident> {
|
|||
_ => panic!("Invalid data type"),
|
||||
}
|
||||
}
|
||||
fn get_access_level(attrs: &Vec<Attribute>, 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<EntryType>
|
||||
fn get(&self, entry: &str, access: AccessLevel) -> Option<EntryType>
|
||||
});
|
||||
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<Option<(String, EntryType)>>
|
||||
fn display(&self, access: AccessLevel) -> Vec<Option<(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 {
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue