use super::session::Mailbox;
use crate::initialize::create_sub_share_dir;
use crate::session::SendUIMessage;
use actix::{AsyncContext, Handler, Message};
use glam::U16Vec2;
use glam::Vec3;
use log::error;
use log::warn;
use metaverse_environment::{
land::Land,
layer_handler::{parse_layer_data, PatchLayer},
};
use metaverse_messages::packet::message::UIMessage;
use metaverse_messages::udp::environment::layer_data::LayerData;
use metaverse_messages::ui::land_update::{LandData, LandUpdate};
use serde::Serialize;
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::PathBuf;
#[derive(Debug)]
pub struct EnvironmentCache {
pub patch_queue: HashMap<U16Vec2, Land>,
pub patch_cache: HashMap<U16Vec2, Land>,
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct HandleLayerData {
pub layer_data: LayerData,
}
#[cfg(feature = "environment")]
impl Handler<HandleLayerData> for Mailbox {
type Result = ();
fn handle(&mut self, msg: HandleLayerData, ctx: &mut Self::Context) -> Self::Result {
if let Some(session) = self.session.as_mut()
&& let Ok(patch_data) = parse_layer_data(&msg.layer_data)
{
match patch_data {
PatchLayer::Land(patches) => {
for land in patches {
session
.environment_cache
.patch_cache
.insert(land.terrain_header.location, land.clone());
let mut layer_meshes = Vec::new();
if let Some(mesh) = land.clone().generate_mesh(
&mut session.environment_cache.patch_queue,
&session.environment_cache.patch_cache,
) {
layer_meshes.push(mesh);
}
let queue_save = session.environment_cache.patch_queue.clone();
for (_location, land) in queue_save {
if let Some(mesh) = land.generate_mesh(
&mut session.environment_cache.patch_queue,
&session.environment_cache.patch_cache,
) {
layer_meshes.push(mesh);
}
}
for (mesh, coordinate) in layer_meshes {
let scale = land.terrain_header.patch_size as f32;
let json_path = write_json(
&LandData {
vertices: mesh.vertices,
indices: mesh.indices,
position: Vec3 {
x: ((coordinate.x as f32) * scale),
y: 0.0,
z: ((coordinate.y as f32) * scale),
},
},
land.terrain_header.filename.clone(),
)
.unwrap();
ctx.address()
.do_send(SendUIMessage{ui_message: UIMessage::new_land_update(LandUpdate {
path: json_path,
})});
}
}
}
PatchLayer::Wind(_patches) => {
warn!("Wind patch received. Currently unimplemented.");
}
PatchLayer::Water(_patches) => {
warn!("Water patch received. Currently unimplemented.");
}
PatchLayer::Cloud(_patches) => {
warn!("Cloud patch received. Currently unimplemented.");
}
}
}
}
}
fn write_json<T: Serialize>(data: &T, filename: String) -> io::Result<PathBuf> {
match create_sub_share_dir("land") {
Ok(mut agent_dir) => match serde_json::to_string(&data) {
Ok(json) => {
agent_dir.push(format!("{}.json", filename));
let mut file = File::create(&agent_dir).unwrap();
file.write_all(json.as_bytes()).unwrap();
Ok(agent_dir)
}
Err(e) => {
error!("Failed to serialize scene group {:?}, {:?}", filename, e);
Err(io::Error::other(e))
}
},
Err(e) => {
error!(
"Failed to create agent dir for {:?}. Unable to cache downloaded items.",
e
);
Err(io::Error::other(e))
}
}
}