public override WebSocketCommandInfo FindCommand(SocketContext context, byte[] readBuffer, int offset, int length, bool isReusableBuffer) { int total = BufferSegments.Count + length; var socketContext = context as WebSocketContext; if (total == 8) { List<byte> key = new List<byte>(); key.AddRange(BufferSegments.ToArrayData()); key.AddRange(readBuffer.Skip(offset).Take(length)); socketContext.SecWebSocketKey3 = key.ToArray(); BufferSegments.ClearSegements(); NextCommandReader = new WebSocketDataReader(this); return CreateHeadCommandInfo(); } else if (total > 8) { List<byte> key = new List<byte>(); key.AddRange(BufferSegments.ToArrayData()); key.AddRange(readBuffer.Skip(offset).Take(8 - BufferSegments.Count)); socketContext.SecWebSocketKey3 = key.ToArray(); BufferSegments.ClearSegements(); AddArraySegment(readBuffer, offset + 8 - BufferSegments.Count, total - 8, isReusableBuffer); NextCommandReader = new WebSocketDataReader(this); return CreateHeadCommandInfo(); } else { AddArraySegment(readBuffer, offset, length, isReusableBuffer); NextCommandReader = this; return null; } }
public Task TryConnect(int port) { socketContext = new SocketContext(); clientConnectedTCS = new TaskCompletionSource<bool>(); socketContext.Connected = (clientSocketContext) => { // Create an effect compiler per connection var effectCompiler = new EffectCompiler(); var tempFilename = Path.GetTempFileName(); var fileStream = new FileStream(tempFilename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); // TODO: Properly close the file, and choose where to copy/move it? var recordedEffectCompile = new EffectLogStore(fileStream); // TODO: This should come from an "init" packet effectCompiler.SourceDirectories.Add(EffectCompilerBase.DefaultSourceShaderFolder); // Make a VFS that will access remotely the DatabaseFileProvider // TODO: Is that how we really want to do that in the future? var networkVFS = new NetworkVirtualFileProvider(clientSocketContext, "/asset"); VirtualFileSystem.RegisterProvider(networkVFS); effectCompiler.FileProvider = networkVFS; clientSocketContext.AddPacketHandler<ShaderCompilerRequest>((packet) => ShaderCompilerRequestHandler(clientSocketContext, recordedEffectCompile, effectCompiler, packet)); clientConnectedTCS.TrySetResult(true); }; // Wait for a connection to be possible on adb forwarded port var clientDone = socketContext.StartClient(IPAddress.Loopback, port); return clientDone; }
private void BeginReceive(SocketContext ctx) { if (ctx.receiveBuffer == null) { Byte[] buffer = new Byte[SessionConfig.ReadBufferSize]; ctx.receiveBuffer = new SocketAsyncEventArgs(); ctx.receiveBuffer.SetBuffer(buffer, 0, buffer.Length); ctx.receiveBuffer.Completed += new EventHandler<SocketAsyncEventArgs>(OnCompleted); ctx.receiveBuffer.UserToken = ctx; } ctx.receiveBuffer.RemoteEndPoint = new IPEndPoint(ctx.Socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0); Boolean willRaiseEvent; try { willRaiseEvent = ctx.Socket.ReceiveFromAsync(ctx.receiveBuffer); } catch (ObjectDisposedException) { // do nothing return; } if (!willRaiseEvent) { ProcessReceive(ctx.receiveBuffer); } }
public void Initialize(Socket socket, IAsyncSocketSession socketSession, SocketContext socketContext) { var token = SocketEventArgs.UserToken as AsyncUserToken; token.Socket = socket; token.SocketSession = socketSession; token.SocketContext = socketContext; }
public static void RegisterServer(SocketContext socketContext) { socketContext.AddPacketHandler<DownloadFileQuery>( async (packet) => { var stream = await VirtualFileSystem.OpenStreamAsync(packet.Url, VirtualFileMode.Open, VirtualFileAccess.Read); var data = new byte[stream.Length]; await stream.ReadAsync(data, 0, data.Length); stream.Close(); socketContext.Send(new DownloadFileAnswer { StreamId = packet.StreamId, Data = data }); }); socketContext.AddPacketHandler<UploadFilePacket>( async (packet) => { var stream = await VirtualFileSystem.OpenStreamAsync(packet.Url, VirtualFileMode.Create, VirtualFileAccess.Write); await stream.WriteAsync(packet.Data, 0, packet.Data.Length); stream.Close(); }); socketContext.AddPacketHandler<FileExistsQuery>( async (packet) => { var fileExists = await VirtualFileSystem.FileExistsAsync(packet.Url); socketContext.Send(new FileExistsAnswer { StreamId = packet.StreamId, FileExists = fileExists }); }); }
public NetworkVirtualFileProvider(SocketContext socketContext, string remoteUrl) : base(null) { this.socketContext = socketContext; RemoteUrl = remoteUrl; if (!RemoteUrl.EndsWith(VirtualFileSystem.DirectorySeparatorChar.ToString())) RemoteUrl += VirtualFileSystem.DirectorySeparatorChar; }
/// <inheritdoc/> protected override IEnumerable<EndPoint> BindInternal(IEnumerable<EndPoint> localEndPoints) { Dictionary<EndPoint, System.Net.Sockets.Socket> newListeners = new Dictionary<EndPoint, System.Net.Sockets.Socket>(); try { // Process all the addresses foreach (EndPoint localEP in localEndPoints) { EndPoint ep = localEP; if (ep == null) ep = new IPEndPoint(IPAddress.Any, 0); System.Net.Sockets.Socket listenSocket = new System.Net.Sockets.Socket(ep.AddressFamily, SocketType.Dgram, ProtocolType.Udp); //listenSocket.Bind(ep); if (ep is IPEndPoint) { IPEndPoint iep = ep as IPEndPoint; listenSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(iep.Address)); IPEndPoint ipep = new IPEndPoint(IPAddress.Any, iep.Port); listenSocket.Bind(ipep); newListeners[listenSocket.LocalEndPoint] = listenSocket; } } } catch (Exception ex) { // Roll back if failed to bind all addresses foreach (System.Net.Sockets.Socket listenSocket in newListeners.Values) { try { listenSocket.Close(); } catch (Exception) { ExceptionMonitor.Instance.ExceptionCaught(ex); } } throw; } foreach (KeyValuePair<EndPoint, System.Net.Sockets.Socket> pair in newListeners) { SocketContext ctx = new SocketContext(pair.Value, SessionConfig); _listenSockets[pair.Key] = ctx; BeginReceive(ctx); } _idleStatusChecker.Start(); return newListeners.Keys; }
private void BeginReceive(SocketContext ctx) { EndPoint remoteEP = new IPEndPoint(ctx.Socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0); try { ctx.Socket.BeginReceiveFrom(ctx.receiveBuffer, 0, ctx.receiveBuffer.Length, SocketFlags.None, ref remoteEP, ReceiveCallback, ctx); } catch (ObjectDisposedException) { // do nothing } }
private async void ShaderCompilerRequestHandler(SocketContext clientSocketContext, EffectLogStore recordedEffectCompile, EffectCompiler effectCompiler, ShaderCompilerRequest shaderCompilerRequest) { // Wait for a client to be connected await clientConnectedTCS.Task; // Yield so that this socket can continue its message loop to answer to shader file request. await Task.Yield(); Console.WriteLine("Compiling shader"); // A shader has been requested, compile it (asynchronously)! var precompiledEffectShaderPass = await effectCompiler.Compile(shaderCompilerRequest.MixinTree, null).AwaitResult(); // Record compilation to asset file (only if parent) recordedEffectCompile[new EffectCompileRequest(shaderCompilerRequest.MixinTree.Name, shaderCompilerRequest.MixinTree.UsedParameters)] = true; // Send compiled shader clientSocketContext.Send(new ShaderCompilerAnswer { StreamId = shaderCompilerRequest.StreamId, EffectBytecode = precompiledEffectShaderPass.Bytecode }); }
public override WebSocketCommandInfo FindCommand(SocketContext context, byte[] readBuffer, int offset, int length, bool isReusableBuffer) { AddArraySegment(readBuffer, offset, length, isReusableBuffer); if (m_StartPos < 0) { m_StartPos = BufferSegments.IndexOf(WebSocketConstant.StartByte); if (m_StartPos < 0) { //Continue to read following bytes to seek start pos NextCommandReader = this; return null; } } int endPos = BufferSegments.IndexOf(WebSocketConstant.EndByte, m_StartPos, BufferSegments.Count - m_StartPos); if (endPos < 0) { //Continue to search end byte NextCommandReader = this; return null; } var commandInfo = new WebSocketCommandInfo(Encoding.UTF8.GetString(BufferSegments.ToArrayData(m_StartPos + 1, endPos - m_StartPos - 1))); BufferSegments.ClearSegements(); int left = BufferSegments.Count - endPos - 1; if (left > 0) AddArraySegment(readBuffer, offset + length - left, left, isReusableBuffer); m_StartPos = -1; NextCommandReader = this; return commandInfo; }
public override WebSocketCommandInfo FindCommand(SocketContext context, byte[] readBuffer, int offset, int length, bool isReusableBuffer) { AddArraySegment(readBuffer, offset, length, isReusableBuffer); int? result = BufferSegments.SearchMark(m_HeaderTerminator); if (!result.HasValue || result.Value <= 0) { NextCommandReader = this; return null; } string header = Encoding.UTF8.GetString(BufferSegments.ToArrayData(0, result.Value)); var socketContext = context as WebSocketContext; WebSocketServer.ParseHandshake(socketContext, new StringReader(header)); var secWebSocketKey1 = socketContext.SecWebSocketKey1; var secWebSocketKey2 = socketContext.SecWebSocketKey2; int left = BufferSegments.Count - result.Value - m_HeaderTerminator.Length; BufferSegments.ClearSegements(); if (string.IsNullOrEmpty(secWebSocketKey1) && string.IsNullOrEmpty(secWebSocketKey2)) { //v.75 if (left > 0) AddArraySegment(readBuffer, offset + length - left, left, isReusableBuffer); NextCommandReader = new WebSocketDataReader(this); return CreateHeadCommandInfo(); } else { //v.76 //Read SecWebSocketKey3(8 bytes) if (left == 8) { socketContext.SecWebSocketKey3 = readBuffer.Skip(offset + length - left).Take(left).ToArray(); NextCommandReader = new WebSocketDataReader(this); return CreateHeadCommandInfo(); } else if (left > 8) { socketContext.SecWebSocketKey3 = readBuffer.Skip(offset + length - left).Take(8).ToArray(); AddArraySegment(readBuffer, offset + length - left + 8, left - 8, isReusableBuffer); NextCommandReader = new WebSocketDataReader(this); return CreateHeadCommandInfo(); } else { //left < 8 if (left > 0) AddArraySegment(readBuffer, offset + length - left, left, isReusableBuffer); NextCommandReader = new WebSocketSecKey3Reader(this); return null; } } }
public abstract ISocketManager Send(SocketContext context);
public abstract ISocketManager Receive(SocketContext context);
/// <summary> /// Sets the socket context. /// </summary> /// <param name="context">The socket context.</param> public void SetContext(SocketContext context) { m_SocketContext = context; m_blDisconnected = false; }
static void Main(string[] args) { Injector.Instance .Register <ILogger>(new ConsoleLogger()) .Register <IDumper>(new HexDumper()) .Register <InputHelper>(new InputHelper()) .Register <ISocketManager>(new TCPServerSocketManager() .Initialize(new IPEndPoint(IPAddress.Any, RDP_DEFAULT_PORT)) .Start()); bool isBlocked = true; byte[] buffer = new byte[] { }; Injector.Instance .Get <ISocketManager>() .Subscribe(EventType.RECEIVE, (rec, ctx) => { var dump = Injector.Instance .Get <IDumper>() .Dump(ctx.Buffer); isBlocked = !ctx.Buffer.SequenceEqual(buffer); }); try { ReadSequencesXML(ChooseSequence(), (seq) => { isBlocked = true; buffer = Injector.Instance .Get <InputHelper>() .TextToByteArray( seq.InnerText, new string[] { "\t", "\n", "\r" }, NumberStyles.HexNumber); while (isBlocked) { ; } }, (seq) => { var server = Injector.Instance .Get <ISocketManager>(); var context = new SocketContext() { Socket = server.Clients.FirstOrDefault().Socket, EndPoint = server.Clients.FirstOrDefault().EndPoint, Buffer = Injector.Instance .Get <InputHelper>() .TextToByteArray( seq.InnerText, new string[] { "\t", "\n", "\r" }, NumberStyles.HexNumber) }; server.Send(context); }); } catch (Exception ex) { Injector.Instance.Get <ILogger>().Error(ex); } }
public static async Task RunDebug(EngineContext engineContext) { var config = AppConfig.GetConfiguration<Config>("ScriptDebug"); var renderingSetup = RenderingSetup.Singleton; engineContext.RenderContext.PrepareEffectPlugins += (effectBuilder, plugins) => { if (effectBuilder.PickingPassMainPlugin != null) { RenderPassPlugin pickingPlugin; if (engineContext.DataContext.RenderPassPlugins.TryGetValue(effectBuilder.Name == "Gizmo" ? "MouseOverPickingPlugin" : "PickingPlugin", out pickingPlugin)) plugins.Add(new PickingShaderPlugin { RenderPassPlugin = (PickingPlugin)pickingPlugin, MainPlugin = effectBuilder.PickingPassMainPlugin }); } if (effectBuilder.SupportWireframe) { RenderPassPlugin wireframePlugin; if (engineContext.DataContext.RenderPassPlugins.TryGetValue("WireframePlugin", out wireframePlugin)) plugins.Add(new WireframeShaderPlugin { RenderPassPlugin = wireframePlugin, MainTargetPlugin = renderingSetup.MainTargetPlugin }); } }; pickingSystem = new PickingSystem(); pickingSystem.PropertyChanged += pickingSystem_PropertyChanged; engineContext.Scheduler.Add(() => pickingSystem.ProcessGizmoAndPicking(engineContext)); var socketContext = new SocketContext(); var socketContextAsync = new SocketContext(); var currentScheduler = Scheduler.Current; var pendingClient = new PendingClient(); socketContext.Connected = (clientSocketContext) => { lock (pendingClient) { pendingClient.MainSocket = clientSocketContext; if (pendingClient.AsyncSocket != null) currentScheduler.Add(() => ProcessClient(engineContext, pendingClient.MainSocket, pendingClient.AsyncSocket)); } }; socketContextAsync.Connected = (clientSocketContext) => { lock (pendingClient) { pendingClient.AsyncSocket = clientSocketContext; if (pendingClient.MainSocket != null) currentScheduler.Add(() => ProcessClient(engineContext, pendingClient.MainSocket, pendingClient.AsyncSocket)); } }; socketContext.StartServer(config.Port); socketContextAsync.StartServer(config.Port + 1); }
public void RaiseIdleState(SocketContext <TMessage> context, IdleStateEvent eventState) { OnIdleState?.Invoke(this, new IdleStateEventArgs <TMessage>(context)); }
public NetworkWriteStream(SocketContext socketContext, string url) : base(new MemoryStream()) { this.memoryStream = (MemoryStream)InternalStream; this.url = url; this.socketContext = socketContext; }
public async static Task ProcessClient(EngineContext engineContext, SocketContext socketContext, SocketContext socketContextAsync) { socketContext.AddPacketHandler<DownloadFileQuery>( async (packet) => { var stream = await VirtualFileSystem.OpenStreamAsync(packet.Url, VirtualFileMode.Open, VirtualFileAccess.Read); var data = new byte[stream.Length]; await stream.ReadAsync(data, 0, data.Length); stream.Close(); socketContext.Send(new DownloadFileAnswer { StreamId = packet.StreamId, Data = data }); }); socketContext.AddPacketHandler<UploadFilePacket>( async (packet) => { var stream = await VirtualFileSystem.OpenStreamAsync(packet.Url, VirtualFileMode.Create, VirtualFileAccess.Write); await stream.WriteAsync(packet.Data, 0, packet.Data.Length); stream.Close(); }); var viewModelGlobalContext = new ViewModelGlobalContext(); selectedEntitiesContext = new ViewModelContext(viewModelGlobalContext); selectedEntitiesContext.ChildrenPropertyEnumerators.Add(new EntityComponentEnumerator(engineContext)); selectedEntitiesContext.ChildrenPropertyEnumerators.Add(new RenderPassPluginEnumerator()); selectedEntitiesContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); //selectedEntitiesContext.ChildrenPropertyEnumerators.Add(new EffectPropertyEnumerator(engineContext)); var renderPassHierarchyContext = new ViewModelContext(viewModelGlobalContext); renderPassHierarchyContext.ChildrenPropertyEnumerators.Add(new RenderPassHierarchyEnumerator()); renderPassHierarchyContext.Root = new ViewModelNode("Root", engineContext.RenderContext.RootRenderPass).GenerateChildren(renderPassHierarchyContext); var renderPassPluginsContext = new ViewModelContext(viewModelGlobalContext); renderPassPluginsContext.ChildrenPropertyEnumerators.Add(new RenderPassPluginsEnumerator { SelectedRenderPassPluginContext = selectedEntitiesContext }); renderPassPluginsContext.Root = new ViewModelNode("Root", new EnumerableViewModelContent<ViewModelReference>( () => engineContext.RenderContext.RenderPassPlugins.Select(x => new ViewModelReference(x, true)))); var entityHierarchyEnumerator = new EntityHierarchyEnumerator(engineContext.EntityManager, selectedEntitiesContext); var entityHierarchyContext = new ViewModelContext(viewModelGlobalContext); entityHierarchyContext.ChildrenPropertyEnumerators.Add(entityHierarchyEnumerator); entityHierarchyContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); entityHierarchyContext.Root = new ViewModelNode("EntityHierarchyRoot", new EnumerableViewModelContent<ViewModelReference>( () => engineContext.EntityManager.Entities .Where(x => { var transformationComponent = x.Transformation; return (transformationComponent == null || transformationComponent.Parent == null); }) .Select(x => new ViewModelReference(x, true)))); entityHierarchyEnumerator.SelectedEntities.CollectionChanged += (sender, args) => { SelectEntity(entityHierarchyEnumerator.SelectedEntities); }; //entityHierarchyContext.Root.Children.Add(new ViewModelNode("SelectedItems", EnumerableViewModelContent.FromUnaryLambda<ViewModelReference, ViewModelReference>(new NullViewModelContent(), // (x) => { return new[] { new ViewModelReference(pickingSystem.SelectedEntity) }; }))); /*(value) => { var entityModelView = value != null ? entityHierarchyContext.GetModelView(value.Guid) : null; var entity = entityModelView != null ? (Entity)entityModelView.NodeValue : null; SelectEntity(entity); })));*/ entityHierarchyContext.Root.Children.Add(new ViewModelNode("DropEntity", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) => { var dropParameters = (DropCommandParameters)parameter; var movedItem = dropParameters.Data is Guid ? entityHierarchyContext.GetModelView((Guid)dropParameters.Data) : null; var newParent = dropParameters.Parent is Guid ? entityHierarchyContext.GetModelView((Guid)dropParameters.Parent) : null; if (newParent == null || movedItem == null) return; var parent = ((Entity)newParent.NodeValue).Transformation; if (dropParameters.TargetIndex > parent.Children.Count) return; var transformationComponent = ((Entity)movedItem.NodeValue).Transformation; transformationComponent.Parent = null; parent.Children.Insert(dropParameters.TargetIndex, transformationComponent); })))); entityHierarchyContext.Root.Children.Add(new ViewModelNode("DropAsset", new RootViewModelContent((ExecuteCommand)(async (viewModel2, parameter) => { var dropParameters = (DropCommandParameters)parameter; var assetUrl = (string)dropParameters.Data; /*var newParent = entityHierarchyContext.GetModelView((Guid)dropParameters.Parent); if (newParent == null || assetUrl == null) return; var parent = ((Entity)newParent.NodeValue).Transformation; if (dropParameters.ItemIndex > parent.Children.Count) return;*/ engineContext.Scheduler.Add(async () => { // Load prefab entity var loadedEntityPrefab = await engineContext.AssetManager.LoadAsync<Entity>(assetUrl + "#"); // Build another entity from prefab var loadedEntity = Prefab.Inherit(loadedEntityPrefab); // Add it to scene engineContext.EntityManager.AddEntity(loadedEntity); if (loadedEntity.ContainsKey(AnimationComponent.Key)) { Scheduler.Current.Add(() => AnimScript.AnimateFBXModel(engineContext, loadedEntity)); } }); })))); var scriptEngineContext = new ViewModelContext(viewModelGlobalContext); scriptEngineContext.ChildrenPropertyEnumerators.Add(new ScriptAssemblyEnumerator(engineContext)); scriptEngineContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); scriptEngineContext.Root = new ViewModelNode(new EnumerableViewModelContent<ViewModelReference>( () => engineContext.ScriptManager.ScriptAssemblies.Select(x => new ViewModelReference(x, true)))); scriptEngineContext.Root.Children.Add(new ViewModelNode("RunScript", new RootViewModelContent((ExecuteCommand)(async (viewModel2, parameter) => { var scriptName = (string)parameter; var matchingScript = engineContext.ScriptManager.Scripts.Where(x => x.TypeName + "." + x.MethodName == scriptName); if (matchingScript.Any()) { var scriptEntry = matchingScript.Single(); var microThread = engineContext.ScriptManager.RunScript(scriptEntry, null); } })))); var runningScriptsContext = new ViewModelContext(viewModelGlobalContext); runningScriptsContext.ChildrenPropertyEnumerators.Add(new MicroThreadEnumerator(selectedEntitiesContext)); runningScriptsContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); runningScriptsContext.Root = new ViewModelNode("MicroThreads", new EnumerableViewModelContent<ViewModelReference>( () => engineContext.Scheduler.MicroThreads.Select(x => new ViewModelReference(x, true)) )); var effectsContext = new ViewModelContext(viewModelGlobalContext); effectsContext.ChildrenPropertyEnumerators.Add(new EffectEnumerator(selectedEntitiesContext)); effectsContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); effectsContext.Root = new ViewModelNode("Effects", new EnumerableViewModelContent<ViewModelReference>( () => engineContext.RenderContext.Effects.Select(x => new ViewModelReference(x, true)) )); //effectsContext.Root.Children.Add(new ViewModelNode("PluginDefinitions", new RootViewModelContent())); var assetBrowserContext = new ViewModelContext(viewModelGlobalContext); assetBrowserContext.ChildrenPropertyEnumerators.Add(new AssetBrowserEnumerator(engineContext)); assetBrowserContext.ChildrenPropertyEnumerators.Add(new ChildrenPropertyInfoEnumerator()); assetBrowserContext.Root = new ViewModelNode("Root", "Root").GenerateChildren(assetBrowserContext); var editorContext = new ViewModelContext(viewModelGlobalContext); editorContext.Root = new ViewModelNode("Root"); editorContext.Root.Children.Add(new ViewModelNode("SwitchSelectionMode", new CommandViewModelContent((sender, parameters) => { pickingSystem.ActiveGizmoActionMode = PickingSystem.GizmoAction.None; }))); editorContext.Root.Children.Add(new ViewModelNode("SwitchTranslationMode", new CommandViewModelContent((sender, parameters) => { pickingSystem.ActiveGizmoActionMode = PickingSystem.GizmoAction.Translation; }))); editorContext.Root.Children.Add(new ViewModelNode("SwitchRotationMode", new CommandViewModelContent((sender, parameters) => { pickingSystem.ActiveGizmoActionMode = PickingSystem.GizmoAction.Rotation; }))); var contexts = new Dictionary<string, Tuple<ViewModelContext, ViewModelState>>(); contexts.Add("Editor", Tuple.Create(editorContext, new ViewModelState())); contexts.Add("RenderPassPlugins", Tuple.Create(renderPassPluginsContext, new ViewModelState())); contexts.Add("RenderPasses", Tuple.Create(renderPassHierarchyContext, new ViewModelState())); contexts.Add("SelectedEntities", Tuple.Create(selectedEntitiesContext, new ViewModelState())); contexts.Add("EntityHierarchy", Tuple.Create(entityHierarchyContext, new ViewModelState())); contexts.Add("ScriptEngine", Tuple.Create(scriptEngineContext, new ViewModelState())); contexts.Add("MicroThreads", Tuple.Create(runningScriptsContext, new ViewModelState())); contexts.Add("AssetBrowser", Tuple.Create(assetBrowserContext, new ViewModelState())); contexts.Add("Effects", Tuple.Create(effectsContext, new ViewModelState())); int lastAckPacket = 0; var entitiesChangePackets = new ConcurrentQueue<EntitiesChangePacket>(); socketContext.AddPacketHandler<EntitiesChangePacket>( (packet) => { entitiesChangePackets.Enqueue(packet); entitiesChangePacketEvent.Set(); }); Action asyncThreadStart = () => { while (true) { Thread.Sleep(100); foreach (var context in contexts) { // Process async data Guid[] path = null; object value = null; lock (context.Value.Item1) { var pendingNode = context.Value.Item1.GetNextPendingAsyncNode(); if (pendingNode != null) { value = pendingNode.Value; path = ViewModelController.BuildPath(pendingNode); } } if (path != null) { // Temporary encoding through our serializer (until our serializer are used for packets) var memoryStream = new MemoryStream(); var writer = new BinarySerializationWriter(memoryStream); writer.SerializeExtended(null, value, ArchiveMode.Serialize); var change = new NetworkChange { Path = path.ToArray(), Type = NetworkChangeType.ValueUpdateAsync, Value = memoryStream.ToArray() }; var packet = new EntitiesChangePacket { GroupKey = context.Key, Changes = new NetworkChange[] { change } }; socketContextAsync.Send(packet); break; } } } }; new Thread(new ThreadStart(asyncThreadStart)).Start(); // TODO: Move some of this code directly inside ViewModelContext/Controller classes while (true) { await TaskEx.WhenAny(TaskEx.Delay(250), entitiesChangePacketEvent.WaitAsync()); EntitiesChangePacket packet; while (entitiesChangePackets.TryDequeue(out packet)) { ViewModelController.NetworkApplyChanges(contexts[packet.GroupKey].Item1, packet.Changes); lastAckPacket = packet.Index; } // Wait a single frame so that network updates get applied properly by all rendering systems for next update await Scheduler.Current.NextFrame(); // If entity disappeared, try to replace it with new one (happen during file reload) // It's little bit cumbersome to test, need some simplification of this specific entity view model root. if (selectedEntitiesContext.Root != null && selectedEntitiesContext.Root.Parent != null && selectedEntitiesContext.Root.Parent.NodeValue is Entity) { var entity = (Entity)selectedEntitiesContext.Root.Parent.NodeValue; if (!engineContext.EntityManager.Entities.Contains(entity)) { entity = engineContext.EntityManager.Entities.FirstOrDefault(x => x.Guid == entity.Guid); if (entity != null) { selectedEntitiesContext.ViewModelByGuid.Clear(); selectedEntitiesContext.Root = selectedEntitiesContext.GetModelView(entity).Children.First(x => x.PropertyName == "Components"); } } } var data = new Dictionary<string, byte[]>(); foreach (var context in contexts) { lock (context.Value.Item1) { if (context.Value.Item1.Root != null) context.Value.Item1.AddModelView(context.Value.Item1.Root); ViewModelController.UpdateReferences(context.Value.Item1, true); data[context.Key] = ViewModelController.NetworkSerialize(context.Value.Item1, context.Value.Item2); } } viewModelGlobalContext.UpdateObjects(contexts.Select(x => x.Value.Item1)); //Console.WriteLine("DataSize: {0}", data.Sum(x => x.Value.Length)); await Task.Factory.StartNew(() => socketContext.Send(new EntitiesUpdatePacket { AckIndex = lastAckPacket, Data = data })); } }