Created
August 27, 2026 19:40
-
-
Save JSandusky/0280b686dd8327a44b9f09401b6d4d1e to your computer and use it in GitHub Desktop.
Skyrim scan
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Mutagen.Bethesda.Skyrim; | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using Mutagen.Bethesda; | |
| using Mutagen.Bethesda.Skyrim; | |
| using Mutagen.Bethesda.Plugins.Cache.Internals.Implementations; | |
| using BBox = System.Collections.Generic.KeyValuePair<Noggog.P3Float, Noggog.P3Float>; | |
| namespace SkyrimData | |
| { | |
| public class SkyrimScan : SharedScan | |
| { | |
| void ReflectFormIDs() | |
| { | |
| ReflectFormIDs(typeof(Mutagen.Bethesda.FormKeys.SkyrimSE.Skyrim)); | |
| ReflectFormIDs(typeof(Mutagen.Bethesda.FormKeys.SkyrimSE.HearthFires)); | |
| ReflectFormIDs(typeof(Mutagen.Bethesda.FormKeys.SkyrimSE.Dawnguard)); | |
| ReflectFormIDs(typeof(Mutagen.Bethesda.FormKeys.SkyrimSE.Dragonborn)); | |
| } | |
| BBox ExtractBounds(PlacedObject placed, string key, ImmutableModLinkCache<ISkyrimMod, ISkyrimModGetter> cache) | |
| { | |
| if (key == "Ingredient") | |
| { | |
| var found = placed.Base.Resolve<Ingredient>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Static") | |
| { | |
| var found = placed.Base.Resolve<Static>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Flora") | |
| { | |
| var found = placed.Base.Resolve<Flora>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "MiscItem") | |
| { | |
| var found = placed.Base.Resolve<MiscItem>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Ingestible") | |
| { | |
| var found = placed.Base.Resolve<Ingestible>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Furniture") | |
| { | |
| var found = placed.Base.Resolve<Furniture>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Container") | |
| { | |
| var found = placed.Base.Resolve<Container>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Book") | |
| { | |
| var found = placed.Base.Resolve<Book>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Armor") | |
| { | |
| var found = placed.Base.Resolve<Armor>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Weapon") | |
| { | |
| var found = placed.Base.Resolve<Weapon>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Tree") | |
| { | |
| var found = placed.Base.Resolve<Tree>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "Light") | |
| { | |
| var found = placed.Base.Resolve<Light>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "MoveableStatic") | |
| { | |
| var found = placed.Base.Resolve<MoveableStatic>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| if (key == "SoundMarker") | |
| { | |
| var found = placed.Base.Resolve<SoundMarker>(cache); | |
| return new BBox(ScaleBnds(found.ObjectBounds.First), ScaleBnds(found.ObjectBounds.Second)); | |
| } | |
| return new BBox(); | |
| } | |
| public void GenerateText(string modPath = "D:/Steam/steamapps/common/SkyrimVR/Data/Skyrim.esm", string outFile = "output.txt") | |
| { | |
| // we need to build this to get good lookups | |
| System.Console.WriteLine("Building form key table... (approximately 10-20 seconds)"); | |
| ReflectFormIDs(); | |
| System.Console.WriteLine("Key table built"); | |
| var fs = System.IO.File.OpenWrite(outFile); | |
| var sw = new System.IO.StreamWriter(fs); | |
| System.Console.WriteLine($"----- LOADING ESM FILE -----"); | |
| SkyrimMod mod = SkyrimMod.CreateFromBinary(modPath, Mutagen.Bethesda.Skyrim.SkyrimRelease.SkyrimVR); | |
| var cache = mod.ToImmutableLinkCache(); | |
| System.Console.WriteLine($"----- STARTING -----"); | |
| int unnamedCt = 0; | |
| foreach (var cellBlock in mod.Cells.Records) | |
| { | |
| foreach (var cellSub in cellBlock.SubBlocks) | |
| { | |
| foreach (var cell in cellSub.Cells) | |
| { | |
| // scan all interiors | |
| if (cell.Flags.HasFlag(Cell.Flag.IsInteriorCell)) | |
| { | |
| string cellName = cell.Name; | |
| if (String.IsNullOrEmpty(cellName)) | |
| cellName = "unnamed_" + (++unnamedCt).ToString(); | |
| cellName += " : " + cell.Temporary.Count; | |
| System.Console.WriteLine(cellName); | |
| sw.WriteLine(cellName); | |
| foreach (var per in cell.Temporary) | |
| { | |
| sw.WriteLine($" {per.GetType().Name}"); | |
| PlacedObject placed = per as PlacedObject; | |
| if (placed != null) | |
| { | |
| KeyValuePair<string, string> v; | |
| if (lut.TryGetValue(placed.Base.FormKey, out v)) | |
| { | |
| sw.WriteLine($" {v.Key} {v.Value}"); | |
| sw.WriteLine($" {placed.Placement.Position * ScalingFactor}"); | |
| sw.WriteLine($" {placed.Placement.Rotation}"); | |
| var bbox = ExtractBounds(placed, v.Key, cache); | |
| sw.WriteLine($" {bbox.Key} : {bbox.Value}"); | |
| } | |
| } | |
| PlacedNpc placedNpc = per as PlacedNpc; | |
| if (placedNpc != null) | |
| { | |
| var npc = placedNpc.Base.Resolve<Npc>(cache); | |
| sw.WriteLine($" {npc.Name}"); | |
| sw.WriteLine($" {placedNpc.Placement.Position * ScalingFactor}"); | |
| sw.WriteLine($" {placedNpc.Placement.Rotation}"); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| System.Console.WriteLine($"----- FINISHED -----"); | |
| sw.Close(); | |
| fs.Close(); | |
| } | |
| public void GenerateBinary(string modPath, string outFile) | |
| { | |
| System.Console.WriteLine("Building form key table... (approximately 10-20 seconds)"); | |
| ReflectFormIDs(); | |
| System.Console.WriteLine("Key table built"); | |
| var fs = System.IO.File.OpenWrite(outFile); | |
| var sw = new System.IO.BinaryWriter(fs); | |
| System.Console.WriteLine($"----- LOADING ESM FILE -----"); | |
| SkyrimMod mod = SkyrimMod.CreateFromBinary(modPath, Mutagen.Bethesda.Skyrim.SkyrimRelease.SkyrimVR); | |
| var cache = mod.ToImmutableLinkCache(); | |
| System.Console.WriteLine($"----- STARTING -----"); | |
| int unnamedCt = 0; | |
| foreach (var cellBlock in mod.Cells) | |
| { | |
| foreach (var cellSub in cellBlock.SubBlocks) | |
| { | |
| foreach (var cell in cellSub.Cells) | |
| { | |
| // scan all interiors | |
| if (cell.Flags.HasFlag(Cell.Flag.IsInteriorCell)) | |
| { | |
| sw.Write(ASCIICodes.FS); | |
| string cellName = cell.Name; | |
| if (String.IsNullOrEmpty(cellName)) | |
| cellName = "unnamed_" + (++unnamedCt).ToString(); | |
| cellName += " : " + cell.Temporary.Count; | |
| System.Console.WriteLine(cellName); | |
| sw.Write(cellName); | |
| foreach (var per in cell.Temporary) | |
| { | |
| PlacedObject placed = per as PlacedObject; | |
| if (placed != null) | |
| { | |
| KeyValuePair<string, string> v; | |
| if (lut.TryGetValue(placed.Base.FormKey, out v)) | |
| { | |
| sw.Write(ASCIICodes.RS); | |
| sw.Write("${per.GetType().Name}"); | |
| sw.Write(placed.Placement.Position.X); | |
| sw.Write(placed.Placement.Position.Y); | |
| sw.Write(placed.Placement.Position.Z); | |
| sw.Write(placed.Placement.Rotation.X); | |
| sw.Write(placed.Placement.Rotation.Y); | |
| sw.Write(placed.Placement.Rotation.Z); | |
| var bbox = ExtractBounds(placed, v.Key, cache); | |
| sw.Write(bbox.Key.X); | |
| sw.Write(bbox.Key.Y); | |
| sw.Write(bbox.Key.Z); | |
| sw.Write(bbox.Value.X); | |
| sw.Write(bbox.Value.Y); | |
| sw.Write(bbox.Value.Z); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| System.Console.WriteLine($"----- FINISHED -----"); | |
| sw.Close(); | |
| fs.Close(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment