Compare commits

...

4 Commits
1.1.0 ... main

Author SHA1 Message Date
3015237661 BlessRNG 2023-06-29 19:30:53 +03:00
c6576c0e11 SPT-AKI 3.5.x 2023-06-21 00:59:14 +03:00
1bdddc3dc5 actual update for 3.2.2 2022-09-02 02:36:59 +03:00
1aae2f194c add loot generation code partially stolen from CWX and update for aki 3.2.2 2022-09-02 02:28:40 +03:00
10 changed files with 271 additions and 297 deletions

View File

@ -1,308 +1,105 @@
using EFT.Interactive;
using Comfort.Common;
using EFT;
using EFT.Interactive;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Aki.Custom.Airdrops.Utils;
using UnityEngine;
namespace SamSWAT.HeliCrash
{
public class HeliCrash : MonoBehaviour
{
private AssetBundle UH60Bundle;
private GameObject Choppa;
private Location HeliLocation;
private LootableContainer ChoppaContainer;
private string playerlocation;
//public GameObject fpscamera;
//private int counter = 0;
private AssetBundle _heliBundle;
public async void Init(string location)
{
playerlocation = location;
string path = Plugin.Directory + "Assets/Content/Vehicles/sikorsky_uh60_blackhawk.bundle";
var heliLocation = GetHeliCrashLocation(location);
var choppa = Instantiate(await LoadChoppaAsync(), heliLocation.Position, Quaternion.Euler(heliLocation.Rotation));
var container = choppa.GetComponentInChildren<LootableContainer>();
var itemCrate = Utils.CreateItem("goofyahcontainer", "6223349b3136504a544d1608");
LootItem.CreateLootContainer(container, itemCrate, "Heavy crate", Singleton<GameWorld>.Instance);
new ItemFactoryUtil().AddLoot(container);
}
private void OnDestroy()
{
_heliBundle.Unload(true);
}
private Location GetHeliCrashLocation(string location)
{
switch (location)
{
case "bigmap":
{
return Plugin.HeliCrashLocations.Customs.Shuffle().SelectRandom();
}
case "Interchange":
{
return Plugin.HeliCrashLocations.Interchange.Shuffle().SelectRandom();;
}
case "RezervBase":
{
return Plugin.HeliCrashLocations.Rezerv.Shuffle().SelectRandom();;
}
case "Shoreline":
{
return Plugin.HeliCrashLocations.Shoreline.Shuffle().SelectRandom();;
}
case "Woods":
{
return Plugin.HeliCrashLocations.Woods.Shuffle().SelectRandom();;
}
case "Lighthouse":
{
return Plugin.HeliCrashLocations.Lighthouse.Shuffle().SelectRandom();;
}
case "TarkovStreets":
{
return Plugin.HeliCrashLocations.StreetsOfTarkov.Shuffle().SelectRandom();;
}
case "develop":
{
return Plugin.HeliCrashLocations.Develop.Shuffle().SelectRandom();;
}
default: return new Location();
}
}
private async Task<GameObject> LoadChoppaAsync()
{
var path = $"{Plugin.Directory}/Assets/Content/Vehicles/sikorsky_uh60_blackhawk.bundle";
var bundleLoadRequest = AssetBundle.LoadFromFileAsync(path);
while (!bundleLoadRequest.isDone)
await Task.Yield();
UH60Bundle = bundleLoadRequest.assetBundle;
_heliBundle = bundleLoadRequest.assetBundle;
if (UH60Bundle == null)
if (_heliBundle == null)
{
Plugin.LogSource.LogFatal("Can't load UH-60 Blackhawk bundle");
Debug.LogError("[SamSWAT.HeliCrash]: Can't load UH-60 Blackhawk bundle");
return;
return null;
}
var assetLoadRequest = UH60Bundle.LoadAllAssetsAsync<GameObject>();
var assetLoadRequest = _heliBundle.LoadAllAssetsAsync<GameObject>();
while (!assetLoadRequest.isDone)
await Task.Yield();
Choppa = assetLoadRequest.allAssets[0] as GameObject;
var requestedGo = assetLoadRequest.allAssets[0] as GameObject;
if (Choppa == null)
{
Debug.LogError("[SamSWAT.HeliCrash]: failed to load asset");
return;
}
if (requestedGo != null) return requestedGo;
Plugin.LogSource.LogFatal("Failed to load heli asset");
Debug.LogError("[SamSWAT.HeliCrash]: failed to load heli asset");
return null;
HeliLocation = HeliCrashLocation();
Choppa = Instantiate(Choppa, HeliLocation.Position, Quaternion.Euler(HeliLocation.Rotation));
UH60Bundle.Unload(false);
ChoppaContainer = Choppa.GetComponentInChildren<LootableContainer>();
var airdropsyncobjects = LocationScene.GetAll<SynchronizableObject>().Where(x => x.GetComponent<AirdropSynchronizableObject>());
var airdropcrates = new List<LootableContainer>();
foreach(var crate in airdropsyncobjects)
{
airdropcrates.Add(crate.GetComponentInChildren<LootableContainer>());
}
FieldInfo itemOwner = typeof(LootableContainer).GetField("ItemOwner");
object items = itemOwner.GetValue(PickRandom(airdropcrates));
itemOwner.SetValue(ChoppaContainer, items);
//fpscamera = GameObject.Find("FPS Camera");
}
private Location HeliCrashLocation()
{
switch (playerlocation)
{
case "bigmap":
{
return PickRandom(Plugin.HeliCrashLocations.Customs);
}
case "Interchange":
{
return PickRandom(Plugin.HeliCrashLocations.Interchange);
}
case "RezervBase":
{
return PickRandom(Plugin.HeliCrashLocations.Rezerv);
}
case "Shoreline":
{
return PickRandom(Plugin.HeliCrashLocations.Shoreline);
}
case "Woods":
{
return PickRandom(Plugin.HeliCrashLocations.Woods);
}
case "Lighthouse":
{
return PickRandom(Plugin.HeliCrashLocations.Lighthouse);
}
case "develop":
{
return PickRandom(Plugin.HeliCrashLocations.Develop);
}
default: return new Location();
}
}
private T PickRandom<T>(List<T> list)
{
return list[Random.Range(0, list.Count)];
}
/* private void Update()
{
if (Input.GetKeyDown(KeyCode.Keypad5))
{
var cumpos = fpscamera.transform.position;
var cumrot = fpscamera.transform.eulerAngles;
Physics.Raycast(cumpos, Vector3.down, out var raycastHit, 50f);
Choppa.transform.position = new Vector3(cumpos.x, raycastHit.point.y - 0.12f, cumpos.z);
Choppa.transform.eulerAngles = new Vector3(0, cumrot.y, 0);
}
if (Input.GetKeyDown(KeyCode.Keypad6))
{
switch (playerlocation)
{
case "bigmap":
{
Plugin.heliCrashSites.Customs.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "Interchange":
{
Plugin.heliCrashSites.Interchange.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "RezervBase":
{
Plugin.heliCrashSites.Rezerv.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "Shoreline":
{
Plugin.heliCrashSites.Shoreline.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "Woods":
{
Plugin.heliCrashSites.Woods.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "Lighthouse":
{
Plugin.heliCrashSites.Lighthouse.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
case "develop":
{
Plugin.heliCrashSites.Develop.Add(new Location { Position = Choppa.transform.position, Rotation = Choppa.transform.rotation.eulerAngles });
break;
}
}
}
if (Input.GetKeyDown(KeyCode.Keypad0))
{
File.WriteAllText(Plugin.Directory + "HeliCrashLocations.json", JsonConvert.SerializeObject(Plugin.heliCrashSites));
Debug.LogError("Data has been saved to file");
}
if (Input.GetKeyDown(KeyCode.Keypad8))
{
switch (playerlocation)
{
case "bigmap":
{
if (counter < Plugin.heliCrashSites.Customs.Count)
{
var loca = Plugin.heliCrashSites.Customs[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Customs[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "Interchange":
{
if (counter < Plugin.heliCrashSites.Interchange.Count)
{
var loca = Plugin.heliCrashSites.Interchange[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Interchange[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "RezervBase":
{
if (counter < Plugin.heliCrashSites.Rezerv.Count)
{
var loca = Plugin.heliCrashSites.Rezerv[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Rezerv[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "Shoreline":
{
if (counter < Plugin.heliCrashSites.Shoreline.Count)
{
var loca = Plugin.heliCrashSites.Shoreline[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Shoreline[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "Woods":
{
if (counter < Plugin.heliCrashSites.Woods.Count)
{
var loca = Plugin.heliCrashSites.Woods[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Woods[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "Lighthouse":
{
if (counter < Plugin.heliCrashSites.Lighthouse.Count)
{
var loca = Plugin.heliCrashSites.Lighthouse[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Lighthouse[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
case "develop":
{
if (counter < Plugin.heliCrashSites.Develop.Count)
{
var loca = Plugin.heliCrashSites.Develop[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
else
{
counter = 0;
var loca = Plugin.heliCrashSites.Develop[counter];
Choppa.transform.position = loca.Position;
Choppa.transform.eulerAngles = loca.Rotation;
counter++;
}
break;
}
}
}
}*/
}
}

View File

@ -1,6 +1,8 @@
using Aki.Reflection.Patching;
using Aki.Reflection.Utils;
using Comfort.Common;
using EFT;
using EFT.Airdrop;
using System.Linq;
using System.Reflection;
using UnityEngine;
@ -11,26 +13,21 @@ namespace SamSWAT.HeliCrash
{
protected override MethodBase GetTargetMethod()
{
return typeof(GameWorld).GetMethod("OnGameStarted", BindingFlags.Public | BindingFlags.Instance);
//return PatchConstants.LocalGameType.BaseType.GetMethod("method_10", BindingFlags.NonPublic | BindingFlags.Instance);
return typeof(GameWorld).GetMethod(nameof(GameWorld.OnGameStarted));
}
[PatchPostfix]
public static void PatchPostFix()
public static void PatchPostfix()
{
var gameWorld = Singleton<GameWorld>.Instance;
var crashAvailable = LocationScene.GetAll<AirdropPoint>().Any();
string location = gameWorld.RegisteredPlayers[0].Location;
if (gameWorld != null && crashAvailable && WillHeliCrash())
{
var heliCrash = gameWorld.gameObject.AddComponent<HeliCrash>();
heliCrash.Init(location);
}
}
public static bool WillHeliCrash()
{
return Random.Range(0, 100) <= Plugin.HeliCrashChance.Value;
var location = gameWorld.RegisteredPlayers[0].Location;
if (gameWorld == null || !crashAvailable || !BlessRNG.RngBool(Plugin.HeliCrashChance.Value)) return;
var heliCrash = gameWorld.gameObject.AddComponent<HeliCrash>();
heliCrash.Init(location);
}
}
}

View File

@ -2,21 +2,25 @@
using BepInEx.Configuration;
using Newtonsoft.Json;
using System.IO;
using System.Reflection;
using BepInEx.Logging;
namespace SamSWAT.HeliCrash
{
[BepInPlugin("com.SamSWAT.HeliCrash", "SamSWAT.HeliCrash", "1.1.0")]
[BepInPlugin("com.SamSWAT.HeliCrash", "SamSWAT.HeliCrash", "2.1.0")]
public class Plugin : BaseUnityPlugin
{
public static HeliCrashLocations HeliCrashLocations;
internal static HeliCrashLocations HeliCrashLocations;
internal static string Directory;
internal static ConfigEntry<int> HeliCrashChance;
internal static ManualLogSource LogSource;
private void Awake()
{
Directory = Path.Combine(BepInEx.Paths.PluginPath, "SamSWAT.HeliCrash/").Replace("\\", "/");
LogSource = Logger;
Directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
new HeliCrashPatch().Enable();
var json = new StreamReader(Directory + "HeliCrashLocations.json").ReadToEnd();
var json = File.ReadAllText($"{Directory}/HeliCrashLocations.json");
HeliCrashLocations = JsonConvert.DeserializeObject<HeliCrashLocations>(json);
HeliCrashChance = Config.Bind(

Binary file not shown.

Binary file not shown.

View File

@ -31,10 +31,14 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="aki-custom">
<HintPath>References\aki-custom.dll</HintPath>
</Reference>
<Reference Include="Aki.Reflection">
<HintPath>References\Aki.Reflection.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>References\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="BepInEx">
@ -59,10 +63,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="HeliCrash.cs" />
<Compile Include="HeliCrashLocations.cs" />
<Compile Include="HeliCrashPatch.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\BlessRNG.cs" />
<Compile Include="Utils\HeliCrashLocations.cs" />
<Compile Include="Utils\Utils.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SamSWAT.HeliCrash
{
internal static class BlessRNG
{
private static readonly Random Rng = new Random((int) DateTime.Now.Ticks);
private static float Random(float a, float b)
{
var num = (float) Rng.NextDouble();
return a + (b - a) * num;
}
public static T SelectRandom<T>(this IReadOnlyList<T> list)
{
if (list.Count == 0)
{
return default;
}
var index = Rng.Next(0, list.Count);
return list[index];
}
public static bool RngBool(float chanceInPercent = 50f)
{
return Random(0f, 100f) < chanceInPercent;
}
internal static List<T> Shuffle<T>(this List<T> l)
{
return l.OrderBy(x => Random(0.0f, 5f)).ToList();
}
}
}

View File

@ -17,6 +17,7 @@ namespace SamSWAT.HeliCrash
public List<Location> Lighthouse { get; set; }
public List<Location> Rezerv { get; set; }
public List<Location> Shoreline { get; set; }
public List<Location> StreetsOfTarkov { get; set; }
public List<Location> Develop { get; set; }
}
}

View File

@ -0,0 +1,131 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using Comfort.Common;
using EFT.InventoryLogic;
namespace SamSWAT.HeliCrash
{
public static class Utils
{
private static CreateItemDelegate _createItemDelegate;
private delegate Item CreateItemDelegate(object instance, string id, string tplId, object diff = null);
static Utils()
{
var createItemMethod = typeof(ItemFactory).GetMethod("CreateItem");
_createItemDelegate = MethodDelegate<CreateItemDelegate>(createItemMethod, false);
}
public static Item CreateItem(string id, string tplId)
{
return _createItemDelegate(Singleton<ItemFactory>.Instance, id, tplId);
}
//stolen from kmyuhkyuk
private static DelegateType MethodDelegate<DelegateType>(MethodInfo method, bool virtualCall = true) where DelegateType : Delegate
{
if (method == null)
{
throw new ArgumentNullException(nameof(method));
}
var delegateType = typeof(DelegateType);
var declaringType = method.DeclaringType;
var delegateMethod = delegateType.GetMethod("Invoke");
var delegateParameters = delegateMethod.GetParameters();
var delegateParameterTypes = delegateParameters.Select(x => x.ParameterType).ToArray();
Type returnType;
bool needBox;
if (delegateMethod.ReturnType == typeof(object) && method.ReturnType.IsValueType)
{
returnType = typeof(object);
needBox = true;
}
else
{
returnType = method.ReturnType;
needBox = false;
}
var dmd = new DynamicMethod("OpenInstanceDelegate_" + method.Name, returnType, delegateParameterTypes);
var ilGen = dmd.GetILGenerator();
Type[] parameterTypes;
int num;
if (!method.IsStatic)
{
var parameters = method.GetParameters();
var numParameters = parameters.Length;
parameterTypes = new Type[numParameters + 1];
parameterTypes[0] = typeof(object);
for (int i = 0; i < numParameters; i++)
{
parameterTypes[i + 1] = parameters[i].ParameterType;
}
if (declaringType != null && declaringType.IsValueType)
{
ilGen.Emit(OpCodes.Ldarga_S, 0);
}
else
{
ilGen.Emit(OpCodes.Ldarg_0);
}
ilGen.Emit(OpCodes.Castclass, declaringType);
num = 1;
}
else
{
parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
num = 0;
}
for (int i = num; i < parameterTypes.Length; i++)
{
ilGen.Emit(OpCodes.Ldarg, i);
var parameterType = parameterTypes[i];
var isValueType = parameterType.IsValueType;
if (!isValueType)
{
ilGen.Emit(OpCodes.Castclass, parameterType);
}
else if (delegateParameterTypes[i] == typeof(object))
{
ilGen.Emit(OpCodes.Unbox_Any, parameterType);
}
}
if (method.IsStatic || !virtualCall)
{
ilGen.Emit(OpCodes.Call, method);
}
else
{
ilGen.Emit(OpCodes.Callvirt, method);
}
if (needBox)
{
ilGen.Emit(OpCodes.Box, method.ReturnType);
}
ilGen.Emit(OpCodes.Ret);
return (DelegateType)dmd.CreateDelegate(delegateType);
}
}
}