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"; }