protected override void OnMessage(MessageEventArgs e) { if (e.Data == "chatfull") { Send(RconManager.GetFullChatLog()); } if (e.Data[0].Equals('1')) { RconManager.Instance.ReceiveRconChat(e.Data); } }
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode) { if (scene.name == "Lobby") { IsInGame = false; Managers.instance.SetScreenForLobby(); } else { IsInGame = true; Managers.instance.SetScreenForGame(); SetPlayerPreferences(); } if (CustomNetworkManager.Instance.isNetworkActive) { //Reset stuff if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null || Instance.testServer) { IsHeadlessServer = true; } if (IsInGame && GameManager.Instance != null && CustomNetworkManager.Instance._isServer) { GameManager.Instance.ResetRoundTime(); } return; } //force vsync when not-headless if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null && !Instance.testServer && !IsHeadlessServer) { Application.targetFrameRate = 60; QualitySettings.vSyncCount = 1; } //Check if running in batchmode (headless server) if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null || Instance.testServer) { float calcFrameRate = 1f / Time.fixedDeltaTime; Application.targetFrameRate = (int)calcFrameRate; Logger.Log("START SERVER HEADLESS MODE"); IsHeadlessServer = true; StartCoroutine(WaitToStartServer()); if (rconManager == null) { GameObject rcon = Instantiate(Resources.Load("Rcon/RconManager") as GameObject, null) as GameObject; rconManager = rcon.GetComponent <RconManager>(); Logger.Log("Start rcon server", Category.Rcon); } } }
private void PropagateChatToClients(ChatEvent chatEvent) { var players = PlayerList.Instance.InGamePlayers; //Local chat range checks: if (chatEvent.channels == ChatChannel.Local || chatEvent.channels == ChatChannel.Combat) { // var speaker = PlayerList.Instance.Get(chatEvent.speaker); RaycastHit2D hit; LayerMask layerMask = 1 << 9; //Walls layer for (int i = 0; i < players.Count(); i++) { if (Vector2.Distance(chatEvent.position, //speaker.GameObject.transform.position, players[i].GameObject.transform.position) > 14f) { //Player in the list is too far away for local chat, remove them: players.Remove(players[i]); } else { //within range, but check if they are in another room or hiding behind a wall if (Physics2D.Linecast(chatEvent.position, //speaker.GameObject.transform.position, players[i].GameObject.transform.position, layerMask)) { //if it hit a wall remove that player players.Remove(players[i]); } } } } for (var i = 0; i < players.Count; i++) { var playerScript = players[i].GameObject.GetComponent <PlayerScript>(); ChatChannel channels = playerScript.GetAvailableChannelsMask(false) & chatEvent.channels; UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.message); } if (RconManager.Instance != null) { string name = ""; if ((namelessChannels & chatEvent.channels) != chatEvent.channels) { name = "<b>[" + chatEvent.channels + "]</b> "; } RconManager.AddChatLog(name + chatEvent.message); } }
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode) { if (scene.name == "Lobby") { IsInGame = false; Managers.instance.SetScreenForLobby(); } else { IsInGame = true; Managers.instance.SetScreenForGame(); SetPlayerPreferences(); } if (CustomNetworkManager.Instance.isNetworkActive) { //Reset stuff CheckHeadlessState(); if (IsInGame && GameManager.Instance != null && CustomNetworkManager.Instance._isServer) { GameManager.Instance.ResetRoundTime(); } return; } //Check if running in batchmode (headless server) if (CheckHeadlessState()) { // float calcFrameRate = 1f / Time.deltaTime; // Application.targetFrameRate = (int) calcFrameRate; // Logger.Log($"Starting server in HEADLESS mode. Target framerate is {Application.targetFrameRate}", // Category.Server); Logger.Log($"FrameRate limiting has been disabled on Headless Server", Category.Server); IsHeadlessServer = true; StartCoroutine(WaitToStartServer()); if (rconManager == null) { GameObject rcon = Instantiate(Resources.Load("Rcon/RconManager") as GameObject, null) as GameObject; rconManager = rcon.GetComponent <RconManager>(); Logger.Log("Start rcon server", Category.Rcon); } } }
protected override void OnMessage(MessageEventArgs e) { if (e.Data == "lastlog") { Send(RconManager.GetLastLog()); } if (e.Data == "logfull") { Send(RconManager.GetFullLog()); } if (e.Data[0].Equals('1')) { RconManager.Instance.ReceiveRconCommand(e.Data); } }
public static void AmendLog(string msg) { if (RconManager.Instance != null) { RconManager.AddLog(msg); } DebugLog += msg + "\n"; LastLog = msg; if (DebugLog.Length > 10000) { DebugLog = DebugLog.Substring(9000); } //if it is null it means the object is still disabled and is about be enabled if (Instance != null) { Instance.RefreshLogDisplay(); } }
public void PropagateChatToClients(ChatEvent chatEvent) { List <ConnectedPlayer> players = PlayerList.Instance.AllPlayers; //Local chat range checks: if (chatEvent.channels.HasFlag(ChatChannel.Local) || chatEvent.channels.HasFlag(ChatChannel.Combat) || chatEvent.channels.HasFlag(ChatChannel.Action)) { for (int i = players.Count - 1; i >= 0; i--) { if (players[i].Script == null) { //joined viewer, don't message them players.RemoveAt(i); continue; } if (players[i].Script.gameObject == chatEvent.originator) { //Always send the originator chat to themselves continue; } if (players[i].Script.IsGhost && players[i].Script.IsPlayerSemiGhost == false) { //send all to ghosts continue; } if (chatEvent.position == TransformState.HiddenPos) { //show messages with no provided position to everyone continue; } //Send chat to PlayerChatLocation pos, usually just the player object but for AI is its vessel var playerPosition = players[i].Script.PlayerChatLocation.OrNull()?.AssumedWorldPosServer() ?? players[i].Script.gameObject.AssumedWorldPosServer(); //Do player position to originator distance check if (DistanceCheck(playerPosition) == false) { //Distance check failed so if we are Ai, then try send action and combat messages to their camera location //as well as if possible if (chatEvent.channels.HasFlag(ChatChannel.Local) == false && players[i].Script.PlayerState == PlayerScript.PlayerStates.Ai && players[i].Script.TryGetComponent <AiPlayer>(out var aiPlayer) && aiPlayer.IsCarded == false) { playerPosition = players[i].Script.gameObject.AssumedWorldPosServer(); //Check camera pos if (DistanceCheck(playerPosition)) { //Camera can see player, allow Ai to see action/combat messages continue; } } //Player failed distance checks remove them players.RemoveAt(i); } bool DistanceCheck(Vector3 playerPos) { //TODO maybe change this to (chatEvent.position - playerPos).sqrMagnitude > 196f to avoid square root for performance? if (Vector2.Distance(chatEvent.position, playerPos) > 14f) { //Player in the list is too far away for local chat, remove them: return(false); } //Within range, but check if they are in another room or hiding behind a wall if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls, layerMask, playerPos).ItHit) { //If it hit a wall remove that player return(false); } //Player can see the position return(true); } } //Get NPCs in vicinity var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask); foreach (Collider2D coll in npcs) { var npcPosition = coll.gameObject.AssumedWorldPosServer(); if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls, layerMask, npcPosition).ItHit == false) { //NPC is in hearing range, pass the message on: var mobAi = coll.GetComponent <MobAI>(); if (mobAi != null) { mobAi.LocalChatReceived(chatEvent); } } } } for (var i = 0; i < players.Count; i++) { ChatChannel channels = chatEvent.channels; if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) || channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) || channels.HasFlag(ChatChannel.Action)) { //Binary check here to avoid speaking in local when speaking on binary if (!channels.HasFlag(ChatChannel.Binary) || (players[i].Script.IsGhost && players[i].Script.IsPlayerSemiGhost == false)) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker, chatEvent.stripTags); continue; } } if (players[i].Script == null) { channels &= ChatChannel.OOC; } else { channels &= players[i].Script.GetAvailableChannelsMask(false); } //if the mask ends up being a big fat 0 then don't do anything if (channels != ChatChannel.None) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker, chatEvent.stripTags); } } if (rconManager != null) { string name = ""; if ((namelessChannels & chatEvent.channels) != chatEvent.channels) { name = "<b>[" + chatEvent.channels + "]</b> "; } RconManager.AddChatLog(name + chatEvent.message); } }
private void PropagateChatToClients(ChatEvent chatEvent) { List <ConnectedPlayer> players = PlayerList.Instance.AllPlayers; //Local chat range checks: if (chatEvent.channels.HasFlag(ChatChannel.Local) || chatEvent.channels.HasFlag(ChatChannel.Combat) || chatEvent.channels.HasFlag(ChatChannel.Action)) { for (int i = players.Count - 1; i >= 0; i--) { if (players[i].Script == null) { //joined viewer, don't message them players.RemoveAt(i); continue; } if (players[i].Script.IsGhost) { //send all to ghosts continue; } if (chatEvent.position == TransformState.HiddenPos) { //show messages with no provided position to everyone continue; } var playerPosition = players[i].GameObject.AssumedWorldPosServer(); if (Vector2.Distance(chatEvent.position, playerPosition) > 14f) { //Player in the list is too far away for local chat, remove them: players.RemoveAt(i); } else { //within range, but check if they are in another room or hiding behind a wall if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls , layerMask, playerPosition).ItHit) { //if it hit a wall remove that player players.RemoveAt(i); } } } //Get NPCs in vicinity var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask); foreach (Collider2D coll in npcs) { var npcPosition = coll.gameObject.AssumedWorldPosServer(); if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls, layerMask, npcPosition).ItHit == false) { //NPC is in hearing range, pass the message on: var mobAi = coll.GetComponent <MobAI>(); if (mobAi != null) { mobAi.LocalChatReceived(chatEvent); } } } } for (var i = 0; i < players.Count; i++) { ChatChannel channels = chatEvent.channels; if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) || channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) || channels.HasFlag(ChatChannel.Action)) { if (!channels.HasFlag(ChatChannel.Binary) || players[i].Script.IsGhost) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker); continue; } } if (players[i].Script == null) { channels &= ChatChannel.OOC; } else { channels &= players[i].Script.GetAvailableChannelsMask(false); } //if the mask ends up being a big fat 0 then don't do anything if (channels != ChatChannel.None) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker); } } if (rconManager != null) { string name = ""; if ((namelessChannels & chatEvent.channels) != chatEvent.channels) { name = "<b>[" + chatEvent.channels + "]</b> "; } RconManager.AddChatLog(name + chatEvent.message); } }
/// <summary> /// A debug entry is received /// </summary> /// <param name="logString">The Debug.Log/LogError/LogWarning/LogException/LogAssertion string</param> /// <param name="stackTrace">The debug entry trace</param> /// <param name="logType">Error, warning, informational message</param> private void ReceivedLog(string logString, string stackTrace, LogType logType) { DebugLogEntry logEntry = new DebugLogEntry(logString, stackTrace, null); // Check if this entry is a duplicate (i.e. has been received before) int logEntryIndex; bool isEntryInCollapsedEntryList = collapsedLogEntriesMap.TryGetValue(logEntry, out logEntryIndex); if (isEntryInCollapsedEntryList == false) { // It is not a duplicate, // add it to the list of unique debug entries logEntry.logTypeSpriteRepresentation = logSpriteRepresentations[logType]; if (RconManager.Instance != null) { RconManager.AddLog(logString); } logEntryIndex = collapsedLogEntries.Count; collapsedLogEntries.Add(logEntry); collapsedLogEntriesMap[logEntry] = logEntryIndex; } else { // It is a duplicate, // increment the original debug item's collapsed count logEntry = collapsedLogEntries[logEntryIndex]; logEntry.count++; } // Add the index of the unique debug entry to the list // that stores the order the debug entries are received uncollapsedLogEntriesIndices.Add(logEntryIndex); // If this debug entry matches the current filters, // add it to the list of debug entries to show Sprite logTypeSpriteRepresentation = logEntry.logTypeSpriteRepresentation; if (isCollapseOn && isEntryInCollapsedEntryList) { if (isLogWindowVisible) { recycledListView.OnCollapsedLogEntryAtIndexUpdated(logEntryIndex); } } else if (logFilter == DebugLogFilter.All || (logTypeSpriteRepresentation == infoLog && ((logFilter & DebugLogFilter.Info) == DebugLogFilter.Info)) || (logTypeSpriteRepresentation == warningLog && ((logFilter & DebugLogFilter.Warning) == DebugLogFilter.Warning)) || (logTypeSpriteRepresentation == errorLog && ((logFilter & DebugLogFilter.Error) == DebugLogFilter.Error))) { indicesOfListEntriesToShow.Add(logEntryIndex); if (isLogWindowVisible) { recycledListView.OnLogEntriesUpdated(false); } } if (logType == LogType.Log) { infoEntryCount++; infoEntryCountText.text = infoEntryCount.ToString(); // If debug popup is visible, notify it of the new debug entry if (isLogWindowVisible == false) { popupManager.NewInfoLogArrived(); } } else if (logType == LogType.Warning) { warningEntryCount++; warningEntryCountText.text = warningEntryCount.ToString(); // If debug popup is visible, notify it of the new debug entry if (isLogWindowVisible == false) { popupManager.NewWarningLogArrived(); } } else { errorEntryCount++; errorEntryCountText.text = errorEntryCount.ToString(); // If debug popup is visible, notify it of the new debug entry if (isLogWindowVisible == false) { popupManager.NewErrorLogArrived(); } } }
private static void TryLog(string message, Level messageLevel, Category category = Category.Unknown, params object[] args) { Level referenceLevel = LogLevel; if (LogOverrides.ContainsKey(category)) { referenceLevel = LogOverrides[category]; } if (referenceLevel < messageLevel) { return; } string categoryPrefix = category == Category.Unknown ? "" : "[" + category + "] "; string msg = categoryPrefix + message; if (args.Length > 0) { switch (messageLevel) { case Level.Off: break; case Level.Error: Debug.LogErrorFormat(msg, args); break; case Level.Warning: Debug.LogWarningFormat(msg, args); break; case Level.Info: Debug.LogFormat(msg, args); break; case Level.Trace: Debug.LogFormat(msg, args); break; } } else { switch (messageLevel) { case Level.Off: break; case Level.Error: Debug.LogError(msg); break; case Level.Warning: Debug.LogWarning(msg); break; case Level.Info: Debug.Log(msg); break; case Level.Trace: Debug.Log(msg); break; } } if (RconManager.Instance != null) { RconManager.AddLog(msg); } DebugConsole.AmendLog(msg); }
private void PropagateChatToClients(ChatEvent chatEvent) { List <ConnectedPlayer> players; if (chatEvent.matrix != MatrixInfo.Invalid) { //get players only on provided matrix players = PlayerList.Instance.GetPlayersOnMatrix(chatEvent.matrix); } else { players = PlayerList.Instance.AllPlayers; } //Local chat range checks: if (chatEvent.channels == ChatChannel.Local || chatEvent.channels == ChatChannel.Combat || chatEvent.channels == ChatChannel.Action) { // var speaker = PlayerList.Instance.Get(chatEvent.speaker); LayerMask layerMask = LayerMask.GetMask("Walls", "Door Closed"); for (int i = 0; i < players.Count(); i++) { if (players[i].Script == null) { //joined viewer, don't message them players.Remove(players[i]); continue; } if (players[i].Script.IsGhost) { //send all to ghosts continue; } if (Vector2.Distance(chatEvent.position, //speaker.GameObject.transform.position, players[i].GameObject.transform.position) > 14f) { //Player in the list is too far away for local chat, remove them: players.Remove(players[i]); } else { //within range, but check if they are in another room or hiding behind a wall if (Physics2D.Linecast(chatEvent.position, //speaker.GameObject.transform.position, players[i].GameObject.transform.position, layerMask)) { //if it hit a wall remove that player players.Remove(players[i]); } } } //Get NPCs in vicinity var npcMask = LayerMask.GetMask("NPC"); var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask); foreach (Collider2D coll in npcs) { if (!Physics2D.Linecast(chatEvent.position, coll.transform.position, layerMask)) { //NPC is in hearing range, pass the message on: var mobAi = coll.GetComponent <MobAI>(); if (mobAi != null) { mobAi.LocalChatReceived(chatEvent); } } } } for (var i = 0; i < players.Count; i++) { ChatChannel channels = chatEvent.channels; if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) || channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) || channels.HasFlag(ChatChannel.Action)) { if (!channels.HasFlag(ChatChannel.Binary) || players[i].Script.IsGhost) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker); continue; } } if (players[i].Script == null) { channels &= ChatChannel.OOC; } else { channels &= players[i].Script.GetAvailableChannelsMask(false); } //if the mask ends up being a big fat 0 then don't do anything if (channels != ChatChannel.None) { UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers, chatEvent.originator, chatEvent.speaker); } } if (RconManager.Instance != null) { string name = ""; if ((namelessChannels & chatEvent.channels) != chatEvent.channels) { name = "<b>[" + chatEvent.channels + "]</b> "; } RconManager.AddChatLog(name + chatEvent.message); } }
private async void Startup() { // Print exception messages in English Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; // Set the AppDomain working directory to the current resource root Environment.CurrentDirectory = Path.GetFullPath(API.GetResourcePath(API.GetCurrentResourceName())); new Logger().Info($"NFive {typeof(Program).Assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>().First().InformationalVersion}"); // TODO: Check and warn if local CitizenFX.Core.Server.dll is found var config = ConfigurationManager.Load <CoreConfiguration>("core.yml"); // Use configured culture for output Thread.CurrentThread.CurrentCulture = config.Locale.Culture.First(); CultureInfo.DefaultThreadCurrentCulture = config.Locale.Culture.First(); ServerConfiguration.Locale = config.Locale; ServerLogConfiguration.Output = config.Log.Output; var logger = new Logger(config.Log.Core); API.SetGameType(config.Display.Game); API.SetMapName(config.Display.Map); // Setup RPC handlers RpcManager.Configure(config.Log.Comms, this.EventHandlers, this.Players); var events = new EventManager(config.Log.Comms); var comms = new CommunicationManager(events); var rcon = new RconManager(comms); // Load core controllers try { var dbController = new DatabaseController(new Logger(config.Log.Core, "Database"), ConfigurationManager.Load <DatabaseConfiguration>("database.yml"), comms); await dbController.Loaded(); this.controllers.Add(new Name("NFive/Database"), new List <Controller> { dbController }); } catch (Exception ex) { logger.Error(ex, "Database connection error"); logger.Warn("Fatal error, exiting"); Environment.Exit(1); } var eventController = new EventController(new Logger(config.Log.Core, "FiveM"), comms); await eventController.Loaded(); this.controllers.Add(new Name("NFive/RawEvents"), new List <Controller> { eventController }); var sessionController = new SessionController(new Logger(config.Log.Core, "Session"), ConfigurationManager.Load <SessionConfiguration>("session.yml"), comms); await sessionController.Loaded(); this.controllers.Add(new Name("NFive/Session"), new List <Controller> { sessionController }); // Resolve dependencies var graph = DefinitionGraph.Load(); // IoC var assemblies = new List <Assembly>(); assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Include != null).SelectMany(p => p.Server.Include.Select(i => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{i}.net.dll"))))); assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Main != null).SelectMany(p => p.Server.Main.Select(m => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{m}.net.dll"))))); var registrar = new ContainerRegistrar(); registrar.RegisterService <ILogger>(s => new Logger()); registrar.RegisterInstance <IRconManager>(rcon); registrar.RegisterInstance <IBaseScriptProxy>(new BaseScriptProxy(this.EventHandlers, this.Exports, this.Players)); registrar.RegisterInstance <ICommunicationManager>(comms); registrar.RegisterInstance <IClientList>(new ClientList(new Logger(config.Log.Core, "ClientList"), comms)); registrar.RegisterPluginComponents(assemblies.Distinct()); // DI var container = registrar.Build(); var pluginDefaultLogLevel = config.Log.Plugins.ContainsKey("default") ? config.Log.Plugins["default"] : LogLevel.Info; // Load plugins into the AppDomain foreach (var plugin in graph.Plugins) { logger.Info($"Loading {plugin.FullName}"); // Load include files foreach (var includeName in plugin.Server?.Include ?? new List <string>()) { var includeFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{includeName}.net.dll"); if (!File.Exists(includeFile)) { throw new FileNotFoundException(includeFile); } AppDomain.CurrentDomain.Load(File.ReadAllBytes(includeFile)); } // Load main files foreach (var mainName in plugin.Server?.Main ?? new List <string>()) { var mainFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{mainName}.net.dll"); if (!File.Exists(mainFile)) { throw new FileNotFoundException(mainFile); } var asm = Assembly.LoadFrom(mainFile); var sdkVersion = asm.GetCustomAttribute <ServerPluginAttribute>(); if (sdkVersion == null) { throw new Exception("Unable to load outdated SDK plugin"); // TODO } if (sdkVersion.Target != SDK.Server.SDK.Version) { throw new Exception("Unable to load outdated SDK plugin"); } var types = Assembly.LoadFrom(mainFile).GetTypes().Where(t => !t.IsAbstract && t.IsClass).ToList(); // Find migrations foreach (var migrationType in types.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(MigrationConfiguration <>))) { var configuration = (DbMigrationsConfiguration)Activator.CreateInstance(migrationType); var migrator = new DbMigrator(configuration); if (!migrator.GetPendingMigrations().Any()) { continue; } if (!ServerConfiguration.AutomaticMigrations) { throw new MigrationsPendingException($"Plugin {plugin.FullName} has pending migrations but automatic migrations are disabled"); } foreach (var migration in migrator.GetPendingMigrations()) { new Logger(config.Log.Core, "Database").Debug($"[{mainName}] Running migration: {migration}"); migrator.Update(migration); } } // Find controllers foreach (var controllerType in types.Where(t => t.IsSubclassOf(typeof(Controller)) || t.IsSubclassOf(typeof(ConfigurableController <>)))) { var logLevel = config.Log.Plugins.ContainsKey(plugin.Name) ? config.Log.Plugins[plugin.Name] : pluginDefaultLogLevel; var constructorArgs = new List <object> { new Logger(logLevel, plugin.Name) }; // Check if controller is configurable if (controllerType.BaseType != null && controllerType.BaseType.IsGenericType && controllerType.BaseType.GetGenericTypeDefinition() == typeof(ConfigurableController <>)) { // Initialize the controller configuration constructorArgs.Add(ConfigurationManager.InitializeConfig(plugin.Name, controllerType.BaseType.GetGenericArguments()[0])); } // Resolve IoC arguments constructorArgs.AddRange(controllerType.GetConstructors()[0].GetParameters().Skip(constructorArgs.Count).Select(p => container.Resolve(p.ParameterType))); Controller controller = null; try { // Construct controller instance controller = (Controller)Activator.CreateInstance(controllerType, constructorArgs.ToArray()); } catch (Exception ex) { // TODO: Dispose of controller logger.Error(ex, $"Unhandled exception in plugin {plugin.FullName}"); } if (controller == null) { continue; } try { await controller.Loaded(); if (!this.controllers.ContainsKey(plugin.Name)) { this.controllers.Add(plugin.Name, new List <Controller>()); } this.controllers[plugin.Name].Add(controller); } catch (Exception ex) { // TODO: Dispose of controller logger.Error(ex, $"Unhandled exception loading plugin {plugin.FullName}"); } } } } await Task.WhenAll(this.controllers.SelectMany(c => c.Value).Select(s => s.Started())); rcon.Controllers = this.controllers; comms.Event(CoreEvents.ClientPlugins).FromClients().OnRequest(e => e.Reply(graph.Plugins)); logger.Debug($"{graph.Plugins.Count.ToString(CultureInfo.InvariantCulture)} plugin(s) loaded, {this.controllers.Count.ToString(CultureInfo.InvariantCulture)} controller(s) created"); comms.Event(ServerEvents.ServerInitialized).ToServer().Emit(); logger.Info("Server ready"); }
public Program() { // Set the AppDomain working directory to the current resource root Environment.CurrentDirectory = FileManager.ResolveResourcePath(); var config = ConfigurationManager.Load <CoreConfiguration>("nfive.yml"); var logger = new Logger(config.Log.Core); //ServerConfiguration.LogLevel = config.Log.Level; API.SetGameType(config.Display.Game); API.SetMapName(config.Display.Map); // Setup RPC handlers RpcManager.Configure(config.Log.Rpc, this.EventHandlers); var events = new EventManager(config.Log.Events); var rcon = new RconManager(new RpcHandler()); // Load core controllers this.controllers.Add(new Name("NFive/Server"), new List <Controller>()); var dbController = new DatabaseController(new Logger(config.Log.Core, "Database"), events, new RpcHandler(), rcon, ConfigurationManager.Load <DatabaseConfiguration>("database.yml")); this.controllers[new Name("NFive/Server")].Add(dbController); // Resolve dependencies var graph = DefinitionGraph.Load(); var pluginDefaultLogLevel = config.Log.Plugins.ContainsKey("default") ? config.Log.Plugins["default"] : LogLevel.Info; // Load plugins into the AppDomain foreach (var plugin in graph.Plugins) { logger.Info($"Loading {plugin.FullName}"); // Load include files foreach (var includeName in plugin.Server?.Include ?? new List <string>()) { var includeFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{includeName}.net.dll"); if (!File.Exists(includeFile)) { throw new FileNotFoundException(includeFile); } AppDomain.CurrentDomain.Load(File.ReadAllBytes(includeFile)); } // Load main files foreach (var mainName in plugin.Server?.Main ?? new List <string>()) { var mainFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{mainName}.net.dll"); if (!File.Exists(mainFile)) { throw new FileNotFoundException(mainFile); } var types = Assembly.LoadFrom(mainFile).GetTypes().Where(t => !t.IsAbstract && t.IsClass).ToList(); //logger.Debug($"{mainName}: {types.Count} {string.Join(Environment.NewLine, types)}"); // Find migrations foreach (var migrationType in types.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(MigrationConfiguration <>))) { var configuration = (DbMigrationsConfiguration)Activator.CreateInstance(migrationType); var migrator = new DbMigrator(configuration); if (!migrator.GetPendingMigrations().Any()) { continue; } if (!ServerConfiguration.AutomaticMigrations) { throw new MigrationsPendingException($"Plugin {plugin.FullName} has pending migrations but automatic migrations are disabled"); } logger.Debug($"{mainName}: Running migrations {string.Join(", ", migrator.GetPendingMigrations())}"); migrator.Update(); } // Find controllers foreach (var controllerType in types.Where(t => t.IsSubclassOf(typeof(Controller)) || t.IsSubclassOf(typeof(ConfigurableController <>)))) { var logLevel = config.Log.Plugins.ContainsKey(plugin.Name) ? config.Log.Plugins[plugin.Name] : pluginDefaultLogLevel; var constructorArgs = new List <object> { new Logger(logLevel, plugin.Name), events, new RpcHandler(), rcon }; // Check if controller is configurable if (controllerType.BaseType != null && controllerType.BaseType.IsGenericType && controllerType.BaseType.GetGenericTypeDefinition() == typeof(ConfigurableController <>)) { // Initialize the controller configuration constructorArgs.Add(ConfigurationManager.InitializeConfig(plugin.Name, controllerType.BaseType.GetGenericArguments()[0])); } // Construct controller instance var controller = (Controller)Activator.CreateInstance(controllerType, constructorArgs.ToArray()); if (!this.controllers.ContainsKey(plugin.Name)) { this.controllers.Add(plugin.Name, new List <Controller>()); } this.controllers[plugin.Name].Add(controller); } } } rcon.Controllers = this.controllers; new RpcHandler().Event(SDK.Core.Rpc.RpcEvents.ClientPlugins).On(e => e.Reply(graph.Plugins)); events.Raise(SDK.Server.Events.ServerEvents.ServerInitialized); logger.Info($"{graph.Plugins.Count} plugins loaded, {this.controllers.Count} controller(s) created"); }
private async void Startup() { // Set the AppDomain working directory to the current resource root Environment.CurrentDirectory = Path.GetFullPath(API.GetResourcePath(API.GetCurrentResourceName())); Logger.Initialize(); new Logger().Info($"NFive {typeof(Program).Assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>().First().InformationalVersion}"); var config = ConfigurationManager.Load <CoreConfiguration>("nfive.yml"); ServerLogConfiguration.Output = config.Log.Output; //ServerConfiguration.LogLevel = config.Log.Level; var logger = new Logger(config.Log.Core); API.SetGameType(config.Display.Game); API.SetMapName(config.Display.Map); // Setup RPC handlers RpcManager.Configure(config.Log.Rpc, this.EventHandlers); // Client log mirroring new RpcHandler().Event("nfive:log:mirror").On(new Action <IRpcEvent, DateTime, LogLevel, string, string>((e, dt, level, prefix, message) => { new Logger(LogLevel.Trace, $"Client#{e.Client.Handle}|{prefix}").Log(message, level); })); var events = new EventManager(config.Log.Events); var rcon = new RconManager(new RpcHandler()); // Load core controllers var dbController = new DatabaseController(new Logger(config.Log.Core, "Database"), events, new RpcHandler(), rcon, ConfigurationManager.Load <DatabaseConfiguration>("database.yml")); await dbController.Loaded(); this.controllers.Add(new Name("NFive/Database"), new List <Controller> { dbController }); var sessionController = new SessionController(new Logger(config.Log.Core, "Session"), events, new RpcHandler(), rcon, ConfigurationManager.Load <SessionConfiguration>("session.yml")); await sessionController.Loaded(); this.controllers.Add(new Name("NFive/Session"), new List <Controller> { sessionController }); // Resolve dependencies var graph = DefinitionGraph.Load(); var pluginDefaultLogLevel = config.Log.Plugins.ContainsKey("default") ? config.Log.Plugins["default"] : LogLevel.Info; // IoC var assemblies = new List <Assembly>(); assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Include != null).SelectMany(p => p.Server.Include.Select(i => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{i}.net.dll"))))); assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Main != null).SelectMany(p => p.Server.Main.Select(m => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{m}.net.dll"))))); var registrar = new ContainerRegistrar(); registrar.RegisterService <ILogger>(s => new Logger()); registrar.RegisterType <IRpcHandler, RpcHandler>(); registrar.RegisterInstance <IEventManager>(events); registrar.RegisterInstance <IRconManager>(rcon); registrar.RegisterInstance <IClientList>(new ClientList(new Logger(config.Log.Core, "ClientList"), new RpcHandler())); registrar.RegisterSdkComponents(assemblies.Distinct()); // DI var container = registrar.Build(); // Load plugins into the AppDomain foreach (var plugin in graph.Plugins) { logger.Info($"Loading {plugin.FullName}"); // Load include files foreach (var includeName in plugin.Server?.Include ?? new List <string>()) { var includeFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{includeName}.net.dll"); if (!File.Exists(includeFile)) { throw new FileNotFoundException(includeFile); } AppDomain.CurrentDomain.Load(File.ReadAllBytes(includeFile)); } // Load main files foreach (var mainName in plugin.Server?.Main ?? new List <string>()) { var mainFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{mainName}.net.dll"); if (!File.Exists(mainFile)) { throw new FileNotFoundException(mainFile); } var types = Assembly.LoadFrom(mainFile).GetTypes().Where(t => !t.IsAbstract && t.IsClass).ToList(); // Find migrations foreach (var migrationType in types.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(MigrationConfiguration <>))) { var configuration = (DbMigrationsConfiguration)Activator.CreateInstance(migrationType); var migrator = new DbMigrator(configuration); if (!migrator.GetPendingMigrations().Any()) { continue; } if (!ServerConfiguration.AutomaticMigrations) { throw new MigrationsPendingException($"Plugin {plugin.FullName} has pending migrations but automatic migrations are disabled"); } foreach (var migration in migrator.GetPendingMigrations()) { new Logger(config.Log.Core, "Database").Debug($"[{mainName}] Running migration: {migration}"); migrator.Update(migration); } } // Find controllers foreach (var controllerType in types.Where(t => t.IsSubclassOf(typeof(Controller)) || t.IsSubclassOf(typeof(ConfigurableController <>)))) { var logLevel = config.Log.Plugins.ContainsKey(plugin.Name) ? config.Log.Plugins[plugin.Name] : pluginDefaultLogLevel; var constructorArgs = new List <object> { new Logger(logLevel, plugin.Name), events, new RpcHandler(), rcon }; // Check if controller is configurable if (controllerType.BaseType != null && controllerType.BaseType.IsGenericType && controllerType.BaseType.GetGenericTypeDefinition() == typeof(ConfigurableController <>)) { // Initialize the controller configuration constructorArgs.Add(ConfigurationManager.InitializeConfig(plugin.Name, controllerType.BaseType.GetGenericArguments()[0])); } // Resolve IoC arguments constructorArgs.AddRange(controllerType.GetConstructors()[0].GetParameters().Skip(constructorArgs.Count).Select(p => container.Resolve(p.ParameterType))); Controller controller = null; try { // Construct controller instance controller = (Controller)Activator.CreateInstance(controllerType, constructorArgs.ToArray()); } catch (Exception ex) { // TODO: Dispose of controller logger.Error(ex, $"Unhandled exception in plugin {plugin.FullName}"); } if (controller == null) { continue; } try { await controller.Loaded(); if (!this.controllers.ContainsKey(plugin.Name)) { this.controllers.Add(plugin.Name, new List <Controller>()); } this.controllers[plugin.Name].Add(controller); } catch (Exception ex) { // TODO: Dispose of controller logger.Error(ex, $"Unhandled exception loading plugin {plugin.FullName}"); } } } } #pragma warning disable 4014 foreach (var controller in this.controllers.SelectMany(c => c.Value)) { controller.Started(); } #pragma warning restore 4014 rcon.Controllers = this.controllers; new RpcHandler().Event(SDK.Core.Rpc.RpcEvents.ClientPlugins).On(e => e.Reply(graph.Plugins)); events.Raise(ServerEvents.ServerInitialized); logger.Debug($"{graph.Plugins.Count} plugin(s) loaded, {this.controllers.Count} controller(s) created"); }
private void InitEvents() { PlayerLife.OnTellHealth_Global += BasePlayerEvents.InternalOnTellHealth; PlayerLife.OnTellFood_Global += BasePlayerEvents.InternalOnTellFood; PlayerLife.OnTellWater_Global += BasePlayerEvents.InternalOnTellWater; PlayerLife.OnTellVirus_Global += BasePlayerEvents.InternalOnTellVirus; PlayerLife.OnTellBleeding_Global += BasePlayerEvents.InternalOnTellBleeding; PlayerLife.OnTellBroken_Global += BasePlayerEvents.InternalOnTellBroken; PlayerLife.OnRevived_Global += BasePlayerEvents.InternalOnRevived; PlayerLife.onPlayerDied += BasePlayerEvents.InternalOnPlayerDied; PlayerAnimator.OnGestureChanged_Global += BasePlayerEvents.InternalOnGestureChanged; PlayerSkills.OnExperienceChanged_Global += BasePlayerEvents.InternalOnExperienceChanged; PlayerStance.OnStanceChanged_Global += BasePlayerEvents.InternalOnStanceChanged; CommandWindow.onCommandWindowInputted += (string text, ref bool exe) => { if (!text.StartsWith("/")) { return; } CommandManager.ExecuteCommand(ConsolePlayer.DefaultPlayer, text); exe = false; }; CommandWindow.onCommandWindowOutputted += (obj, color) => { if (!SettingsManager.RemoteSetting.Enabled || !RconManager.IsInit) { return; } }; Provider.onCheckValid += (ValidateAuthTicketResponse_t callback, ref bool valid) => { var(prefix, postfix) = callback.m_SteamID.GetPrefixAndSuffix(); if (prefix == "" && postfix == "") { return; } var pending = callback.m_SteamID.GetPending(); if (pending == null) { return; } if (prefix != "" && !pending.playerID.characterName.StartsWith(prefix)) { pending.playerID.characterName = $"{prefix}{pending.playerID.characterName}"; } if (postfix != "" && !pending.playerID.characterName.EndsWith(postfix)) { pending.playerID.characterName = $"{pending.playerID.characterName}{postfix}"; } }; ChatManager.onCheckPermissions += (SteamPlayer player, string text, ref bool exe, ref bool list) => { if (!text.StartsWith("/")) { exe = false; return; } CommandManager.ExecuteCommand(player.ToBasePlayer(), text); list = false; }; Provider.onServerHosted += OnServerHosted; if (SettingsManager.RemoteSetting.Enabled) { RconManager.Init(); } }