added basic tcp server to update inspector values

master
hheik 2023-03-23 02:21:25 +02:00
parent 2a17262f70
commit 920cff3bbe
5 changed files with 212 additions and 17 deletions

View File

@ -1,21 +1,27 @@
use bevy::prelude::*;
use bevy_egui::EguiContexts;
use crate::{database::load_url_asset, pokemon::*, ui::UiAssets};
use crate::{
database::{load_url_asset, Database},
pokemon::*,
server::Request,
ui::{UiAssets, UiState},
};
pub struct InspectorPlugin;
impl Plugin for InspectorPlugin {
fn build(&self, app: &mut App) {
app.register_type::<InspectorPokemon>()
.insert_resource(InspectorPokemon::default())
.add_system(state_changed);
app.register_type::<Inspector>()
.insert_resource(Inspector::default())
.add_system(state_changed)
.add_system(request_handler.in_base_set(CoreSet::PreUpdate));
}
}
#[derive(Reflect, Resource, Default, Debug, Clone)]
#[reflect(Resource)]
pub struct InspectorPokemon {
pub struct Inspector {
pub pokemon: Option<Pokemon>,
pub nature: Option<Nature>,
pub characteristic: Option<Characteristic>,
@ -23,7 +29,7 @@ pub struct InspectorPokemon {
}
fn state_changed(
inspector: Res<InspectorPokemon>,
inspector: Res<Inspector>,
assets: Res<AssetServer>,
mut ui_assets: ResMut<UiAssets>,
mut contexts: EguiContexts,
@ -44,3 +50,59 @@ fn state_changed(
}
}
}
fn request_handler(
mut request_events: EventReader<Request>,
mut inspector: ResMut<Inspector>,
mut ui: ResMut<UiState>,
characteristics: Res<Database<Characteristic>>,
natures: Res<Database<Nature>>,
) {
for request in request_events.iter() {
info!("{:#}", request);
match request.urn.as_str() {
"clear" => {
inspector.pokemon = None;
inspector.nature = None;
inspector.characteristic = None;
inspector.derived_stats = DerivedStats::default();
ui.name = String::from("");
ui.level = String::from("");
ui.derived_stats.clear();
}
"update" => {
let data = request.data.clone();
if let Some(name) = data["name"].as_str() {
ui.name = name.to_string();
}
if let Some(level) = data["level"].as_i32() {
ui.level = level.to_string();
inspector.derived_stats.level = Some(level);
}
if let Some(nature) = data["nature"].as_str() {
if let Some(nature) = natures.map.get(&nature.to_lowercase()).cloned() {
inspector.nature = Some(nature);
}
}
if let Some(characteristic) = data["characteristic"].as_str() {
if let Some(characteristic) = characteristics
.map
.get(&characteristic.to_lowercase())
.cloned()
{
inspector.characteristic = Some(characteristic);
}
}
for stat in BaseStat::all() {
if let Some(value) = data[stat.key()].as_i32() {
ui.derived_stats.insert(stat, value.to_string());
inspector.derived_stats.set_stat_value(stat, Some(value));
}
}
}
_ => {
warn!("Unknown urn");
}
}
}
}

View File

@ -3,6 +3,7 @@ use bevy::{prelude::*, window::WindowResolution};
pub mod database;
pub mod inspector;
pub mod pokemon;
pub mod server;
pub mod ui;
fn main() {
@ -23,5 +24,6 @@ fn main() {
.add_plugin(database::DatabasePlugin)
.add_plugin(inspector::InspectorPlugin)
.add_plugin(ui::UiPlugin)
.add_plugin(server::ServerPlugin)
.run();
}

View File

@ -63,6 +63,11 @@ impl DerivedStats {
BaseStat::Speed => &mut self.speed,
}
}
pub fn set_stat_value(&mut self, stat: BaseStat, value: Option<StatValue>) {
let val = self.value_mut(stat);
*val = value;
}
}
#[derive(Default, Debug, Clone, Reflect, FromReflect, PartialEq)]
@ -167,6 +172,32 @@ pub enum BaseStat {
Speed,
}
impl BaseStat {
pub fn all() -> Vec<Self> {
vec![
BaseStat::Hp,
BaseStat::Attack,
BaseStat::Defense,
BaseStat::SpecialAttack,
BaseStat::SpecialDefense,
BaseStat::Speed,
]
}
}
impl GetKey for BaseStat {
fn key(&self) -> String {
match self {
BaseStat::Hp => "hp".to_string(),
BaseStat::Attack => "attack".to_string(),
BaseStat::Defense => "defense".to_string(),
BaseStat::SpecialAttack => "special_attack".to_string(),
BaseStat::SpecialDefense => "special_defense".to_string(),
BaseStat::Speed => "speed".to_string(),
}
}
}
impl fmt::Display for BaseStat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {

107
src/server.rs Normal file
View File

@ -0,0 +1,107 @@
use bevy::prelude::*;
use json::JsonValue;
use std::{
io::Read,
net,
sync::{Arc, Mutex},
thread,
time::Duration,
};
pub struct ServerPlugin;
impl Plugin for ServerPlugin {
fn build(&self, app: &mut App) {
app.add_event::<Request>()
.insert_resource(Server::default())
.add_startup_system(init_server)
.add_system(flush_messages.in_base_set(CoreSet::First));
}
}
#[derive(Resource, Default)]
pub struct Server {
messages: Arc<Mutex<Vec<String>>>,
}
pub struct Request {
pub urn: String,
pub data: JsonValue,
}
impl std::fmt::Display for Request {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {}",
self.urn,
json::stringify_pretty(self.data.clone(), 4)
)
}
}
fn init_server(server: Res<Server>) {
let messages = server.messages.clone();
thread::spawn(move || {
let listener = listen("localhost:8888");
for stream in listener.incoming() {
match stream {
Ok(stream) => handle_message(stream, &messages),
_ => (),
}
}
});
}
fn flush_messages(server: Res<Server>, mut request_events: EventWriter<Request>) {
match server.messages.lock() {
Ok(mut messages) => {
for message in messages.drain(..) {
if let Some(request) = try_parse_request(&message) {
request_events.send(request);
}
}
}
Err(err) => {
error!("{}", err);
}
};
}
fn listen(address: &str) -> net::TcpListener {
net::TcpListener::bind(address).unwrap()
}
fn handle_message(mut stream: net::TcpStream, messages: &Arc<Mutex<Vec<String>>>) {
let mut buffer = String::new();
stream
.set_read_timeout(Some(Duration::from_secs(10)))
.expect("Could not set read timeout for socket");
match stream.read_to_string(&mut buffer) {
Ok(_size) => {
match messages.lock() {
Ok(mut messages) => {
messages.push(buffer);
}
Err(err) => {
error!("{}", err);
}
};
}
_ => (),
}
}
fn try_parse_request(raw: &str) -> Option<Request> {
let obj = json::parse(raw).ok()?;
if !obj.is_object() {
return None;
}
let urn = obj["urn"].as_str()?;
let data = obj["data"].clone();
Some(Request {
urn: urn.to_string(),
data,
})
}

View File

@ -3,7 +3,7 @@ use bevy_egui::{egui, EguiContexts, EguiPlugin};
use lazy_static::lazy_static;
use std::collections::HashMap;
use crate::{database::Database, inspector::InspectorPokemon, pokemon::*};
use crate::{database::Database, inspector::Inspector, pokemon::*};
const INPUT_LABEL_WIDTH: f32 = 100.0;
const INPUT_TEXT_WIDTH: f32 = 150.0;
@ -69,7 +69,7 @@ fn load_assets(mut ui_assets: ResMut<UiAssets>, assets: Res<AssetServer>) {
fn handle_state(
ui_state: Res<UiState>,
pokemon: Res<Database<Pokemon>>,
mut inspector: ResMut<InspectorPokemon>,
mut inspector: ResMut<Inspector>,
) {
if ui_state.is_changed() {
if let Some(pokemon) = pokemon.map.get(ui_state.name.to_lowercase().as_str()) {
@ -80,7 +80,7 @@ fn handle_state(
fn ui_system(
mut contexts: EguiContexts,
mut inspector: ResMut<InspectorPokemon>,
mut inspector: ResMut<Inspector>,
ui_assets: Res<UiAssets>,
mut ui_state: ResMut<UiState>,
mut rendered_texture_id: Local<egui::TextureId>,
@ -243,14 +243,7 @@ fn ui_system(
});
// Stats
for stat in vec![
BaseStat::Hp,
BaseStat::Attack,
BaseStat::Defense,
BaseStat::SpecialAttack,
BaseStat::SpecialDefense,
BaseStat::Speed,
] {
for stat in BaseStat::all() {
let mut column_size = COLUMNS.iter();
ui.horizontal(|ui| {
// Nature modifier