use std::collections::HashMap;
use godot::classes::*;
use godot::prelude::*;
use crate::godot::reg::set_variant;
#[derive(GodotClass)]
#[class(base=Node)]
pub struct SiloWorld {
#[base]
base: Base<Node>,
#[export]
pub world: i64,
#[export]
pub def_entries: Dictionary<GString, Option<Gd<PackedScene>>>,
#[export]
pub def_skins: Dictionary<GString, Option<Gd<PackedScene>>>,
ch: crate::base::Chan,
entitys: HashMap<u64, HashMap<u64, Gd<SiloObject>>>,
}
impl SiloWorld {
pub fn get_skin(&self, t: &String) -> Option<Gd<PackedScene>> {
self.def_skins.get(t.as_str()).flatten()
}
fn spawn(&mut self, id: u64, t: &String, world: u64) {
godot_print!("spawn {} {} {}", id, t, world);
let entity_to_instantiate: Option<Gd<PackedScene>> =
self.def_entries.get(t.as_str()).flatten();
if let Some(entity) = entity_to_instantiate {
let mut object: Gd<Node> = entity.instantiate().expect("Failed to instantiate entity");
let name = format!("{}#{}", t.replace("::", "#"), id);
object.set_name(&name);
match object.try_cast::<SiloObject>() {
Ok(mut silo_object) => {
{
let mut silo_object_mut = silo_object.bind_mut();
silo_object_mut.t = t.to_string();
silo_object_mut.id = id;
silo_object_mut.world = world;
}
self.base_mut().add_child(&silo_object);
self.entitys
.entry(world)
.or_default()
.insert(id, silo_object);
}
Err(_) => {}
}
}
}
fn despawn(&mut self, id: u64, world: u64) {
godot_print!("despawn {} {}", id, world);
if let Some(object) = self.entitys.get_mut(&world).and_then(|map| map.remove(&id)) {
self.base_mut().remove_child(&object);
}
}
fn change(&self, id: u64, world: u64, t: &String, v: &bytes::Bytes) {
godot_print!("change {} {} {} size:{}", id, world, t, v.len());
if let Some(object) = self.entitys.get(&world).and_then(|map| map.get(&id)) {
object.bind().set_value(self, t, v);
}
}
}
#[godot_api]
impl INode for SiloWorld {
fn init(base: Base<Node>) -> Self {
Self {
base,
def_entries: Dictionary::new(),
def_skins: Dictionary::new(),
ch: crate::base::RUNTIME.chan(),
entitys: HashMap::new(),
world: 0,
}
}
fn ready(&mut self) {
godot_print!("ready");
}
fn physics_process(&mut self, _delta: f64) {
while let Ok(v) = self.ch.rx.try_recv() {
match v {
crate::base::Message::Event(event) => match event {
crate::base::Event::Spawn { id, t, world } => {
if self.world as u64 == world {
self.spawn(id, &t, world);
}
}
crate::base::Event::Despawn { id, world } => {
if self.world as u64 == world {
self.despawn(id, world);
}
}
crate::base::Event::Change { id, world, t, v } => {
if self.world as u64 == world {
self.change(id, world, &t, &v);
}
}
_ => {}
},
_ => {}
}
}
}
}
#[derive(GodotClass)]
#[class(base=Node)]
pub struct SiloObject {
#[base]
base: Base<Node>,
t: String,
id: u64,
world: u64,
}
impl SiloObject {
fn set_value(&self, world: &crate::godot::nodes::SiloWorld, t: &String, v: &bytes::Bytes) {
let pattern = t.replace("::", "#");
let vs = self.base().find_children(&pattern);
for i in 0..vs.len() {
if let Some(node) = vs.get(i) {
if let Ok(mut silo_variant) = node.try_cast::<SiloVariant>() {
set_variant(world, silo_variant.bind_mut(), t, v);
}
}
}
}
}
#[godot_api]
impl INode for SiloObject {
fn init(base: Base<Node>) -> Self {
Self {
base,
t: String::new(),
id: 0,
world: 0,
}
}
}
#[derive(GodotClass)]
#[class(init,base=Node)]
pub struct SiloVariant {
#[base]
base: Base<Node>,
}
#[godot_api]
impl INode for SiloVariant {}