aboutsummaryrefslogtreecommitdiff
path: root/core/src/pad_data
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/pad_data')
-rw-r--r--core/src/pad_data/game_layout.rs9
-rw-r--r--core/src/pad_data/game_profile.rs99
-rw-r--r--core/src/pad_data/mod.rs4
-rw-r--r--core/src/pad_data/pad_messages.rs176
-rw-r--r--core/src/pad_data/pad_player_info.rs126
5 files changed, 414 insertions, 0 deletions
diff --git a/core/src/pad_data/game_layout.rs b/core/src/pad_data/game_layout.rs
new file mode 100644
index 0000000..62afbcc
--- /dev/null
+++ b/core/src/pad_data/game_layout.rs
@@ -0,0 +1,9 @@
+pub mod game_layout {
+ use bincode::{Decode, Encode};
+ use serde::{Deserialize, Serialize};
+
+ #[derive(Encode, Decode, Serialize, Deserialize, PartialEq, Debug)]
+ pub struct GameLayout {
+
+ }
+} \ No newline at end of file
diff --git a/core/src/pad_data/game_profile.rs b/core/src/pad_data/game_profile.rs
new file mode 100644
index 0000000..8d6e279
--- /dev/null
+++ b/core/src/pad_data/game_profile.rs
@@ -0,0 +1,99 @@
+pub mod game_profile {
+ use std::fmt::Display;
+ use bincode::{Decode, Encode};
+ use serde::{Deserialize, Serialize};
+
+ #[derive(Encode, Decode, Serialize, Deserialize, PartialEq, Debug)]
+ pub struct GameProfile {
+
+ // 游戏名称
+ pub game_name: String,
+
+ // 游戏描述
+ pub game_description: String,
+
+ // 游戏组织
+ pub organization: String,
+
+ // 游戏版本
+ pub version: String,
+
+ // 工作室 & 游戏 主页
+ pub website: String,
+
+ // 交流邮箱
+ pub email: String
+ }
+
+ impl Default for GameProfile {
+ fn default() -> Self {
+ GameProfile {
+ game_name: "Unnamed Game".to_string(),
+ game_description: "".to_string(),
+ organization: "".to_string(),
+ version: "0.1".to_string(),
+ website: "".to_string(),
+ email: "".to_string()
+ }
+ }
+ }
+
+ impl Clone for GameProfile {
+ fn clone(&self) -> Self {
+ GameProfile {
+ game_name: self.game_name.clone(),
+ game_description: self.game_description.clone(),
+ organization: self.organization.clone(),
+ version: self.version.clone(),
+ website: self.website.clone(),
+ email: self.email.clone()
+ }
+ }
+ }
+
+ impl Display for GameProfile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut string = String::new();
+ string += format!("Game Name: {}\n", self.game_name).as_str();
+ if !self.game_description.eq("") { string += format!("Description: {}\n", self.game_description).as_str(); }
+ if !self.organization.eq("") { string += format!("Org: {}\n", self.organization).as_str(); }
+ if !self.website.eq("") { string += format!("- Web: {}\n", self.website).as_str(); }
+ if !self.version.eq("") { string += format!("Version: {}\n", self.version).as_str(); }
+ if !self.email.eq("") { string += format!("- E-mail: {}\n", self.email).as_str(); }
+
+ write!(f, "{}", string)
+ }
+ }
+
+ impl GameProfile {
+ pub fn game_name(&mut self, game_name: &str) -> &mut GameProfile {
+ self.game_name = game_name.to_string();
+ self
+ }
+
+ pub fn game_description(&mut self, game_description: &str) -> &mut GameProfile {
+ self.game_description = game_description.to_string();
+ self
+ }
+
+ pub fn organization(&mut self, organization: &str) -> &mut GameProfile {
+ self.organization = organization.to_string();
+ self
+ }
+
+ pub fn version(&mut self, version: &str) -> &mut GameProfile {
+ self.version = version.to_string();
+ self
+ }
+
+ pub fn website(&mut self, website: &str) -> &mut GameProfile {
+ self.website = website.to_string();
+ self
+ }
+
+ pub fn email(&mut self, email: &str) -> &mut GameProfile {
+ self.email = email.to_string();
+ self
+ }
+ }
+} \ No newline at end of file
diff --git a/core/src/pad_data/mod.rs b/core/src/pad_data/mod.rs
new file mode 100644
index 0000000..8ff024a
--- /dev/null
+++ b/core/src/pad_data/mod.rs
@@ -0,0 +1,4 @@
+pub mod pad_messages;
+pub mod pad_player_info;
+pub mod game_profile;
+mod game_layout; \ No newline at end of file
diff --git a/core/src/pad_data/pad_messages.rs b/core/src/pad_data/pad_messages.rs
new file mode 100644
index 0000000..f081e5d
--- /dev/null
+++ b/core/src/pad_data/pad_messages.rs
@@ -0,0 +1,176 @@
+pub mod nogamepads_messages {
+ use bincode::{Decode, Encode};
+ use crate::pad_data::game_profile::game_profile::GameProfile;
+ use crate::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum ControlMessage {
+
+ Msg(String),
+
+ Pressed(u8),
+
+ Released(u8),
+
+ Axis(u8, f64),
+
+ Dir(u8, (f64, f64)),
+
+ Exit,
+
+ Err
+ }
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum GameMessage {
+
+ SkinEventTrigger(u8),
+
+ DisableKey(u8),
+
+ EnableKey(u8),
+
+ Leave(LeaveReason),
+
+ Err
+ }
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum LeaveReason {
+
+ GameOver,
+
+ ServerClosed,
+
+ YouAreKicked,
+
+ YouAreBanned
+ }
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum ConnectionMessage {
+
+ Connection(PlayerInfo),
+
+ RequestProfile,
+
+ RequestLayoutConfigure,
+
+ RequestSkinPackage,
+
+ Ready,
+
+ Err
+ }
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum ConnectionCallbackMessage {
+
+ Profile(GameProfile),
+
+ Deny(ConnectionErrorType),
+
+ Fail(ConnectionErrorType),
+
+ Ok,
+
+ Welcome,
+
+ Err
+ }
+
+ #[derive(Encode, Decode, PartialEq, Debug, Clone)]
+ pub enum ConnectionErrorType {
+
+ ContainSamePlayer,
+
+ PlayerBanned,
+
+ Timeout,
+
+ GameLocked,
+
+ WhatTheHell
+ }
+}
+
+pub mod nogamepads_message_encoder {
+ use bincode::{Decode, Encode};
+ use crate::{BINCODE_CONFIG, BINCODE_CONVERT_FAILED};
+ use crate::pad_data::pad_messages::nogamepads_messages::{ConnectionCallbackMessage, ConnectionMessage, ControlMessage, GameMessage};
+
+ pub trait NgpdMessageEncoder<Message: Encode + Decode<()>> {
+ fn err_result_decode () -> Message;
+ fn err_result_encode () -> Vec<u8> {
+ BINCODE_CONVERT_FAILED
+ }
+
+ fn en(&self) -> Vec<u8> where Self : Encode {
+ bincode::encode_to_vec(self, BINCODE_CONFIG)
+ .unwrap_or_else(|_| Self::err_result_encode())
+ }
+
+ fn de(encoded : Vec<u8>) -> Message {
+ match bincode::decode_from_slice(&encoded[..], BINCODE_CONFIG) {
+ Ok((decoded, _)) => decoded,
+ Err(_) => Self::err_result_decode()
+ }
+ }
+ }
+
+ impl NgpdMessageEncoder<ControlMessage> for ControlMessage {
+ fn err_result_decode() -> ControlMessage {
+ ControlMessage::Err
+ }
+ }
+
+ impl NgpdMessageEncoder<GameMessage> for GameMessage {
+ fn err_result_decode() -> GameMessage {
+ GameMessage::Err
+ }
+ }
+
+ impl NgpdMessageEncoder<ConnectionMessage> for ConnectionMessage {
+ fn err_result_decode() -> ConnectionMessage {
+ ConnectionMessage::Err
+ }
+ }
+
+ impl NgpdMessageEncoder<ConnectionCallbackMessage> for ConnectionCallbackMessage {
+ fn err_result_decode() -> ConnectionCallbackMessage {
+ ConnectionCallbackMessage::Err
+ }
+ }
+}
+
+pub mod nogamepads_message_transfer {
+ use bincode::{Decode, Encode};
+ use log::error;
+ use tokio::io::{AsyncReadExt, AsyncWriteExt};
+ use tokio::net::TcpStream;
+ use crate::pad_data::pad_messages::nogamepads_message_encoder::NgpdMessageEncoder;
+
+ pub async fn send_msg <Message>(stream: &mut TcpStream, msg: impl NgpdMessageEncoder<Message> + Decode<()> + Encode)
+ where Message: NgpdMessageEncoder<Message> + Decode<()> + Encode {
+ match stream.write_all(NgpdMessageEncoder::en(&msg).as_slice()).await {
+ Ok(_) => {}
+ Err(_) => {
+ error!("Failed to send message.");
+ }
+ }
+ }
+
+ pub async fn read_msg<Message>(buffer: &mut [u8], stream: &mut TcpStream) -> Message
+ where Message: NgpdMessageEncoder<Message> + Decode<()> + Encode {
+ match stream.read(buffer).await {
+ Ok(read) => {
+ let received = &buffer[..read];
+ <Message as NgpdMessageEncoder<Message>>::de(Vec::from(received))
+ }
+ Err(err) => {
+ error!("Error reading from socket: {}", err);
+ <Message as NgpdMessageEncoder<Message>>::err_result_decode()
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/core/src/pad_data/pad_player_info.rs b/core/src/pad_data/pad_player_info.rs
new file mode 100644
index 0000000..ab0f6fd
--- /dev/null
+++ b/core/src/pad_data/pad_player_info.rs
@@ -0,0 +1,126 @@
+pub mod nogamepads_player_info {
+
+ use bincode::{Decode, Encode};
+ use hex::encode;
+ use sha1::{Digest, Sha1};
+ use serde::{Deserialize, Serialize};
+
+ pub const ACCOUNT_HASH_SALT : &str = "Mr.Weicao";
+
+ #[derive(Encode, Decode,
+ Serialize, Deserialize,
+ PartialEq, Debug)]
+ pub struct PlayerInfo {
+ pub account: PlayerAccountInfo,
+ pub customize: PlayerCustomizeInfo
+ }
+
+ #[derive(Encode, Decode,
+ Serialize, Deserialize,
+ PartialEq, Debug)]
+ pub struct PlayerAccountInfo {
+ pub id: String,
+ pub player_hash: String
+ }
+
+ #[derive(Encode, Decode,
+ Serialize, Deserialize,
+ PartialEq, Debug)]
+ pub struct PlayerCustomizeInfo {
+ pub nickname: String,
+
+ pub color_hue: i32, // 0 - 360
+ pub color_saturation: f64, // 0 - 1
+ pub color_value: f64 // 0 - 1
+ }
+
+ impl PlayerInfo {
+
+ pub fn new() -> PlayerInfo {
+ PlayerInfo {
+ customize: PlayerCustomizeInfo::default(),
+ account: PlayerAccountInfo::default()
+ }
+ }
+
+ pub fn set_nickname(&mut self, name: &str) -> &mut PlayerInfo {
+ self.customize.nickname = String::from(name);
+ self
+ }
+
+ pub fn set_customize_color_hue(&mut self, mut hue: i32) -> &mut PlayerInfo {
+ hue = hue.clamp(0, 360);
+ self.customize.color_hue = hue;
+ self
+ }
+
+ pub fn set_customize_color_hsv(&mut self, mut hue: i32, mut saturation: f64, mut value: f64) -> &mut PlayerInfo {
+ hue = hue.clamp(0, 360);
+ saturation = saturation.clamp(0.0, 1.0);
+ value = value.clamp(0.0, 1.0);
+
+ self.customize.color_hue = hue;
+ self.customize.color_saturation = saturation;
+ self.customize.color_value = value;
+ self
+ }
+
+ pub fn setup_account_info(&mut self, id: &str, password: &str) -> &mut PlayerInfo {
+
+ let combined = format!("{}{}{}", id, password, ACCOUNT_HASH_SALT);
+ let mut hasher = Sha1::new();
+ hasher.update(combined);
+ let result = hasher.finalize();
+
+ self.account.id = String::from(id);
+ self.account.player_hash = encode(&result[..]);
+ self
+ }
+ }
+
+ impl Clone for PlayerInfo {
+ fn clone(&self) -> PlayerInfo {
+ PlayerInfo {
+ account: PlayerAccountInfo {
+ id: String::from(self.account.id.clone()),
+ player_hash: String::from(self.account.player_hash.clone())
+ },
+ customize: PlayerCustomizeInfo {
+ nickname: self.customize.nickname.clone(),
+ color_hue: self.customize.color_hue.clone(),
+ color_saturation: self.customize.color_saturation.clone(),
+ color_value: self.customize.color_value.clone()
+ }
+ }
+ }
+ }
+
+ impl Default for PlayerCustomizeInfo {
+ fn default() -> Self {
+ PlayerCustomizeInfo {
+ nickname: String::from("unnamed"),
+
+ color_hue: 120,
+ color_saturation: 1.0,
+ color_value: 1.0
+ }
+ }
+ }
+
+ impl Default for PlayerAccountInfo {
+ fn default() -> Self {
+ PlayerAccountInfo {
+ id: String::from("empty"),
+ player_hash: String::from("")
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod player_info_test {
+ #[test]
+ fn test_player_info_setup() {
+
+ }
+} \ No newline at end of file