using GsConfigTool.Models;
using System.Globalization;
using System.Text;
namespace GsConfigTool.Services;
public static class ArkConfigGeneratorService
{
private static string F(float val) =>
val.ToString("0.000000", CultureInfo.InvariantCulture);
public static (string gameIni, string gameUserSettings) Generate(ArkServerSettings s)
{
return (BuildGameIni(s), BuildGameUserSettings(s));
}
private static string BuildGameIni(ArkServerSettings s)
{
var sb = new StringBuilder();
sb.AppendLine("[/script/shootergame.shootergamemode]");
if (s.UnlockAllEngrams)
sb.AppendLine("bAutoUnlockAllEngrams=True");
foreach (var eng in s.EngramOverrides)
{
sb.Append("OverrideNamedEngramEntries=(EngramClassName=\"");
sb.Append(eng.EngramClassName);
sb.Append("\",EngramHidden=");
sb.Append(eng.Hidden ? "True" : "False");
if (eng.EngramPointsCost >= 0)
{
sb.Append(",EngramPointsCost=");
sb.Append(eng.EngramPointsCost);
}
if (eng.EngramLevelRequirement >= 0)
{
sb.Append(",EngramLevelRequirement=");
sb.Append(eng.EngramLevelRequirement);
}
if (eng.RemoveEngramPreReq)
sb.Append(",RemoveEngramPreReq=True");
sb.AppendLine(")");
}
foreach (var cr in s.CreatureMultipliers)
{
if (cr.Disabled) continue;
sb.Append("DinoClassDamageMultipliers=(ClassName=\"");
sb.Append(cr.DinoClassName);
sb.Append("\",Multiplier=");
sb.Append(F(cr.DinoDamageMultiplier));
sb.AppendLine(")");
sb.Append("DinoClassResistanceMultipliers=(ClassName=\"");
sb.Append(cr.DinoClassName);
sb.Append("\",Multiplier=");
sb.Append(F(cr.DinoResistanceMultiplier));
sb.AppendLine(")");
sb.Append("TamedDinoClassDamageMultipliers=(ClassName=\"");
sb.Append(cr.DinoClassName);
sb.Append("\",Multiplier=");
sb.Append(F(cr.TamingSpeedMultiplier));
sb.AppendLine(")");
}
// ── PerLevelStats ────────────────────────────────────────────────
if (s.UseCustomPerLevelStats)
{
var ps = s.PerLevelStats;
for (int i = 0; i < 12; i++)
{
sb.AppendLine($"PerLevelStatsMultiplier_Player[{i}]={F(ps.Player[i])}");
sb.AppendLine($"PerLevelStatsMultiplier_DinoWild[{i}]={F(ps.DinoWild[i])}");
sb.AppendLine($"PerLevelStatsMultiplier_DinoTamed[{i}]={F(ps.DinoTamed[i])}");
sb.AppendLine($"PerLevelStatsMultiplier_DinoTamed_Add[{i}]={F(ps.DinoTamedAdd[i])}");
sb.AppendLine($"PerLevelStatsMultiplier_DinoTamed_Affinity[{i}]={F(ps.DinoTamedAffinity[i])}");
}
}
// ── Harvest Multipliers ──────────────────────────────────────────
foreach (var h in s.HarvestMultipliers)
{
sb.AppendLine($"HarvestResourceItemAmountClassMultipliers=(ClassName=\"{h.ClassName}\",Multiplier={F(h.Multiplier)})");
}
// ── Stack Size Overrides ─────────────────────────────────────────
foreach (var st in s.StackSizeOverrides)
{
sb.AppendLine($"ConfigOverrideItemMaxQuantity=(ItemClassString=\"{st.ItemClassString}\",Quantity=(MaxItemQuantity={st.MaxItemQuantity},bIgnoreMultiplier={B(st.bIgnoreMultiplier)}))");
}
// ── Spawn Overrides ──────────────────────────────────────────────
foreach (var spawn in s.SpawnOverrides)
{
sb.Append($"NPCSpawnEntriesContainerClassOverrides=(ContainerClassString=\"{spawn.NPCSpawnEntriesContainerClassString}\",bAddToExistingSet={B(spawn.bAddToExistingSet)},NPCSpawnEntries=(");
for (int ei = 0; ei < spawn.Entries.Count; ei++)
{
var entry = spawn.Entries[ei];
if (ei > 0) sb.Append(",");
sb.Append($"(AnEntryName=\"{entry.AnEntryName}\",EntryWeight={F(entry.EntryWeight)},NPCsToSpawn=(");
for (int ni = 0; ni < entry.NPCsToSpawn.Count; ni++)
{
var npc = entry.NPCsToSpawn[ni];
if (ni > 0) sb.Append(",");
sb.Append($"\"{npc.NPCClass}\"");
}
sb.Append("),NPCsToSpawnPercentageChance=(");
for (int ni = 0; ni < entry.NPCsToSpawn.Count; ni++)
{
if (ni > 0) sb.Append(",");
sb.Append(F(entry.NPCsToSpawn[ni].SpawnPercentageChance));
}
sb.Append("))");
}
sb.AppendLine("),NPCSpawnLimits=())");
}
foreach (var drop in s.LootDropOverrides)
{
sb.Append("ConfigOverrideSupplyCrateItems=(SupplyCrateClassString=\"");
sb.Append(drop.SupplyCrateClassString);
sb.Append("\",MinQualityMultiplier=");
sb.Append(F(drop.MinQualityMultiplier));
sb.Append(",MaxQualityMultiplier=");
sb.Append(F(drop.MaxQualityMultiplier));
sb.Append(",bNoRepeats=");
sb.Append(drop.bNoRepeats ? "True" : "False");
sb.Append(",bSetsRandomWithoutReplacement=");
sb.Append(drop.bSetsRandomWithoutReplacement ? "True" : "False");
sb.Append(",bAppendItemSets=");
sb.Append(drop.bAppendItemSets ? "True" : "False");
sb.Append(",NumItemSetsPower=1.0,ItemSets=(");
for (int si = 0; si < drop.ItemSets.Count; si++)
{
var set = drop.ItemSets[si];
if (si > 0) sb.Append(",");
sb.Append("(MinNumItems=");
sb.Append(F(set.MinNumItems));
sb.Append(",MaxNumItems=");
sb.Append(F(set.MaxNumItems));
sb.Append(",NumItemsPower=");
sb.Append(F(set.NumItemsPower));
sb.Append(",SetWeight=");
sb.Append(F(set.SetWeight));
sb.Append(",bItemsRandomWithoutReplacement=");
sb.Append(set.bItemsRandomWithoutReplacement ? "True" : "False");
sb.Append(",ItemEntries=(");
for (int ii = 0; ii < set.Items.Count; ii++)
{
var item = set.Items[ii];
if (ii > 0) sb.Append(",");
sb.Append("(ItemClassStrings=(\"");
sb.Append(item.ItemClassString);
sb.Append("\"),MinQuantity=");
sb.Append(F(item.MinQuantity));
sb.Append(",MaxQuantity=");
sb.Append(F(item.MaxQuantity));
sb.Append(",MinQuality=");
sb.Append(F(item.MinQuality));
sb.Append(",MaxQuality=");
sb.Append(F(item.MaxQuality));
sb.Append(",bForceBlueprint=");
sb.Append(item.bForceBlueprint ? "True" : "False");
sb.Append(",ItemWeight=");
sb.Append(F(item.ItemWeight));
sb.Append(",ChanceToBeBlueprint=");
sb.Append(F(item.ChanceToBeBlueprint));
sb.Append(")");
}
sb.Append("))");
}
sb.AppendLine(")");
}
return sb.ToString();
}
private static string BuildGameUserSettings(ArkServerSettings s)
{
var sb = new StringBuilder();
sb.AppendLine("[ServerSettings]");
sb.AppendLine($"ServerCrosshair={B(s.CrosshairEnabled)}");
sb.AppendLine($"MapPlayerLocation={B(s.MapPlayerLocation)}");
sb.AppendLine($"ServerHardcore={B(s.ServerHardcore)}");
sb.AppendLine($"ServerPVE={B(s.PvE)}");
sb.AppendLine($"PreventOfflinePvP={B(s.PreventOfflinePvP)}");
sb.AppendLine($"PreventTribeAlliances={B(s.PreventTribeAlliances)}");
sb.AppendLine($"AllowThirdPersonPlayer={B(s.AllowThirdPersonPlayer)}");
sb.AppendLine($"KickIdlePlayersPeriod={F(s.KickIdlePlayersPeriod)}");
sb.AppendLine($"DifficultyOffset={F(s.DifficultyOffset)}");
sb.AppendLine($"OverrideOfficialDifficulty={F(s.OverrideOfficialDifficulty)}");
sb.AppendLine($"XPMultiplier={F(s.XPMultiplier)}");
sb.AppendLine($"TamingSpeedMultiplier={F(s.TamingSpeedMultiplier)}");
sb.AppendLine($"HarvestAmountMultiplier={F(s.HarvestAmountMultiplier)}");
sb.AppendLine($"HarvestHealthMultiplier={F(s.HarvestHealthMultiplier)}");
sb.AppendLine($"ResourcesRespawnPeriodMultiplier={F(s.ResourcesRespawnPeriodMultiplier)}");
sb.AppendLine($"DayCycleSpeedScale={F(s.DayCycleSpeedScale)}");
sb.AppendLine($"DayTimeSpeedScale={F(s.DayTimeSpeedScale)}");
sb.AppendLine($"NightTimeSpeedScale={F(s.NightTimeSpeedScale)}");
sb.AppendLine($"MatingIntervalMultiplier={F(s.MatingIntervalMultiplier)}");
sb.AppendLine($"MatingSpeedMultiplier={F(s.MatingSpeedMultiplier)}");
sb.AppendLine($"EggHatchSpeedMultiplier={F(s.EggHatchSpeedMultiplier)}");
sb.AppendLine($"BabyMatureSpeedMultiplier={F(s.BabyMatureSpeedMultiplier)}");
sb.AppendLine($"BabyFoodConsumptionSpeedMultiplier={F(s.BabyFoodConsumptionSpeedMultiplier)}");
sb.AppendLine($"BabyCuddleIntervalMultiplier={F(s.BabyCuddleIntervalMultiplier)}");
sb.AppendLine($"BabyImprintAmountMultiplier={F(s.BabyImprintAmountMultiplier)}");
sb.AppendLine($"BabyImprintingStatScaleMultiplier={F(s.BabyImprintingStatScaleMultiplier)}");
sb.AppendLine($"LayEggIntervalMultiplier={F(s.LayEggIntervalMultiplier)}");
sb.AppendLine($"PlayerDamageMultiplier={F(s.PlayerDamageMultiplier)}");
sb.AppendLine($"PlayerResistanceMultiplier={F(s.PlayerResistanceMultiplier)}");
sb.AppendLine($"PlayerWaterDrainMultiplier={F(s.PlayerWaterDrainMultiplier)}");
sb.AppendLine($"PlayerFoodDrainMultiplier={F(s.PlayerFoodDrainMultiplier)}");
sb.AppendLine($"PlayerStaminaDrainMultiplier={F(s.PlayerStaminaDrainMultiplier)}");
sb.AppendLine($"PlayerHealthRecoveryMultiplier={F(s.PlayerHealthRecoveryMultiplier)}");
sb.AppendLine($"PlayerHarvestingDamageMultiplier={F(s.PlayerHarvestingDamageMultiplier)}");
sb.AppendLine($"PlayerTurretDamageMultiplier={F(s.PlayerTurretDamageMultiplier)}");
sb.AppendLine($"DinoDamageMultiplier={F(s.DinoDamageMultiplier)}");
sb.AppendLine($"DinoResistanceMultiplier={F(s.DinoResistanceMultiplier)}");
sb.AppendLine($"TamedDinoDamageMultiplier={F(s.TamedDinoDamageMultiplier)}");
sb.AppendLine($"TamedDinoResistanceMultiplier={F(s.TamedDinoResistanceMultiplier)}");
sb.AppendLine($"DinoHarvestingDamageMultiplier={F(s.DinoHarvestingDamageMultiplier)}");
sb.AppendLine($"DinoTurretDamageMultiplier={F(s.DinoTurretDamageMultiplier)}");
sb.AppendLine($"MaxTamedDinos={s.MaxTamedDinos}");
sb.AppendLine($"MaxPersonalTamedDinos={s.MaxPersonalTamedDinos}");
sb.AppendLine($"DisableStructureDecayPvE={B(s.DisableStructureDecayPvE)}");
sb.AppendLine($"StructureResistanceMultiplier={F(s.StructureResistanceMultiplier)}");
sb.AppendLine($"StructureDamageRepairCooldown={F(s.StructureDamageRepairCooldown)}");
sb.AppendLine($"PerPlatformMaxStructuresMultiplier={F(s.PerPlatformMaxStructuresMultiplier)}");
sb.AppendLine($"bAllowFlyerCarryPvE={B(s.AllowFlyerCarryPvE)}");
sb.AppendLine($"MaxNumberOfPlayersInTribe={s.MaxNumberOfPlayersInTribe}");
sb.AppendLine($"MaxAlliancesPerTribe={s.MaxAlliancesPerTribe}");
sb.AppendLine($"MaxTribesPerAlliance={s.MaxTribesPerAlliance}");
sb.AppendLine($"GlobalSpoilingTimeMultiplier={F(s.GlobalSpoilingTimeMultiplier)}");
sb.AppendLine($"GlobalItemDecompositionTimeMultiplier={F(s.GlobalItemDecompositionTimeMultiplier)}");
sb.AppendLine($"GlobalCorpseDecompositionTimeMultiplier={F(s.GlobalCorpseDecompositionTimeMultiplier)}");
sb.AppendLine($"CropGrowthSpeedMultiplier={F(s.CropGrowthSpeedMultiplier)}");
sb.AppendLine($"FuelConsumptionIntervalMultiplier={F(s.FuelConsumptionIntervalMultiplier)}");
sb.AppendLine($"CustomRecipeEffectivenessMultiplier={F(s.CustomRecipeEffectivenessMultiplier)}");
sb.AppendLine($"CustomRecipeSkillMultiplier={F(s.CustomRecipeSkillMultiplier)}");
sb.AppendLine($"PassiveTameFoodConsumptionMultiplier={F(s.PassiveTameFoodConsumptionMultiplier)}");
if (s.OverrideMaxExperiencePointsPlayer > 0)
sb.AppendLine($"OverrideMaxExperiencePointsPlayer={s.OverrideMaxExperiencePointsPlayer}");
if (s.OverrideMaxExperiencePointsDino > 0)
sb.AppendLine($"OverrideMaxExperiencePointsDino={s.OverrideMaxExperiencePointsDino}");
sb.AppendLine();
sb.AppendLine("[SessionSettings]");
sb.AppendLine($"SessionName={s.ServerName}");
sb.AppendLine($"MaxPlayers={s.MaxPlayers}");
if (!string.IsNullOrWhiteSpace(s.ServerPassword))
sb.AppendLine($"ServerPassword={s.ServerPassword}");
sb.AppendLine($"ServerAdminPassword={s.AdminPassword}");
sb.AppendLine($"QueryPort={s.QueryPort}");
sb.AppendLine();
sb.AppendLine("[/Script/Engine.GameSession]");
sb.AppendLine($"MaxPlayers={s.MaxPlayers}");
if (!string.IsNullOrWhiteSpace(s.ActiveMods))
{
sb.AppendLine();
sb.AppendLine("[ModInstaller]");
sb.AppendLine($"ModIDs={s.ActiveMods}");
}
// ── Cluster Settings ─────────────────────────────────────────────
var c = s.Cluster;
if (!string.IsNullOrWhiteSpace(c.ClusterID))
{
sb.AppendLine();
sb.AppendLine("[ServerSettings]");
sb.AppendLine($"ClusterID={c.ClusterID}");
if (!string.IsNullOrWhiteSpace(c.ClusterPassword))
sb.AppendLine($"ClusterPassword={c.ClusterPassword}");
sb.AppendLine($"PreventDownloadSurvivors={B(c.PreventDownloadSurvivors)}");
sb.AppendLine($"PreventDownloadItems={B(c.PreventDownloadItems)}");
sb.AppendLine($"PreventDownloadDinos={B(c.PreventDownloadDinos)}");
sb.AppendLine($"PreventUploadSurvivors={B(c.PreventUploadSurvivors)}");
sb.AppendLine($"PreventUploadItems={B(c.PreventUploadItems)}");
sb.AppendLine($"PreventUploadDinos={B(c.PreventUploadDinos)}");
sb.AppendLine($"NoTributeDownloads={B(c.NoTributeDownloads)}");
sb.AppendLine($"TributeItemExpirationSeconds={c.TributeItemExpirationSeconds}");
sb.AppendLine($"TributeDinoExpirationSeconds={c.TributeDinoExpirationSeconds}");
sb.AppendLine($"TributeCharacterExpirationSeconds={c.TributeCharacterExpirationSeconds}");
sb.AppendLine($"bAllowUnlimitedRespecs={B(c.bAllowUnlimitedRespecs)}");
sb.AppendLine($"MaxTribeLogs={c.MaxTribeLogs}");
}
// ── RCON ─────────────────────────────────────────────────────────
if (s.RCON.RCONEnabled)
{
sb.AppendLine();
sb.AppendLine("[RCONEnabled]");
sb.AppendLine($"RCONEnabled={B(s.RCON.RCONEnabled)}");
sb.AppendLine($"RCONPort={s.RCON.RCONPort}");
sb.AppendLine($"RCONServerGameLogBuffer={s.RCON.RCONServerGameLogBuffer}");
}
return sb.ToString();
}
private static string B(bool val) => val ? "True" : "False";
}