Skip to content

Commit 36af29f

Browse files
committed
Implemented Record indexing to speed up read operations, write operations currently suffer an equivalent slowdown, so no net gains, will improve later
Plugins now contain a list of EVERY group and record within the plugin, instead of requiring navigation through groups to find subgroups and records Plugins now load their masters before they load themselves, errors abound if a master doesn't exist
1 parent 3a96fc4 commit 36af29f

11 files changed

Lines changed: 500 additions & 59 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace ESPSharp.DataTypes
8+
{
9+
public class LoadOrderFormID : FormID
10+
{
11+
public LoadOrderFormID(FormID fileFormID, ElderScrollsPlugin file)
12+
{
13+
uint fileIndex = fileFormID.RawValue >> 24;
14+
uint recordIndex = fileFormID.RawValue & 0x00FFFFFF;
15+
16+
string masterName = file.Masters[(int)fileIndex];
17+
ElderScrollsPlugin master = ElderScrollsPlugin.LoadedPlugins.FirstOrDefault(esp => esp.Name == masterName);
18+
19+
if (master == null)
20+
throw new Exception();
21+
22+
uint newFileIndex = (uint)(ElderScrollsPlugin.LoadedPlugins.IndexOf(master) << 24);
23+
24+
RawValue = newFileIndex | recordIndex;
25+
}
26+
27+
public RecordView GetWinningView()
28+
{
29+
return ElderScrollsPlugin.LoadedRecordViews[this].Last();
30+
}
31+
32+
public List<RecordView> GetViews()
33+
{
34+
return ElderScrollsPlugin.LoadedRecordViews[this];
35+
}
36+
}
37+
}

ESPSharp/ESPSharp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<DesignTime>True</DesignTime>
6363
<DependentUpon>FormID.tt</DependentUpon>
6464
</Compile>
65+
<Compile Include="DataTypes\LoadOrderFormID.cs" />
6566
<Compile Include="DataTypes\TypeStringArgData.cs" />
6667
<Compile Include="Enums\ActorValuesByte.cs" />
6768
<Compile Include="Enums\Alignment.cs" />
@@ -603,7 +604,6 @@
603604
<Compile Include="Subrecords\SubMarker.cs" />
604605
<Compile Include="Subrecords\UndecodedSubrecord.cs" />
605606
<Compile Include="Utility.cs" />
606-
<Compile Include="GroupView.cs" />
607607
<Compile Include="Zlib.cs" />
608608
<None Include="SubrecordCollections\GeneratedCode\TerminalMenu.tt">
609609
<Generator>TextTemplatingFileGenerator</Generator>

ESPSharp/ElderScrollsPlugin.cs

Lines changed: 151 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,71 @@
44
using System.Text;
55
using System.Threading.Tasks;
66
using System.IO;
7+
using System.IO.MemoryMappedFiles;
78
using System.Xml.Linq;
9+
using ESPSharp.Enums;
10+
using ESPSharp.Enums.Flags;
11+
using ESPSharp.Interfaces;
12+
using ESPSharp.Subrecords;
13+
using ESPSharp.SubrecordCollections;
14+
using ESPSharp.DataTypes;
815

916
namespace ESPSharp
1017
{
11-
public class ElderScrollsPlugin
18+
public class ElderScrollsPlugin : IDisposable
1219
{
13-
public Record Header;
14-
public List<Group> Groups = new List<Group>();
20+
public static List<ElderScrollsPlugin> LoadedPlugins = new List<ElderScrollsPlugin>();
21+
public static Dictionary<LoadOrderFormID, List<RecordView>> LoadedRecordViews = new Dictionary<LoadOrderFormID, List<RecordView>>();
22+
23+
protected string name = "";
24+
public List<string> Masters = new List<string>();
25+
public RecordView Header;
26+
public List<Group> TopGroups = new List<Group>();
27+
public List<Group> AllGroups = new List<Group>();
28+
public HashSet<RecordView> RecordViews = new HashSet<RecordView>();
29+
30+
protected MemoryMappedFile mmf;
31+
32+
public string Name
33+
{
34+
get
35+
{
36+
if (Header.Flags.HasFlag(RecordFlag.IsMasterFile))
37+
return name + ".esm";
38+
else
39+
return name + ".esp";
40+
}
41+
protected set
42+
{
43+
name = Path.GetFileNameWithoutExtension(value);
44+
}
45+
}
46+
47+
public ElderScrollsPlugin()
48+
{
49+
}
50+
51+
public ElderScrollsPlugin(string name)
52+
{
53+
Name = name;
54+
}
55+
56+
public void Read(string source)
57+
{
58+
if (source == "")
59+
throw new Exception();
60+
61+
if (File.Exists(source))
62+
ReadBinary(source);
63+
else if (Directory.Exists(source))
64+
ReadXML(source);
65+
}
1566

1667
public void WriteXML(string destinationFolder)
1768
{
18-
Header.WriteXML(Path.Combine(destinationFolder, "Header.xml"));
69+
Header.Record.WriteXML(Path.Combine(destinationFolder, "Header.xml"));
1970

20-
foreach (Group group in Groups.Where(g => g.ToString() != "Interior Cells" && g.ToString() != "Worldspaces" && g.ToString() != "Dialog Topics"))
71+
foreach (Group group in TopGroups.Where(g => g.ToString() != "Interior Cells" && g.ToString() != "Worldspaces" && g.ToString() != "Dialog Topics"))
2172
{
2273
string newDir = Path.Combine(destinationFolder, group.ToString());
2374
Directory.CreateDirectory(newDir);
@@ -28,38 +79,121 @@ public void WriteXML(string destinationFolder)
2879
public static ElderScrollsPlugin ReadXML(string sourceFolder)
2980
{
3081
ElderScrollsPlugin outPlug = new ElderScrollsPlugin();
31-
outPlug.Header = Record.ReadXML(Path.Combine(sourceFolder, "Header.xml"));
82+
outPlug.name = Path.GetDirectoryName(sourceFolder);
83+
outPlug.Header = new RecordView(Path.Combine(sourceFolder, "Header.xml"));
84+
85+
ESPSharp.Records.Header headRec = outPlug.Header.Record as ESPSharp.Records.Header;
86+
87+
if (headRec.MasterFiles != null)
88+
{
89+
foreach (var masterData in headRec.MasterFiles)
90+
{
91+
ElderScrollsPlugin master = new ElderScrollsPlugin(masterData.FileName.Value);
92+
master.Read(masterData.FileName.Value);
93+
outPlug.Masters.Add(masterData.FileName.Value);
94+
}
95+
}
96+
97+
outPlug.Masters.Add(outPlug.Name);
3298

3399
foreach (var folder in Directory.EnumerateDirectories(sourceFolder, "*.*", SearchOption.TopDirectoryOnly))
34100
{
35-
Group newGroup = Group.ReadXML(folder);
101+
Group newGroup = Group.CreateGroup(folder);
36102

37-
outPlug.Groups.Add(newGroup);
103+
newGroup.GroupAdded += (g) => outPlug.AllGroups.Add(g);
104+
newGroup.RecordViewAdded += (r) => outPlug.RecordViews.Add(r);
105+
outPlug.TopGroups.Add(newGroup);
106+
outPlug.AllGroups.Add(newGroup);
107+
108+
newGroup.ReadXML(folder);
38109
}
39110

111+
ElderScrollsPlugin.LoadedPlugins.Add(outPlug);
112+
40113
return outPlug;
41114
}
42115

43116
public void WriteBinary(ESPWriter writer)
44117
{
45-
Header.WriteBinary(writer);
118+
Header.Record.WriteBinary(writer);
46119

47-
foreach (var group in Groups)
120+
foreach (var group in TopGroups)
48121
group.WriteBinary(writer);
49122
}
50123

51-
public void ReadBinary(ESPReader reader)
124+
public void ReadBinary(string file)
52125
{
53-
Header = Record.CreateRecord(reader);
54-
Header.ReadBinary(reader);
126+
name = Path.GetFileNameWithoutExtension(file);
127+
FileInfo fi = new FileInfo(file);
128+
mmf = MemoryMappedFile.CreateFromFile(file, FileMode.Open, Path.GetFileNameWithoutExtension(file), fi.Length, MemoryMappedFileAccess.Read);
129+
130+
using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, fi.Length, MemoryMappedFileAccess.Read))
131+
using (ESPReader reader = new ESPReader(stream))
132+
{
133+
Header = new RecordView(reader, mmf);
134+
135+
Masters = new List<string>();
136+
137+
ESPSharp.Records.Header headRec = Header.Record as ESPSharp.Records.Header;
138+
139+
if (headRec.MasterFiles != null)
140+
{
141+
foreach (var masterData in headRec.MasterFiles)
142+
{
143+
ElderScrollsPlugin master = new ElderScrollsPlugin(masterData.FileName.Value);
144+
master.Read(masterData.FileName.Value);
145+
Masters.Add(masterData.FileName.Value);
146+
}
147+
}
148+
149+
Masters.Add(Name);
150+
151+
while (reader.BaseStream.Position < reader.BaseStream.Length)
152+
{
153+
var group = Group.CreateGroup(reader);
154+
155+
group.GroupAdded += (g) => AllGroups.Add(g);
156+
group.RecordViewAdded += (r) => RecordViews.Add(r);
157+
TopGroups.Add(group);
158+
AllGroups.Add(group);
159+
160+
group.ReadBinary(reader, mmf);
161+
}
162+
}
55163

56-
while (reader.BaseStream.Position < reader.BaseStream.Length)
164+
ElderScrollsPlugin.LoadedPlugins.Add(this);
165+
166+
foreach (RecordView view in RecordViews)
57167
{
58-
var group = Group.CreateGroup(reader);
59-
group.ReadBinary(reader);
168+
LoadOrderFormID loID = new LoadOrderFormID(view.FormID, this);
169+
170+
List<RecordView> viewList;
171+
172+
if (!ElderScrollsPlugin.LoadedRecordViews.TryGetValue(loID, out viewList))
173+
{
174+
viewList = new List<RecordView>();
175+
ElderScrollsPlugin.LoadedRecordViews.Add(loID, viewList);
176+
}
177+
178+
viewList.Add(view);
179+
}
180+
}
60181

61-
Groups.Add(group);
182+
public static void Clear()
183+
{
184+
foreach (ElderScrollsPlugin plugin in LoadedPlugins)
185+
{
186+
plugin.Dispose();
62187
}
188+
189+
LoadedPlugins = new List<ElderScrollsPlugin>();
190+
LoadedRecordViews = new Dictionary<LoadOrderFormID, List<RecordView>>();
191+
}
192+
193+
public void Dispose()
194+
{
195+
if (mmf != null)
196+
mmf.Dispose();
63197
}
64198
}
65199
}

ESPSharp/Enums/AnimationSoundType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace ESPSharp.Enums
88
{
9-
public enum AnimationSoundType
9+
public enum AnimationSoundType : uint
1010
{
1111
Walk = 17,
1212
Sneak = 18,

0 commit comments

Comments
 (0)