mirror of
https://github.com/maca134/ExileLootDrop.git
synced 2024-08-30 17:22:13 +00:00
First Commit
This commit is contained in:
commit
cd8989f228
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.hg/*
|
||||
@ExileLootDrop/*
|
||||
src/ExileLootDrop/bin/*
|
||||
src/ExileLootDrop/obj/*
|
||||
src/ExileLootDropTester/bin/*
|
||||
src/ExileLootDropTester/obj/*
|
||||
*.suo
|
||||
src/packages/*
|
||||
.hgignore
|
2803
ExileLootDrop.VR/description.ext
Normal file
2803
ExileLootDrop.VR/description.ext
Normal file
File diff suppressed because it is too large
Load Diff
37
ExileLootDrop.VR/init.sqf
Normal file
37
ExileLootDrop.VR/init.sqf
Normal file
@ -0,0 +1,37 @@
|
||||
ExileServer_system_lootManager_dropItem_sqf = {
|
||||
private["_lootTableName","_itemClassName","_lootTableConfig","_sum","_count","_half","_halfIndex","_lootTableEntries","_maxPossible","_chance","_startIndex","_endIndex","_i","_entry"];
|
||||
_lootTableName = _this;
|
||||
_itemClassName = "";
|
||||
_lootTableConfig = missionConfigFile >> "CfgLootTables" >> _lootTableName;
|
||||
_sum = getNumber(_lootTableConfig >> "sum");
|
||||
_count = getNumber(_lootTableConfig >> "count");
|
||||
_half = getNumber(_lootTableConfig >> "half");
|
||||
_halfIndex = getNumber(_lootTableConfig >> "halfIndex");
|
||||
_lootTableEntries = getArray(_lootTableConfig >> "items");
|
||||
_maxPossible = (count _lootTableEntries)-1;
|
||||
_chance = random(_sum);
|
||||
if (_chance >= _half) then
|
||||
{
|
||||
_startIndex = _halfIndex;
|
||||
_endIndex = _count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_startIndex = 0;
|
||||
_endIndex = _halfIndex + 1;
|
||||
};
|
||||
if (_endIndex > _maxPossible) then
|
||||
{
|
||||
_endIndex = _maxPossible;
|
||||
};
|
||||
for "_i" from _startIndex to _endIndex do
|
||||
{
|
||||
_entry = _lootTableEntries select _i;
|
||||
if (_chance <= (_entry select 0)) exitWith
|
||||
{
|
||||
_itemClassName = _entry select 1;
|
||||
};
|
||||
};
|
||||
_itemClassName
|
||||
};
|
||||
ExileServer_system_lootManager_dropItem_ext = compile preprocessFileLineNumbers '\ExileLootDrop\ExileServer_system_lootManager_dropItem.sqf';
|
BIN
ExileLootDrop.VR/mission.sqm
Normal file
BIN
ExileLootDrop.VR/mission.sqm
Normal file
Binary file not shown.
7
LICENSE.txt
Normal file
7
LICENSE.txt
Normal file
@ -0,0 +1,7 @@
|
||||
Exile Loot Drop
|
||||
www.maca134.co.uk
|
||||
© 2016 maca134
|
||||
|
||||
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
|
||||
|
28
README.txt
Normal file
28
README.txt
Normal file
@ -0,0 +1,28 @@
|
||||
Exile Loot Drop
|
||||
|
||||
A server mod/extension to replace the Exile loot drop function with a dll.
|
||||
|
||||
Examples:
|
||||
Get single item (returns string so is backwards compatible with Exile):
|
||||
_item = 'table' call ExileServer_system_lootManager_dropItem;
|
||||
|
||||
Get multiple items (returns an array of items, this is good for mission stuff):
|
||||
_items = ['table', 10] call ExileServer_system_lootManager_dropItem;
|
||||
|
||||
ExileLootDrop.VR mission contains the original Exile method for loot and the original tables for testing
|
||||
|
||||
// SQF
|
||||
'CivillianLowerClass' call ExileServer_system_lootManager_dropItem_sqf
|
||||
|
||||
// DLL
|
||||
'CivillianLowerClass' call ExileServer_system_lootManager_dropItem_ext
|
||||
|
||||
To Install:
|
||||
Run the mod on the server and stick the below into CfgExileCustomCode in you mission files
|
||||
```
|
||||
class CfgExileCustomCode
|
||||
{
|
||||
...
|
||||
ExileServer_system_lootManager_dropItem = "\ExileLootDrop\ExileServer_system_lootManager_dropItem.sqf";
|
||||
...
|
||||
};
|
14
build.bat
Normal file
14
build.bat
Normal file
@ -0,0 +1,14 @@
|
||||
set MSBUILD="C:\Program Files (x86)\MSBuild\14.0\Bin\MsBuild.exe"
|
||||
set MAKEPBO="C:\Program Files (x86)\Mikero\DePboTools\bin\MakePbo.exe"
|
||||
|
||||
rd /s /q @ExileLootDrop
|
||||
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 LICENSE.txt @ExileLootDrop
|
||||
copy README.txt @ExileLootDrop
|
||||
|
||||
|
||||
%MAKEPBO% -U -W -P -@=ExileLootDrop sqf @ExileLootDrop\addons\ExileLootDrop.pbo
|
39
sqf/ExileServer_system_lootManager_dropItem.sqf
Normal file
39
sqf/ExileServer_system_lootManager_dropItem.sqf
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* ExileServer_system_lootManager_dropItem
|
||||
*
|
||||
* maca134
|
||||
* www.maca134.co.uk
|
||||
* © 2016 maca134
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
|
||||
*
|
||||
* Examples:
|
||||
* Get single item (returns string so is backwards compatible with Exile):
|
||||
* _item = 'table' call ExileServer_system_lootManager_dropItem;
|
||||
*
|
||||
* Get multiple items (returns an array of items, this is good for mission stuff):
|
||||
* _items = ['table', 10] call ExileServer_system_lootManager_dropItem;
|
||||
*
|
||||
*/
|
||||
|
||||
private _input = _this;
|
||||
if (typeName _input == 'STRING') then {
|
||||
_input = [_input, 1];
|
||||
};
|
||||
_input params [
|
||||
['_table', '', ['']],
|
||||
['_amount', 1, [0]]
|
||||
];
|
||||
private _packet = format['%1|%2', _table, _amount];
|
||||
private _response = 'ExileLootDrop' callExtension _packet;
|
||||
if (_response == 'ERROR') exitWith {
|
||||
diag_log format['ExileLootDrop: Extension return error. Check logs! - %1', _packet];
|
||||
""
|
||||
};
|
||||
private _return = if (_amount > 1) then {
|
||||
_response splitString '|'
|
||||
} else {
|
||||
_response
|
||||
};
|
||||
_return
|
10
sqf/config.cpp
Normal file
10
sqf/config.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
class CfgPatches {
|
||||
class ExileLootDrop {
|
||||
requiredVersion = 0.1;
|
||||
requiredAddons[] = {"exile_server"};
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
magazines[] = {};
|
||||
ammo[] = {};
|
||||
};
|
||||
};
|
28
src/ExileLootDrop.sln
Normal file
28
src/ExileLootDrop.sln
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExileLootDrop", "ExileLootDrop\ExileLootDrop.csproj", "{F3DEC0AD-F490-4761-84A5-E51240FA3D91}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExileLootDropTester", "ExileLootDropTester\ExileLootDropTester.csproj", "{D4C0452C-055B-4773-920B-D9C7A70EB9D6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F3DEC0AD-F490-4761-84A5-E51240FA3D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3DEC0AD-F490-4761-84A5-E51240FA3D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3DEC0AD-F490-4761-84A5-E51240FA3D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F3DEC0AD-F490-4761-84A5-E51240FA3D91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D4C0452C-055B-4773-920B-D9C7A70EB9D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D4C0452C-055B-4773-920B-D9C7A70EB9D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4C0452C-055B-4773-920B-D9C7A70EB9D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4C0452C-055B-4773-920B-D9C7A70EB9D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
85
src/ExileLootDrop/CfgGroup.cs
Normal file
85
src/ExileLootDrop/CfgGroup.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to represent each Loot group in a config file
|
||||
/// </summary>
|
||||
public class CfgGroup
|
||||
{
|
||||
private const string BlockComments = @"/\*(.*?)\*/";
|
||||
private const string LineComments = @"//[^\n]+";
|
||||
|
||||
/// <summary>
|
||||
/// Load a loot config into a List of CfgGroups
|
||||
/// </summary>
|
||||
/// <param name="file">Path to loot config. If relative will start in the same directory as this extension</param>
|
||||
/// <returns>CfgGroup List</returns>
|
||||
public static List<CfgGroup> Load(string file)
|
||||
{
|
||||
if (!Path.IsPathRooted(file))
|
||||
{
|
||||
var basepath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
if (basepath != null)
|
||||
file = Path.Combine(basepath, file);
|
||||
}
|
||||
if (!File.Exists(file))
|
||||
throw new CfgGroupException($"File not found: {file}");
|
||||
var lootcfg = Regex.Replace(File.ReadAllText(file),
|
||||
BlockComments + "|" + LineComments,
|
||||
"\n",
|
||||
RegexOptions.Singleline);
|
||||
var groups = new List<CfgGroup>();
|
||||
CfgGroup group = null;
|
||||
foreach (var line in lootcfg.Split('\r', '\n').Where(l => !string.IsNullOrWhiteSpace(l)))
|
||||
{
|
||||
if (line[0] == '>')
|
||||
{
|
||||
group = new CfgGroup(line.Substring(1).Trim());
|
||||
groups.Add(group);
|
||||
continue;
|
||||
}
|
||||
group?.Add(line);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
/// <summary>
|
||||
/// Name of the group
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of loot items
|
||||
/// </summary>
|
||||
public List<CfgGroupItem> Items { get; } = new List<CfgGroupItem>();
|
||||
|
||||
/// <summary>
|
||||
/// CfgGroup constructor
|
||||
/// </summary>
|
||||
/// <param name="name">Group name</param>
|
||||
public CfgGroup(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a loot item
|
||||
/// </summary>
|
||||
/// <param name="line">Line from the loot config</param>
|
||||
internal void Add(string line)
|
||||
{
|
||||
try
|
||||
{
|
||||
Items.Add(new CfgGroupItem(line));
|
||||
}
|
||||
catch (CfgGroupItemException ex)
|
||||
{
|
||||
throw new CfgGroupException($"Failed to add GroupItem: {line}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/ExileLootDrop/CfgGroupException.cs
Normal file
25
src/ExileLootDrop/CfgGroupException.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
[Serializable]
|
||||
public class CfgGroupException : Exception
|
||||
{
|
||||
public CfgGroupException()
|
||||
{
|
||||
}
|
||||
|
||||
public CfgGroupException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public CfgGroupException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected CfgGroupException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
31
src/ExileLootDrop/CfgGroupItem.cs
Normal file
31
src/ExileLootDrop/CfgGroupItem.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
public class CfgGroupItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Item chance
|
||||
/// </summary>
|
||||
public int Chance { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Item/group name
|
||||
/// </summary>
|
||||
public string Item { get; }
|
||||
|
||||
/// <summary>
|
||||
/// CfgGroupItem constructor
|
||||
/// </summary>
|
||||
/// <param name="line">Line from the loot config</param>
|
||||
public CfgGroupItem(string line)
|
||||
{
|
||||
var parts = line.Split(',');
|
||||
if (parts.Length != 2)
|
||||
throw new CfgGroupItemException($"Item line is invalid: {line}");
|
||||
int chance;
|
||||
if (!int.TryParse(parts[0], out chance))
|
||||
throw new CfgGroupItemException($"Could not parse chance: {line}");
|
||||
Chance = chance;
|
||||
Item = parts[1].Trim();
|
||||
}
|
||||
}
|
||||
}
|
25
src/ExileLootDrop/CfgGroupItemException.cs
Normal file
25
src/ExileLootDrop/CfgGroupItemException.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
[Serializable]
|
||||
public class CfgGroupItemException : CfgGroupException
|
||||
{
|
||||
public CfgGroupItemException()
|
||||
{
|
||||
}
|
||||
|
||||
public CfgGroupItemException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public CfgGroupItemException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected CfgGroupItemException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
31
src/ExileLootDrop/DllEntry.cs
Normal file
31
src/ExileLootDrop/DllEntry.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using RGiesecke.DllExport;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point class for ARMA
|
||||
/// </summary>
|
||||
public class DllEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point method for ARMA
|
||||
/// </summary>
|
||||
[DllExport("_RVExtension@12", CallingConvention = CallingConvention.Winapi)]
|
||||
public static void RvExtension(StringBuilder output, int outputSize, [MarshalAs(UnmanagedType.LPStr)] string function)
|
||||
{
|
||||
try
|
||||
{
|
||||
output.Append(Loot.Invoke(function));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log(Logger.Level.Error, "Uncaught Exception!");
|
||||
Logger.Log(ex);
|
||||
output.Append("ERROR");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1158
src/ExileLootDrop/ExileLootDrop.cfg
Normal file
1158
src/ExileLootDrop/ExileLootDrop.cfg
Normal file
File diff suppressed because it is too large
Load Diff
77
src/ExileLootDrop/ExileLootDrop.csproj
Normal file
77
src/ExileLootDrop/ExileLootDrop.csproj
Normal file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{F3DEC0AD-F490-4761-84A5-E51240FA3D91}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ExileLootDrop</RootNamespace>
|
||||
<AssemblyName>ExileLootDrop</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="RGiesecke.DllExport.Metadata, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8f52d83c1a22df51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\UnmanagedExports.1.2.7\lib\net\RGiesecke.DllExport.Metadata.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DllEntry.cs" />
|
||||
<Compile Include="Logger.cs" />
|
||||
<Compile Include="Loot.cs" />
|
||||
<Compile Include="CfgGroup.cs" />
|
||||
<Compile Include="CfgGroupException.cs" />
|
||||
<Compile Include="CfgGroupItemException.cs" />
|
||||
<Compile Include="CfgGroupItem.cs" />
|
||||
<Compile Include="LootTableNotFoundException.cs" />
|
||||
<Compile Include="LootException.cs" />
|
||||
<Compile Include="LootItem.cs" />
|
||||
<Compile Include="LootTable.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ExileLootDrop.cfg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="../packages/UnmanagedExports.1.2.7/tools/RGiesecke.DllExport.targets" Condition="Exists('../packages/UnmanagedExports.1.2.7/tools/RGiesecke.DllExport.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
441
src/ExileLootDrop/Logger.cs
Normal file
441
src/ExileLootDrop/Logger.cs
Normal file
@ -0,0 +1,441 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
internal static class Logger
|
||||
{
|
||||
private static readonly LogPublisher LogPublisher;
|
||||
|
||||
private static readonly object Sync = new object();
|
||||
private static bool _isTurned = true;
|
||||
private static bool _isTurnedDebug = true;
|
||||
|
||||
static Logger()
|
||||
{
|
||||
lock (Sync)
|
||||
{
|
||||
LogPublisher = new LogPublisher();
|
||||
Modules = new ModuleManager();
|
||||
Debug = new DebugLogger();
|
||||
}
|
||||
}
|
||||
|
||||
internal static Level DefaultLevel { get; set; } = Level.Info;
|
||||
|
||||
internal static ILoggerHandlerManager LoggerHandlerManager => LogPublisher;
|
||||
|
||||
internal static IEnumerable<LogMessage> Messages => LogPublisher.Messages;
|
||||
|
||||
internal static DebugLogger Debug { get; }
|
||||
|
||||
internal static ModuleManager Modules { get; }
|
||||
|
||||
internal static void Log()
|
||||
{
|
||||
Log("There is no message");
|
||||
}
|
||||
|
||||
internal static void Log(string message)
|
||||
{
|
||||
Log(DefaultLevel, message);
|
||||
}
|
||||
|
||||
internal static void Log(Level level, string message)
|
||||
{
|
||||
var stackFrame = FindStackFrame();
|
||||
var methodBase = GetCallingMethodBase(stackFrame);
|
||||
var callingMethod = methodBase.Name;
|
||||
var callingClass = methodBase.ReflectedType?.Name;
|
||||
var lineNumber = stackFrame.GetFileLineNumber();
|
||||
|
||||
Log(level, message, callingClass, callingMethod, lineNumber);
|
||||
}
|
||||
|
||||
internal static void Log(Exception exception)
|
||||
{
|
||||
Log(Level.Error, exception.Message);
|
||||
Modules.ExceptionLog(exception);
|
||||
}
|
||||
|
||||
internal static void Log<TClass>(Exception exception) where TClass : class
|
||||
{
|
||||
var message = $"Log exception -> Message: {exception.Message}\nStackTrace: {exception.StackTrace}";
|
||||
Log<TClass>(Level.Error, message);
|
||||
}
|
||||
|
||||
internal static void Log<TClass>(string message) where TClass : class
|
||||
{
|
||||
Log<TClass>(DefaultLevel, message);
|
||||
}
|
||||
|
||||
internal static void Log<TClass>(Level level, string message) where TClass : class
|
||||
{
|
||||
var stackFrame = FindStackFrame();
|
||||
var methodBase = GetCallingMethodBase(stackFrame);
|
||||
var callingMethod = methodBase.Name;
|
||||
var callingClass = typeof (TClass).Name;
|
||||
var lineNumber = stackFrame.GetFileLineNumber();
|
||||
|
||||
Log(level, message, callingClass, callingMethod, lineNumber);
|
||||
}
|
||||
|
||||
private static void Log(Level level, string message, string callingClass, string callingMethod, int lineNumber)
|
||||
{
|
||||
if (!_isTurned || (!_isTurnedDebug && level == Level.Debug))
|
||||
return;
|
||||
|
||||
var currentDateTime = DateTime.Now;
|
||||
|
||||
Modules.BeforeLog();
|
||||
var logMessage = new LogMessage(level, message, currentDateTime, callingClass, callingMethod, lineNumber);
|
||||
LogPublisher.Publish(logMessage);
|
||||
Modules.AfterLog(logMessage);
|
||||
}
|
||||
|
||||
private static MethodBase GetCallingMethodBase(StackFrame stackFrame)
|
||||
{
|
||||
return stackFrame == null
|
||||
? MethodBase.GetCurrentMethod()
|
||||
: stackFrame.GetMethod();
|
||||
}
|
||||
|
||||
private static StackFrame FindStackFrame()
|
||||
{
|
||||
var stackTrace = new StackTrace();
|
||||
var frames = stackTrace.GetFrames();
|
||||
if (frames == null)
|
||||
return null;
|
||||
for (var i = 0; i < frames.Length; i++)
|
||||
{
|
||||
var methodBase = stackTrace.GetFrame(i).GetMethod();
|
||||
var name = MethodBase.GetCurrentMethod().Name;
|
||||
if (!methodBase.Name.Equals("Log") && !methodBase.Name.Equals(name))
|
||||
return new StackFrame(i, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void On()
|
||||
{
|
||||
_isTurned = true;
|
||||
}
|
||||
|
||||
internal static void Off()
|
||||
{
|
||||
_isTurned = false;
|
||||
}
|
||||
|
||||
internal static void DebugOn()
|
||||
{
|
||||
_isTurnedDebug = true;
|
||||
}
|
||||
|
||||
internal static void DebugOff()
|
||||
{
|
||||
_isTurnedDebug = false;
|
||||
}
|
||||
|
||||
internal enum Level
|
||||
{
|
||||
None,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Severe,
|
||||
Fine,
|
||||
Debug
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ILoggerFormatter
|
||||
{
|
||||
string ApplyFormat(LogMessage logMessage);
|
||||
}
|
||||
|
||||
internal interface ILoggerHandlerManager
|
||||
{
|
||||
ILoggerHandlerManager AddHandler(ILoggerHandler loggerHandler);
|
||||
|
||||
bool RemoveHandler(ILoggerHandler loggerHandler);
|
||||
}
|
||||
|
||||
internal interface ILoggerHandler
|
||||
{
|
||||
void Publish(LogMessage logMessage);
|
||||
}
|
||||
|
||||
internal class LogMessage
|
||||
{
|
||||
public LogMessage()
|
||||
{
|
||||
}
|
||||
|
||||
public LogMessage(Logger.Level level, string text, DateTime dateTime, string callingClass, string callingMethod,
|
||||
int lineNumber)
|
||||
{
|
||||
Level = level;
|
||||
Text = text;
|
||||
DateTime = dateTime;
|
||||
CallingClass = callingClass;
|
||||
CallingMethod = callingMethod;
|
||||
LineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public DateTime DateTime { get; set; }
|
||||
public Logger.Level Level { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string CallingClass { get; set; }
|
||||
public string CallingMethod { get; set; }
|
||||
public int LineNumber { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return new DefaultLoggerFormatter().ApplyFormat(this);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultLoggerFormatter : ILoggerFormatter
|
||||
{
|
||||
public string ApplyFormat(LogMessage logMessage)
|
||||
{
|
||||
return
|
||||
$"{logMessage.DateTime:dd.MM.yyyy HH:mm}: {logMessage.Level} [line: {logMessage.LineNumber} {logMessage.CallingClass} -> {logMessage.CallingMethod}()]: {logMessage.Text}";
|
||||
}
|
||||
}
|
||||
|
||||
internal class DebugLogger
|
||||
{
|
||||
private const Logger.Level DebugLevel = Logger.Level.Debug;
|
||||
|
||||
public void Log()
|
||||
{
|
||||
Log("There is no message");
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
Logger.Log(DebugLevel, message);
|
||||
}
|
||||
|
||||
public void Log(Exception exception)
|
||||
{
|
||||
Logger.Log(DebugLevel, exception.Message);
|
||||
}
|
||||
|
||||
public void Log<TClass>(Exception exception) where TClass : class
|
||||
{
|
||||
var message = $"Log exception -> Message: {exception.Message}\nStackTrace: {exception.StackTrace}";
|
||||
Logger.Log<TClass>(DebugLevel, message);
|
||||
}
|
||||
|
||||
public void Log<TClass>(string message) where TClass : class
|
||||
{
|
||||
Logger.Log<TClass>(DebugLevel, message);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ModuleManager
|
||||
{
|
||||
private readonly IDictionary<string, LoggerModule> _modules;
|
||||
|
||||
public ModuleManager()
|
||||
{
|
||||
_modules = new Dictionary<string, LoggerModule>();
|
||||
}
|
||||
|
||||
public void BeforeLog()
|
||||
{
|
||||
foreach (var loggerModule in _modules.Values)
|
||||
loggerModule.BeforeLog();
|
||||
}
|
||||
|
||||
public void AfterLog(LogMessage logMessage)
|
||||
{
|
||||
foreach (var loggerModule in _modules.Values)
|
||||
loggerModule.AfterLog(logMessage);
|
||||
}
|
||||
|
||||
public void ExceptionLog(Exception exception)
|
||||
{
|
||||
foreach (var loggerModule in _modules.Values)
|
||||
loggerModule.ExceptionLog(exception);
|
||||
}
|
||||
|
||||
public void Install(LoggerModule module)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!_modules.ContainsKey(module.Name))
|
||||
{
|
||||
module.Initialize();
|
||||
_modules.Add(module.Name, module);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reinstall module
|
||||
Uninstall(module.Name);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Uninstall(LoggerModule module)
|
||||
{
|
||||
if (_modules.ContainsKey(module.Name))
|
||||
_modules.Remove(module.Name);
|
||||
}
|
||||
|
||||
public void Uninstall(string moduleName)
|
||||
{
|
||||
if (_modules.ContainsKey(moduleName))
|
||||
_modules.Remove(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class LoggerModule
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual void BeforeLog()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void AfterLog(LogMessage logMessage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ExceptionLog(Exception exception)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class LogPublisher : ILoggerHandlerManager
|
||||
{
|
||||
private readonly IList<ILoggerHandler> _loggerHandlers;
|
||||
private readonly IList<LogMessage> _messages;
|
||||
|
||||
public LogPublisher()
|
||||
{
|
||||
_loggerHandlers = new List<ILoggerHandler>();
|
||||
_messages = new List<LogMessage>();
|
||||
}
|
||||
|
||||
public IEnumerable<LogMessage> Messages => _messages;
|
||||
|
||||
public ILoggerHandlerManager AddHandler(ILoggerHandler loggerHandler)
|
||||
{
|
||||
if (loggerHandler != null)
|
||||
_loggerHandlers.Add(loggerHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool RemoveHandler(ILoggerHandler loggerHandler)
|
||||
{
|
||||
return _loggerHandlers.Remove(loggerHandler);
|
||||
}
|
||||
|
||||
public void Publish(LogMessage logMessage)
|
||||
{
|
||||
_messages.Add(logMessage);
|
||||
foreach (var loggerHandler in _loggerHandlers)
|
||||
loggerHandler.Publish(logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ConsoleLoggerHandler : ILoggerHandler
|
||||
{
|
||||
private readonly ILoggerFormatter _loggerFormatter;
|
||||
|
||||
internal ConsoleLoggerHandler() : this(new DefaultLoggerFormatter())
|
||||
{
|
||||
}
|
||||
|
||||
internal ConsoleLoggerHandler(ILoggerFormatter loggerFormatter)
|
||||
{
|
||||
_loggerFormatter = loggerFormatter;
|
||||
}
|
||||
|
||||
public void Publish(LogMessage logMessage)
|
||||
{
|
||||
Console.WriteLine(_loggerFormatter.ApplyFormat(logMessage));
|
||||
}
|
||||
}
|
||||
|
||||
internal class FileLoggerHandler : ILoggerHandler
|
||||
{
|
||||
private static readonly object Sync = new object();
|
||||
private readonly string _directory;
|
||||
private readonly string _fileName;
|
||||
private readonly ILoggerFormatter _loggerFormatter;
|
||||
|
||||
internal FileLoggerHandler() : this(CreateFileName())
|
||||
{
|
||||
}
|
||||
|
||||
internal FileLoggerHandler(string fileName) : this(fileName, string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
internal FileLoggerHandler(string fileName, string directory)
|
||||
: this(new DefaultLoggerFormatter(), fileName, directory)
|
||||
{
|
||||
}
|
||||
|
||||
internal FileLoggerHandler(ILoggerFormatter loggerFormatter) : this(loggerFormatter, CreateFileName())
|
||||
{
|
||||
}
|
||||
|
||||
internal FileLoggerHandler(ILoggerFormatter loggerFormatter, string fileName)
|
||||
: this(loggerFormatter, fileName, string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
internal FileLoggerHandler(ILoggerFormatter loggerFormatter, string fileName, string directory)
|
||||
{
|
||||
_loggerFormatter = loggerFormatter;
|
||||
_fileName = fileName;
|
||||
_directory = directory;
|
||||
}
|
||||
|
||||
public void Publish(LogMessage logMessage)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_directory))
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(Path.Combine(_directory));
|
||||
if (!directoryInfo.Exists)
|
||||
directoryInfo.Create();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
lock (Sync)
|
||||
{
|
||||
using (
|
||||
var writer = new StreamWriter(File.Open(Path.Combine(_directory, _fileName), FileMode.Append)))
|
||||
writer.WriteLine(_loggerFormatter.ApplyFormat(logMessage));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateFileName()
|
||||
{
|
||||
var currentDate = DateTime.Now;
|
||||
var guid = Guid.NewGuid();
|
||||
return
|
||||
$"Log_{currentDate.Year:0000}{currentDate.Month:00}{currentDate.Day:00}-{currentDate.Hour:00}{currentDate.Minute:00}_{guid}.log";
|
||||
}
|
||||
}
|
||||
}
|
174
src/ExileLootDrop/Loot.cs
Normal file
174
src/ExileLootDrop/Loot.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
public class Loot
|
||||
{
|
||||
private static bool _hasErrored;
|
||||
|
||||
/// <summary>
|
||||
/// Extension path
|
||||
/// </summary>
|
||||
public static string BasePath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";
|
||||
|
||||
/// <summary>
|
||||
/// Max depth for table groups
|
||||
/// </summary>
|
||||
public static int MaxDepth { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Loot tables
|
||||
/// </summary>
|
||||
public static Loot LootTable { get; } = new Loot();
|
||||
|
||||
/// <summary>
|
||||
/// Static method for ARMA's callExtension
|
||||
/// </summary>
|
||||
/// <param name="input">Input from ARMA</param>
|
||||
/// <returns>Results to send back to ARMA</returns>
|
||||
public static string Invoke(string input)
|
||||
{
|
||||
if (_hasErrored)
|
||||
{
|
||||
Logger.Log<Loot>(Logger.Level.Error, "Trying to run ext after an error has occured!");
|
||||
return "ERROR";
|
||||
}
|
||||
var parts = input.Split('|');
|
||||
var table = parts[0];
|
||||
var count = (parts.Length == 2) ? int.Parse(parts[1]) : 1;
|
||||
try
|
||||
{
|
||||
return string.Join("|", LootTable.GetItems(table, count));
|
||||
}
|
||||
catch (LootTableNotFoundException ex)
|
||||
{
|
||||
Logger.Log<Loot>(Logger.Level.Error, $"Looks like you tried to get loot from a table that didnt exist: {input}");
|
||||
Logger.Log<Loot>(ex);
|
||||
return "ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<CfgGroup> _cfgGroups;
|
||||
private Dictionary<string, LootTable> Table { get; } = new Dictionary<string, LootTable>();
|
||||
|
||||
/// <summary>
|
||||
/// Loot constructor
|
||||
/// </summary>
|
||||
private Loot()
|
||||
{
|
||||
const string cfgpath = "ExileLootDrop.cfg";
|
||||
Logger.LoggerHandlerManager.AddHandler(new ConsoleLoggerHandler());
|
||||
var logfile = Path.Combine(BasePath, "output.log");
|
||||
try
|
||||
{
|
||||
if (File.Exists(logfile))
|
||||
{
|
||||
File.Delete(logfile);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
Logger.LoggerHandlerManager.AddHandler(new FileLoggerHandler(logfile));
|
||||
Logger.Log<Loot>(Logger.Level.Info, "=====================================================================");
|
||||
Logger.Log<Loot>(Logger.Level.Info, "Exile Loot Drop Extension");
|
||||
Logger.Log<Loot>(Logger.Level.Info, "By maca134");
|
||||
Logger.Log<Loot>(Logger.Level.Info, "Please remember to donate for more cool shit!");
|
||||
Logger.Log<Loot>(Logger.Level.Info, "http://maca134.co.uk");
|
||||
Logger.Log<Loot>(Logger.Level.Info, "=====================================================================");
|
||||
|
||||
var start = DateTime.Now;
|
||||
try
|
||||
{
|
||||
_cfgGroups = CfgGroup.Load(cfgpath);
|
||||
}
|
||||
catch (CfgGroupException ex)
|
||||
{
|
||||
_hasErrored = true;
|
||||
Logger.Log<Loot>(Logger.Level.Error, $"There was an error loading the loot cfg {cfgpath}: {ex.Message}");
|
||||
throw new LootException($"There was an error loading the loot cfg {cfgpath}", ex);
|
||||
}
|
||||
foreach (var group in _cfgGroups)
|
||||
{
|
||||
var list = FlattenGroups(group);
|
||||
var table = new LootTable(group.Name, list);
|
||||
Table.Add(group.Name, table);
|
||||
}
|
||||
var span = DateTime.Now - start;
|
||||
Logger.Log<Loot>($"Took {span.Milliseconds}ms to load and parse loot cfg");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flattens cfg groups (recursive)
|
||||
/// </summary>
|
||||
/// <param name="group">Base group</param>
|
||||
/// <param name="depth">Current depth</param>
|
||||
/// <returns></returns>
|
||||
private List<LootItem> FlattenGroups(CfgGroup group, int depth = 0)
|
||||
{
|
||||
var list = new List<LootItem>();
|
||||
if (depth > MaxDepth)
|
||||
{
|
||||
Logger.Log<Loot>(Logger.Level.Warning, $"The loot table is too deep: {depth} > {MaxDepth}");
|
||||
return list;
|
||||
}
|
||||
var total = group.Items.Select(i => i.Chance).Sum();
|
||||
foreach (var item in group.Items.OrderByDescending(a => a.Chance))
|
||||
{
|
||||
var chance = (decimal)item.Chance / total;
|
||||
var child = _cfgGroups.Find(g => g.Name == item.Item);
|
||||
if (child != null)
|
||||
{
|
||||
var childlist = FlattenGroups(child, depth++);
|
||||
childlist.ForEach(i =>
|
||||
{
|
||||
list.Add(new LootItem
|
||||
{
|
||||
Item = i.Item,
|
||||
Chance = i.Chance * chance
|
||||
});
|
||||
});
|
||||
continue;
|
||||
}
|
||||
list.Add(new LootItem
|
||||
{
|
||||
Item = item.Item,
|
||||
Chance = chance
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops X amount of loot items from table
|
||||
/// </summary>
|
||||
/// <param name="table">Loot table name</param>
|
||||
/// <param name="count">Amount of items to return</param>
|
||||
/// <returns></returns>
|
||||
public string[] GetItems(string table, int count = 1)
|
||||
{
|
||||
if (!Table.ContainsKey(table))
|
||||
throw new LootTableNotFoundException($"No loot table called {table}");
|
||||
|
||||
var items = new List<string>();
|
||||
for (var i = 0; i < count; i++)
|
||||
items.Add(Table[table].Drop());
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get tables
|
||||
/// </summary>
|
||||
/// <returns>List of table names</returns>
|
||||
public string[] GetTables()
|
||||
{
|
||||
return LootTable.Table.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
25
src/ExileLootDrop/LootException.cs
Normal file
25
src/ExileLootDrop/LootException.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
[Serializable]
|
||||
internal class LootException : Exception
|
||||
{
|
||||
public LootException()
|
||||
{
|
||||
}
|
||||
|
||||
public LootException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public LootException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected LootException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
20
src/ExileLootDrop/LootItem.cs
Normal file
20
src/ExileLootDrop/LootItem.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
public class LootItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Item classname
|
||||
/// </summary>
|
||||
public string Item { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Chance for item
|
||||
/// </summary>
|
||||
public decimal Chance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cumulative
|
||||
/// </summary>
|
||||
public decimal Sum { get; set; }
|
||||
}
|
||||
}
|
52
src/ExileLootDrop/LootTable.cs
Normal file
52
src/ExileLootDrop/LootTable.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
public class LootTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Loot table name
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of loot items
|
||||
/// </summary>
|
||||
public LootItem[] LootItems { get; }
|
||||
|
||||
private readonly Random _rnd = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// LootTable constuctor
|
||||
/// </summary>
|
||||
/// <param name="name">Table name</param>
|
||||
/// <param name="lootList">Item list</param>
|
||||
public LootTable(string name, List<LootItem> lootList)
|
||||
{
|
||||
Name = name;
|
||||
var sum = 0m;
|
||||
lootList.ForEach(i =>
|
||||
{
|
||||
sum += i.Chance;
|
||||
i.Sum = sum;
|
||||
});
|
||||
LootItems = lootList.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drop a loot item
|
||||
/// </summary>
|
||||
/// <returns>Item classname</returns>
|
||||
public string Drop()
|
||||
{
|
||||
var rnd = (decimal)_rnd.NextDouble();
|
||||
foreach (var item in LootItems)
|
||||
{
|
||||
if (item.Sum >= rnd)
|
||||
return item.Item;
|
||||
}
|
||||
throw new LootException("Erm shouldnt be here... rnd more than 1? C# is broken");
|
||||
}
|
||||
}
|
||||
}
|
25
src/ExileLootDrop/LootTableNotFoundException.cs
Normal file
25
src/ExileLootDrop/LootTableNotFoundException.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ExileLootDrop
|
||||
{
|
||||
[Serializable]
|
||||
internal class LootTableNotFoundException : LootException
|
||||
{
|
||||
public LootTableNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
public LootTableNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public LootTableNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected LootTableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
35
src/ExileLootDrop/Properties/AssemblyInfo.cs
Normal file
35
src/ExileLootDrop/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DropItem")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DropItem")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f3dec0ad-f490-4761-84a5-e51240fa3d91")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
4
src/ExileLootDrop/packages.config
Normal file
4
src/ExileLootDrop/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="UnmanagedExports" version="1.2.7" targetFramework="net452" />
|
||||
</packages>
|
6
src/ExileLootDropTester/App.config
Normal file
6
src/ExileLootDropTester/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
1158
src/ExileLootDropTester/ExileLootDrop.cfg
Normal file
1158
src/ExileLootDropTester/ExileLootDrop.cfg
Normal file
File diff suppressed because it is too large
Load Diff
69
src/ExileLootDropTester/ExileLootDropTester.csproj
Normal file
69
src/ExileLootDropTester/ExileLootDropTester.csproj
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{D4C0452C-055B-4773-920B-D9C7A70EB9D6}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ExileLootDropTester</RootNamespace>
|
||||
<AssemblyName>ExileLootDropTester</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="ExileLootDrop.cfg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ExileLootDrop\ExileLootDrop.csproj">
|
||||
<Project>{f3dec0ad-f490-4761-84a5-e51240fa3d91}</Project>
|
||||
<Name>ExileLootDrop</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
68
src/ExileLootDropTester/Program.cs
Normal file
68
src/ExileLootDropTester/Program.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ExileLootDrop;
|
||||
|
||||
namespace ExileLootDropTester
|
||||
{
|
||||
class Program
|
||||
{
|
||||
const int Loops = 1000000;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Loading Loot");
|
||||
//Loot.LootTable
|
||||
Console.WriteLine();
|
||||
|
||||
var tables = Loot.LootTable.GetTables();
|
||||
for (var i = 0; i < tables.Length; i++)
|
||||
{
|
||||
var table = tables[i];
|
||||
Console.WriteLine($"{i}: {table}");
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Select a table: ");
|
||||
var input = Console.ReadLine();
|
||||
Console.WriteLine();
|
||||
int index;
|
||||
if (!int.TryParse(input, out index))
|
||||
{
|
||||
Console.WriteLine("input error");
|
||||
return;
|
||||
}
|
||||
if (index >= tables.Length)
|
||||
{
|
||||
Console.WriteLine("input out of range");
|
||||
return;
|
||||
}
|
||||
var selectedTable = tables[index];
|
||||
Console.WriteLine($"\"{selectedTable}\" selected");
|
||||
Console.WriteLine($"Calculating Loot - Running {Loops} iterations...");
|
||||
Console.WriteLine();
|
||||
|
||||
var lootdrops = new Dictionary<string, int>();
|
||||
var start = DateTime.Now;
|
||||
for (var i = 0; i < Loops - 1; i++)
|
||||
{
|
||||
var item = Loot.Invoke(selectedTable);
|
||||
if (!lootdrops.ContainsKey(item))
|
||||
lootdrops[item] = 0;
|
||||
lootdrops[item]++;
|
||||
}
|
||||
var timetaken = DateTime.Now - start;
|
||||
var items = from pair in lootdrops
|
||||
orderby pair.Value descending
|
||||
select pair;
|
||||
|
||||
foreach (var pair in items)
|
||||
{
|
||||
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Took {timetaken.TotalMilliseconds}ms to do {Loops} items - {timetaken.TotalMilliseconds / Loops}ms per item");
|
||||
Console.WriteLine("Press any key to exit");
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
}
|
36
src/ExileLootDropTester/Properties/AssemblyInfo.cs
Normal file
36
src/ExileLootDropTester/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DropItemTester")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DropItemTester")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d4c0452c-055b-4773-920b-d9c7a70eb9d6")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
Loading…
Reference in New Issue
Block a user