I DID STUFF, GOD A PROC MACRO AND SHIT

This commit is contained in:
Rusty Striker 2024-09-22 23:46:51 +03:00
commit 22319e84a1
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
28 changed files with 3101 additions and 0 deletions

18
src/api/game_actions.rs Normal file
View file

@ -0,0 +1,18 @@
//! General game actions
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Ping {
/// Which texture got pinged
pub texture: String,
/// Where the ping occured in the window
pub pos: (i32, i32),
}
#[derive(Serialize, Deserialize)]
pub struct ShowImage {
/// Which texture to show
pub texture: String
}

0
src/api/get_table.rs Normal file
View file

12
src/api/login.rs Normal file
View file

@ -0,0 +1,12 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct LoginRequest {
pub username: String,
pub hashed_password: String,
}
#[derive(Serialize, Deserialize)]
pub struct LoginData {
// TODO: Figure out what the user needs on successful login to reduce traffic
}

16
src/api/map_actions.rs Normal file
View file

@ -0,0 +1,16 @@
//! Map specific game actions
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct MoveToken {
/// Moved token
pub token: String,
/// Token original position - in case wall detection is required
pub from: (i32, i32),
/// Token final position
pub to: (i32, i32),
}
pub struct InsertToken {
pub token: String
}

12
src/api/mod.rs Normal file
View file

@ -0,0 +1,12 @@
pub mod login;
pub mod game_actions;
pub mod map_actions;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ResultBase<T: Serialize> {
pub success: bool,
pub fail_reason: Option<String>,
pub data: Option<T>
}

View file

@ -0,0 +1,61 @@
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 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)>>;
/// Gets a character sheet entry value
fn get(&self, entry: &str) -> Option<EntryType>;
/// Sets a cahrater sheet entry value
fn set(&mut self, entry: &str, value: EntryType);
}
#[derive(Debug)]
pub enum EntryType {
Number(i32),
Text(String),
Bool(bool),
}
impl Default for EntryType {
fn default() -> Self {
EntryType::Number(0)
}
}
impl EntryType {
pub fn as_num(&self) -> i32 {
if let EntryType::Number(n) = *self {
n
}
else {
0
}
}
pub fn as_text(&self) -> String {
if let EntryType::Text(t) = self {
t.clone()
}
else {
String::new()
}
}
pub fn as_bool(&self) -> bool {
if let EntryType::Bool(b) = *self {
b
}
else {
false
}
}
}
impl std::fmt::Display for EntryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match(self) {
EntryType::Number(n) => write!(f, "{}", n),
EntryType::Text(t) => write!(f, "{}", t),
EntryType::Bool(b) => write!(f, "{}", b),
}
}
}

33
src/game/interaction.rs Normal file
View file

@ -0,0 +1,33 @@
pub struct Interaction {
/// Max number of entities that can be targeted in one go, 0 for non.
pub max_targets: u32,
}
pub struct ChatMessage {
/// Optional text portion
text: String,
/// Optional action buttons, for a chat message this will be empty
actions: Vec<String>,
/// Source/Caster/Whoever initiated the action/sent the message
actor: String,
/// Targets of the action, for a chat message this will be empty
targets: Vec<String>
}
pub struct RollDialogOption {
/// Field name
name: String,
/// dice size (aka d6, d12, d20)
dice: u16,
/// amount of dice (aka 1d6, 2d12, 10d20)
dice_amount: u16,
/// Constant amout to add (+7, +3, -1)
constant: i16,
/// Extra data, like damage type
extra: String,
/// should be enabled by default
enabled: bool
}

5
src/game/mod.rs Normal file
View file

@ -0,0 +1,5 @@
//! Game Parser and Data types
pub mod character_sheet;
pub mod interaction;

5
src/lib.rs Normal file
View file

@ -0,0 +1,5 @@
pub mod user;
pub mod table;
pub mod api;
pub mod game;
pub mod pathfinder2r_impl;

84
src/main.rs Normal file
View file

@ -0,0 +1,84 @@
use axum::{
extract::ws, response, routing, Router
};
use open_tavern::{game::character_sheet::{CharacterSheet, EntryType}, pathfinder2r_impl};
#[tokio::main]
async fn main() {
let mut pf = pathfinder2r_impl::Pathfinder2rCharacterSheet::default();
pf.set("Dexterity", EntryType::Number(10));
pf.set("Name", EntryType::Text("AAAA".to_string()));
pf.set("Items", EntryType::Text("Short Sword, Dragonleather Helmet".to_string()));
let d = pf.display();
for e in d {
if let Some((s, v)) = e {
println!("{}: {}", s, v);
}
else {
println!();
}
}
println!();
// let app = Router::new()
// .route("/", routing::get(root))
// .route("/socket.js", routing::get(socket))
// .route("/ws", routing::get(ws_handler))
// ;
// let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
// axum::serve(listener, app).await.unwrap();
}
async fn ws_handler(ws: ws::WebSocketUpgrade) -> impl axum::response::IntoResponse {
ws.on_upgrade(handle_socket)
}
async fn handle_socket(mut socket: ws::WebSocket) {
if socket.send(ws::Message::Text("This is my test message!".to_string())).await.is_ok() {
println!("pinged!");
}
let mut logged_in = false;
loop {
if let Some(msg) = socket.recv().await {
if let Ok(msg) = msg {
match msg {
ws::Message::Text(t) => {
println!("Got message: {}", t);
if !logged_in && t.starts_with("login") {
let mut split = t.splitn(2, ' ');
split.next(); // the login part
let user = split.next().unwrap();
if open_tavern::user::User::default_admin().login(user) {
socket.send(ws::Message::Text("ok".to_string())).await.unwrap();
logged_in = true;
}
else {
socket.send(ws::Message::Text("bad".to_string())).await.unwrap();
}
}
}
ws::Message::Binary(b) => println!("got bytes: {:?}", b),
ws::Message::Ping(_) => todo!(),
ws::Message::Pong(_) => todo!(),
ws::Message::Close(_) => break,
}
}
}
else {
break;
}
}
println!("Done with so-cat");
}
async fn root() -> axum::response::Html<&'static str> {
response::Html(include_str!("../assets/web/index.html"))
}
async fn socket() -> &'static str {
include_str!("../assets/web/socket.js")
}

View file

@ -0,0 +1,44 @@
use tavern_macros::CharacterSheet;
use crate::game::character_sheet::*;
#[derive(Default, CharacterSheet)]
pub struct Pathfinder2rCharacterSheet {
// Genral stuff
#[Input("Name")]
name: String,
#[Input("Items")]
items: String,
// Attributes
#[Seperator]
#[Input("Strength")]
str: i32,
#[Input("Dexterity")]
dex: i32,
#[Input("Constitution")]
con: i32,
#[Input("Intelligence")]
int: i32,
#[Input("Wisdom")]
wis: i32,
#[Input("Charisma")]
cha: i32,
// Skills
#[Seperator]
#[Field("Acrobatics")]
#[FieldExpr(self.dex + self.acrobatics_prof * 2)]
_acro: i32,
#[Input("Acrobatics Prof")]
acrobatics_prof: i32,
#[Field("Arcana")]
#[FieldExpr(self.int + self.arcana_prof * 2)]
_arca: i32,
#[Input("Arcana Prof")]
arcana_prof: i32,
#[Field("Crafting")]
#[FieldExpr(self.int + self.crafting_prof * 2)]
_crafting: i32,
#[Input("Crafting Prof")]
crafting_prof: i32,
// TODO: Add more skills
// TODO: Also add all the rest of the sheet items
}

9
src/table/entity.rs Normal file
View file

@ -0,0 +1,9 @@
use crate::user::User;
pub struct Entity {
/// Id will be an increasing u64, which might cause problems if the game has (way too) many entities
pub id: u64,
pub owner: User
}

4
src/table/mod.rs Normal file
View file

@ -0,0 +1,4 @@
mod texture;
pub mod entity;
pub use texture::*;

33
src/table/texture.rs Normal file
View file

@ -0,0 +1,33 @@
pub enum Grid {
Square { width: u32 },
Hexagon { width: u32 },
Triangle { width: u32 },
}
/// Texture directory source and file
pub enum TextureSource {
// TODO: I think os string would better fit, to do later
/// Server's shared textures directory
Shared(String),
/// Custom table directory
Custom(String),
/// Game shared textures directory
Game(String),
}
pub enum TextureType {
Image,
Token,
Map {
/// Grid type and size
grid: Grid,
/// grid offset from (0, 0)
grid_offset: (i32, i32),
}
}
pub struct Texture {
pub source: TextureSource,
pub ttype: TextureType,
}

16
src/user.rs Normal file
View file

@ -0,0 +1,16 @@
pub struct User {
username: String,
}
impl User {
pub fn default_admin() -> User {
User {
username: "admin".to_string(),
}
}
pub fn login(&self, username: &str) -> bool {
self.username == username
}
}