Skip to content

Commit

Permalink
Merge pull request #590 from sailro/dev-0.15.5.33420
Browse files Browse the repository at this point in the history
[WIP] Support for upcoming SPT 3.10, using EFT 0.15.5.33420
  • Loading branch information
sailro authored Nov 26, 2024
2 parents 499ecff + faf689a commit 6f6bcef
Show file tree
Hide file tree
Showing 36 changed files with 737 additions and 185 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ env:
CONFIGURATION: ${{ inputs.configuration != '' && inputs.configuration || 'Release' }}
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: 1
INSTALLER_DOTNET_VERSION: '8.0'
INSTALLER_DOTNET_VERSION: '9.0'
INSTALLER_PLATFORM: 'win-x64'

jobs:
Expand Down
24 changes: 0 additions & 24 deletions ConsoleCommands/BaseTemplateCommand.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Comfort.Common;
using EFT.InventoryLogic;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class BaseTemplateCommand : ConsoleCommandWithArgument
{
public override string Pattern => RequiredArgumentPattern;

protected static ItemTemplate[] FindTemplates(string searchShortNameOrTemplateId)
{
if (!Singleton<ItemFactory>.Instantiated)
return [];

var templates = Singleton<ItemFactory>
.Instance
.ItemTemplates;

// Match by TemplateId
if (templates.TryGetValue(searchShortNameOrTemplateId, out var template))
return [template];

// Match by short name(s)
return templates
.Values
.Where(t => t.ShortNameLocalizationKey.Localized().IndexOf(searchShortNameOrTemplateId, StringComparison.OrdinalIgnoreCase) >= 0
|| t.NameLocalizationKey.Localized().IndexOf(searchShortNameOrTemplateId, StringComparison.OrdinalIgnoreCase) >= 0)
.ToArray();
}
}
87 changes: 80 additions & 7 deletions ConsoleCommands/Spawn.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
Expand All @@ -10,7 +11,6 @@
using EFT.Trainer.Features;
using EFT.Trainer.Properties;
using JetBrains.Annotations;
using UnityEngine;
using Random = UnityEngine.Random;

#nullable enable
Expand All @@ -33,7 +33,7 @@ public override void Execute(Match match)
return;

var search = matchGroup.Value;
var templates = FindTemplates(search);
var templates = TemplateHelper.FindTemplates(search);

switch (templates.Length)
{
Expand All @@ -54,7 +54,7 @@ public override void Execute(Match match)

internal static void SpawnTemplate(string template, Player player, ConsoleCommand command, Func<ItemTemplate, bool> filter)
{
var result = FindTemplates(template)
var result = TemplateHelper.FindTemplates(template)
.FirstOrDefault(filter);

if (result == null)
Expand All @@ -79,21 +79,19 @@ private static void SpawnTemplate(ItemTemplate template, Player player, ConsoleC
}
else
{
var itemFactory = Singleton<ItemFactory>.Instance;
var itemFactory = Singleton<ItemFactoryClass>.Instance;
var item = itemFactory.CreateItem(MongoID.Generate(), template._id, null);
if (item == null)
{
command.AddConsoleLog(Strings.ErrorFailedToCreateItem.Red());
}
else
{
item.SpawnedInSession = true; // found in raid

_ = new TraderControllerClass(item, item.Id, item.ShortName);
var go = poolManager.CreateLootPrefab(item, ECameraType.Default);

go.SetActive(value: true);
var lootItem = Singleton<GameWorld>.Instance.CreateLootWithRigidbody(go, item, item.ShortName, Singleton<GameWorld>.Instance, randomRotation: false, null, out _);
var lootItem = Singleton<GameWorld>.Instance.CreateLootWithRigidbody(go, item, item.ShortName, randomRotation: false, null, out _, true);

var transform = player.Transform;
var position = transform.position
Expand All @@ -103,11 +101,86 @@ private static void SpawnTemplate(ItemTemplate template, Player player, ConsoleC

lootItem.transform.SetPositionAndRotation(position, transform.rotation);
lootItem.LastOwner = player;

// setup after loot item is created, else we are hitting issues with weapon
SetupItem(itemFactory, item);
}
}
});

return Task.CompletedTask;
});
}

private static void SetupItem(ItemFactoryClass itemFactory, Item item)
{
item.SpawnedInSession = true; // found in raid

if (item.TryGetItemComponent<DogtagComponent>(out var dogtag))
{
dogtag.AccountId = Random.Range(0, int.MaxValue).ToString();
dogtag.ProfileId = Random.Range(0, int.MaxValue).ToString();
dogtag.Nickname = $"Rambo{Random.Range(1, 256)}";
dogtag.Side = Enum.GetValues(typeof(EPlayerSide)).Cast<EPlayerSide>().Random();
dogtag.Level = Random.Range(1, 69);
dogtag.Time = DateTime.Now;
dogtag.Status = "died";
dogtag.KillerAccountId = Random.Range(0, int.MaxValue).ToString();
dogtag.KillerProfileId = Random.Range(0, int.MaxValue).ToString();
dogtag.KillerName = "";
dogtag.WeaponName = "";
}

if (item.TryGetItemComponent<ArmorHolderComponent>(out var armorHolder))
FillSlots(itemFactory, armorHolder.ArmorSlots);

if (item.TryGetItemComponent<RepairableComponent>(out var repairable))
{
repairable.MaxDurability = repairable.TemplateDurability;
repairable.Durability = repairable.MaxDurability;
}

if (item is CompoundItem compound)
FillSlots(itemFactory, compound.AllSlots);

if (item is IAmmoContainer container) // AmmoBox or Magazine
FillStackSlot(itemFactory, container.Cartridges);
}

private static void FillSlots(ItemFactoryClass itemFactory, IEnumerable<Slot> slots)
{
foreach (var slot in slots)
{
if (slot.Items.Any())
continue;

var filter = slot
.Filters.FirstOrDefault()?
.Filter.Random();

if (filter == null)
continue;

var item = itemFactory.CreateItem(MongoID.Generate(), filter, null);
SetupItem(itemFactory, item);

slot.AddWithoutRestrictions(item);
}
}

private static void FillStackSlot(ItemFactoryClass itemFactory, StackSlot slot)
{
var filter = slot
.Filters.FirstOrDefault()?
.Filter.Random();

if (filter == null)
return;

while (slot.Count < slot.MaxCount)
{
var item = itemFactory.CreateItem(MongoID.Generate(), filter, null);
slot.Add(item, false);
}
}
}
40 changes: 40 additions & 0 deletions ConsoleCommands/SpawnHideoutItems.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Linq;
using EFT.Trainer.Extensions;
using EFT.Trainer.Features;
using EFT.Trainer.Properties;
using HarmonyLib;
using JetBrains.Annotations;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

[UsedImplicitly]
internal class SpawnHideoutItems : ConsoleCommandWithoutArgument
{
public override string Name => Strings.CommandSpawnHideoutItems;

public override void Execute()
{
var player = GameState.Current?.LocalPlayer;
if (!player.IsValid())
return;

var manager = player.Profile?.WishlistManager;
if (manager == null)
return;

// Find the obfuscated method that returns the computed hidout items
// We need to have the auto-add hideout items enabled in EFT settings
var method = AccessTools
.GetDeclaredMethods(manager.GetType())
.FirstOrDefault(m => m.ReturnType == typeof(IEnumerable<MongoID>));

if (method?.Invoke(manager, []) is not IEnumerable<MongoID> templates)
return;

foreach (var template in templates)
Spawn.SpawnTemplate(template, player, this, i => true);
}
}
10 changes: 3 additions & 7 deletions ConsoleCommands/Template.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Linq;
using System.Text.RegularExpressions;
using Comfort.Common;
using System.Text.RegularExpressions;
using EFT.Trainer.Extensions;
using EFT.Trainer.Features;
using EFT.Trainer.Properties;
using JetBrains.Annotations;

Expand All @@ -20,12 +19,9 @@ public override void Execute(Match match)
if (matchGroup is not { Success: true })
return;

if (!Singleton<ItemFactory>.Instantiated)
return;

var search = matchGroup.Value;

var templates = FindTemplates(search).ToArray();
var templates = TemplateHelper.FindTemplates(search);

foreach (var template in templates)
AddConsoleLog(string.Format(Strings.CommandTemplateEnumerateFormat, template._id, template.ShortNameLocalizationKey.Localized().Green(), template.NameLocalizationKey.Localized()));
Expand Down
2 changes: 1 addition & 1 deletion ConsoleCommands/TrackList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal static void ShowTrackList(ConsoleCommand command, Features.LootItems lo
command.AddConsoleLog(Strings.CommandTrackListUpdated);

foreach (var templateId in lootItems.Wishlist)
command.AddConsoleLog(string.Format(Strings.CommandTrackListWishListEnumerateFormat, templateId.LocalizedShortName()));
command.AddConsoleLog(string.Format(Strings.CommandTrackListWishListEnumerateFormat, ((MongoID)templateId).LocalizedShortName()));

foreach (var item in lootItems.TrackedNames)
{
Expand Down
4 changes: 2 additions & 2 deletions Extensions/ItemExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public static bool IsFiltered(this Item item)
if (ItemViewFactory.IsSecureContainer(item))
return true;

if (item.CurrentAddress?.Container is { ParentItem.TemplateId: KnownTemplateIds.BossContainer })
if (item.CurrentAddress?.Container?.ParentItem?.TemplateId.ToString() == KnownTemplateIds.BossContainer)
return true;

return item.TemplateId switch
return item.TemplateId.ToString() switch
{
KnownTemplateIds.DefaultInventory or KnownTemplateIds.Pockets => true,
_ => false
Expand Down
2 changes: 1 addition & 1 deletion Features/Aimbot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected static bool CreateShotPrefix(object ammo, Vector3 origin, ref Vector3
}

[UsedImplicitly]
protected static bool ApplyShotPrefix(DamageInfo damageInfo, EBodyPart bodyPartType, EBodyPartColliderType colliderType, EArmorPlateCollider armorPlateCollider, object shotId, Player? __instance)
protected static bool ApplyShotPrefix(DamageInfoStruct damageInfo, EBodyPart bodyPartType, EBodyPartColliderType colliderType, EArmorPlateCollider armorPlateCollider, object shotId, Player? __instance)
{
var feature = FeatureFactory.GetFeature<Aimbot>();
if (feature == null || !feature.SilentAim || feature._silentAimTarget == null)
Expand Down
31 changes: 31 additions & 0 deletions Features/AirDrop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Linq;
using Comfort.Common;
using EFT.InventoryLogic;
using EFT.Trainer.Properties;
using JetBrains.Annotations;
using UnityEngine;

#nullable enable

namespace EFT.Trainer.Features;

[UsedImplicitly]
internal class AirDrop : TriggerFeature
{
public override string Name => Strings.FeatureAirDropName;
public override string Description => Strings.FeatureAirDropDescription;

public override KeyCode Key { get; set; } = KeyCode.None;

protected override void UpdateOnceWhenTriggered()
{
var player = GameState.Current?.LocalPlayer;
if (player == null)
return;

if (TemplateHelper.FindTemplates(KnownTemplateIds.RedSignalFlare).FirstOrDefault() is not AmmoTemplate template)
return;

player.HandleFlareSuccessEvent(player.Transform.position, template);
}
}
6 changes: 3 additions & 3 deletions Features/Ammunition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private static void ShootPostfix(object shot)
var magazine = weapon.GetCurrentMagazine();
if (magazine != null)
{
if (magazine is CylinderMagazineClass cylinderMagazine)
if (magazine is CylinderMagazineItemClass cylinderMagazine)
{
// Rhino case
foreach (var slot in cylinderMagazine.Camoras)
Expand All @@ -62,11 +62,11 @@ private static void ShootPostfix(object shot)

private static Item CreateAmmo(Item ammo)
{
var instantiated = Singleton<ItemFactory>.Instantiated;
var instantiated = Singleton<ItemFactoryClass>.Instantiated;
if (!instantiated)
return ammo;

var instance = Singleton<ItemFactory>.Instance;
var instance = Singleton<ItemFactoryClass>.Instance;
var itemId = Guid.NewGuid().ToString("N").Substring(0, 24);
return instance.CreateItem(itemId, ammo.TemplateId, null) ?? ammo;
}
Expand Down
4 changes: 4 additions & 0 deletions Features/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ protected override void Update()
if (!PreloaderUI.Instantiated)
return;

#if DEBUG
ConsoleScreen.IAmDevShowMeLogs = true;
#endif

RegisterPropertyDisplays();
RegisterCommands();
}
Expand Down
20 changes: 10 additions & 10 deletions Features/Examine.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using EFT.InventoryLogic;
using EFT.Trainer.ConsoleCommands;
using EFT.Trainer.Properties;
using JetBrains.Annotations;
using static EFT.Player;

#nullable enable

Expand All @@ -22,32 +24,30 @@ protected static bool ExaminedPrefix(ref bool __result)
return true; // keep using original code, we are not enabled

__result = true;
return false; // skip the original code and all other prefix methods
return false; // skip the original code and all other prefix methods
}

#pragma warning disable IDE0060
[UsedImplicitly]
protected static bool GetSearchStatePrefix(SearchableItemClass __instance)
protected static bool SinglePlayerInventoryControllerConstructorPrefix(Player player, Profile profile, bool isBot, ref bool examined)
{
var feature = FeatureFactory.GetFeature<Examine>();
if (feature == null || !feature.Enabled)
return true; // keep using original code, we are not enabled

var player = GameState.Current?.LocalPlayer;
if (player == null)
return true;

__instance.UncoverAll(player.ProfileId);
// this will make the game use the passthrough type implementing IPlayerSearchController, ISearchController with all items known and searched
examined = true;
return true;
}

#pragma warning restore IDE0060

protected override void UpdateWhenEnabled()
{
HarmonyPatchOnce(harmony =>
{
HarmonyPrefix(harmony, typeof(Profile), nameof(Profile.Examined), nameof(ExaminedPrefix), [typeof(string)]);
HarmonyPrefix(harmony, typeof(Profile), nameof(Profile.Examined), nameof(ExaminedPrefix), [typeof(MongoID)]);
HarmonyPrefix(harmony, typeof(Profile), nameof(Profile.Examined), nameof(ExaminedPrefix), [typeof(Item)]);
HarmonyPrefix(harmony, typeof(SearchableItemClass), nameof(SearchableItemClass.GetSearchState), nameof(GetSearchStatePrefix));
HarmonyConstructorPrefix(harmony, typeof(SinglePlayerInventoryController), nameof(SinglePlayerInventoryControllerConstructorPrefix), [typeof(Player), typeof(Profile), typeof(bool), typeof(bool)]);
});
}
}
Loading

0 comments on commit 6f6bcef

Please sign in to comment.