Skip to content

Commit

Permalink
Move plugin configuration into separate files
Browse files Browse the repository at this point in the history
  • Loading branch information
compujuckel committed Jan 13, 2024
1 parent 0d77c96 commit 1fad46b
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 185 deletions.
2 changes: 1 addition & 1 deletion AssettoServer/Network/Http/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void ConfigureContainer(ContainerBuilder builder)
builder.RegisterModule(plugin.Instance);
}

_configuration.Extra.LoadPluginConfig(_loader, builder);
_configuration.LoadPluginConfiguration(_loader, builder);
}

// This method gets called by the runtime. Use this method to add services to the container.
Expand Down
157 changes: 101 additions & 56 deletions AssettoServer/Server/Configuration/ACServerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
using System.Text.RegularExpressions;
using AssettoServer.Server.Configuration.Extra;
using AssettoServer.Server.Configuration.Kunos;
using AssettoServer.Server.Plugin;
using AssettoServer.Shared.Model;
using AssettoServer.Shared.Network.Http.Responses;
using AssettoServer.Utils;
using Autofac;
using FluentValidation;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Serilog;
using YamlDotNet.Serialization;

Expand All @@ -23,9 +26,9 @@ public class ACServerConfiguration
public List<SessionConfiguration> Sessions { get; }
[YamlIgnore] public string FullTrackName { get; }
[YamlIgnore] public CSPTrackOptions CSPTrackOptions { get; }
[YamlIgnore] public string WelcomeMessage { get; } = "";
[YamlIgnore] public string WelcomeMessage { get; }
public ACExtraConfiguration Extra { get; private set; } = new();
[YamlIgnore] public CMContentConfiguration? ContentConfiguration { get; private set; }
[YamlIgnore] public CMContentConfiguration? ContentConfiguration { get; }
public string ServerVersion { get; }
[YamlIgnore] public string? CSPExtraOptions { get; }
[YamlIgnore] public string BaseFolder { get; }
Expand All @@ -50,46 +53,86 @@ public ACServerConfiguration(string preset, ConfigurationLocations locations, bo
{
BaseFolder = locations.BaseFolder;
LoadPluginsFromWorkdir = loadPluginsFromWorkdir;
Server = LoadServerConfiguration(locations.ServerCfgPath);
EntryList = LoadEntryList(locations.EntryListPath);
WelcomeMessage = LoadWelcomeMessage(preset);
CSPExtraOptions = LoadCspExtraOptions(locations.CSPExtraOptionsPath);
ContentConfiguration = LoadContentConfiguration(Path.Join(BaseFolder, "cm_content/content.json"));
ServerVersion = ThisAssembly.AssemblyInformationalVersion;
FullTrackName = string.IsNullOrEmpty(Server.TrackConfig) ? Server.Track : Server.Track + "-" + Server.TrackConfig;
CSPTrackOptions = CSPTrackOptions.Parse(Server.Track);
Sessions = PrepareSessions();

var extraCfgSchemaPath = ConfigurationSchemaGenerator.WriteExtraCfgSchema();
LoadExtraConfig(locations.ExtraCfgPath, extraCfgSchemaPath);
ACExtraConfiguration.WriteReferenceConfig(extraCfgSchemaPath);

Log.Debug("Loading server_cfg.ini from {Path}", locations.ServerCfgPath);
if (!File.Exists(locations.ServerCfgPath))
ApplyConfigurationFixes();

var validator = new ACServerConfigurationValidator();
validator.ValidateAndThrow(this);
}

private ServerConfiguration LoadServerConfiguration(string path)
{
Log.Debug("Loading server_cfg.ini from {Path}", path);
if (!File.Exists(path))
{
Directory.CreateDirectory(Path.GetDirectoryName(locations.ServerCfgPath)!);
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var serverCfg = Assembly.GetExecutingAssembly().GetManifestResourceStream("AssettoServer.Assets.server_cfg.ini")!;
using var outFile = File.Create(locations.ServerCfgPath);
using var outFile = File.Create(path);
serverCfg.CopyTo(outFile);
}
Server = ServerConfiguration.FromFile(locations.ServerCfgPath);
return ServerConfiguration.FromFile(path);
}

Log.Debug("Loading entry_list.ini from {Path}", locations.EntryListPath);
if (!File.Exists(locations.EntryListPath))
private EntryList LoadEntryList(string path)
{
Log.Debug("Loading entry_list.ini from {Path}", path);
if (!File.Exists(path))
{
Directory.CreateDirectory(Path.GetDirectoryName(locations.EntryListPath)!);
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var entryList = Assembly.GetExecutingAssembly().GetManifestResourceStream("AssettoServer.Assets.entry_list.ini")!;
using var outFile = File.Create(locations.EntryListPath);
using var outFile = File.Create(path);
entryList.CopyTo(outFile);
}
EntryList = EntryList.FromFile(locations.EntryListPath);

ServerVersion = ThisAssembly.AssemblyInformationalVersion;
FullTrackName = string.IsNullOrEmpty(Server.TrackConfig) ? Server.Track : Server.Track + "-" + Server.TrackConfig;
CSPTrackOptions = CSPTrackOptions.Parse(Server.Track);
return EntryList.FromFile(path);
}

string welcomeMessagePath = string.IsNullOrEmpty(preset) ? Server.WelcomeMessagePath : Path.Join(BaseFolder, Server.WelcomeMessagePath);
private string LoadWelcomeMessage(string preset)
{
var welcomeMessage = "";
var welcomeMessagePath = string.IsNullOrEmpty(preset) ? Server.WelcomeMessagePath : Path.Join(BaseFolder, Server.WelcomeMessagePath);
if (File.Exists(welcomeMessagePath))
{
WelcomeMessage = File.ReadAllText(welcomeMessagePath);
welcomeMessage = File.ReadAllText(welcomeMessagePath);
}
else if(!string.IsNullOrEmpty(welcomeMessagePath))
{
Log.Warning("Welcome message not found at {Path}", Path.GetFullPath(welcomeMessagePath));
}

if (File.Exists(locations.CSPExtraOptionsPath))

return welcomeMessage;
}

private static string? LoadCspExtraOptions(string path)
{
return File.Exists(path) ? File.ReadAllText(path) : null;
}

private static CMContentConfiguration? LoadContentConfiguration(string path)
{
CMContentConfiguration? contentConfiguration = null;
if (File.Exists(path))
{
CSPExtraOptions = File.ReadAllText(locations.CSPExtraOptionsPath);
contentConfiguration = JsonConvert.DeserializeObject<CMContentConfiguration>(File.ReadAllText(path));
}

return contentConfiguration;
}

private List<SessionConfiguration> PrepareSessions()
{
var sessions = new List<SessionConfiguration>();

if (Server.Practice != null)
Expand All @@ -113,16 +156,15 @@ public ACServerConfiguration(string preset, ConfigurationLocations locations, bo
sessions.Add(Server.Race);
}

Sessions = sessions;
return sessions;
}

private void ApplyConfigurationFixes()
{
if (Server.MaxClients == 0)
{
Server.MaxClients = EntryList.Cars.Count;
}

LoadExtraConfig(locations.ExtraCfgPath);
WriteReferenceExtraConfig(Path.Join(locations.BaseFolder, "extra_cfg.reference.yml"));
ACExtraConfiguration.WriteSchema(Path.Join(locations.BaseFolder, "schema.json"));

if (Extra is { EnableAi: true, AiParams.AutoAssignTrafficCars: true })
{
Expand All @@ -144,40 +186,52 @@ public ACServerConfiguration(string preset, ConfigurationLocations locations, bo
{
Extra.AiParams.MaxAiTargetCount = EntryList.Cars.Count(c => c.AiMode == AiMode.None) * Extra.AiParams.AiPerPlayerTargetCount;
}

var validator = new ACServerConfigurationValidator();
validator.ValidateAndThrow(this);
}

private void WriteReferenceExtraConfig(string path)
internal void LoadPluginConfiguration(ACPluginLoader loader, ContainerBuilder builder)
{
FileInfo? info = null;
if (File.Exists(path))
{
info = new FileInfo(path);
info.IsReadOnly = false;
}

using (var writer = File.CreateText(path))
foreach (var plugin in loader.LoadedPlugins)
{
writer.WriteLine($"# AssettoServer {ThisAssembly.AssemblyInformationalVersion} Reference Configuration");
writer.WriteLine("# This file serves as an overview of all possible options with their default values.");
writer.WriteLine("# It is NOT read by the server - edit extra_cfg.yml instead!");
writer.WriteLine();
if (plugin.ConfigurationType == null) continue;

ACExtraConfiguration.ReferenceConfiguration.ToStream(writer, true);
var schemaPath = ConfigurationSchemaGenerator.WritePluginConfigurationSchema(plugin.ConfigurationType);
var configPath = Path.Join(BaseFolder, PluginConfigurationTypeToFilename(plugin.ConfigurationType.Name));
if (File.Exists(configPath))
{
var deserializer = new DeserializerBuilder().Build();
using var file = File.OpenText(configPath);
var configObj = deserializer.Deserialize(file, plugin.ConfigurationType)!;

// TODO validation and better error handling

builder.RegisterInstance(configObj).AsSelf();
}
else
{
var serializer = new SerializerBuilder().Build();
using var file = File.CreateText(configPath);
ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath);
var configObj = Activator.CreateInstance(plugin.ConfigurationType)!;
serializer.Serialize(file, configObj, plugin.ConfigurationType);
}
}
}

info ??= new FileInfo(path);
info.IsReadOnly = true;
public static string PluginConfigurationTypeToFilename(string type, string ending = "yml")
{
var strat = new SnakeCaseNamingStrategy();
type = type.Replace("Configuration", "Cfg");
return $"{strat.GetPropertyName(type, false)}.{ending}";
}

private void LoadExtraConfig(string path) {
private void LoadExtraConfig(string path, string schemaPath) {
Log.Debug("Loading extra_cfg.yml from {Path}", path);

if (!File.Exists(path))
{
new ACExtraConfiguration().ToFile(path);
using var file = File.CreateText(path);
ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath);
new ACExtraConfiguration().ToStream(file);
}

Extra = ACExtraConfiguration.FromFile(path);
Expand All @@ -195,15 +249,6 @@ private void LoadExtraConfig(string path) {
throw new ConfigurationException(errorMsg) { HelpLink = "https://assettoserver.org/docs/common-configuration-errors#wrong-server-details" };
}
}

if (Extra.EnableServerDetails)
{
string cmContentPath = Path.Join(BaseFolder, "cm_content/content.json");
if (File.Exists(cmContentPath))
{
ContentConfiguration = JsonConvert.DeserializeObject<CMContentConfiguration>(File.ReadAllText(cmContentPath));
}
}
}

private (PropertyInfo? Property, object Parent) GetNestedProperty(string key)
Expand Down

This file was deleted.

Loading

0 comments on commit 1fad46b

Please sign in to comment.