protected override void OnOpen() { var protocols = Context.SecWebSocketProtocols; foreach (var item in protocols) { if (item == "dev") { this.Encoder = CoflnetJsonEncoder.Instance; Send("runing on dev, Format"); Send(MessagePackSerializer.SerializeToJson( new CoflnetJsonEncoder.DevCommandData(ServerCommandData.SerializeServerCommandData (new KeyValuePair <string, string>("exampleKey", "This is an example of a valid command"), "setValue", this.Encoder)))); // CommandData.SerializeCommandData("hi", "setValue"))))); } } if (this.Encoder == null) { this.Encoder = CoflnetEncoder.Instance; } System.Timers.Timer timer = new System.Timers.Timer(); timer.AutoReset = true; timer.Elapsed += t_Elapsed; timer.Start(); }
private bool VerifyVersionData(ServerCommandData data) { CoreLog.Log(CoreLogLevel.Debug, $"Received {data.Command} while waiting for server announcement."); if (data.Command == ServerCommand.Announce) { var protocolVersion = ValueConverter.ToUInt32(data.Data, 0); var pluginVersion = ValueConverter.ToVersion(data.Data, 4); if (protocolVersion != CoreVersion.ProtocolVersion) { var updatee = protocolVersion > CoreVersion.ProtocolVersion ? "game mode" : "server"; CoreLog.Log(CoreLogLevel.Error, $"Protocol version mismatch! The server is running protocol {protocolVersion} but the game mode is running {CoreVersion.ProtocolVersion}"); CoreLog.Log(CoreLogLevel.Error, $"Please update your {updatee}."); return(false); } CoreLog.Log(CoreLogLevel.Info, $"Connected to version {pluginVersion.ToString(3)} via protocol {protocolVersion}"); ServerPath = ValueConverter.ToString(data.Data, 8, Encoding.ASCII); return(true); } CoreLog.Log(CoreLogLevel.Error, $"Received command {data.Command.ToString().ToLower()} instead of announce."); return(false); }
public bool Process(ServerCommandData command, bool force) { if (_condition != command.Command && !force) { return(false); } _result = command; _semaphore.Release(); return(true); }
/// <summary> /// Save the specified data. Will drop the data if the receiver and sender are the same. /// </summary> /// <param name="commandData">Data to save.</param> public override void SaveMessage(CommandData commandData) { // messages to oneself won't be saved if (commandData.SenderId == commandData.Recipient) { return; } var serverData = commandData as ServerCommandData; if (serverData == null) { serverData = new ServerCommandData(commandData); } FileController.AppendLineAs <ServerCommandData>(PathToSource(commandData.Recipient), serverData); }
public ServerCommandData Wait() { _semaphore.Wait(); var result = _result; _result = default(ServerCommandData); // If we're not waiting for this command, don't recycle this handle. if (result.Command == _condition) { _owner.Recycle(this); } return(result); }
protected override void OnMessage(MessageEventArgs e) { // try to parse and execute the command sent try { ServerCommandData commandData = Encoder.Deserialize(e); // if connection information is needed commandData.Connection = this; if (commandData.Recipient.ServerId == 0) { throw new CoflnetException("unknown_server", "this server is unknown (There is no server with the id 0)"); } // prevent id spoofing if (commandData.SenderId != new EntityId() && !AuthenticatedIds.Contains(commandData.SenderId)) { throw new NotAuthenticatedAsException(commandData.SenderId); } EntityManager.Instance.ExecuteForReference(commandData); // var controllerForObject = ReferenceManager.Instance.GetResource(commandData.rId) // .GetCommandController(); // controllerForObject.ExecuteCommand(commandData); } catch (CoflnetException ex) { Encoder.Send(new CoflnetExceptionTransmit(ex), this); Track.instance.Error(ex.Message, e.Data, ex.StackTrace); } /* * catch (Exception ex) * { * Track.instance.Error(ex.Message, e.Data, ex.StackTrace); * }*/ //Logger.Log(ID); //Logger.Log("Got some data :)"); }
public void Release(ServerCommandData command) { // Find wait handle waiting for this command. lock (_waitHandles) { // Process the command in REVERSE order (stack) because of natives calling callbacks // calling natives calling callbacks... The deepest native should first receive a response. // When forcing an unhandled command down some wait handle (next while loop), the order does // not matter. var current = _waitHandles.Last; while (current != null) { if (current.Value.Process(command, false)) { _waitHandles.Remove(current); return; } current = current.Previous; } // Force it down some wait handle... Can't let asyncQueue handle it because at this point // the main thread might be waiting for the response of a native, while the server might be // waiting for the response to a callback invoked by the native. Deadlocks, yay! If no wait // handles are available, the async queue should be able to handle this because the main thread // is likely idle. current = _waitHandles.First; while (current != null) { if (current.Value.Process(command, true)) { return; } current = current.Next; } } // If no wait handles are able to process this command, put it on the queue for when the main thread // is idle. _asyncQueue.Enqueue(command); _semaphore.Release(); }
private void ProcessCommand(ServerCommandData data) { switch (data.Command) { case ServerCommand.Nop: break; case ServerCommand.Tick: // The server expects at least a message every 5 seconds or else the debug pause // detector kicks in. Send one at least every 3 to be safe. if (DateTime.UtcNow - _lastSend > TimeSpan.FromSeconds(3)) { Send(ServerCommand.Alive, null); } if (!_canTick) { break; } try { _gameModeProvider.Tick(); } catch (Exception e) { OnUnhandledException(new UnhandledExceptionEventArgs("Tick", e)); } break; case ServerCommand.Pong: if (_pongs.Count == 0) { CoreLog.Log(CoreLogLevel.Error, "Received a random pong"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); } else { _pongs.Dequeue().Pong(); } break; case ServerCommand.Announce: CoreLog.Log(CoreLogLevel.Error, "Received a random server announcement"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); break; case ServerCommand.PublicCall: var name = ValueConverter.ToString(data.Data, 0, Encoding); var isInit = name == "OnGameModeInit"; if (CoreLog.DoesLog(CoreLogLevel.Verbose)) { CoreLog.LogVerbose("Incoming public call: {0}", name); } if ((_startBehaviour == GameModeStartBehaviour.Gmx || _startBehaviour == GameModeStartBehaviour.FakeGmx) && !_initReceived && !isInit) { CoreLog.Log(CoreLogLevel.Debug, $"Skipping callback {name} because OnGameModeInit has not yet been called"); Send(ServerCommand.Response, AZero); break; } var isFirstInit = isInit && !_initReceived; if (isFirstInit) { _initReceived = true; } if (_callbacks.TryGetValue(name, out var callback)) { int?result = null; try { result = callback.Invoke(data.Data, name.Length + 1); CoreLog.LogVerbose("Public call response for {0}: {1}", name, result); } catch (Exception e) { OnUnhandledException(new UnhandledExceptionEventArgs(name, e)); } Send(ServerCommand.Response, result != null ? AOne.Concat(ValueConverter.GetBytes(result.Value)) : AZero); } else { CoreLog.Log(CoreLogLevel.Error, "Received unknown callback " + name); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); } if (isFirstInit) { if (_startBehaviour == GameModeStartBehaviour.FakeGmx) { FakeGmxRotate(); } _canTick = true; } else if (_initReceived && name == "OnGameModeExit") { CoreLog.Log(CoreLogLevel.Info, "OnGameModeExit received, sending reconnect signal..."); Send(ServerCommand.Reconnect, null); // Give the server time to receive the reconnect signal. Thread.Sleep(100); CleanUp(); } break; default: CoreLog.Log(CoreLogLevel.Error, $"Unknown command {data.Command} received with {data.Data?.Length.ToString() ?? "NULL"} data"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); break; } }
private void ProcessCommand(ServerCommandData data) { switch (data.Command) { case ServerCommand.Tick: if (!_canTick) { break; } _gameModeProvider.Tick(); // The server expects at least a message every 5 seconds or else the debug pause // detector kicks in. Send one at least every 3 to be safe. if (DateTime.UtcNow - _lastSend > TimeSpan.FromSeconds(3)) { Send(ServerCommand.Alive, null); } break; case ServerCommand.Pong: if (_pongs.Count == 0) { CoreLog.Log(CoreLogLevel.Error, "Received a random pong"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); } else { _pongs.Dequeue().Pong(); } break; case ServerCommand.Announce: CoreLog.Log(CoreLogLevel.Error, "Received a random server announcement"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); break; case ServerCommand.PublicCall: var name = ValueConverter.ToString(data.Data, 0, Encoding); var isInit = name == "OnGameModeInit"; if (CoreLog.DoesLog(CoreLogLevel.Verbose)) { CoreLog.LogVerbose("Incoming public call: {0}", name); } if ((_startBehaviour == GameModeStartBehaviour.Gmx || _startBehaviour == GameModeStartBehaviour.FakeGmx) && !_initReceived && !isInit) { CoreLog.Log(CoreLogLevel.Debug, $"Skipping callback {name} because OnGameModeInit has not yet been called"); Send(ServerCommand.Response, AZero); break; } var isFirstInit = isInit && !_initReceived; if (isFirstInit) { _initReceived = true; } if (_callbacks.TryGetValue(name, out var callback)) { int?result = null; try { result = callback.Invoke(data.Data, name.Length + 1); CoreLog.LogVerbose("Public call response for {0}: {1}", name, result); } catch (Exception e) { OnUnhandledException(new UnhandledExceptionEventArgs(e)); } Send(ServerCommand.Response, result != null ? AOne.Concat(ValueConverter.GetBytes(result.Value)) : AZero); } else { CoreLog.Log(CoreLogLevel.Error, "Received unknown callback " + name); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); } if (isFirstInit) { if (_startBehaviour == GameModeStartBehaviour.FakeGmx) { _callbacks.TryGetValue("OnIncomingConnection", out var onIncomingConnection); _callbacks.TryGetValue("OnPlayerConnect", out var onPlayerConnect); _callbacks.TryGetValue("OnPlayerRequestClass", out var onPlayerRequestClass); var natIsPlayerConnected = NativeLoader.Load("IsPlayerConnected", new[] { NativeParameterInfo.ForType(typeof(int)) }); var natGetPlayerPoolSize = NativeLoader.Load("GetPlayerPoolSize", new NativeParameterInfo[0]); var natForceClassSelection = NativeLoader.Load("ForceClassSelection", new[] { NativeParameterInfo.ForType(typeof(int)) }); var natTogglePlayerSpectating = NativeLoader.Load("TogglePlayerSpectating", new[] { NativeParameterInfo.ForType(typeof(int)), NativeParameterInfo.ForType(typeof(int)) }); var natGetPlayerIp = NativeLoader.Load("GetPlayerIp", new[] { NativeParameterInfo.ForType(typeof(int)), new NativeParameterInfo(NativeParameterType.StringReference, 2), NativeParameterInfo.ForType(typeof(int)), }); var poolSize = natGetPlayerPoolSize.Invoke(); for (var i = 0; i <= poolSize; i++) { var isConnected = natIsPlayerConnected.Invoke(i); if (isConnected == 0) { continue; } var args = new object[] { i, null, 16 }; natGetPlayerIp.Invoke(args); if (args[1] is string ip) { onIncomingConnection?.Invoke( ValueConverter.GetBytes(i) .Concat(ValueConverter.GetBytes(ip, Encoding.ASCII)) .Concat(ValueConverter.GetBytes(9999999)) .ToArray(), 0); } onPlayerConnect?.Invoke(ValueConverter.GetBytes(i), 0); natForceClassSelection.Invoke(i); natTogglePlayerSpectating.Invoke(i, 1); natTogglePlayerSpectating.Invoke(i, 0); onPlayerRequestClass?.Invoke( ValueConverter.GetBytes(i) .Concat(ValueConverter.GetBytes(0)) .ToArray(), 0); } } _canTick = true; } else if (_initReceived && name == "OnGameModeExit") { CoreLog.Log(CoreLogLevel.Info, "OnGameModeExit received, sending reconnect signal..."); Send(ServerCommand.Reconnect, null); // Give the server time to receive the reconnect signal. // TODO: This is an ugly freeze/comms-deadlock fix. Thread.Sleep(100); CleanUp(); } break; default: CoreLog.Log(CoreLogLevel.Error, $"Unknown command {data.Command} recieved with {data.Data?.Length.ToString() ?? "NULL"} data"); CoreLog.Log(CoreLogLevel.Debug, Environment.StackTrace); break; } }
public void Release(ServerCommandData command) { _asyncQueue.Enqueue(command); _semaphore.Release(); }