using GsConfigTool.Models;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
namespace GsConfigTool.Services;
public static class ConfigImportService
{
public static ArkServerSettings ImportArk(string gusContent, string gameIniContent)
{
var s = new ArkServerSettings();
var gus = ParseIni(gusContent);
var game = ParseIni(gameIniContent);
// Session
s.ServerName = gus.Get("SessionSettings", "SessionName", s.ServerName);
s.ServerPassword = gus.Get("SessionSettings", "ServerPassword", s.ServerPassword);
s.AdminPassword = gus.Get("SessionSettings", "ServerAdminPassword", s.AdminPassword);
s.MaxPlayers = gus.GetInt("SessionSettings", "MaxPlayers", s.MaxPlayers);
s.QueryPort = gus.GetInt("SessionSettings", "QueryPort", s.QueryPort);
// ServerSettings
s.PvE = gus.GetBool("ServerSettings", "ServerPVE", s.PvE);
s.ServerHardcore = gus.GetBool("ServerSettings", "ServerHardcore", s.ServerHardcore);
s.CrosshairEnabled = gus.GetBool("ServerSettings", "ServerCrosshair", s.CrosshairEnabled);
s.MapPlayerLocation = gus.GetBool("ServerSettings", "MapPlayerLocation", s.MapPlayerLocation);
s.PreventOfflinePvP = gus.GetBool("ServerSettings", "PreventOfflinePvP", s.PreventOfflinePvP);
s.PreventTribeAlliances = gus.GetBool("ServerSettings", "PreventTribeAlliances", s.PreventTribeAlliances);
s.AllowThirdPersonPlayer = gus.GetBool("ServerSettings", "AllowThirdPersonPlayer", s.AllowThirdPersonPlayer);
s.DifficultyOffset = gus.GetFloat("ServerSettings", "DifficultyOffset", s.DifficultyOffset);
s.OverrideOfficialDifficulty = gus.GetFloat("ServerSettings", "OverrideOfficialDifficulty", s.OverrideOfficialDifficulty);
s.XPMultiplier = gus.GetFloat("ServerSettings", "XPMultiplier", s.XPMultiplier);
s.TamingSpeedMultiplier = gus.GetFloat("ServerSettings", "TamingSpeedMultiplier", s.TamingSpeedMultiplier);
s.HarvestAmountMultiplier = gus.GetFloat("ServerSettings", "HarvestAmountMultiplier", s.HarvestAmountMultiplier);
s.HarvestHealthMultiplier = gus.GetFloat("ServerSettings", "HarvestHealthMultiplier", s.HarvestHealthMultiplier);
s.ResourcesRespawnPeriodMultiplier = gus.GetFloat("ServerSettings", "ResourcesRespawnPeriodMultiplier", s.ResourcesRespawnPeriodMultiplier);
s.MatingIntervalMultiplier = gus.GetFloat("ServerSettings", "MatingIntervalMultiplier", s.MatingIntervalMultiplier);
s.EggHatchSpeedMultiplier = gus.GetFloat("ServerSettings", "EggHatchSpeedMultiplier", s.EggHatchSpeedMultiplier);
s.BabyMatureSpeedMultiplier = gus.GetFloat("ServerSettings", "BabyMatureSpeedMultiplier", s.BabyMatureSpeedMultiplier);
s.BabyFoodConsumptionSpeedMultiplier = gus.GetFloat("ServerSettings", "BabyFoodConsumptionSpeedMultiplier", s.BabyFoodConsumptionSpeedMultiplier);
s.DayCycleSpeedScale = gus.GetFloat("ServerSettings", "DayCycleSpeedScale", s.DayCycleSpeedScale);
s.DayTimeSpeedScale = gus.GetFloat("ServerSettings", "DayTimeSpeedScale", s.DayTimeSpeedScale);
s.NightTimeSpeedScale = gus.GetFloat("ServerSettings", "NightTimeSpeedScale", s.NightTimeSpeedScale);
s.PlayerDamageMultiplier = gus.GetFloat("ServerSettings", "PlayerDamageMultiplier", s.PlayerDamageMultiplier);
s.PlayerResistanceMultiplier = gus.GetFloat("ServerSettings", "PlayerResistanceMultiplier", s.PlayerResistanceMultiplier);
s.PlayerWaterDrainMultiplier = gus.GetFloat("ServerSettings", "PlayerWaterDrainMultiplier", s.PlayerWaterDrainMultiplier);
s.PlayerFoodDrainMultiplier = gus.GetFloat("ServerSettings", "PlayerFoodDrainMultiplier", s.PlayerFoodDrainMultiplier);
s.PlayerStaminaDrainMultiplier = gus.GetFloat("ServerSettings", "PlayerStaminaDrainMultiplier", s.PlayerStaminaDrainMultiplier);
s.PlayerHealthRecoveryMultiplier = gus.GetFloat("ServerSettings", "PlayerHealthRecoveryMultiplier", s.PlayerHealthRecoveryMultiplier);
s.DinoDamageMultiplier = gus.GetFloat("ServerSettings", "DinoDamageMultiplier", s.DinoDamageMultiplier);
s.DinoResistanceMultiplier = gus.GetFloat("ServerSettings", "DinoResistanceMultiplier", s.DinoResistanceMultiplier);
s.TamedDinoDamageMultiplier = gus.GetFloat("ServerSettings", "TamedDinoDamageMultiplier", s.TamedDinoDamageMultiplier);
s.TamedDinoResistanceMultiplier = gus.GetFloat("ServerSettings", "TamedDinoResistanceMultiplier", s.TamedDinoResistanceMultiplier);
s.MaxTamedDinos = gus.GetInt("ServerSettings", "MaxTamedDinos", s.MaxTamedDinos);
s.GlobalSpoilingTimeMultiplier = gus.GetFloat("ServerSettings", "GlobalSpoilingTimeMultiplier", s.GlobalSpoilingTimeMultiplier);
s.GlobalItemDecompositionTimeMultiplier = gus.GetFloat("ServerSettings", "GlobalItemDecompositionTimeMultiplier", s.GlobalItemDecompositionTimeMultiplier);
s.DisableStructureDecayPvE = gus.GetBool("ServerSettings", "DisableStructureDecayPvE", s.DisableStructureDecayPvE);
s.MaxNumberOfPlayersInTribe = gus.GetInt("ServerSettings", "MaxNumberOfPlayersInTribe", s.MaxNumberOfPlayersInTribe);
// Mods
s.ActiveMods = gus.Get("ModInstaller", "ModIDs", s.ActiveMods);
// PerLevelStats from Game.ini
var ps = s.PerLevelStats;
bool hasPerLevel = false;
for (int i = 0; i < 12; i++)
{
var pKey = $"PerLevelStatsMultiplier_Player[{i}]";
var dKey = $"PerLevelStatsMultiplier_DinoWild[{i}]";
var dtKey = $"PerLevelStatsMultiplier_DinoTamed[{i}]";
if (game.GetRaw("/script/shootergame.shootergamemode", pKey) is string pVal)
{
ps.Player[i] = ParseFloat(pVal); hasPerLevel = true;
}
if (game.GetRaw("/script/shootergame.shootergamemode", dKey) is string dVal)
ps.DinoWild[i] = ParseFloat(dVal);
if (game.GetRaw("/script/shootergame.shootergamemode", dtKey) is string dtVal)
ps.DinoTamed[i] = ParseFloat(dtVal);
}
s.UseCustomPerLevelStats = hasPerLevel;
return s;
}
public static PalworldServerSettings ImportPalworld(string iniContent)
{
var s = new PalworldServerSettings();
var rawLine = iniContent.Split('\n')
.Select(l => l.Trim())
.FirstOrDefault(l => l.StartsWith("OptionSettings=("));
if (rawLine == null) return s;
var inner = rawLine.Substring("OptionSettings=(".Length).TrimEnd(')');
foreach (var pair in SplitTopLevel(inner))
{
var eq = pair.IndexOf('=');
if (eq < 0) continue;
var key = pair[..eq].Trim();
var val = pair[(eq + 1)..].Trim().Trim('"');
switch (key)
{
case "Difficulty": s.Difficulty = val; break;
case "DayTimeSpeedRate": s.DayTimeSpeedRate = ParseFloat(val); break;
case "NightTimeSpeedRate": s.NightTimeSpeedRate = ParseFloat(val); break;
case "ExpRate": s.ExpRate = ParseFloat(val); break;
case "PalCaptureRate": s.PalCaptureRate = ParseFloat(val); break;
case "PalSpawnNumRate": s.PalSpawnNumRate = ParseFloat(val); break;
case "PalDamageRateAttack": s.PalDamageRateAttack = ParseFloat(val); break;
case "PalDamageRateDefense": s.PalDamageRateDefense = ParseFloat(val); break;
case "PlayerDamageRateAttack": s.PlayerDamageRateAttack = ParseFloat(val); break;
case "PlayerDamageRateDefense": s.PlayerDamageRateDefense = ParseFloat(val); break;
case "EnemyDropItemRate": s.EnemyDropItemRate = ParseFloat(val); break;
case "DeathPenalty": s.DeathPenalty = val; break;
case "bIsPvP": s.bIsPvP = val == "True"; break;
case "bEnablePlayerToPlayerDamage": s.bEnablePlayerToPlayerDamage = val == "True"; break;
case "bEnableFriendlyFire": s.bEnableFriendlyFire = val == "True"; break;
case "ServerName": s.ServerName = val; break;
case "ServerDescription": s.ServerDescription = val; break;
case "AdminPassword": s.AdminPassword = val; break;
case "ServerPassword": s.ServerPassword = val; break;
case "PublicPort": s.PublicPort = ParseInt(val); break;
case "PublicIP": s.PublicIP = val; break;
case "ServerPlayerMaxNum": s.ServerPlayerMaxNum = ParseInt(val); break;
case "RCONEnabled": s.RCONEnabled = val == "True"; break;
case "RCONPort": s.RCONPort = ParseInt(val); break;
case "CollectionDropRate": s.CollectionDropRate = ParseFloat(val); break;
case "CollectionObjectHpRate": s.CollectionObjectHpRate = ParseFloat(val); break;
case "CollectionObjectRespawnSpeedRate": s.CollectionObjectRespawnSpeedRate = ParseFloat(val); break;
case "BuildObjectDamageRate": s.BuildObjectDamageRate = ParseFloat(val); break;
case "BuildObjectDeteriorationDamageRate": s.BuildObjectDeteriorationDamageRate = ParseFloat(val); break;
case "BaseCampMaxNum": s.BaseCampMaxNum = ParseInt(val); break;
case "BaseCampWorkerMaxNum": s.BaseCampWorkerMaxNum = ParseInt(val); break;
case "DropItemMaxNum": s.DropItemMaxNum = ParseInt(val); break;
case "bEnableFastTravel": s.bEnableFastTravel = val == "True"; break;
case "bIsStartLocationSelectByMap": s.bIsStartLocationSelectByMap = val == "True"; break;
case "bEnableNonLoginPenalty": s.bEnableNonLoginPenalty = val == "True"; break;
case "bEnableInvaderEnemy": s.bEnableInvaderEnemy = val == "True"; break;
case "bUseAuth": s.bUseAuth = val == "True"; break;
case "BanListURL": s.BanListURL = val; break;
}
}
return s;
}
private static IEnumerable<string> SplitTopLevel(string s)
{
int depth = 0;
int start = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '(') depth++;
else if (s[i] == ')') depth--;
else if (s[i] == ',' && depth == 0)
{
yield return s[start..i];
start = i + 1;
}
}
if (start < s.Length) yield return s[start..];
}
private static float ParseFloat(string v) =>
float.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out var r) ? r : 0f;
private static int ParseInt(string v) =>
int.TryParse(v, out var r) ? r : 0;
private static IniData ParseIni(string content)
{
var data = new IniData();
string currentSection = "";
foreach (var rawLine in content.Split('\n'))
{
var line = rawLine.Trim();
if (string.IsNullOrEmpty(line) || line.StartsWith(';') || line.StartsWith('#')) continue;
if (line.StartsWith('[') && line.EndsWith(']'))
{
currentSection = line[1..^1].ToLowerInvariant();
continue;
}
var eq = line.IndexOf('=');
if (eq < 0) continue;
var key = line[..eq].Trim();
var val = line[(eq + 1)..].Trim();
data.Set(currentSection, key, val);
}
return data;
}
private class IniData
{
private readonly Dictionary<string, Dictionary<string, string>> _data = new();
public void Set(string section, string key, string value)
{
var s = section.ToLowerInvariant();
if (!_data.ContainsKey(s)) _data[s] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
_data[s][key] = value;
}
public string? GetRaw(string section, string key)
{
var s = section.ToLowerInvariant();
return _data.TryGetValue(s, out var dict) && dict.TryGetValue(key, out var v) ? v : null;
}
public string Get(string section, string key, string def = "")
=> GetRaw(section, key) ?? def;
public float GetFloat(string section, string key, float def = 0f)
=> float.TryParse(GetRaw(section, key), NumberStyles.Float, CultureInfo.InvariantCulture, out var r) ? r : def;
public int GetInt(string section, string key, int def = 0)
=> int.TryParse(GetRaw(section, key), out var r) ? r : def;
public bool GetBool(string section, string key, bool def = false)
{
var v = GetRaw(section, key);
if (v == null) return def;
return v.Equals("True", StringComparison.OrdinalIgnoreCase) || v == "1";
}
}
}