Add project files.

This commit is contained in:
DrakiaXYZ
2024-04-21 22:10:38 -07:00
parent 2276c7cdec
commit e66681c90a
10 changed files with 671 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
/// <summary>
/// Class that specifies how a setting should be displayed inside the ConfigurationManager settings window.
///
/// Usage:
/// This class template has to be copied inside the plugin's project and referenced by its code directly.
/// make a new instance, assign any fields that you want to override, and pass it as a tag for your setting.
///
/// If a field is null (default), it will be ignored and won't change how the setting is displayed.
/// If a field is non-null (you assigned a value to it), it will override default behavior.
/// </summary>
///
/// <example>
/// Here's an example of overriding order of settings and marking one of the settings as advanced:
/// <code>
/// // Override IsAdvanced and Order
/// Config.Bind("X", "1", 1, new ConfigDescription("", null, new ConfigurationManagerAttributes { IsAdvanced = true, Order = 3 }));
/// // Override only Order, IsAdvanced stays as the default value assigned by ConfigManager
/// Config.Bind("X", "2", 2, new ConfigDescription("", null, new ConfigurationManagerAttributes { Order = 1 }));
/// Config.Bind("X", "3", 3, new ConfigDescription("", null, new ConfigurationManagerAttributes { Order = 2 }));
/// </code>
/// </example>
///
/// <remarks>
/// You can read more and see examples in the readme at https://github.com/BepInEx/BepInEx.ConfigurationManager
/// You can optionally remove fields that you won't use from this class, it's the same as leaving them null.
/// </remarks>
#pragma warning disable 0169, 0414, 0649
internal sealed class ConfigurationManagerAttributes
{
/// <summary>
/// Should the setting be shown as a percentage (only use with value range settings).
/// </summary>
public bool? ShowRangeAsPercent;
/// <summary>
/// Custom setting editor (OnGUI code that replaces the default editor provided by ConfigurationManager).
/// See below for a deeper explanation. Using a custom drawer will cause many of the other fields to do nothing.
/// </summary>
public System.Action<BepInEx.Configuration.ConfigEntryBase> CustomDrawer;
/// <summary>
/// Custom setting editor that allows polling keyboard input with the Input (or UnityInput) class.
/// Use either CustomDrawer or CustomHotkeyDrawer, using both at the same time leads to undefined behaviour.
/// </summary>
public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
/// <summary>
/// Custom setting draw action that allows polling keyboard input with the Input class.
/// Note: Make sure to focus on your UI control when you are accepting input so user doesn't type in the search box or in another setting (best to do this on every frame).
/// If you don't draw any selectable UI controls You can use `GUIUtility.keyboardControl = -1;` on every frame to make sure that nothing is selected.
/// </summary>
/// <example>
/// CustomHotkeyDrawer = (ConfigEntryBase setting, ref bool isEditing) =>
/// {
/// if (isEditing)
/// {
/// // Make sure nothing else is selected since we aren't focusing on a text box with GUI.FocusControl.
/// GUIUtility.keyboardControl = -1;
///
/// // Use Input.GetKeyDown and others here, remember to set isEditing to false after you're done!
/// // It's best to check Input.anyKeyDown and set isEditing to false immediately if it's true,
/// // so that the input doesn't have a chance to propagate to the game itself.
///
/// if (GUILayout.Button("Stop"))
/// isEditing = false;
/// }
/// else
/// {
/// if (GUILayout.Button("Start"))
/// isEditing = true;
/// }
///
/// // This will only be true when isEditing is true and you hold any key
/// GUILayout.Label("Any key pressed: " + Input.anyKey);
/// }
/// </example>
/// <param name="setting">
/// Setting currently being set (if available).
/// </param>
/// <param name="isCurrentlyAcceptingInput">
/// Set this ref parameter to true when you want the current setting drawer to receive Input events.
/// The value will persist after being set, use it to see if the current instance is being edited.
/// Remember to set it to false after you are done!
/// </param>
public delegate void CustomHotkeyDrawerFunc(BepInEx.Configuration.ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
/// <summary>
/// Show this setting in the settings screen at all? If false, don't show.
/// </summary>
public bool? Browsable;
/// <summary>
/// Category the setting is under. Null to be directly under the plugin.
/// </summary>
public string Category;
/// <summary>
/// If set, a "Default" button will be shown next to the setting to allow resetting to default.
/// </summary>
public object DefaultValue;
/// <summary>
/// Force the "Reset" button to not be displayed, even if a valid DefaultValue is available.
/// </summary>
public bool? HideDefaultButton;
/// <summary>
/// Force the setting name to not be displayed. Should only be used with a <see cref="CustomDrawer"/> to get more space.
/// Can be used together with <see cref="HideDefaultButton"/> to gain even more space.
/// </summary>
public bool? HideSettingName;
/// <summary>
/// Optional description shown when hovering over the setting.
/// Not recommended, provide the description when creating the setting instead.
/// </summary>
public string Description;
/// <summary>
/// Name of the setting.
/// </summary>
public string DispName;
/// <summary>
/// Order of the setting on the settings list relative to other settings in a category.
/// 0 by default, higher number is higher on the list.
/// </summary>
public int? Order;
/// <summary>
/// Only show the value, don't allow editing it.
/// </summary>
public bool? ReadOnly;
/// <summary>
/// If true, don't show the setting by default. User has to turn on showing advanced settings or search for it.
/// </summary>
public bool? IsAdvanced;
/// <summary>
/// Custom converter from setting type to string for the built-in editor textboxes.
/// </summary>
public System.Func<object, string> ObjToStr;
/// <summary>
/// Custom converter from string to setting type for the built-in editor textboxes.
/// </summary>
public System.Func<string, object> StrToObj;
}

49
Helpers/Settings.cs Normal file
View File

@@ -0,0 +1,49 @@
using BepInEx.Configuration;
using System;
using System.Collections.Generic;
namespace DrakiaXYZ.LootRadius.Helpers
{
internal class Settings
{
public const string GeneralSectionTitle = "1. General";
public static ConfigFile Config;
public static ConfigEntry<float> LootRadius;
public static List<ConfigEntryBase> ConfigEntries = new List<ConfigEntryBase>();
public static void Init(ConfigFile Config)
{
Settings.Config = Config;
ConfigEntries.Add(LootRadius = Config.Bind(
GeneralSectionTitle,
"Loot Radius",
2f,
new ConfigDescription(
"The distance to include loot from. Note that increasing this may result in pulling loot through walls/floors",
null,
new ConfigurationManagerAttributes { })));
RecalcOrder();
}
private static void RecalcOrder()
{
// Set the Order field for all settings, to avoid unnecessary changes when adding new settings
int settingOrder = ConfigEntries.Count;
foreach (var entry in ConfigEntries)
{
ConfigurationManagerAttributes attributes = entry.Description.Tags[0] as ConfigurationManagerAttributes;
if (attributes != null)
{
attributes.Order = settingOrder;
}
settingOrder--;
}
}
}
}

40
Helpers/Utils.cs Normal file
View File

@@ -0,0 +1,40 @@
using Comfort.Common;
using EFT;
using EFT.Interactive;
using HarmonyLib;
using System.Collections;
using System.Reflection;
namespace DrakiaXYZ.LootRadius.Helpers
{
internal class Utils
{
private static FieldInfo _lootListField;
public static LootItem FindLootById(string id)
{
if (_lootListField == null)
{
_lootListField = AccessTools.Field(typeof(GameWorld), "LootList");
}
IList lootList = _lootListField.GetValue(Singleton<GameWorld>.Instance) as IList;
foreach (var loot in lootList)
{
// We only care about loot items
if (!(loot is LootItem))
{
continue;
}
LootItem lootItem = (LootItem)loot;
if (lootItem.ItemId == id)
{
return lootItem;
}
}
return null;
}
}
}

22
LootRadiusPlugin.cs Normal file
View File

@@ -0,0 +1,22 @@
using BepInEx;
using DrakiaXYZ.LootRadius.Helpers;
using DrakiaXYZ.LootRadius.Patches;
namespace DrakiaXYZ.LootRadius
{
[BepInPlugin("xyz.drakia.lootradius", "DrakiaXYZ-LootRadius", "1.0.0")]
[BepInDependency("com.spt-aki.core", "3.8.0")]
public class LootRadiusPlugin : BaseUnityPlugin
{
public static StashClass RadiusStash;
private void Awake()
{
Settings.Init(Config);
new GameStartedPatch().Enable();
new LootPanelOpenPatch().Enable();
new LootPanelClosePatch().Enable();
}
}
}

View File

@@ -0,0 +1,51 @@
using Aki.Reflection.Patching;
using EFT.InventoryLogic;
using EFT;
using System;
using System.Reflection;
using Comfort.Common;
namespace DrakiaXYZ.LootRadius.Patches
{
public class GameStartedPatch : ModulePatch
{
private static StashClass _stash {
get { return LootRadiusPlugin.RadiusStash; }
set { LootRadiusPlugin.RadiusStash = value; }
}
protected override MethodBase GetTargetMethod()
{
return typeof(GameWorld).GetMethod(nameof(GameWorld.OnGameStarted));
}
[PatchPostfix]
public static void PatchPostfix()
{
// Setup the radius stash on raid start
if (_stash == null)
{
// Create our fake stash, note we use "fake" here to have the label show as "LOOT"
_stash = Singleton<ItemFactory>.Instance.CreateFakeStash("fake");
StashGridClass stashGridClass = new StashGridClass(_stash.Id, 10, 10, true, false, Array.Empty<ItemFilter>(), _stash);
_stash.Grids = new StashGridClass[] { stashGridClass };
var traderController = new TraderControllerClass(_stash, "RadiusStash", "Nearby Items", false, EOwnerType.Profile, null, null);
// Destroy the loot item from the world when we take it
traderController.RemoveItemEvent += (GEventArgs3 args) => {
// Only trigger on Success
if (args.Status != CommandStatus.Succeed)
{
return;
}
// Only destroy if it exists, to avoid throwing errors
if (Helpers.Utils.FindLootById(args.Item.Id) != null)
{
Singleton<GameWorld>.Instance.DestroyLoot(args.Item.Id);
}
};
}
}
}
}

View File

@@ -0,0 +1,61 @@
using Aki.Reflection.Patching;
using EFT.UI;
using EFT;
using System;
using System.Linq;
using System.Reflection;
using Comfort.Common;
using HarmonyLib;
using EFT.InventoryLogic;
namespace DrakiaXYZ.LootRadius.Patches
{
public class LootPanelClosePatch : ModulePatch
{
private static MethodInfo _addMethod;
private static StashClass _stash
{
get { return LootRadiusPlugin.RadiusStash; }
set { LootRadiusPlugin.RadiusStash = value; }
}
protected override MethodBase GetTargetMethod()
{
_addMethod = AccessTools.Method(typeof(ItemAddress), "Add");
return typeof(ItemsPanel).GetMethod(nameof(ItemsPanel.Close));
}
[PatchPostfix]
public static void PatchPostfix()
{
if (_stash == null)
{
return;
}
var grid = _stash.Grids[0];
// Store a copy of the items, so we can restore their state or throw them as loose loot
var items = grid.Items.ToList();
// Clear all the items
grid.RemoveAll();
// Restore items and throw as loose loot, as necessary
foreach (var item in items)
{
// If the original address is null, or the item isn't in the loose loot pool, it's a discarded item
if (item.OriginalAddress == null || Helpers.Utils.FindLootById(item.Id) == null)
{
Singleton<GameWorld>.Instance.ThrowItem(item, Singleton<GameWorld>.Instance.MainPlayer, null);
}
else
{
_addMethod.Invoke(item.OriginalAddress, new object[] { item, Array.Empty<string>(), false });
}
}
}
}
}

View File

@@ -0,0 +1,101 @@
using Aki.Reflection.Patching;
using EFT.Interactive;
using EFT.UI;
using EFT;
using HarmonyLib;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;
using Comfort.Common;
using DrakiaXYZ.LootRadius.Helpers;
using EFT.InventoryLogic;
namespace DrakiaXYZ.LootRadius.Patches
{
public class LootPanelOpenPatch : ModulePatch
{
private static FieldInfo _stashViewField;
private static FieldInfo _rightPaneField;
private static MethodInfo _addMethod;
private static MethodInfo _removeMethod;
private static LayerMask _interactiveLayerMask = 1 << LayerMask.NameToLayer("Interactive");
private static StashClass _stash
{
get { return LootRadiusPlugin.RadiusStash; }
set { LootRadiusPlugin.RadiusStash = value; }
}
protected override MethodBase GetTargetMethod()
{
_addMethod = AccessTools.Method(typeof(StashGridClass), "Add", new Type[] { typeof(Item) });
_removeMethod = AccessTools.Method(typeof(ItemAddress), "Remove");
// Find the stash interface variable, based on the implemented types of the SimpleStashPanel
Type stashInterfaceType = null;
Type[] stashInterfaceTypes = typeof(SimpleStashPanel).GetInterfaces();
foreach (Type type in stashInterfaceTypes)
{
if (type.Name.StartsWith("GInterface"))
{
stashInterfaceType = type;
break;
}
}
_stashViewField = AccessTools.GetDeclaredFields(typeof(ItemsPanel)).Single(x => x.FieldType == stashInterfaceType);
// Find the variable that stores the right hand grid in the ItemUiContext, so we can Ctrl+Click
_rightPaneField = AccessTools.GetDeclaredFields(typeof(ItemUiContext)).Single(x => x.FieldType == typeof(LootItemClass[]));
return typeof(ItemsPanel).GetMethod(nameof(ItemsPanel.Show));
}
[PatchPostfix]
public static async void PatchPostfix(
ItemsPanel __instance,
Task __result,
ItemContextAbstractClass sourceContext,
LootItemClass lootItem,
InventoryControllerClass inventoryController,
ItemsPanel.EItemsTab currentTab,
SimpleStashPanel ____simpleStashPanel
)
{
// Wait for original to finish
await __result;
// If lootItem isn't null, don't do anything, it means there's a right hand panel already
if (lootItem != null)
{
return;
}
// Collect the items around the player, and add them to the fake stash
var grid = _stash.Grids[0];
Vector3 playerPosition = Singleton<GameWorld>.Instance.MainPlayer.Position;
Collider[] colliders = Physics.OverlapSphere(playerPosition, Settings.LootRadius.Value, _interactiveLayerMask);
if (colliders.Length > 0)
{
foreach (Collider collider in colliders)
{
var item = collider.gameObject.GetComponentInParent<LootItem>();
if (item != null && item.Item.Parent.Container != grid)
{
item.Item.OriginalAddress = item.Item.CurrentAddress;
_removeMethod.Invoke(item.Item.CurrentAddress, new object[] { item.Item, string.Empty, false });
_addMethod.Invoke(grid, new object[] { item.Item });
}
}
}
// Show the stash in the inventory panel
____simpleStashPanel.Configure(_stash, inventoryController, sourceContext.CreateChild(_stash));
_stashViewField.SetValue(__instance, ____simpleStashPanel);
____simpleStashPanel.Show(inventoryController, currentTab);
_rightPaneField.SetValue(ItemUiContext.Instance, new LootItemClass[] { _stash });
}
}
}

View 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("DrakiaXYZ-LootRadius")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DrakiaXYZ-LootRadius")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[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("527d490b-c576-49f4-8ec4-d34fd57c5bff")]
// 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")]

137
SPT-LootRadius.csproj Normal file
View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" 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>{527D490B-C576-49F4-8EC4-D34FD57C5BFF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DrakiaXYZ.LootRadius</RootNamespace>
<AssemblyName>DrakiaXYZ-LootRadius</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</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>
</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>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\..\BepInEx\core\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Aki.Build">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Aki.Build.dll</HintPath>
</Reference>
<Reference Include="Aki.Common">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Aki.Common.dll</HintPath>
</Reference>
<Reference Include="Aki.Reflection">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Aki.Reflection.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="BepInEx">
<HintPath>..\..\BepInEx\core\BepInEx.dll</HintPath>
</Reference>
<Reference Include="Comfort">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
</Reference>
<Reference Include="Comfort.Unity, Version=1.0.0.4, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Comfort.Unity.dll</HintPath>
</Reference>
<Reference Include="DissonanceVoip, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\DissonanceVoip.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Sirenix.Serialization, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Sirenix.Serialization.dll</HintPath>
</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" />
<Reference Include="Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\Unity.TextMeshPro.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\EscapeFromTarkov_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference>
</ItemGroup>
<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="Helpers\ConfigurationManagerAttributes.cs" />
<Compile Include="Helpers\Settings.cs" />
<Compile Include="Helpers\Utils.cs" />
<Compile Include="LootRadiusPlugin.cs" />
<Compile Include="Patches\GameStartedPatch.cs" />
<Compile Include="Patches\LootPanelClosePatch.cs" />
<Compile Include="Patches\LootPanelOpenPatch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy "$(TargetPath)" "$(ProjectDir)\..\..\BepInEx\plugins\$(TargetFileName)"</PostBuildEvent>
</PropertyGroup>
</Project>

25
SPT-LootRadius.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34316.72
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SPT-LootRadius", "SPT-LootRadius.csproj", "{527D490B-C576-49F4-8EC4-D34FD57C5BFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{527D490B-C576-49F4-8EC4-D34FD57C5BFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{527D490B-C576-49F4-8EC4-D34FD57C5BFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{527D490B-C576-49F4-8EC4-D34FD57C5BFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{527D490B-C576-49F4-8EC4-D34FD57C5BFF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5BF5B272-9FE7-40C5-A406-3C2A02AC91E2}
EndGlobalSection
EndGlobal