extern crate amethyst;
extern crate crossbeam_channel;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde;
extern crate serde_json;
use std::collections::HashMap;
use amethyst::core::bundle::{Result as BundleResult, SystemBundle};
use amethyst::ecs::*;
use amethyst::shred::Resource;
use crossbeam_channel::{Receiver, Sender};
use serde::Serialize;
use serde::export::PhantomData;
use std::net::UdpSocket;
pub use editor_log::EditorLogger;
pub use ::serializable_entity::SerializableEntity;
mod editor_log;
mod serializable_entity;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Message<T> {
#[serde(rename = "type")]
ty: &'static str,
data: T,
}
#[derive(Debug, Clone, Default, Serialize)]
struct SerializedComponent<'a, T: 'a> {
name: &'static str,
data: HashMap<u32, &'a T>,
}
#[derive(Debug, Clone, Serialize)]
struct SerializedResource<'a, T: 'a> {
name: &'static str,
data: &'a T,
}
enum SerializedData {
Resource(String),
Component(String),
Message(String),
}
#[derive(Clone)]
pub struct EditorConnection {
sender: Sender<SerializedData>,
}
impl EditorConnection {
fn new(sender: Sender<SerializedData>) -> Self {
Self { sender }
}
fn send_data(&self, data: SerializedData) {
self.sender.send(data);
}
pub fn send_message<T: Serialize>(&self, message_type: &'static str, data: T) {
let serialize_data = Message {
ty: message_type,
data,
};
if let Ok(serialized) = serde_json::to_string(&serialize_data) {
self.send_data(SerializedData::Message(serialized));
} else {
error!("Failed to serialize message");
}
}
}
pub struct SyncEditorBundle<T, U> where
T: ComponentSet,
U: ResourceSet,
{
component_names: Vec<&'static str>,
resource_names: Vec<&'static str>,
sender: Sender<SerializedData>,
receiver: Receiver<SerializedData>,
_phantom: PhantomData<(T, U)>,
}
impl SyncEditorBundle<(), ()> {
pub fn new() -> SyncEditorBundle<(), ()> {
let (sender, receiver) = crossbeam_channel::unbounded();
SyncEditorBundle {
component_names: Vec::new(),
resource_names: Vec::new(),
sender,
receiver,
_phantom: PhantomData,
}
}
}
impl<T, U> SyncEditorBundle<T, U> where
T: ComponentSet,
U: ResourceSet,
{
pub fn sync_component<C>(mut self, name: &'static str) -> SyncEditorBundle<(C, T), U>
where
C: Component + Serialize+Send,
{
self.component_names.push(name);
SyncEditorBundle {
component_names: self.component_names,
resource_names: self.resource_names,
sender: self.sender,
receiver: self.receiver,
_phantom: PhantomData,
}
}
pub fn sync_resource<R>(mut self, name: &'static str) -> SyncEditorBundle<T, (R, U)>
where
R: Resource + Serialize,
{
self.resource_names.push(name);
SyncEditorBundle {
component_names: self.component_names,
resource_names: self.resource_names,
sender: self.sender,
receiver: self.receiver,
_phantom: PhantomData,
}
}
pub fn get_connection(&self) -> EditorConnection {
EditorConnection::new(self.sender.clone())
}
}
impl<'a, 'b, T, U> SystemBundle<'a, 'b> for SyncEditorBundle<T, U> where
T: ComponentSet,
U: ResourceSet,
{
fn build(mut self, dispatcher: &mut DispatcherBuilder<'a, 'b>) -> BundleResult<()> {
self.component_names.reverse();
self.resource_names.reverse();
let sync_system = SyncEditorSystem::from_channel(self.sender, self.receiver);
let connection = sync_system.get_connection();
dispatcher.add_barrier();
T::create_sync_systems(dispatcher, &connection, &self.component_names);
U::create_sync_systems(dispatcher, &connection, &self.resource_names);
dispatcher.add_barrier();
dispatcher.add(sync_system, "", &[]);
Ok(())
}
}
pub struct SyncEditorSystem {
receiver: Receiver<SerializedData>,
sender: Sender<SerializedData>,
socket: UdpSocket,
}
impl SyncEditorSystem {
pub fn new() -> Self {
let (sender, receiver) = crossbeam_channel::unbounded();
Self::from_channel(sender, receiver)
}
fn from_channel(sender: Sender<SerializedData>, receiver: Receiver<SerializedData>) -> Self {
let socket = UdpSocket::bind("0.0.0.0:0").expect("Failed to bind socket");
socket.connect("127.0.0.1:8000").expect("Failed to connect to editor");
Self { receiver, sender, socket }
}
pub fn get_connection(&self) -> EditorConnection {
EditorConnection::new(self.sender.clone())
}
}
impl<'a> System<'a> for SyncEditorSystem {
type SystemData = Entities<'a>;
fn run(&mut self, entities: Self::SystemData) {
let mut components = Vec::new();
let mut resources = Vec::new();
let mut messages = Vec::new();
while let Some(serialized) = self.receiver.try_recv() {
match serialized {
SerializedData::Component(c) => components.push(c),
SerializedData::Resource(r) => resources.push(r),
SerializedData::Message(m) => messages.push(m),
}
}
let mut entity_data = Vec::<SerializableEntity>::new();
for (entity,) in (&*entities,).join() {
entity_data.push(entity.into());
}
let entity_string = serde_json::to_string(&entity_data).expect("Failed to serialize entities");
let mut message_string = format!(
r#"{{
"type": "message",
"data": {{
"entities": {},
"components": [{}],
"resources": [{}],
"messages": [{}]
}}
}}"#,
entity_string,
components.join(","),
resources.join(","),
messages.join(","),
);
message_string.push_str("\u{C}");
self.socket.send(message_string.as_bytes()).expect("Failed to send message");
}
}
pub struct SyncComponentSystem<T> {
name: &'static str,
connection: EditorConnection,
_phantom: PhantomData<T>,
}
impl<T> SyncComponentSystem<T> {
pub fn new(name: &'static str, connection: EditorConnection) -> Self {
Self {
name,
connection,
_phantom: PhantomData,
}
}
}
impl<'a, T> System<'a> for SyncComponentSystem<T> where T: Component+Serialize {
type SystemData = (Entities<'a>, ReadStorage<'a, T>);
fn run(&mut self, (entities, components): Self::SystemData) {
let data = (&*entities, &components)
.join()
.map(|(e, c)| (e.id(), c))
.collect();
let serialize_data = SerializedComponent { name: self.name, data };
if let Ok(serialized) = serde_json::to_string(&serialize_data) {
self.connection.send_data(SerializedData::Component(serialized));
} else {
error!("Failed to serialize component of type {}", self.name);
}
}
}
pub struct SyncResourceSystem<T> {
name: &'static str,
connection: EditorConnection,
_phantom: PhantomData<T>,
}
impl<T> SyncResourceSystem<T> {
pub fn new(name: &'static str, connection: EditorConnection) -> Self {
Self {
name,
connection,
_phantom: PhantomData,
}
}
}
impl<'a, T> System<'a> for SyncResourceSystem<T> where T: Resource+Serialize {
type SystemData = ReadExpect<'a, T>;
fn run(&mut self, resource: Self::SystemData) {
let serialize_data = SerializedResource {
name: self.name,
data: &*resource,
};
if let Ok(serialized) = serde_json::to_string(&serialize_data) {
self.connection.send_data(SerializedData::Resource(serialized));
} else {
error!("Failed to serialize resource of type {}", self.name);
}
}
}
pub trait ComponentSet {
fn create_sync_systems(dispatcher: &mut DispatcherBuilder, connection: &EditorConnection, names: &[&'static str]);
}
impl ComponentSet for () {
fn create_sync_systems(_: &mut DispatcherBuilder, _: &EditorConnection, _: &[&'static str]) { }
}
impl<A, B> ComponentSet for (A, B)
where
A: Component + Serialize + Send,
B: ComponentSet,
{
fn create_sync_systems(dispatcher: &mut DispatcherBuilder, connection: &EditorConnection, names: &[&'static str]) {
B::create_sync_systems(dispatcher, connection, &names[1..]);
dispatcher.add(SyncComponentSystem::<A>::new(names[0], connection.clone()), "", &[]);
}
}
pub trait ResourceSet {
fn create_sync_systems(dispatcher: &mut DispatcherBuilder, connection: &EditorConnection, names: &[&'static str]);
}
impl ResourceSet for () {
fn create_sync_systems(_: &mut DispatcherBuilder, _: &EditorConnection, _: &[&'static str]) { }
}
impl<A, B> ResourceSet for (A, B)
where
A: Resource + Serialize,
B: ResourceSet,
{
fn create_sync_systems(dispatcher: &mut DispatcherBuilder, connection: &EditorConnection, names: &[&'static str]) {
B::create_sync_systems(dispatcher, connection, &names[1..]);
dispatcher.add(SyncResourceSystem::<A>::new(names[0], connection.clone()), "", &[]);
}
}