/// <summary> /// Function to conver the TCv4 excel files to SP client formats. /// </summary> public static void ConvertTCv4ExcelToSP() { // init file manager and load excel files FileManager fileManager = new FileManager(Config.HglDir); fileManager.ExtractAllExcel(); FileManager fileManagerTCv4 = new FileManager(Config.HglDir, FileManager.ClientVersions.TestCenter); fileManager.LoadTableFiles(); fileManagerTCv4.LoadTableFiles(true); if (fileManager.DataFiles.Count == 0) { Debug.WriteLine("Error: No Excel files loaded!"); return; } if (fileManagerTCv4.DataFiles.Count == 0) { Debug.WriteLine("Error: No TCv4 Excel files loaded!"); return; } // convert tables //int converted = -1; Dictionary<String, ObjectDelegator> objectDelegators = new Dictionary<String, ObjectDelegator>(); foreach (ExcelFile excelFile in fileManager.DataFiles.Values.Where(dataFile => dataFile.IsExcelFile)) { //if (++converted >= 5) break; Debug.WriteLine("Converting Excel table " + excelFile.StringId + "..."); // obviously don't want to convert this one if (excelFile.StringId == "EXCELTABLES") continue; // we can't convert stats as some index entries are hard-coded... if (excelFile.StringId == "STATS") continue; // game crashes with this converted... if (excelFile.StringId == "UNITMODES") continue; // don't bother with these two as there's no TCv4 equivalent (they don't matter anyways) if (excelFile.StringId == "LANGUAGE" || excelFile.StringId == "REGION") continue; // ensure we have a TCv4 version loaded String stringIdTCv4 = "_TCv4_" + excelFile.StringId; ExcelFile excelFileTCv4 = (ExcelFile)fileManagerTCv4.GetDataFile(stringIdTCv4); if (excelFileTCv4 == null) { Debug.WriteLine("Error: TCv4 Excel file not found: " + stringIdTCv4); continue; } // table specialisation stuffs bool isAchievements = false; bool isAffixes = false; bool isCharacterClass = false; //bool isCharDisplay = false; //bool isInventory = false; switch (excelFile.StringId) { case "ACHIEVEMENTS": isAchievements = true; break; case "AFFIXES": isAffixes = true; break; case "CHARACTER_CLASS": isCharacterClass = true; break; //case "CHARDISPLAY": // isCharDisplay = true; // break; //case "INVENTORY": // isInventory = true; // break; } // genereal type-init stuffs; get our object delegators ObjectDelegator excelDelegator; ObjectDelegator excelDelegatorTCv41; ObjectDelegator excelDelegatorTCv42 = null; Type rowType = excelFile.Attributes.RowType; Type rowTypeTCv41 = excelFileTCv4.Attributes.RowType; Type rowTypeTCv42 = null; FieldInfo[] fieldInfos = rowType.GetFields(); FieldInfo[] fieldInfosTCv41 = rowTypeTCv41.GetFields(); FieldInfo[] fieldInfosTCv42 = null; // need to copy row headers (private field) as well FieldInfo rowHeaderField = rowType.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo rowHeaderFieldTCv4 = rowTypeTCv41.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Array.Resize(ref fieldInfos, fieldInfos.Length + 1); Array.Resize(ref fieldInfosTCv41, fieldInfosTCv41.Length + 1); fieldInfos[fieldInfos.Length - 1] = rowHeaderField; fieldInfosTCv41[fieldInfosTCv41.Length - 1] = rowHeaderFieldTCv4; // create delegates if (!objectDelegators.TryGetValue(excelFile.StringId, out excelDelegator)) { excelDelegator = new ObjectDelegator(fieldInfos); objectDelegators.Add(excelFile.StringId, excelDelegator); } if (!objectDelegators.TryGetValue(stringIdTCv4, out excelDelegatorTCv41)) { excelDelegatorTCv41 = new ObjectDelegator(fieldInfosTCv41); objectDelegators.Add(stringIdTCv4, excelDelegatorTCv41); } // table specialisation inititialisation //// achievements Dictionary<int, int> unitTypeOverflow = null; if (isAchievements) { unitTypeOverflow = new Dictionary<int, int>(); } //// affixes ExcelFile affixGroupsTable = null; List<String> affixGroupsList = null; List<Int32> affixGroupWeightScripts = null; if (isAffixes) { affixGroupsTable = fileManagerTCv4.GetDataFile("_TCv4_AFFIX_GROUPS") as ExcelFile; affixGroupsList = new List<String>(); affixGroupWeightScripts = new List<Int32>(); Debug.Assert(affixGroupsTable != null); rowTypeTCv42 = affixGroupsTable.Attributes.RowType; fieldInfosTCv42 = rowTypeTCv42.GetFields(); FieldInfo rowHeaderFieldTCv42 = rowTypeTCv42.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Array.Resize(ref fieldInfosTCv42, fieldInfosTCv42.Length + 1); fieldInfosTCv42[fieldInfosTCv42.Length - 1] = rowHeaderFieldTCv42; excelDelegatorTCv42 = new ObjectDelegator(fieldInfosTCv42); } // debug: ensure we have same columns if (!isAchievements && !isCharacterClass && !isAffixes) { bool hasSameFields = true; foreach (FieldInfo fieldInfo in fieldInfos) { FieldInfo fieldInfoTCv4 = (from fi in fieldInfosTCv41 where fi.Name == fieldInfo.Name select fi).FirstOrDefault(); if (fieldInfoTCv4 == null) { Debug.WriteLine("Field not found in TCv4 table: " + fieldInfo.Name); hasSameFields = false; continue; } if (fieldInfo.FieldType == fieldInfoTCv4.FieldType || fieldInfo.FieldType.BaseType == typeof(Enum)) continue; Debug.WriteLine(String.Format("FieldInfo '{0}' of type '{1}' does not match TCv4 of type '{2}'", fieldInfo.Name, fieldInfo.FieldType, fieldInfoTCv4.FieldType)); hasSameFields = false; } if (!hasSameFields) { Debug.WriteLine("Error: The Excel types do not have the same fields!"); continue; } } // begin conversion process Object[] rows = new Object[excelFileTCv4.Rows.Count]; bool failed = false; int col = -1; byte[] scriptBuffer = new byte[1024]; int scriptBufferOffset = 1; // first byte is null foreach (FieldInfo fieldInfo in fieldInfos) // loop by column { col++; ObjectDelegator.FieldGetValueDelegate getTCv4Value1 = null; ObjectDelegator.FieldGetValueDelegate getTCv4Value2 = null; ObjectDelegator.FieldGetValueDelegate getTCv4Value3 = null; ObjectDelegator.FieldSetValueDelegate setValue1 = excelDelegator.GetFieldSetDelegate(fieldInfo.Name); ObjectDelegator.FieldSetValueDelegate setValue2 = null; ObjectDelegator.FieldGetValueDelegate getValue = excelDelegator.GetFieldGetDelegate(fieldInfo.Name); ExcelFile.OutputAttribute outputAttribute = ExcelFile.GetExcelAttribute(fieldInfo); // table specialisation stuffs bool isUnitTypeField = false; // achievements bool isItemField = false; // achievements bool isUnitVersionToGetSkillRespec = false; // character class bool isGroup = false; // affixes if (isAchievements && (fieldInfo.Name.StartsWith("unitType") || fieldInfo.Name == "item")) { if (fieldInfo.Name.StartsWith("unitType")) { String monsterFieldName = "monsterUnitType" + fieldInfo.Name.Last(); String itemFieldName = "itemUnitType" + fieldInfo.Name.Last(); getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(monsterFieldName); getTCv4Value2 = excelDelegatorTCv41.GetFieldGetDelegate(itemFieldName); isUnitTypeField = true; } else if (fieldInfo.Name == "item") { isItemField = true; } } else if (isCharacterClass && fieldInfo.Name == "unitVersionToGetSkillRespec") { isUnitVersionToGetSkillRespec = true; } else if (isAffixes && (fieldInfo.Name == "group" || fieldInfo.Name == "groupWeight")) { if (fieldInfo.Name == "groupWeight") continue; // we can skip it as we're setting it during group column getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(fieldInfo.Name); // to get group affix index getTCv4Value2 = excelDelegatorTCv42.GetFieldGetDelegate("name"); // to get group affix name getTCv4Value3 = excelDelegatorTCv42.GetFieldGetDelegate("weight"); // to get group affix weight setValue2 = excelDelegator.GetFieldSetDelegate("groupWeight"); // to set group weight isGroup = true; } else { getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(fieldInfo.Name); } // copy/convert field data int row = -1; foreach (Object rowTCv4 in excelFileTCv4.Rows) // loop by row { if (rows[++row] == null) rows[row] = Activator.CreateInstance(excelFile.Attributes.RowType); Object value; // achievements special stuffs if (isAchievements && (isUnitTypeField || isItemField)) { if (isUnitTypeField) { int monsterValue = (int)getTCv4Value1(rowTCv4); int itemValue = (int)getTCv4Value2(rowTCv4); if (monsterValue != 0 && itemValue != 0) { Debug.Assert(!unitTypeOverflow.ContainsKey(row)); unitTypeOverflow.Add(row, itemValue); itemValue = 0; } else if (monsterValue == 0 && itemValue == 0 && unitTypeOverflow.ContainsKey(row)) { itemValue = unitTypeOverflow[row]; unitTypeOverflow.Remove(row); } value = (itemValue == 0) ? monsterValue : itemValue; } else { value = 0; } } else if (isCharacterClass && isUnitVersionToGetSkillRespec) { value = getValue(excelFile.Rows[row]); } else if (isAffixes && isGroup) { Debug.Assert(getTCv4Value1 != null && getTCv4Value2 != null && getTCv4Value3 != null); int affixGroupRowIndex = (int)getTCv4Value1(rowTCv4); if (affixGroupRowIndex == -1) { setValue2(rows[row], 0); value = -1; } else { int affixGroupStringOffset = (int)getTCv4Value2(affixGroupsTable.Rows[affixGroupRowIndex]); int affixGroupWeight = (int)getTCv4Value3(affixGroupsTable.Rows[affixGroupRowIndex]); setValue2(rows[row], scriptBufferOffset); FileTools.WriteToBuffer(ref scriptBuffer, ref scriptBufferOffset, new[] { (Int32)ExcelScript.ScriptOpCodes.Push, affixGroupWeight, 0 }.ToByteArray()); String affixGroupString = affixGroupsTable.ReadStringTable(affixGroupStringOffset); int affixGroupStringIndex = affixGroupsList.IndexOf(affixGroupString); if (affixGroupStringIndex == -1) { affixGroupStringIndex = affixGroupsList.Count; affixGroupsList.Add(affixGroupString); } value = affixGroupStringIndex; } } else { Debug.Assert(getTCv4Value1 != null); value = getTCv4Value1(rowTCv4); } if (outputAttribute == null) { setValue1(rows[row], value); continue; } if (outputAttribute.IsBitmask) { if (value.GetType().BaseType != typeof(Enum)) { Debug.WriteLine("Error: IsBitmask is not of type Enum: " + fieldInfo.Name); failed = true; break; } Type spBitMask = fieldInfo.FieldType; Type tcBitMask = value.GetType(); uint currentMask = (uint)value; uint convertedMask = 0; for (int i = 0; i < 32; i++) { uint testBit = (uint)1 << i; if ((currentMask & testBit) == 0) continue; String bitString = Enum.GetName(tcBitMask, testBit); if (bitString == null) continue; if (Enum.IsDefined(spBitMask, bitString)) { convertedMask += (uint)Enum.Parse(spBitMask, bitString); } } value = convertedMask; } else if (outputAttribute.IsScript) { //int scriptOffset = (int)value; //if (scriptOffset != 0) //{ // ExcelScript excelScriptTCv4 = new ExcelScript(fileManagerTCv4); // try // { // excelScriptTCv4.Decompile(excelFileTCv4.ScriptBuffer, scriptOffset, null, excelFileTCv4.StringId, row, col, fieldInfo.Name); // } // catch (Exception e) // { // Debug.WriteLine("TCv4 Decompile Error:\n" + e); // continue; // } // ExcelScript excelScriptCompiler = new ExcelScript(fileManagerTCv4, true, true); // try // { // excelScriptCompiler.Compile(excelScriptTCv4.ScriptString, null, excelFileTCv4.StringId, row, col, fieldInfo.Name); // value = scriptBufferOffset; // } // catch (Exceptions.ScriptUnknownFunctionException e) // { // if (isCharDisplay || isInventory) // { // value = 0; // } // else // { // Debug.WriteLine("SP Recompile Error: \n" + excelScriptTCv4.ScriptString + "\n" + e); // value = 0; // //continue; // } // } // catch (Exception e) // { // Debug.WriteLine("SP Recompile Error: \n" + excelScriptTCv4.ScriptString + "\n" + e); // value = 0; // //continue; // } // if ((int)value != 0) // { // FileTools.WriteToBuffer(ref scriptBuffer, ref scriptBufferOffset, excelScriptCompiler.ScriptCode.ToByteArray()); // } //} } setValue1(rows[row], value); } if (failed) break; } if (failed) { Debug.WriteLine("Error: Excel conversion failed: " + excelFile.StringId); continue; } // finish conversion process by "changing" the TCv4 type excelFileTCv4.ConvertType(excelFile, rows); if (scriptBufferOffset != 1) { excelFileTCv4.SetScriptCode(scriptBuffer); } if (isAffixes) { excelFileTCv4.SetSecondaryStringsCollection(affixGroupsList); } byte[] convertedBytes = excelFileTCv4.ToByteArray(); String writePath = Path.Combine(Config.HglDir, excelFile.FilePath); String backupPath = writePath + ".bak"; if (File.Exists(backupPath)) File.Delete(backupPath); File.Move(writePath, backupPath); File.WriteAllBytes(writePath, convertedBytes); //int bp2 = 0; } //int bp1 = 0; }