Skip to content
Snippets Groups Projects
Commit 43516d13 authored by Martins Mozeiko's avatar Martins Mozeiko
Browse files

Initial code for running master and connecting to cluster to clients

parent 40e0d8a1
No related branches found
No related tags found
No related merge requests found
Showing
with 1052 additions and 74 deletions
fileFormatVersion: 2
guid: 1456417bceb89384d804f93a409b862d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
MIT License
Copyright (c) 2019 Ruslan Pyrch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
fileFormatVersion: 2
guid: 82a04b3b3a505a543b70e3a8ac18b851
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File added
fileFormatVersion: 2
guid: b655bae97152cb1499f4c24522a19e0b
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 047db2f9c8b3f93408ee50f9636a6039
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections.Concurrent;
using LiteNetLib;
using LiteNetLib.Utils;
using UnityEngine;
using System.ComponentModel;
using UnityEngine.SceneManagement;
using System.Linq;
using System.Globalization;
namespace Simulator.Network
{
public class ClientManager : MonoBehaviour, INetEventListener
{
State ClientState = State.Initial;
NetManager Manager;
NetPacketProcessor Packets = new NetPacketProcessor();
NetPeer Master;
ConcurrentQueue<Action> Actions = new ConcurrentQueue<Action>();
void Awake()
{
Packets.RegisterNestedType(SerializationHelpers.SerializeLoadAgent, SerializationHelpers.DeserializeLoadAgent);
Packets.SubscribeReusable<Commands.Load>(OnLoadCommand);
Packets.SubscribeReusable<Commands.Run>(OnRunCommand);
Manager = new NetManager(this);
Manager.UpdateTime = 1;
Manager.Start(Constants.Port);
DontDestroyOnLoad(this);
}
void OnApplicationQuit()
{
Manager.Stop();
}
void Update()
{
Manager.PollEvents();
while (Actions.TryDequeue(out var action))
{
action();
}
}
void OnDestroy()
{
Manager.Stop();
}
public void OnPeerConnected(NetPeer peer)
{
Debug.Assert(ClientState == State.Initial);
Master = peer;
Debug.Log($"Master {peer.EndPoint} connected");
var info = new Commands.Info()
{
Version = "todo",
UnityVersion = Application.unityVersion,
OperatingSystem = SystemInfo.operatingSystemFamily.ToString(),
};
Packets.Send(Master, info, DeliveryMethod.ReliableOrdered);
ClientState = State.Connected;
}
public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
Debug.Log($"Peer {peer.EndPoint} disconnected: reason={disconnectInfo.Reason}, error={disconnectInfo.SocketErrorCode}");
ClientState = State.Initial;
Master = null;
}
public void OnNetworkError(IPEndPoint endPoint, SocketError socketError)
{
Debug.Log($"Error {socketError} for {endPoint} endpoint");
// if master != null then raise exceptions
}
public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod)
{
Debug.Assert(Master == peer);
Packets.ReadAllPackets(reader, peer);
}
public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
{
}
public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
}
public void OnConnectionRequest(ConnectionRequest request)
{
Debug.Assert(ClientState == State.Initial);
if (Master == null)
{
request.AcceptIfKey(Constants.ConnectionKey);
}
else
{
request.Reject();
}
}
public void OnLoadCommand(Commands.Load load)
{
Debug.Assert(ClientState == State.Connected);
ClientState = State.Loading;
Debug.Log("Preparing simulation");
try
{
using (var web = new WebClient())
{
var mapPath = Path.Combine(Web.Config.Root, load.Name);
if (!File.Exists(mapPath))
{
Debug.Log($"Downloading {load.Name}");
AsyncCompletedEventHandler mapDownloadHandler = null;
Action<object, AsyncCompletedEventArgs> mapDownloaded = (sender, args) =>
{
web.DownloadFileCompleted -= mapDownloadHandler;
if (args.Error != null)
{
Debug.LogException(args.Error);
var err = new Commands.LoadResult()
{
Success = false,
ErrorMessage = args.Error.ToString(),
};
Packets.Send(Master, err, DeliveryMethod.ReliableOrdered);
return;
}
LoadMapBundle(load);
};
mapDownloadHandler = new AsyncCompletedEventHandler(mapDownloaded);
web.DownloadFileCompleted += mapDownloadHandler;
web.DownloadFileAsync(new Uri($"http://{Master.EndPoint.Address}:8080/download/map/{load.Name}"), mapPath);
}
else
{
Debug.Log($"Map {load.Name} exists");
LoadMapBundle(load);
}
}
}
catch (Exception ex)
{
Debug.LogException(ex);
var err = new Commands.LoadResult()
{
Success = false,
ErrorMessage = ex.ToString(),
};
Packets.Send(Master, err, DeliveryMethod.ReliableOrdered);
Loader.ResetLoaderScene();
}
}
public void OnRunCommand(Commands.Run run)
{
Debug.Assert(ClientState == State.Ready);
ClientState = State.Running;
SimulatorManager.SetTimeScale(1.0f);
}
void DownloadVehicleBundles(Commands.Load load)
{
try
{
using (var web = new WebClient())
{
foreach (var agent in load.Agents)
{
var vehiclePath = Path.Combine(Web.Config.Root, agent.Name);
if (!File.Exists(vehiclePath))
{
Debug.Log($"Downloading {agent.Name}");
web.DownloadFile($"http://{Master.EndPoint.Address}:8080/download/vehicle/{agent.Name}", agent.Name);
}
else
{
Debug.Log($"Vehicle {agent.Name} exists");
}
}
}
}
catch (Exception ex)
{
Debug.LogException(ex);
var err = new Commands.LoadResult()
{
Success = false,
ErrorMessage = ex.ToString(),
};
Packets.Send(Master, err, DeliveryMethod.ReliableOrdered);
Loader.ResetLoaderScene();
}
}
GameObject[] LoadVehicleBundles(Commands.Load load)
{
return load.Agents.Select(agent =>
{
var vehiclePath = Path.Combine(Web.Config.Root, agent.Name);
var vehicleBundle = AssetBundle.LoadFromFile(vehiclePath);
if (vehicleBundle == null)
{
throw new Exception($"Failed to load '{vehiclePath}' vehicle asset bundle");
}
try
{
var vehicleAssets = vehicleBundle.GetAllAssetNames();
if (vehicleAssets.Length != 1)
{
throw new Exception($"Unsupported '{vehiclePath}' vehicle asset bundle, only 1 asset expected");
}
return vehicleBundle.LoadAsset<GameObject>(vehicleAssets[0]);
}
finally
{
vehicleBundle.Unload(false);
}
}).ToArray();
}
void LoadMapBundle(Commands.Load load)
{
DownloadVehicleBundles(load);
var mapPath = Path.Combine(Web.Config.Root, load.Name);
var mapBundle = AssetBundle.LoadFromFile(mapPath);
if (mapBundle == null)
{
throw new Exception($"Failed to load environment from '{mapPath}' asset bundle");
}
var scenes = mapBundle.GetAllScenePaths();
if (scenes.Length != 1)
{
throw new Exception($"Unsupported environment in '{mapPath}' asset bundle, only 1 scene expected");
}
var sceneName = Path.GetFileNameWithoutExtension(scenes[0]);
var loader = SceneManager.LoadSceneAsync(sceneName);
loader.completed += op =>
{
if (op.isDone)
{
mapBundle.Unload(false);
try
{
var prefabs = LoadVehicleBundles(load);
Loader.Instance.SimConfig = new SimulationConfig()
{
Name = load.Name,
ApiOnly = load.ApiOnly,
Headless = load.Headless,
Interactive = load.Interactive,
TimeOfDay = DateTime.ParseExact(load.TimeOfDay, "o", CultureInfo.InvariantCulture),
Rain = load.Rain,
Fog = load.Fog,
Wetness = load.Wetness,
Cloudiness = load.Cloudiness,
UseTraffic = load.UseTraffic,
UsePedestrians = load.UsePedestrians,
Agents = load.Agents.Zip(prefabs, (agent, prefab) =>
{
var config = new AgentConfig()
{
Name = agent.Name,
Prefab = prefab,
Connection = agent.Connection,
Sensors = agent.Sensors,
};
if (!string.IsNullOrEmpty(agent.Bridge))
{
config.Bridge = Web.Config.Bridges.Find(bridge => bridge.Name == agent.Bridge);
if (config.Bridge == null)
{
throw new Exception($"Bridge {agent.Bridge} not found");
}
}
return config;
}).ToArray(),
};
Loader.CreateSimulationManager();
Debug.Log($"Client ready to start");
var result = new Commands.LoadResult()
{
Success = true,
};
Packets.Send(Master, result, DeliveryMethod.ReliableOrdered);
ClientState = State.Ready;
}
catch (Exception ex)
{
Debug.LogException(ex);
var err = new Commands.LoadResult()
{
Success = false,
ErrorMessage = ex.ToString(),
};
Packets.Send(Master, err, DeliveryMethod.ReliableOrdered);
Loader.ResetLoaderScene();
}
}
};
}
}
}
fileFormatVersion: 2
guid: 3cce4e3118e79104983f5ea64056d0a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
using LiteNetLib.Utils;
using System;
namespace Simulator.Network
{
[AttributeUsage(AttributeTargets.Class)]
public class CommandAttribute : Attribute
{
public byte Id { get; private set; }
public CommandAttribute(byte id)
{
Id = id;
}
}
public static class Commands
{
public class Info
{
public string Version { get; set; }
public string UnityVersion { get; set; }
public string OperatingSystem { get; set; }
}
public struct LoadAgent
{
public string Name { get; set; }
public string Bridge { get; set; }
public string Connection { get; set; }
public string Sensors { get; set; }
}
public class Load
{
public string Name { get; set; }
public bool ApiOnly { get; set; }
public bool Headless { get; set; }
public bool Interactive { get; set; }
public string TimeOfDay { get; set; }
public float Rain { get; set; }
public float Fog { get; set; }
public float Wetness { get; set; }
public float Cloudiness { get; set; }
public LoadAgent[] Agents { get; set; }
public bool UseTraffic { get; set; }
public bool UsePedestrians { get; set; }
}
public class LoadResult
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
public class Run
{
}
}
}
fileFormatVersion: 2
guid: 54e261fdb926d494a9ada758464f2807
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
namespace Simulator.Network
{
enum State
{
Initial,
Connecting, // waiting from "init" command
Connected, // init" command is received
Loading, // client is loading bundles
Ready, // client finished all bundle loading
Running, // simulation is running
}
public static class Constants
{
public const string ConnectionKey = "simulator"; // TODO: this can be unique per run
public const int Port = 9999;
};
}
fileFormatVersion: 2
guid: 5651367b29dfa6242b85ffc01d17bcaa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
using System;
using System.Net;
using System.Linq;
using System.Net.Sockets;
using System.Collections.Concurrent;
using LiteNetLib;
using LiteNetLib.Utils;
using UnityEngine;
using System.Collections.Generic;
using System.Globalization;
using Web;
using UnityEngine.SceneManagement;
namespace Simulator.Network
{
public class MasterManager : MonoBehaviour, INetEventListener
{
enum State
{
Initial,
Connecting, // waiting from "init" command
Connected, // init" command is received
Loading, // client is loading bundles
Ready, // client finished all bundle loading
Running, // simulation is running
}
class Client
{
public NetPeer Peer;
public State State;
}
State MasterState = State.Initial;
NetManager Manager;
NetPacketProcessor Packets = new NetPacketProcessor();
List<Client> Clients = new List<Client>();
ConcurrentQueue<Action> Actions = new ConcurrentQueue<Action>();
[NonSerialized]
public SimulationConfig Simulation;
void Awake()
{
Packets.RegisterNestedType(SerializationHelpers.SerializeLoadAgent, SerializationHelpers.DeserializeLoadAgent);
Packets.SubscribeReusable<Commands.Info, NetPeer>(OnInfoCommand);
Packets.SubscribeReusable<Commands.LoadResult, NetPeer>(OnLoadResultCommand);
Manager = new NetManager(this);
Manager.UpdateTime = 1;
Manager.Start();
}
public void AddClients(string[] addresses)
{
Debug.Assert(MasterState == State.Initial);
foreach (var address in addresses)
{
var peer = Manager.Connect(address, Constants.Port, Constants.ConnectionKey);
Clients.Add(new Client() { Peer = peer, State = State.Initial });
}
MasterState = State.Connecting;
}
void Update()
{
Manager.PollEvents();
while (Actions.TryDequeue(out var action))
{
action();
}
}
void OnApplicationQuit()
{
Manager.Stop();
}
void OnDestroy()
{
Manager.Stop();
}
public void OnPeerConnected(NetPeer peer)
{
Debug.Assert(MasterState == State.Connecting);
var client = Clients.Find(c => c.Peer == peer);
Debug.Assert(client != null);
Debug.Assert(client.State == State.Initial);
client.State = State.Connecting;
}
public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
// TODO: handle disconnects in various stages of simulation
Clients.RemoveAll(c => c.Peer == peer);
}
public void OnNetworkError(IPEndPoint endPoint, SocketError socketError)
{
Debug.Log($"Error {socketError} for {endPoint} endpoint");
}
public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod)
{
Packets.ReadAllPackets(reader, peer);
}
public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
{
}
public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
}
public void OnConnectionRequest(ConnectionRequest request)
{
}
public void OnInfoCommand(Commands.Info info, NetPeer peer)
{
Debug.Assert(MasterState == State.Connecting);
var client = Clients.Find(c => c.Peer == peer);
Debug.Assert(client != null);
Debug.Assert(client.State == State.Connecting);
Debug.Log($"NET: Client connected from {peer.EndPoint}");
Debug.Log($"NET: Client version = {info.Version}");
Debug.Log($"NET: Client Unity version = {info.UnityVersion}");
Debug.Log($"NET: Client OS = {info.OperatingSystem}");
client.State = State.Connected;
if (!Loader.Instance.PendingSimulation.ApiOnly.GetValueOrDefault())
{
if (Clients.All(c => c.State == State.Connected))
{
var load = new Commands.Load()
{
Name = Simulation.MapName,
ApiOnly = Simulation.ApiOnly,
Headless = Simulation.Headless,
Interactive = Simulation.Interactive,
TimeOfDay = Simulation.TimeOfDay.ToString("o", CultureInfo.InvariantCulture),
Rain = Simulation.Rain,
Fog = Simulation.Fog,
Wetness = Simulation.Wetness,
Cloudiness = Simulation.Cloudiness,
Agents = Simulation.Agents.Select(a => new Commands.LoadAgent()
{
Name = a.Name,
Bridge = a.Bridge == null ? String.Empty : a.Bridge.Name,
Connection = a.Connection,
Sensors = a.Sensors,
}).ToArray(),
UseTraffic = Simulation.UseTraffic,
UsePedestrians = Simulation.UsePedestrians,
};
foreach (var c in Clients)
{
Packets.Send(c.Peer, load, DeliveryMethod.ReliableOrdered);
c.State = State.Loading;
}
MasterState = State.Loading;
}
}
}
public void OnLoadResultCommand(Commands.LoadResult res, NetPeer peer)
{
Debug.Assert(MasterState == State.Loading);
var client = Clients.Find(c => c.Peer == peer);
Debug.Assert(client != null);
Debug.Assert(client.State == State.Loading);
if (res.Success)
{
Debug.Log("Client loaded");
}
else
{
// TODO: stop simulation / cancel loading for other clients
Debug.LogError($"Client failed to load: ${res.ErrorMessage}");
// TODO: reset all other clients
Debug.Log($"Failed to start '{Simulation.Name}' simulation");
// TODO: update simulation status in DB
// simulation.Status = "Invalid";
// db.Update(simulation);
// NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner);
Loader.ResetLoaderScene();
Clients.Clear();
return;
}
client.State = State.Ready;
if (!Loader.Instance.PendingSimulation.ApiOnly.GetValueOrDefault())
{
if (Clients.All(c => c.State == State.Ready))
{
Debug.Log("All clients are ready. Resuming time.");
var run = new Commands.Run();
foreach (var c in Clients)
{
Packets.Send(c.Peer, run, DeliveryMethod.ReliableOrdered);
c.State = State.Running;
}
MasterState = State.Running;
Loader.Instance.CurrentSimulation = Loader.Instance.PendingSimulation;
Loader.Instance.PendingSimulation = null;
SimulatorManager.SetTimeScale(1.0f);
}
}
}
}
}
fileFormatVersion: 2
guid: 17449bd81d2b4d543b6f038bd75cc931
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
using LiteNetLib.Utils;
using System;
using System.Globalization;
namespace Simulator.Network
{
public static class SerializationHelpers
{
public static void SerializeLoadAgent(NetDataWriter writer, Commands.LoadAgent agent)
{
writer.Put(agent.Name);
writer.Put(agent.Bridge);
writer.Put(agent.Connection);
writer.Put(agent.Sensors);
}
public static Commands.LoadAgent DeserializeLoadAgent(NetDataReader reader)
{
return new Commands.LoadAgent()
{
Name = reader.GetString(),
Bridge = reader.GetString(),
Connection = reader.GetString(),
Sensors = reader.GetString(),
};
}
}
}
fileFormatVersion: 2
guid: 67ead4042c06f8547be902961da6f4d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
......@@ -20,17 +20,17 @@ using Simulator.Web.Modules;
using Simulator.Utilities;
using Web;
using Simulator.Bridge;
using Nancy.Cryptography;
using System.Security;
using System.Text;
using System.Security.Cryptography;
using Simulator.Database.Services;
using System.Linq;
namespace Simulator
{
public class AgentConfig
{
public string Name;
public string AssetBundle;
public GameObject Prefab;
public IBridgeFactory Bridge;
public string Connection;
......@@ -43,12 +43,11 @@ namespace Simulator
{
public string Name;
public string MapName;
public string Cluster;
public string[] Clusters;
public string ClusterName;
public bool ApiOnly;
public bool Headless;
public bool Interactive;
public bool OffScreen;
public DateTime TimeOfDay;
public float Rain;
public float Fog;
......@@ -68,6 +67,10 @@ namespace Simulator
public SimulatorManager SimulatorManagerPrefab;
public ApiManager ApiManagerPrefab;
public Network.MasterManager Master;
public Network.ClientManager Client;
public SimulationModel PendingSimulation;
public LoaderUI LoaderUI => FindObjectOfType<LoaderUI>();
// NOTE: When simulation is not running this reference will be null.
......@@ -76,7 +79,7 @@ namespace Simulator
ConcurrentQueue<Action> Actions = new ConcurrentQueue<Action>();
string LoaderScene;
public SimulationConfig SimConfig { get; private set; }
public SimulationConfig SimConfig;
// Loader object is never destroyed, even between scene reloads
public static Loader Instance { get; private set; }
......@@ -107,6 +110,13 @@ namespace Simulator
return;
}
if (!Config.RunAsMaster)
{
// TODO: change UI and do not run rest of code
var obj = new GameObject("ClientManager");
obj.AddComponent<Network.ClientManager>();
}
DatabaseManager.Init();
try
......@@ -184,7 +194,7 @@ namespace Simulator
continue;
}
added.Add(uri);
SIM.LogWeb(SIM.Web.VehicleDownloadStart, vehicle.Name);
DownloadManager.AddDownloadToQueue(
uri,
......@@ -247,12 +257,11 @@ namespace Simulator
Instance.SimConfig = new SimulationConfig()
{
Name = simulation.Name,
Cluster = db.Single<ClusterModel>(simulation.Cluster).Ips,
Clusters = db.Single<ClusterModel>(simulation.Cluster).Ips.Split(',').Where(c => c != "127.0.0.1").ToArray(),
ClusterName = db.Single<ClusterModel>(simulation.Cluster).Name,
ApiOnly = simulation.ApiOnly.GetValueOrDefault(),
Headless = simulation.Headless.GetValueOrDefault(),
Interactive = simulation.Interactive.GetValueOrDefault(),
OffScreen = simulation.Headless.GetValueOrDefault(),
TimeOfDay = simulation.TimeOfDay.GetValueOrDefault(DateTime.MinValue.AddHours(12)),
Rain = simulation.Rain.GetValueOrDefault(),
Fog = simulation.Fog.GetValueOrDefault(),
......@@ -263,14 +272,47 @@ namespace Simulator
Seed = simulation.Seed,
};
if (simulation.Vehicles == null || simulation.Vehicles.Length == 0)
{
Instance.SimConfig.Agents = Array.Empty<AgentConfig>();
}
else
{
Instance.SimConfig.Agents = simulation.Vehicles.Select(v =>
{
var vehicle = db.SingleOrDefault<VehicleModel>(v.Id);
var config = new AgentConfig()
{
Name = vehicle.Name,
AssetBundle = vehicle.LocalPath,
Connection = v.Connection,
Sensors = vehicle.Sensors,
};
if (!string.IsNullOrEmpty(vehicle.BridgeType))
{
config.Bridge = Config.Bridges.Find(bridge => bridge.Name == vehicle.BridgeType);
if (config.Bridge == null)
{
throw new Exception($"Bridge {vehicle.BridgeType} not found");
}
}
return config;
}).ToArray();
}
// load environment
if (Instance.SimConfig.ApiOnly)
{
var api = Instantiate(Instance.ApiManagerPrefab);
api.name = "ApiManager";
// ready to go!
Instance.CurrentSimulation = simulation;
// ready to go!
Instance.CurrentSimulation.Status = "Running";
NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner);
......@@ -296,6 +338,7 @@ namespace Simulator
var sceneName = Path.GetFileNameWithoutExtension(scenes[0]);
Instance.SimConfig.MapName = sceneName;
var loader = SceneManager.LoadSceneAsync(sceneName);
loader.completed += op =>
{
......@@ -305,6 +348,7 @@ namespace Simulator
SetupScene(simulation);
}
};
}
}
catch (Exception ex)
......@@ -386,75 +430,57 @@ namespace Simulator
{
try
{
if (simulation.Vehicles == null || simulation.Vehicles.Length == 0)
{
Instance.SimConfig.Agents = Array.Empty<AgentConfig>();
}
else
foreach (var agentConfig in Instance.SimConfig.Agents)
{
var agents = new List<AgentConfig>();
foreach (var vehicleId in simulation.Vehicles)
var bundlePath = agentConfig.AssetBundle;
// TODO: make this async
var vehicleBundle = AssetBundle.LoadFromFile(bundlePath);
if (vehicleBundle == null)
{
var vehicle = db.SingleOrDefault<VehicleModel>(vehicleId.Vehicle);
var bundlePath = vehicle.LocalPath;
throw new Exception($"Failed to load '{agentConfig.Name}' vehicle asset bundle");
}
// TODO: make this async
var vehicleBundle = AssetBundle.LoadFromFile(bundlePath);
if (vehicleBundle == null)
try
{
var vehicleAssets = vehicleBundle.GetAllAssetNames();
if (vehicleAssets.Length != 1)
{
throw new Exception($"Failed to load '{vehicle.Name}' vehicle asset bundle");
throw new Exception($"Unsupported '{agentConfig.Name}' vehicle asset bundle, only 1 asset expected");
}
try
{
var vehicleAssets = vehicleBundle.GetAllAssetNames();
if (vehicleAssets.Length != 1)
{
throw new Exception($"Unsupported '{vehicle.Name}' vehicle asset bundle, only 1 asset expected");
}
// TODO: make this async
var prefab = vehicleBundle.LoadAsset<GameObject>(vehicleAssets[0]);
var agent = new AgentConfig()
{
Name = vehicle.Name,
Prefab = prefab,
Sensors = vehicle.Sensors,
Connection = vehicleId.Connection,
};
if (!string.IsNullOrEmpty(vehicle.BridgeType))
{
agent.Bridge = Config.Bridges.Find(bridge => bridge.Name == vehicle.BridgeType);
if (agent.Bridge == null)
{
throw new Exception($"Bridge {vehicle.BridgeType} not found");
}
}
agents.Add(agent);
}
finally
{
vehicleBundle.Unload(false);
}
// TODO: make this async
agentConfig.Prefab = vehicleBundle.LoadAsset<GameObject>(vehicleAssets[0]);
}
finally
{
vehicleBundle.Unload(false);
}
Instance.SimConfig.Agents = agents.ToArray();
}
// simulation manager
var sim = CreateSimulationManager();
// TODO: connect to cluster instances
//if (Instance.SimConfig.Clusters.Length > 0)
//{
// SimulatorManager.SetTimeScale(0);
// Instance.PendingSimulation = simulation;
// StartNetworkMaster();
// Instance.Master.AddClients(Instance.SimConfig.Clusters);
//}
//else
{
var sim = Instantiate(Instance.SimulatorManagerPrefab);
sim.name = "SimulatorManager";
sim.Init();
}
Instance.CurrentSimulation = simulation;
// Notify WebUI simulation is running
Instance.CurrentSimulation = simulation;
Instance.CurrentSimulation.Status = "Running";
NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner);
// Notify WebUI simulation is running
Instance.CurrentSimulation.Status = "Running";
NotificationManager.SendNotification("simulation", SimulationResponse.Create(Instance.CurrentSimulation), Instance.CurrentSimulation.Owner);
// Flash main window to let user know simulation is ready
WindowFlasher.Flash();
// Flash main window to let user know simulation is ready
WindowFlasher.Flash();
}
}
catch (Exception ex)
{
......@@ -468,17 +494,22 @@ namespace Simulator
// TODO: take ex.Message and append it to response here
NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner);
if (SceneManager.GetActiveScene().name != Instance.LoaderScene)
{
SceneManager.LoadScene(Instance.LoaderScene);
AssetBundle.UnloadAllAssetBundles(true);
Instance.CurrentSimulation = null;
}
ResetLoaderScene();
}
}
}
string ByteArrayToString(byte[] ba)
public static void ResetLoaderScene()
{
if (SceneManager.GetActiveScene().name != Instance.LoaderScene)
{
SceneManager.LoadScene(Instance.LoaderScene);
AssetBundle.UnloadAllAssetBundles(true);
Instance.CurrentSimulation = null;
}
}
static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
......@@ -486,7 +517,7 @@ namespace Simulator
return hex.ToString();
}
byte[] StringToByteArray(string hex)
static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
......@@ -494,5 +525,20 @@ namespace Simulator
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
static void StartNetworkMaster()
{
var obj = new GameObject("NetworkMaster");
Instance.Master = obj.AddComponent<Network.MasterManager>();
Instance.Master.Simulation = Instance.SimConfig;
}
public static SimulatorManager CreateSimulationManager()
{
var sim = Instantiate(Instance.SimulatorManagerPrefab);
sim.name = "SimulatorManager";
sim.Init();
return sim;
}
}
}
/**
* Copyright (c) 2019 LG Electronics, Inc.
*
* This software contains code licensed as described in LICENSE.
*
*/
using Nancy;
using Nancy.Responses;
using Simulator.Database;
using System.IO;
namespace Simulator.Web.Modules
{
public class DownloadModule : NancyModule
{
public DownloadModule() : base("download")
{
#if ENABLE_FOR_CLUSTERS
Get("/map/{name}", x =>
{
string name = x.name;
// TODO: authenticate client
// TODO: proper DB stuff
using (var db = DatabaseManager.Open())
{
var map = db.First<MapModel>(PetaPoco.Sql.Builder.Where("name = @0", name));
var file = new FileStream(map.LocalPath, FileMode.Open);
var response = new StreamResponse(() => file, "application/octet-stream");
return response.AsAttachment(name);
}
});
Get("/vehicle/{name}", x =>
{
string name = x.name;
// TODO: authenticate client
// TODO: proper DB stuff
using (var db = DatabaseManager.Open())
{
var vehicle = db.First<VehicleModel>(PetaPoco.Sql.Builder.Where("name = @0", name));
var file = new FileStream(vehicle.LocalPath, FileMode.Open);
var response = new StreamResponse(() => file, "application/octet-stream");
return response.AsAttachment(name);
}
});
#endif
}
}
}
fileFormatVersion: 2
guid: 21204d9333f00cb49b4b7ba1ff8d524d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment