I DID STUFF, GOD A PROC MACRO AND SHIT
This commit is contained in:
commit
22319e84a1
28 changed files with 3101 additions and 0 deletions
18
src/api/game_actions.rs
Normal file
18
src/api/game_actions.rs
Normal 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
0
src/api/get_table.rs
Normal file
12
src/api/login.rs
Normal file
12
src/api/login.rs
Normal 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
16
src/api/map_actions.rs
Normal 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
12
src/api/mod.rs
Normal 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>
|
||||
}
|
61
src/game/character_sheet.rs
Normal file
61
src/game/character_sheet.rs
Normal 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
33
src/game/interaction.rs
Normal 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
5
src/game/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
//! Game Parser and Data types
|
||||
|
||||
|
||||
pub mod character_sheet;
|
||||
pub mod interaction;
|
5
src/lib.rs
Normal file
5
src/lib.rs
Normal 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
84
src/main.rs
Normal 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")
|
||||
}
|
||||
|
44
src/pathfinder2r_impl/mod.rs
Normal file
44
src/pathfinder2r_impl/mod.rs
Normal 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
9
src/table/entity.rs
Normal 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
4
src/table/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
mod texture;
|
||||
pub mod entity;
|
||||
|
||||
pub use texture::*;
|
33
src/table/texture.rs
Normal file
33
src/table/texture.rs
Normal 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
16
src/user.rs
Normal 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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue