Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor commands #488

Merged
merged 4 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions ConsoleCommands/BaseListCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using EFT.InventoryLogic;
using EFT.Trainer.Extensions;
using EFT.Trainer.Features;
using JsonType;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System;
using System.Linq;
using Comfort.Common;
using EFT.Interactive;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class BaseListCommand : LootItemsRelatedCommand
{
public override string Pattern => OptionalArgumentPattern;
protected virtual ELootRarity? Rarity => null;

public override void Execute(Match match)
{
ListLootItems(match, Rarity);
}

private void ListLootItems(Match match, ELootRarity? rarityFilter = null)
{
var search = string.Empty;
var matchGroup = match.Groups[ValueGroup];
if (matchGroup is {Success: true})
{
search = matchGroup.Value.Trim();
if (search == TrackedItem.MatchAll)
search = string.Empty;
}

var world = Singleton<GameWorld>.Instance;
if (world == null)
return;

var itemsPerName = new Dictionary<string, List<Item>>();

// Step 1 - look outside containers and inside corpses (loot items)
FindLootItems(world, itemsPerName);

// Step 2 - look inside containers (items)
if (LootItems.SearchInsideContainers)
FindItemsInContainers(world, itemsPerName);

var names = itemsPerName.Keys.ToList();
names.Sort();
names.Reverse();

var count = 0;
foreach (var itemName in names)
{
if (itemName.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0)
continue;

var list = itemsPerName[itemName];
var rarity = list.First().Template.GetEstimatedRarity();
if (rarityFilter.HasValue && rarityFilter.Value != rarity)
continue;

var extra = rarity != ELootRarity.Not_exist ? $" ({rarity.Color()})" : string.Empty;
AddConsoleLog($"{itemName} [{list.Count.ToString().Cyan()}]{extra}");

count += list.Count;
}

AddConsoleLog("------");
AddConsoleLog($"found {count.ToString().Cyan()} item(s)");
sailro marked this conversation as resolved.
Show resolved Hide resolved
}

private static void FindItemsInRootItem(Dictionary<string, List<Item>> itemsPerName, Item? rootItem)
{
var items = rootItem?
.GetAllItems()?
.ToArray();

if (items == null)
return;

IndexItems(items, itemsPerName);
}

private void FindLootItems(GameWorld world, Dictionary<string, List<Item>> itemsPerName)
{
var lootItems = world.LootItems;
var filteredItems = new List<Item>();
for (var i = 0; i < lootItems.Count; i++)
{
var lootItem = lootItems.GetByIndex(i);
if (!lootItem.IsValid())
continue;

if (lootItem is Corpse corpse)
{
if (LootItems.SearchInsideCorpses)
FindItemsInRootItem(itemsPerName, corpse.ItemOwner?.RootItem);

continue;
}

filteredItems.Add(lootItem.Item);
}

IndexItems(filteredItems, itemsPerName);
}

private static void IndexItems(IEnumerable<Item> items, Dictionary<string, List<Item>> itemsPerName)
{
foreach (var item in items)
{
if (!item.IsValid() || item.IsFiltered())
continue;

var itemName = item.ShortName.Localized();
if (!itemsPerName.TryGetValue(itemName, out var pnList))
{
pnList = [];
itemsPerName[itemName] = pnList;
}

pnList.Add(item);
}
}

private static void FindItemsInContainers(GameWorld world, Dictionary<string, List<Item>> itemsPerName)
{
var owners = world.ItemOwners; // contains all containers: corpses, LootContainers, ...
foreach (var owner in owners)
{
var rootItem = owner.Key.RootItem;
if (rootItem is not { IsContainer: true })
continue;

if (!rootItem.IsValid() || rootItem.IsFiltered()) // filter default inventory container here, given we special case the corpse container
continue;

FindItemsInRootItem(itemsPerName, rootItem);
}
}
}
34 changes: 34 additions & 0 deletions ConsoleCommands/BaseTemplateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using EFT.InventoryLogic;
using System.Collections.Generic;
using System.Linq;
using Comfort.Common;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

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

protected static IEnumerable<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);
}
}
35 changes: 35 additions & 0 deletions ConsoleCommands/BaseTrackCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using EFT.Trainer.Configuration;
using EFT.Trainer.Extensions;
using JsonType;
using System.Text.RegularExpressions;
using UnityEngine;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class BaseTrackCommand : LootItemsRelatedCommand
{
private static string ColorNames => string.Join("|", ColorConverter.ColorNames());
public override string Pattern => $"(?<{ValueGroup}>.+?)(?<{ExtraGroup}> ({ColorNames}|\\[[\\.,\\d ]*\\]{{1}}))?";
protected virtual ELootRarity? Rarity => null;

public override void Execute(Match match)
{
TrackLootItem(match, Rarity);
}

private void TrackLootItem(Match match, ELootRarity? rarity = null)
{
var matchGroup = match.Groups[ValueGroup];
if (matchGroup is not {Success: true})
return;

Color? color = null;
var extraGroup = match.Groups[ExtraGroup];
if (extraGroup is {Success: true})
color = ColorConverter.Parse(extraGroup.Value);

TrackList.ShowTrackList(this, LootItems, LootItems.Track(matchGroup.Value, color, rarity));
}
}
31 changes: 31 additions & 0 deletions ConsoleCommands/BaseTrackListCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.RegularExpressions;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class BaseTrackListCommand : LootItemsRelatedCommand
{
public override string Pattern => RequiredArgumentPattern;

protected static bool TryGetTrackListFilename(Match match, [NotNullWhen(true)] out string? filename)
{
filename = null;

var matchGroup = match.Groups[ValueGroup];
if (matchGroup is not {Success: true})
return false;

filename = matchGroup.Value;

if (!Path.IsPathRooted(filename))
filename = Path.Combine(Context.UserPath, filename);

if (!Path.HasExtension(filename))
filename += ".tl";

return true;
}
}
15 changes: 15 additions & 0 deletions ConsoleCommands/BuiltInCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal class BuiltInCommand(string name, Action action) : ConsoleCommandWithoutArgument
{
public override string Name => name;

public override void Execute()
{
action();
}
}
18 changes: 18 additions & 0 deletions ConsoleCommands/ConsoleCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using EFT.UI;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class ConsoleCommand
{
public abstract string Name { get; }

internal void AddConsoleLog(string log)
{
if (PreloaderUI.Instantiated)
ConsoleScreen.Log(log);
}

public abstract void Register();
}
38 changes: 38 additions & 0 deletions ConsoleCommands/ConsoleCommandWithArgument.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Text.RegularExpressions;
using EFT.UI;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class ConsoleCommandWithArgument : ConsoleCommand
{
public abstract string Pattern { get; }

public abstract void Execute(Match match);

protected const string ValueGroup = "value";
protected const string ExtraGroup = "extra";

protected const string RequiredArgumentPattern = $"(?<{ValueGroup}>.+)";
protected const string OptionalArgumentPattern = $"(?<{ValueGroup}>.*)";

public override void Register()
{
#if DEBUG
AddConsoleLog($"Registering {Name} command with arguments...");
#endif
ConsoleScreen.Processor.RegisterCommand(Name, (string args) =>
{
var regex = new Regex("^" + Pattern + "$");
if (regex.IsMatch(args))
{
Execute(regex.Match(args));
}
else
{
ConsoleScreen.LogError("Invalid arguments");
}
});
}
}
18 changes: 18 additions & 0 deletions ConsoleCommands/ConsoleCommandWithoutArgument.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using EFT.UI;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

internal abstract class ConsoleCommandWithoutArgument : ConsoleCommand
{
public abstract void Execute();

public override void Register()
{
#if DEBUG
AddConsoleLog($"Registering {Name} command...");
#endif
ConsoleScreen.Processor.RegisterCommand(Name, Execute);
}
}
54 changes: 54 additions & 0 deletions ConsoleCommands/Dump.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.IO;
using EFT.Trainer.Features;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.SceneManagement;

#nullable enable

namespace EFT.Trainer.ConsoleCommands;

[UsedImplicitly]
internal class Dump : ConsoleCommandWithoutArgument
{
public override string Name => "dump";

public override void Execute()
{
var dumpfolder = Path.Combine(Context.UserPath, "Dumps");
var thisDump = Path.Combine(dumpfolder, $"{DateTime.Now:yyyyMMdd-HHmmss}");

Directory.CreateDirectory(thisDump);

AddConsoleLog("Dumping scenes...");
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (!scene.isLoaded)
continue;

var json = SceneDumper.DumpScene(scene).ToPrettyJson();
File.WriteAllText(Path.Combine(thisDump, GetSafeFilename($"@scene - {scene.name}.txt")), json);
}

AddConsoleLog("Dumping game objects...");
foreach (var go in UnityEngine.Object.FindObjectsOfType<GameObject>())
{
if (go == null || go.transform.parent != null || !go.activeSelf)
continue;

var filename = GetSafeFilename(go.name + "-" + go.GetHashCode() + ".txt");
var json = SceneDumper.DumpGameObject(go).ToPrettyJson();
File.WriteAllText(Path.Combine(thisDump, filename), json);
}

AddConsoleLog($"Dump created in {thisDump}");
}

private static string GetSafeFilename(string filename)
{
return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));
}

}
Loading