private void FakeGmxRotate() { _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, true), 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); } }
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; } }