Compare commits

...

3 commits

7 changed files with 160 additions and 56 deletions

View file

@ -9,6 +9,7 @@
var mapOffsetX = 0.0; var mapOffsetX = 0.0;
var mapOffsetY = 0.0; var mapOffsetY = 0.0;
var draggedToken = { token: null, offX: 0, offY: 0 }; var draggedToken = { token: null, offX: 0, offY: 0 };
var draggedDiv = { div: null, offX: 0, offY: 0 };
function init() { function init() {
let view = document.getElementById('game-view'); let view = document.getElementById('game-view');
@ -40,6 +41,8 @@
document.body.onclick = (e) => { document.body.onclick = (e) => {
document.getElementById('msg-context-menu').style.display = 'none'; document.getElementById('msg-context-menu').style.display = 'none';
} }
document.body.onmousemove = onMoveableDivDrag;
document.body.onmouseup = onMoveableDivMouseUp;
// TODO: Remove when done dev-ing // TODO: Remove when done dev-ing
tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' }); tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' });
} }
@ -150,7 +153,7 @@
} }
function onGameMouseMove(event) { function onGameMouseMove(event) {
if(event.buttons == 2) { if(event.buttons == 2) {
// middle click // right click
let map = document.getElementById('map'); let map = document.getElementById('map');
let mult = event.ctrlKey ? 2.0 : 1.0; let mult = event.ctrlKey ? 2.0 : 1.0;
mapOffsetX += event.movementX * mult; mapOffsetX += event.movementX * mult;
@ -203,7 +206,7 @@
holder.appendChild(row); holder.appendChild(row);
} }
} }
document.getElementById('dice-roll-title').innerText = action.display_name ?? action.display; document.getElementById('dice-roll-title').innerText = action.display_name ?? action.name;
document.getElementById('dice-roll-popup').style.display = 'flex'; document.getElementById('dice-roll-popup').style.display = 'flex';
} }
function rollPopup() { function rollPopup() {
@ -239,6 +242,30 @@
console.log(rolls); console.log(rolls);
tavern.action_result(holder.action.name, 'Louise', [], rolls); tavern.action_result(holder.action.name, 'Louise', [], rolls);
} }
function onMoveableDivMouseDown(e, id) {
if(e.buttons == 1) {
let div = document.getElementById(id);
let rect = div.getBoundingClientRect();
draggedDiv.div = div;
draggedDiv.offX = e.clientX - rect.x;
draggedDiv.offY = e.clientY - rect.y;
}
}
function onMoveableDivDrag(e) {
if(draggedDiv.div) {
draggedDiv.div.style.right = '';
draggedDiv.div.style.top = `${e.clientY - draggedDiv.offY}px`;
draggedDiv.div.style.left = `${e.clientX - draggedDiv.offX}px`;
}
}
function onMoveableDivMouseUp(e, id) {
draggedDiv.div = null;
}
function showHideDiv(id) {
let div = document.getElementById(id);
div.style.display = div.style.display == 'none' ? 'flex' : 'none';
}
</script> </script>
<style> <style>
html, body { html, body {
@ -342,10 +369,10 @@
</div> </div>
</div> </div>
<div id="game-view" style="display: flex; overflow: hidden; position: relative; top: 0px; left: 0px; flex-grow: 1;" > <div id="game-view" style="display: flex; overflow: hidden; position: relative; top: 0px; left: 0px; flex-grow: 1;" >
<div style="position:absolute; top: 10px; left: 5px; background-color: rgb(255, 166, 0); z-index: 1;" > <div style="position:absolute; top: 10px; left: 5px; background-color: rgb(255, 166, 0); z-index: 5;" >
floating<br>stuff floating<br>stuff
</div> </div>
<div id="dice-roll-popup" style="display:none; justify-content: center; width: 100%; height: 100%; background-color: transparent; position: absolute; z-index: 2; top: 0px; left: 0px"> <div id="dice-roll-popup" style="display:none; justify-content: center; width: 100%; height: 100%; background-color: transparent; position: absolute; z-index: 10; top: 0px; left: 0px">
<div style="display:flex; width: 50%; justify-content: center; flex-direction: column;"> <div style="display:flex; width: 50%; justify-content: center; flex-direction: column;">
<div style="display: flex; height: fit-content; flex-direction: column; background-color: #ffffd6; color: black; border: black solid 1px; padding: 8px; border-radius: 8px;"> <div style="display: flex; height: fit-content; flex-direction: column; background-color: #ffffd6; color: black; border: black solid 1px; padding: 8px; border-radius: 8px;">
<h3 id="dice-roll-title" style="align-self: center;"> <h3 id="dice-roll-title" style="align-self: center;">
@ -361,6 +388,10 @@
</div> </div>
</div> </div>
</div> </div>
<div style="position: absolute; top: 10px; right: 10px; color: black; z-index: 5; display: flex; flex-direction: row;">
<button style="background-color: #ffffd6;"><b>s</b></button>
<button style="background-color: #ffffd6;" onclick="showHideDiv('initiative-tracker')"><b>i</b></button>
</div>
<div id="map" style="position:absolute; transform-origin: top left;"> <div id="map" style="position:absolute; transform-origin: top left;">
<img src="https://rustystriker.dev/molly.jpg" height="200%" > <img src="https://rustystriker.dev/molly.jpg" height="200%" >
</div> </div>
@ -371,5 +402,25 @@
<li>Delete (TODO)</li> <li>Delete (TODO)</li>
</ul> </ul>
</div> </div>
<div id="initiative-tracker" style="position: absolute; background-color: #ffffd6; color:black; display: none; flex-direction: column; top: 40px; right: 8px">
<div style="background-color: black; color:#ffffd6; margin-top: 0px; margin-bottom: 8px; padding: 0 4px; min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'initiative-tracker')">
<h3 style="flex-grow: 1;">Initiative</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button onclick="document.getElementById('initiative-tracker').style.display = 'none';"
style="height: fit-content; align-self: center; background-color: transparent; color:#ffffd6; font-size: 20px; border: 0;">
X
</button>
</div>
<div>
aaaa
</div>
<div>
bbbb
</div>
<div>
cccc
</div>
</div>
</body> </body>
</html> </html>

View file

@ -1,23 +1,31 @@
# WTF how do i implement a game??? # WTF how do i implement a game???
## Client todo ## Features
[ ] implement tavern functions [x] Simple chat
[x] token drag & drop [ ] Simple map view with moveable tokens
[ ] Chat [ ] spawn tokens
[x] Send new chat messages [x] move tokens
[x] recv new chat messages [ ] change map
[ ] roll a die when chat message requests that [ ] show grid
[ ] figure out how to zoom on the mouse instead of the center of the div [ ] multiple maps
[ ] data reqs [ ] Chat actions
[x] Define chat action
## Server todo [x] show roll dialog on chat aciton
[ ] send action roll and get result
[ ] impl different requests [ ] allow modify action roll stuff
[ ] actual normal login [ ] allow adding custom rolls to action roll stuff
[x] allow sending of old info [ ] Roll dice for no reason
[x] chat history [ ] roll dice animation because its fun
[ ] send texture (map/token/image) [ ] Character sheet
[ ] force show something [ ] Create new character sheet
[ ] mouse ping (ideally multiple types) [ ] view sheet
[ ] data reqs [ ] assign sheet (and character by extention) to user
[ ] Display image
[ ] Free move / Turn based movement
[ ] clickable stuff
[ ] only gm visible stuff (like traps and info stuff)
[ ] combat fog
[ ] Characters in current map/scene
[ ] initiative tracker
[ ] cards system (for a playstyle that relies less on the map)

View file

@ -17,15 +17,25 @@ pub trait Character<E: GameEntry> : CharacterSheet {
pub trait CharacterSheet : Default { pub trait CharacterSheet : Default {
/// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength /// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength
fn inputs(&self) -> Vec<(String, EntryType)>; fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>;
/// All fields in the character sheet /// All fields in the character sheet, maybe change it to only a vec of strings?
fn fields(&self) -> Vec<(String, EntryType)>; fn fields(&self) -> Vec<(String, EntryType)>;
/// Character sheet to display, ordered. `None`s can be used to convey a seperator (of any sort) /// 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 /// 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 /// 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)] #[derive(Debug)]

View file

@ -9,8 +9,10 @@ pub mod chat_message;
pub mod entry; pub mod entry;
pub trait GameImpl<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> { pub trait GameImpl<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> {
/// Creates a new game
fn new() -> Self; 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> { 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.push(C::default());
self.characters.len() - 1
} }
} }

View file

@ -30,7 +30,7 @@ impl GameServer {
.with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1)) .with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1))
.with_roll(DiceRoll::new("Fire".to_string(), 4, 2)) .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())) .with_action(ActionDefinition::new("Attack -1".to_string()))
) )
], ],
@ -48,6 +48,7 @@ impl GameServer {
println!("Got message from {}: {:?}", &id, &req); println!("Got message from {}: {:?}", &id, &req);
match req { match req {
// ignore errors and re-login requests
api::Request::Error => {} api::Request::Error => {}
api::Request::Login(_) => {} api::Request::Login(_) => {}
api::Request::Message(mut msg) => { api::Request::Message(mut msg) => {

View file

@ -9,6 +9,7 @@ use entry::{Entry, Weapon};
pub struct Pathfinder2rCharacterSheet { pub struct Pathfinder2rCharacterSheet {
// Genral stuff // Genral stuff
#[Input("Name")] #[Input("Name")]
#[Access(World)]
name: String, name: String,
#[Input("Weapons")] #[Input("Weapons")]
#[InputExpr(set_items, get_items)] #[InputExpr(set_items, get_items)]
@ -30,6 +31,7 @@ pub struct Pathfinder2rCharacterSheet {
// Skills // Skills
#[Seperator] #[Seperator]
#[Field("Acrobatics")] #[Field("Acrobatics")]
#[Access(PartyMember)]
#[FieldExpr(self.dex + self.acrobatics_prof * 2)] #[FieldExpr(self.dex + self.acrobatics_prof * 2)]
_acro: i32, _acro: i32,
#[Input("Acrobatics Prof")] #[Input("Acrobatics Prof")]

View file

@ -1,8 +1,8 @@
use proc_macro2::{Delimiter, Group, Span, TokenStream}; use proc_macro2::{Delimiter, Group, Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt}; 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 { pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput); let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);
let mut output = quote! { let mut output = quote! {
@ -49,13 +49,21 @@ fn get_type_ident_set(ty: &syn::Type) -> Option<Ident> {
_ => panic!("Invalid data type"), _ => 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 { fn impl_inputs(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new(); let mut output = TokenStream::new();
output.extend(quote! { output.extend(quote! {
fn inputs(&self) -> Vec<(String, EntryType)> fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>
}); });
let mut items = TokenStream::new(); let mut items = TokenStream::new();
let mut count = 0_usize;
if let syn::Data::Struct(ds) = data { if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields { if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named { for f in &fs.named {
@ -64,13 +72,17 @@ fn impl_inputs(data: &syn::Data) -> TokenStream {
if let Some(attr) = attr { if let Some(attr) = attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); 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 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 { if let Some(attr) = exp {
let exp: syn::Meta = attr.parse_meta().expect("Failed to parse MetaList!"); let exp: syn::Meta = attr.parse_meta().expect("Failed to parse MetaList!");
if let syn::Meta::List(l) = exp { if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1]; let from_input = &l.nested[1];
items.extend(quote! { items.extend(quote! {
(#arg.to_string(), self.#from_input()), if AccessLevel::#access.has_access(access) {
}) v.push((#arg.to_string(), self.#from_input()));
}
});
} }
else { else {
panic!("Failed parsing InputExpr attribute, expected `(&mut self, EntryType), (&self) -> EntryType`"); panic!("Failed parsing InputExpr attribute, expected `(&mut self, EntryType), (&self) -> EntryType`");
@ -79,15 +91,18 @@ fn impl_inputs(data: &syn::Data) -> TokenStream {
else { else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
items.extend(quote! { 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 }; let mut vec = quote! { let mut v = Vec::with_capacity(#count); };
vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream())); vec.extend(items);
vec.extend(quote! { v });
output.append(Group::new(Delimiter::Brace, vec)); output.append(Group::new(Delimiter::Brace, vec));
output output
@ -159,13 +174,14 @@ fn impl_fields(data: &syn::Data) -> TokenStream {
fn impl_get(data: &syn::Data) -> TokenStream { fn impl_get(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new(); let mut output = TokenStream::new();
output.extend(quote! { 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(); let mut match_hands = TokenStream::new();
if let syn::Data::Struct(ds) = data { if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields { if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named { for f in &fs.named {
let name = f.ident.clone().unwrap(); 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")); let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input"));
if let Some(attr) = input_attr { if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); 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 { if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1]; let from_input = &l.nested[1];
match_hands.extend(quote! { match_hands.extend(quote! {
#arg => Some(self.#from_input()), #arg => if AccessLevel::#access.has_access(access) { Some(self.#from_input()) } else { None },
}); });
} }
else { else {
@ -185,7 +201,7 @@ fn impl_get(data: &syn::Data) -> TokenStream {
else { else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
match_hands.extend(quote! { 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 { if let Some(exp) = field_expr {
let exp: syn::Expr = exp.parse_args().expect("Invalid expression"); let exp: syn::Expr = exp.parse_args().expect("Invalid expression");
match_hands.extend(quote! { match_hands.extend(quote! {
#arg => Some(EntryType::Number(#exp)), #arg => if AccessLevel::#access.has_access(access) { Some(EntryType::Number(#exp)) } else { None },
}) })
} }
else { else {
// No expression, guess we just push this and nothing special (should prob be an input but mehhh) // No expression, guess we just push this and nothing special (should prob be an input but mehhh)
match_hands.extend(quote! { 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 { fn impl_set(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new(); let mut output = TokenStream::new();
output.extend(quote! { 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(); let mut match_hands = TokenStream::new();
@ -230,6 +246,7 @@ fn impl_set(data: &syn::Data) -> TokenStream {
for f in &fs.named { for f in &fs.named {
let name = f.ident.clone().unwrap(); let name = f.ident.clone().unwrap();
let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input")); 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 { if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); 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")); 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 { if let syn::Meta::List(l) = exp {
let to_input = &l.nested[0]; let to_input = &l.nested[0];
match_hands.extend(quote! { match_hands.extend(quote! {
#arg => self.#to_input(value), #arg => if AccessLevel::#access.has_access(access) { self.#to_input(value) },
}); });
} }
else { else {
@ -248,7 +265,7 @@ fn impl_set(data: &syn::Data) -> TokenStream {
else { else {
let t = get_type_ident_set(&f.ty).expect(&format!("Invalid type for input: {}", name)); let t = get_type_ident_set(&f.ty).expect(&format!("Invalid type for input: {}", name));
match_hands.extend(quote! { 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 { fn impl_display(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new(); let mut output = TokenStream::new();
output.extend(quote! { 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 items = TokenStream::new();
let mut count = 0_usize;
if let syn::Data::Struct(ds) = data { if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields { if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named { for f in &fs.named {
let name = f.ident.clone().unwrap(); let name = f.ident.clone().unwrap();
if f.attrs.iter().any(|a| a.path.is_ident("Seperator")) { 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")); let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input"));
if let Some(attr) = input_attr { if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`"); 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 { if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1]; let from_input = &l.nested[1];
items.extend(quote! { 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 { else {
@ -296,7 +318,9 @@ fn impl_display(data: &syn::Data) -> TokenStream {
else { else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name)); let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
items.extend(quote! { 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 { if let Some(exp) = field_expr {
let exp: syn::Expr = exp.parse_args().expect("Invalid expression"); let exp: syn::Expr = exp.parse_args().expect("Invalid expression");
items.extend(quote! { items.extend(quote! {
Some((#arg.to_string(), EntryType::Number(#exp))), if AccessLevel::#access.has_access(access) {
Some((#arg.to_string(), EntryType::Number(#exp)));
}
}) })
} }
else { else {
// No expression, guess we just push this and nothing special (should prob be an input but mehhh) // No expression, guess we just push this and nothing special (should prob be an input but mehhh)
items.extend(quote! { 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 }; let mut vec = quote! { let mut v = Vec::with_capacity(#count); };
vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream())); vec.extend( items);
vec.extend(quote! { v });
output.append(Group::new(Delimiter::Brace, vec)); output.append(Group::new(Delimiter::Brace, vec));
output output