private void ParseFileForStatics(BinaryReader br, Dictionary<string, staticOverride> OverrideList, bool activators, bool includemisc, Dictionary<string, bool> IgnoreList) { int DEBUG_statics = 0; int DEBUG_ignored = 0; //Look for any scripts that might be disabling activators if (activators) { ParseFileForDisableScripts(br, OverrideList); //Rest file position br.BaseStream.Position = 0; } string s = ""; while (br.BaseStream.Position < br.BaseStream.Length) { s = ReadString(br); int size = br.ReadInt32(); br.BaseStream.Position += 8; if (s == "STAT" || s == "ACTI" || s == "DOOR" || s == "CONT" || s == "LIGH") { int read = 0; bool activator = s == "ACTI"; bool misc = s == "DOOR" || s == "CONT" || s == "LIGH"; string name = null; string model = null; string script = null; while (read < size) { s = ReadString(br); int size2 = br.ReadInt32(); read += size2 + 8; switch (s) { case "NAME": name = ReadCString(br).ToLower(Statics.Culture); break; case "MODL": model = ReadCString(br).ToLower(Statics.Culture); break; case "SCRI": script = ReadCString(br).ToLower(Statics.Culture); break; default: br.BaseStream.Position += size2; break; } } if (name != null && model != null && model.Trim () != null) { //Named exceptions if (IgnoreList != null && IgnoreList.ContainsKey(name)) { if (!IgnoreList[name]) { StaticsList[name] = new Static(name, model); if (OverrideList != null && OverrideList.ContainsKey(model) && OverrideList[model].Ignore) { OverrideList[model] = new staticOverride(OverrideList[model], true); if (DEBUG) { DEBUG_statics++; continue; } } } if (DEBUG) DEBUG_ignored++; continue; } //NoScript override if (script != null && OverrideList != null && OverrideList.ContainsKey(model) && OverrideList[model].NoScript) { script = null; } //Special exceptions if (name == "chargen boat" || name == "chargen_plank") { if (DEBUG) DEBUG_ignored++; continue; } //Special model exceptions if (model == "f\\active_blight_large.nif") { if (OverrideList != null && !OverrideList.ContainsKey(model)) { if (DEBUG) DEBUG_ignored++; continue; } } if ((misc && !includemisc) || activator && !activators) { if (OverrideList != null && OverrideList.ContainsKey(model) && !OverrideList[model].Ignore) { if (script != null && DisableScripts != null && DisableScripts.ContainsKey(script) && DisableScripts[script] == true) { if (DEBUG) DEBUG_ignored++; continue; } StaticsList[name] = new Static(name, model); if (DEBUG) DEBUG_statics++; } } else { if (OverrideList == null || !OverrideList.ContainsKey(model) || !OverrideList[model].Ignore) { if (script != null && DisableScripts != null && DisableScripts.ContainsKey(script) && DisableScripts[script] == true) { if (DEBUG) DEBUG_ignored++; continue; } StaticsList[name] = new Static(name, model); if (DEBUG) DEBUG_statics++; } } } } else br.BaseStream.Position += size; } if (DEBUG) allWarnings.Add("Static definitions: " + DEBUG_statics + "; Ignored definitions: " + DEBUG_ignored); }
void workerCreateStatics(object sender, System.ComponentModel.DoWorkEventArgs e) { CreateStaticsArgs args = (CreateStaticsArgs)e.Argument; List<string> warnings = new List<string>(); Dictionary<string, staticOverride> OverrideList = new Dictionary<string, staticOverride>(); Dictionary<string, bool> IgnoreList = new Dictionary<string, bool>(); Dictionary<string, bool> CellList = new Dictionary<string, bool>(); StaticsList.Clear(); UsedStaticsList.Clear(); StaticMap.Clear(); if (args.useOverrideList && args.OverrideList.Count > 0) foreach (string overrideList in args.OverrideList) { if (DEBUG) allWarnings.Add("Loading override: " + overrideList); StreamReader sr = null; try { sr = new StreamReader(File.OpenRead(overrideList)); } catch { warnings.Add("Error: Could not import statics list '" + overrideList + "'"); } if (sr != null) { int index; string section = ""; string line; string escape; while (!sr.EndOfStream) switch (section) { case "": line = sr.ReadLine().ToLower(Statics.Culture); index = line.IndexOf(':'); if (index != -1) line = line.Substring(0, index); line = line.Trim(); if (line.Length > 0 && line[0] != '#') { if (line.StartsWith("[") && line.EndsWith("]")) { section = line.Substring(1, line.Length - 2); continue; } index = line.LastIndexOf('='); if (index != -1) { string mesh = line.Substring(0, index); string value = line.Substring(index + 1); byte type; if (byte.TryParse(value, out type)) { if (type != 3 && type <= 6) OverrideList[line] = new staticOverride(type); else if (type > 6) warnings.Add("Warning: Invalid type specified in statics list '" + overrideList + "' line '" + line + "'"); } else OverrideList[mesh] = new staticOverride(value); } else { warnings.Add("Warning: Failed to parse line in statics list '" + overrideList + "': '" + line + "'"); } } break; case "names": line = sr.ReadLine().ToLower(Statics.Culture); index = line.IndexOf(':'); escape = line; if (index != -1) escape = escape.Substring(0, index); escape = escape.Trim(); if (escape.Length > 0 && escape.StartsWith("[") && escape.EndsWith("]") && !escape.EndsWith("\\]")) { section = escape.Substring(1, escape.Length - 2); continue; } if (line.IndexOf('\u0001') != -1) continue; escape = ""; while ((index = line.IndexOf('\\') + 1) != 0) { if (index == line.Length) break; escape += line[index]; line = line.Substring(0, index - 1) + "\u0001" + (line.Length >= index ? line.Substring(index + 1) : ""); } index = line.IndexOf(':'); if (index != -1) line = line.Substring(0, index); line = line.Trim(); int equals_index = line.LastIndexOf('='); for (var i = 0; (index = line.IndexOf ('\u0001')) != -1; i++) { line = line.Substring(0, index) + escape[i] + (line.Length >= index ? line.Substring(index + 1) : ""); } if (line.Length > 0) { if (equals_index == -1) IgnoreList[line] = true; else { string value = line.Substring(equals_index + 1); line = line.Substring(0, equals_index); switch (value) { case "enable": IgnoreList[line] = false; break; case "disable": IgnoreList[line] = true; break; default: warnings.Add("Warning: Invalid keyword in statics list line '" + line + "'"); break; } } } break; case "interiors": line = sr.ReadLine().ToLower(Statics.Culture); index = line.IndexOf (':'); escape = line; if (index != -1) escape = escape.Substring (0, index); escape = escape.Trim(); if (escape.Length > 0 && escape.StartsWith("[") && escape.EndsWith("]") && !escape.EndsWith("\\]")) { section = escape.Substring(1, escape.Length - 2); continue; } if (line.IndexOf ('\u0001') != -1) continue; escape = ""; while ((index = line.IndexOf('\\') + 1) != 0) { if (index == line.Length) break; escape += line[index]; line = line.Substring(0, index - 1) + "\u0001" + (line.Length >= index ? line.Substring(index + 1) : ""); } index = line.IndexOf(':'); if (index != -1) line = line.Substring(0, index); line = line.Trim(); equals_index = line.LastIndexOf('='); for (var i = 0; (index = line.IndexOf('\u0001')) != -1; i++) { line = line.Substring(0, index) + escape[i] + (line.Length >= index ? line.Substring(index + 1) : ""); } if (line.Length > 0) { if (equals_index == -1) CellList[line] = true; else { string value = line.Substring(equals_index + 1); line = line.Substring(0, equals_index); switch (value) { case "enable": CellList[line] = true; break; case "disable": CellList[line] = false; break; default: warnings.Add("Warning: Invalid keyword in statics cell list line '" + line + "'"); break; } } } break; } sr.Close(); } } Directory.CreateDirectory(Statics.fn_statics); foreach (string file in files) { if (DEBUG) allWarnings.Add("Parsing for statics definitions: " + file); BinaryReader br = new BinaryReader(File.OpenRead(file), System.Text.Encoding.Default); ParseFileForStatics(br, OverrideList, args.activators, args.misc, IgnoreList); br.Close(); } backgroundWorker.ReportProgress(1, strings["StaticsGenerate1"]); UsedStaticsList.Add("", new Dictionary<string, StaticReference>()); foreach (string file in files) { if (DEBUG) allWarnings.Add("Parsing for used statics: " + file); BinaryReader br = new BinaryReader(File.OpenRead(file), System.Text.Encoding.Default); FileInfo fi = new FileInfo(file); try { ParseFileForCells(br, fi.Name, IgnoreList, CellList); } catch (Exception ex) { warnings.Add("Non-fatal error in ParseFileForCells(\"" + file + "\"): " + ex.Message); } br.Close(); } //Generate a list of the NIF files we need to load backgroundWorker.ReportProgress(2, strings["StaticsGenerate2"]); List<string> UsedNifList = new List<string>(); foreach (KeyValuePair<string, Dictionary<string, StaticReference>> cellStatics in UsedStaticsList) { foreach (KeyValuePair<string, StaticReference> pair in cellStatics.Value) { string nif_name = StaticsList[pair.Value.name].mesh; if (!UsedNifList.Contains(nif_name)) UsedNifList.Add(nif_name); } } backgroundWorker.ReportProgress(3, strings["StaticsGenerate3"]); unsafe { NativeMethods.BeginStaticCreation((IntPtr)DXMain.device.ComPointer, Statics.fn_statmesh); } Random rnd = new Random(); try { //Try to load the NIFs and remove any from the list that fail or are too small for (int i = 0; i < UsedNifList.Count; i++) { string name = UsedNifList[i]; byte[] data; //Try to load a version of the file that ends with '_dist' first. // This allows people to supply a different version of the NIF to be // rendered by distant land. For example, a low poly nif. string file_name = name; string extention = ""; int dot_pos = file_name.LastIndexOf ('.'); if (dot_pos != -1) { extention = file_name.Substring (dot_pos, file_name.Length - dot_pos); file_name = file_name.Substring (0, dot_pos); } string dist_name = file_name + "_dist" + extention; try { data = BSA.GetNif (dist_name); } catch { // We didn't find a NIF file with '_dist' in its name, // so search for the normal NIF file now. try { data = BSA.GetNif (name); } catch { data = null; } } if (data == null) { UsedNifList.RemoveAt (i--); } else { try { if (DEBUG) { statusText.Text = strings["StaticsGenerate3Nif"] + name; allWarnings.Add ("Processing NIF: " + name); } float size = -1; if (OverrideList.ContainsKey (name)) { staticOverride so = OverrideList[name]; if (!so.Ignore || so.NamesNoIgnore) size = NativeMethods.ProcessNif (data, data.Length, so.overrideSimplify ? so.Simplify : args.simplify, args.MinSize, (byte)so.Type, (so.OldSimplify ? (byte)1 : (byte)0)); } else { // Set static classification based on the file path if (name.StartsWith ("grass\\")) size = NativeMethods.ProcessNif (data, data.Length, args.simplify, args.MinSize, (byte)StaticType.Grass, 0); else if (name.StartsWith ("trees\\")) size = NativeMethods.ProcessNif (data, data.Length, args.simplify, args.MinSize, (byte)StaticType.Tree, 0); else if (name.StartsWith ("x\\")) size = NativeMethods.ProcessNif (data, data.Length, args.simplify, args.MinSize, (byte)StaticType.Building, 0); else size = NativeMethods.ProcessNif (data, data.Length, args.simplify, args.MinSize, (byte)StaticType.Auto, 0); } if (size < 0) UsedNifList.RemoveAt (i--); } catch (Exception) { warnings.Add ("Failed to process " + name); UsedNifList.RemoveAt (i--); } } } } finally { NativeMethods.EndStaticCreation(); } //Reset used distant static ID numbers to match NIF list order Dictionary<string, uint> NifMap = new Dictionary<string, uint>(); uint count = 0; foreach (string name in UsedNifList) NifMap[name] = count++; List<StaticToRemove> UsedStaticsToRemove = new List<StaticToRemove>(); //Determine floating point grass density float GrassDensity = (float)udStatGrassDensity.Value / 100.0f; foreach (KeyValuePair<string, Dictionary<string, StaticReference>> cellStatics in UsedStaticsList) { foreach (KeyValuePair<string, StaticReference> pair in cellStatics.Value) { string nif_name = StaticsList[pair.Value.name].mesh; if (NifMap.ContainsKey(nif_name)) pair.Value.staticID = NifMap[nif_name]; else UsedStaticsToRemove.Add(new StaticToRemove(cellStatics.Key, pair.Key)); if (nif_name.StartsWith("grass\\") || (OverrideList.ContainsKey (nif_name) && OverrideList[nif_name].Type == StaticType.Grass)) { if (OverrideList.ContainsKey (nif_name)) { if (OverrideList[nif_name].Density >= 0) GrassDensityThreshold (OverrideList[nif_name].Density, cellStatics, pair, rnd, UsedStaticsToRemove); else GrassDensityThreshold (GrassDensity, cellStatics, pair, rnd, UsedStaticsToRemove); } else GrassDensityThreshold (GrassDensity, cellStatics, pair, rnd, UsedStaticsToRemove); } } } foreach (StaticToRemove key in UsedStaticsToRemove) UsedStaticsList[key.worldspace].Remove(key.reference); backgroundWorker.ReportProgress(4, strings["StaticsGenerate4"]); BinaryWriter bw = new BinaryWriter(File.Create(Statics.fn_usagedata), System.Text.Encoding.Default); bw.Write(UsedNifList.Count); bw.Write(UsedStaticsList[""].Count); //uint UseRef = 0; foreach (KeyValuePair<string, StaticReference> pair in UsedStaticsList[""]) pair.Value.Write(bw/*, UseRef++*/); UsedStaticsList[""].Clear(); UsedStaticsList.Remove(""); char[] cellName = new char[64]; foreach (KeyValuePair<string, Dictionary<string, StaticReference>> cellStatics in UsedStaticsList) { bw.Write((int)(cellStatics.Value as Dictionary<string, StaticReference>).Count); int i; for (i = 0; i < 64; ++i) cellName[i] = '\0'; i = 0; foreach (char c in cellStatics.Key) cellName[i++] = c; bw.Write(cellName, 0, 64); foreach (KeyValuePair<string, StaticReference> pair in cellStatics.Value) pair.Value.Write(bw/*, UseRef++*/); } bw.Write((int)0); bw.Write((float)Convert.ToSingle(udStatMinSize.Value)); bw.Close(); if (!File.Exists(Statics.fn_statmesh)) return; setFinishDesc(4); backgroundWorker.ReportProgress(5, strings["StaticsGenerate5"]); { StaticTexCreator stc = new StaticTexCreator(args.MipSkip); BinaryReader br = new BinaryReader(File.OpenRead(Statics.fn_statmesh), System.Text.Encoding.Default); foreach (string name in UsedNifList) { int nodes = br.ReadInt32(); br.BaseStream.Position += 16; //4 - radius, 12 - center int type = br.BaseStream.ReadByte(); for (int j = 0; j < nodes; j++) { br.BaseStream.Position += 40; //4 - radius, 12 - center, 12 - min, 12 - center int verts = br.ReadInt32(); int faces = br.ReadInt32(); int vert_size = NativeMethods.GetCompressedVertSize(); br.BaseStream.Position += verts * vert_size + faces * 6; short chars = br.ReadInt16(); string path = new string(br.ReadChars(chars - 1)); br.BaseStream.Position += 1; try { if (type != (int)StaticType.Grass && type != (int)StaticType.Tree) { bool ok = stc.LoadTexture(path); if(!ok) warnings.Add("Warning: Texture '"+path+"' could not be converted to a distant texture, original texture will be used"); } } catch (ArgumentException) { //warnings.Add("Warning: Texture '"+path+"' on subset "+j+" of mesh '"+pair.Key+"' could not be found"); } } } br.Close(); stc.Dispose(); } if (warnings.Count > 0) e.Result = warnings; }
public staticOverride(staticOverride value, bool enabledInNames) { OldSimplify = value.OldSimplify; Simplify = value.Simplify; Density = value.Density; overrideSimplify = value.overrideSimplify; Ignore = value.Ignore; StaticsOnly = value.StaticsOnly; Type = value.Type; NoScript = value.NoScript; NamesNoIgnore = enabledInNames; }