diff --git a/build.bat b/build.bat
index 280966a..c2f86a7 100644
--- a/build.bat
+++ b/build.bat
@@ -7,6 +7,7 @@ mkdir @ExileLootDrop\addons
%MSBUILD% src\ExileLootDrop.sln /property:Configuration=release /target:Rebuild /verbosity:normal /nologo
copy src\ExileLootDrop\bin\Release\ExileLootDrop.dll @ExileLootDrop
copy src\ExileLootDrop\bin\Release\ExileLootDrop.cfg @ExileLootDrop
+copy src\ExileLootDrop\bin\Release\ExileLootDrop.ini @ExileLootDrop
copy src\ExileLootDropTester\bin\Release\ExileLootDropTester.exe @ExileLootDrop
copy LICENSE.txt @ExileLootDrop
copy README.md @ExileLootDrop
diff --git a/src/ExileLootDrop/ExileLootDrop.csproj b/src/ExileLootDrop/ExileLootDrop.csproj
index e06dae1..1286c06 100644
--- a/src/ExileLootDrop/ExileLootDrop.csproj
+++ b/src/ExileLootDrop/ExileLootDrop.csproj
@@ -47,6 +47,7 @@
+
@@ -63,6 +64,9 @@
Always
+
+ Always
+
diff --git a/src/ExileLootDrop/ExileLootDrop.ini b/src/ExileLootDrop/ExileLootDrop.ini
new file mode 100644
index 0000000..7ffbccd
--- /dev/null
+++ b/src/ExileLootDrop/ExileLootDrop.ini
@@ -0,0 +1,3 @@
+[General]
+LootCfg=ExileLootDrop.cfg
+CacheItems=50000
\ No newline at end of file
diff --git a/src/ExileLootDrop/IniParser.cs b/src/ExileLootDrop/IniParser.cs
new file mode 100644
index 0000000..b07af91
--- /dev/null
+++ b/src/ExileLootDrop/IniParser.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ExileLootDrop
+{
+ public class IniParser
+ {
+ private readonly string _iniFilePath;
+ private readonly Hashtable _keyPairs = new Hashtable();
+ private readonly List _tmpList = new List();
+
+ public readonly string Name;
+
+ public IniParser(string iniPath)
+ {
+ string str2 = null;
+ _iniFilePath = iniPath;
+ Name = Path.GetFileNameWithoutExtension(iniPath);
+
+ if (!File.Exists(iniPath))
+ throw new FileNotFoundException("Unable to locate " + iniPath);
+
+ using (TextReader reader = new StreamReader(iniPath))
+ {
+ for (var str = reader.ReadLine(); str != null; str = reader.ReadLine())
+ {
+ str = str.Trim();
+ if (str == "")
+ continue;
+
+ if (str.StartsWith("[") && str.EndsWith("]"))
+ str2 = str.Substring(1, str.Length - 2);
+ else
+ {
+ SectionPair pair;
+
+ if (str.StartsWith(";"))
+ str = str.Replace("=", "%eq%") + @"=%comment%";
+
+ var strArray = str.Split(new[] { '=' }, 2);
+ string str3 = null;
+ if (str2 == null)
+ {
+ str2 = "ROOT";
+ }
+ pair.Section = str2;
+ pair.Key = strArray[0];
+ if (strArray.Length > 1)
+ {
+ str3 = strArray[1];
+ }
+ _keyPairs.Add(pair, str3);
+ _tmpList.Add(pair);
+ }
+ }
+ }
+ }
+
+ public void AddSetting(string sectionName, string settingName)
+ {
+ AddSetting(sectionName, settingName, null);
+ }
+
+ public void AddSetting(string sectionName, string settingName, string settingValue)
+ {
+ SectionPair pair;
+ pair.Section = sectionName;
+ pair.Key = settingName;
+ if (_keyPairs.ContainsKey(pair))
+ {
+ _keyPairs.Remove(pair);
+ }
+ if (_tmpList.Contains(pair))
+ {
+ _tmpList.Remove(pair);
+ }
+ _keyPairs.Add(pair, settingValue);
+ _tmpList.Add(pair);
+ }
+
+ public int Count()
+ {
+ return Sections.Length;
+ }
+
+ public void DeleteSetting(string sectionName, string settingName)
+ {
+ SectionPair pair;
+ pair.Section = sectionName;
+ pair.Key = settingName;
+ if (!_keyPairs.ContainsKey(pair)) return;
+ _keyPairs.Remove(pair);
+ _tmpList.Remove(pair);
+ }
+
+ public string[] EnumSection(string sectionName)
+ {
+ return (from pair in _tmpList where !pair.Key.StartsWith(";") where pair.Section == sectionName select pair.Key).ToArray();
+ }
+
+ public string[] Sections => (from pair in _tmpList
+ group pair by pair.Section into bySection
+ from IGrouping g in bySection
+ select g.Key).ToArray();
+
+ public string GetSetting(string sectionName, string settingName, string defaultValue = "")
+ {
+ SectionPair pair;
+ pair.Section = sectionName;
+ pair.Key = settingName;
+ return !_keyPairs.ContainsKey(pair) ? defaultValue : ((string)_keyPairs[pair]).Trim();
+ }
+
+ public bool GetBoolSetting(string sectionName, string settingName, bool defaultValue = false)
+ {
+ if (defaultValue)
+ return (GetSetting(sectionName, settingName).ToLower() != "false");
+ return (GetSetting(sectionName, settingName).ToLower() == "true");
+ }
+
+ public void Save()
+ {
+ SaveSettings(_iniFilePath);
+ }
+
+ public void SaveSettings(string newFilePath)
+ {
+ var list = new ArrayList();
+ var str2 = "";
+ foreach (var pair in _tmpList.Where(pair => !list.Contains(pair.Section)))
+ {
+ list.Add(pair.Section);
+ }
+ foreach (string str3 in list)
+ {
+ str2 = str2 + "[" + str3 + "]\r\n";
+ foreach (var pair2 in _tmpList)
+ {
+ if (pair2.Section == str3)
+ {
+ var str = (string)_keyPairs[pair2];
+ if (str != null)
+ {
+ if (str == "%comment%")
+ {
+ str = "";
+ }
+ else
+ {
+ str = "=" + str;
+ }
+ }
+ str2 = str2 + pair2.Key.Replace("%eq%", "=") + str + "\r\n";
+ }
+ }
+ str2 = str2 + "\r\n";
+ }
+
+ using (TextWriter writer = new StreamWriter(newFilePath))
+ writer.Write(str2);
+ }
+
+ public void SetSetting(string sectionName, string settingName, string value)
+ {
+ SectionPair pair;
+ pair.Section = sectionName;
+ pair.Key = settingName;
+ if (_keyPairs.ContainsKey(pair))
+ {
+ _keyPairs[pair] = value;
+ }
+ else
+ {
+ AddSetting(sectionName, settingName, value);
+ }
+ }
+
+ public bool ContainsSetting(string sectionName, string settingName)
+ {
+ SectionPair pair;
+ pair.Section = sectionName;
+ pair.Key = settingName;
+ return _keyPairs.Contains(pair);
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SectionPair
+ {
+ public string Section;
+ public string Key;
+ }
+ }
+}
diff --git a/src/ExileLootDrop/Loot.cs b/src/ExileLootDrop/Loot.cs
index ccdd87b..35b19f3 100644
--- a/src/ExileLootDrop/Loot.cs
+++ b/src/ExileLootDrop/Loot.cs
@@ -56,13 +56,22 @@ public static string Invoke(string input)
private readonly List _cfgGroups;
private Dictionary Table { get; } = new Dictionary();
-
+
///
/// Loot constructor
///
private Loot()
{
- const string cfgpath = "ExileLootDrop.cfg";
+ var assembly = Assembly.GetExecutingAssembly();
+ var assemblyName = Path.GetFileNameWithoutExtension(assembly.Location);
+ var iniPath = Path.Combine(BasePath, $"{assemblyName}.ini");
+ if (!File.Exists(iniPath))
+ throw new LootException($"{assemblyName}.ini was not found");
+
+ var ini = new IniParser(iniPath);
+ var cfgpath = ini.GetSetting("General", "LootCfg", "ExileLootDrop.cfg");
+ var cacheCount = Convert.ToInt32(ini.GetSetting("General", "CacheItems", "0"));
+
Logger.LoggerHandlerManager.AddHandler(new ConsoleLoggerHandler());
var logfile = Path.Combine(BasePath, "output.log");
try
@@ -98,11 +107,11 @@ private Loot()
foreach (var group in _cfgGroups)
{
var list = FlattenGroups(group);
- var table = new LootTable(group.Name, list);
+ var table = new LootTable(group.Name, list, cacheCount);
Table.Add(group.Name, table);
}
var span = DateTime.Now - start;
- Logger.Log($"Took {span.Milliseconds}ms to load and parse loot cfg");
+ Logger.Log($"Took {span.TotalMilliseconds}ms to load and parse loot cfg");
}
///
@@ -157,11 +166,11 @@ public string[] GetItems(string table, int count = 1)
if (!Table.ContainsKey(table))
throw new LootTableNotFoundException($"No loot table called {table}");
- var items = new List();
+ var items = new string[count];
for (var i = 0; i < count; i++)
- items.Add(Table[table].Drop());
+ items[i] = Table[table].Drop();
- return items.ToArray();
+ return items;
}
///
diff --git a/src/ExileLootDrop/LootTable.cs b/src/ExileLootDrop/LootTable.cs
index 3057b07..91e27bd 100644
--- a/src/ExileLootDrop/LootTable.cs
+++ b/src/ExileLootDrop/LootTable.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
namespace ExileLootDrop
{
@@ -16,14 +17,18 @@ public class LootTable
public LootItem[] LootItems { get; }
private readonly Random _rnd = new Random();
+ private readonly int _cacheCount;
+ private int _cachePtr;
+ private readonly LootItem[] _cacheItems;
///
/// LootTable constuctor
///
/// Table name
/// Item list
- public LootTable(string name, List lootList)
+ public LootTable(string name, List lootList, int cacheCount = 0)
{
+ _cacheCount = cacheCount;
Name = name;
var sum = 0m;
lootList.ForEach(i =>
@@ -32,6 +37,19 @@ public LootTable(string name, List lootList)
i.Sum = sum;
});
LootItems = lootList.ToArray();
+ Logger.Log($"Pre caching loot for {Name}");
+ var cache = new List();
+ for (var i = 0; i < _cacheCount; i++)
+ {
+ var rnd = (decimal)_rnd.NextDouble();
+ foreach (var item in LootItems.Where(item => item.Sum >= rnd))
+ {
+ cache.Add(item);
+ break;
+ }
+ }
+ _cachePtr = 0;
+ _cacheItems = cache.ToArray();
}
///
@@ -40,6 +58,11 @@ public LootTable(string name, List lootList)
/// Item classname
public string Drop()
{
+ if (_cacheCount != 0 && _cachePtr < _cacheCount)
+ {
+ return _cacheItems[_cachePtr++].Item;
+ }
+
var rnd = (decimal)_rnd.NextDouble();
foreach (var item in LootItems)
{
diff --git a/src/ExileLootDropTester/Program.cs b/src/ExileLootDropTester/Program.cs
index f71988b..2359751 100644
--- a/src/ExileLootDropTester/Program.cs
+++ b/src/ExileLootDropTester/Program.cs
@@ -7,7 +7,7 @@ namespace ExileLootDropTester
{
class Program
{
- const int Loops = 1000000;
+ const int Loops = 50000;
static void Main(string[] args)
{