added basic tcp server to update inspector values
parent
2a17262f70
commit
920cff3bbe
|
|
@ -1,21 +1,27 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_egui::EguiContexts;
|
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;
|
pub struct InspectorPlugin;
|
||||||
|
|
||||||
impl Plugin for InspectorPlugin {
|
impl Plugin for InspectorPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.register_type::<InspectorPokemon>()
|
app.register_type::<Inspector>()
|
||||||
.insert_resource(InspectorPokemon::default())
|
.insert_resource(Inspector::default())
|
||||||
.add_system(state_changed);
|
.add_system(state_changed)
|
||||||
|
.add_system(request_handler.in_base_set(CoreSet::PreUpdate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Reflect, Resource, Default, Debug, Clone)]
|
#[derive(Reflect, Resource, Default, Debug, Clone)]
|
||||||
#[reflect(Resource)]
|
#[reflect(Resource)]
|
||||||
pub struct InspectorPokemon {
|
pub struct Inspector {
|
||||||
pub pokemon: Option<Pokemon>,
|
pub pokemon: Option<Pokemon>,
|
||||||
pub nature: Option<Nature>,
|
pub nature: Option<Nature>,
|
||||||
pub characteristic: Option<Characteristic>,
|
pub characteristic: Option<Characteristic>,
|
||||||
|
|
@ -23,7 +29,7 @@ pub struct InspectorPokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_changed(
|
fn state_changed(
|
||||||
inspector: Res<InspectorPokemon>,
|
inspector: Res<Inspector>,
|
||||||
assets: Res<AssetServer>,
|
assets: Res<AssetServer>,
|
||||||
mut ui_assets: ResMut<UiAssets>,
|
mut ui_assets: ResMut<UiAssets>,
|
||||||
mut contexts: EguiContexts,
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use bevy::{prelude::*, window::WindowResolution};
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod inspector;
|
pub mod inspector;
|
||||||
pub mod pokemon;
|
pub mod pokemon;
|
||||||
|
pub mod server;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -23,5 +24,6 @@ fn main() {
|
||||||
.add_plugin(database::DatabasePlugin)
|
.add_plugin(database::DatabasePlugin)
|
||||||
.add_plugin(inspector::InspectorPlugin)
|
.add_plugin(inspector::InspectorPlugin)
|
||||||
.add_plugin(ui::UiPlugin)
|
.add_plugin(ui::UiPlugin)
|
||||||
|
.add_plugin(server::ServerPlugin)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,11 @@ impl DerivedStats {
|
||||||
BaseStat::Speed => &mut self.speed,
|
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)]
|
#[derive(Default, Debug, Clone, Reflect, FromReflect, PartialEq)]
|
||||||
|
|
@ -167,6 +172,32 @@ pub enum BaseStat {
|
||||||
Speed,
|
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 {
|
impl fmt::Display for BaseStat {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
15
src/ui.rs
15
src/ui.rs
|
|
@ -3,7 +3,7 @@ use bevy_egui::{egui, EguiContexts, EguiPlugin};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::collections::HashMap;
|
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_LABEL_WIDTH: f32 = 100.0;
|
||||||
const INPUT_TEXT_WIDTH: f32 = 150.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(
|
fn handle_state(
|
||||||
ui_state: Res<UiState>,
|
ui_state: Res<UiState>,
|
||||||
pokemon: Res<Database<Pokemon>>,
|
pokemon: Res<Database<Pokemon>>,
|
||||||
mut inspector: ResMut<InspectorPokemon>,
|
mut inspector: ResMut<Inspector>,
|
||||||
) {
|
) {
|
||||||
if ui_state.is_changed() {
|
if ui_state.is_changed() {
|
||||||
if let Some(pokemon) = pokemon.map.get(ui_state.name.to_lowercase().as_str()) {
|
if let Some(pokemon) = pokemon.map.get(ui_state.name.to_lowercase().as_str()) {
|
||||||
|
|
@ -80,7 +80,7 @@ fn handle_state(
|
||||||
|
|
||||||
fn ui_system(
|
fn ui_system(
|
||||||
mut contexts: EguiContexts,
|
mut contexts: EguiContexts,
|
||||||
mut inspector: ResMut<InspectorPokemon>,
|
mut inspector: ResMut<Inspector>,
|
||||||
ui_assets: Res<UiAssets>,
|
ui_assets: Res<UiAssets>,
|
||||||
mut ui_state: ResMut<UiState>,
|
mut ui_state: ResMut<UiState>,
|
||||||
mut rendered_texture_id: Local<egui::TextureId>,
|
mut rendered_texture_id: Local<egui::TextureId>,
|
||||||
|
|
@ -243,14 +243,7 @@ fn ui_system(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
for stat in vec![
|
for stat in BaseStat::all() {
|
||||||
BaseStat::Hp,
|
|
||||||
BaseStat::Attack,
|
|
||||||
BaseStat::Defense,
|
|
||||||
BaseStat::SpecialAttack,
|
|
||||||
BaseStat::SpecialDefense,
|
|
||||||
BaseStat::Speed,
|
|
||||||
] {
|
|
||||||
let mut column_size = COLUMNS.iter();
|
let mut column_size = COLUMNS.iter();
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
// Nature modifier
|
// Nature modifier
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue