private void ReadGlobalVariables(IniFile campaignsIni) { const string GlobalVariablesSectionName = "GlobalVariables"; IniSection globalVariablesSection = campaignsIni.GetSection(GlobalVariablesSectionName); if (globalVariablesSection == null) { Logger.Log($"{nameof(CampaignHandler)}: [{GlobalVariablesSectionName}] not found from campaign config INI!"); return; } int i = 0; while (true) { string variableInternalName = globalVariablesSection.GetStringValue(i.ToString(), null); if (string.IsNullOrWhiteSpace(variableInternalName)) { break; } var globalVariable = new CampaignGlobalVariable(i, variableInternalName); var section = campaignsIni.GetSection(variableInternalName); if (section != null) { globalVariable.InitFromIniSection(section); } else { Logger.Log($"Section for defined global variable [{variableInternalName}] not found from campaign config INI!"); } GlobalVariables.Add(globalVariable); i++; } }
// Data format: // [Missions] // M_TTD_LOST_POSITION=0,0 ; isunlocked, rank // // [GlobalVariables] // GVAR_XXX = 0,0 ; disabled-unlocked, enabled-unlocked // The data is written into an INI file that then gets base64-encoded // to prevent players with no programming experience from messing with it. // We can't prevent actual programmers from unlocking missions with this method. public static void LoadData(List <Mission> missions, List <CampaignGlobalVariable> globalVariables) { Logger.Log("Loading single-player mission rank data."); string filePath = ProgramConstants.GamePath + SP_SCORE_FILE; if (!File.Exists(filePath)) { return; } IniFile iniFile = null; try { string data = File.ReadAllText(filePath, Encoding.UTF8); if (data.Length > 0 && data.StartsWith("[")) { // We're dealing with raw INI data (before obfuscation) iniFile = new IniFile(filePath); } else { // We're dealing with base64-encoded data (unless it's just corrupted, but let's hope it's not) byte[] decoded = Convert.FromBase64String(data); using (var memoryStream = new MemoryStream(decoded)) { iniFile = new IniFile(memoryStream, Encoding.UTF8); } } } catch (FormatException ex) { Logger.Log("FAILED to load mission competion data due to FormatException: " + ex.Message); return; } var missionsSection = iniFile.GetSection(MISSIONS_SECTION); if (missionsSection != null) { foreach (var kvp in missionsSection.Keys) { string missionName = kvp.Key; string[] unlockAndRank = kvp.Value.Split(','); if (unlockAndRank.Length != 2) { Logger.Log("Invalid mission clear data for mission " + missionName + ": " + kvp.Value); continue; } bool isUnlocked = unlockAndRank[0] == "1"; int rank = Conversions.IntFromString(unlockAndRank[1], 0); Mission mission = missions.Find(m => m.InternalName == missionName); if (mission != null) { if (mission.RequiresUnlocking) { mission.IsUnlocked = isUnlocked; } if (rank >= RANK_MIN && rank <= RANK_MAX) { mission.Rank = (DifficultyRank)rank; } } } } var globalVariablesSection = iniFile.GetSection(GLOBAL_VARIABLES_SECTION); if (globalVariablesSection != null) { foreach (var kvp in globalVariablesSection.Keys) { string globalName = kvp.Key; string[] unlocks = kvp.Value.Split(','); if (unlocks.Length != EXPECTED_GLOBAL_VARIBLE_FIELD_COUNT) { Logger.Log("Invalid global variable unlock data for global variable " + globalName + ": " + kvp.Value); continue; } bool isDisabledOptionUnlocked = unlocks[0] == "1"; bool isEnabledOptionUnlocked = unlocks[1] == "1"; bool isEnabledThroughPreviousScenario = unlocks[2] == "1"; CampaignGlobalVariable globalVariable = globalVariables.Find(gvar => gvar.InternalName == globalName); if (globalVariable != null) { globalVariable.IsDisabledUnlocked = isDisabledOptionUnlocked; globalVariable.IsEnabledUnlocked = isEnabledOptionUnlocked; globalVariable.EnabledThroughPreviousScenario = isEnabledThroughPreviousScenario; } } } }