mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 09:50:43 -05:00
Depends on SPT-AKI/SPT-AssemblyTool#3 * Refactored Modules for better consistency and general readability, along with preparing the code for a publicized assembly * Added `PublicDeclaredFlags` to `PatchConstants` to cover a set of commonly used flags to get methods post-publicizing * Added a replacement to LINQ's `.Single()` - `.SingleCustom()` which has improved logging to help with debugging Module code. Replaced all `.Single()` usages where applicable * Replaced most method info fetching with `AccessTools` for consistency and better readability, especially in places where methods were being retrieved by their name anyways **NOTE:** As a side effect of publicizing all properties, some property access code such as `Player.Position` will now show "ambiguous reference" errors during compile, due to there being multiple interfaces with the Property name being defined on the class. The way to get around this is to use a cast to an explicit interface Example: ```cs Singleton<GameWorld>.Instance.MainPlayer.Position ``` will now need to be ```cs ((IPlayer)Singleton<GameWorld>.Instance.MainPlayer).Position ``` Co-authored-by: Terkoiz <terkoiz@spt.dev> Reviewed-on: SPT-AKI/Modules#58 Co-authored-by: Terkoiz <terkoiz@noreply.dev.sp-tarkov.com> Co-committed-by: Terkoiz <terkoiz@noreply.dev.sp-tarkov.com>
73 lines
2.7 KiB
C#
73 lines
2.7 KiB
C#
using Aki.Common.Utils;
|
|
using Aki.Reflection.Patching;
|
|
using BepInEx.Bootstrap;
|
|
using EFT.Communications;
|
|
using EFT.UI;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
namespace Aki.SinglePlayer.Patches.MainMenu
|
|
{
|
|
/***
|
|
* On the first show of the main menu, check if any BepInEx plugins have failed to load, and inform
|
|
* the user. This is done via a toast in the bottom right, with a more detailed console message, as
|
|
* well as having the errors forwarded to the server console
|
|
**/
|
|
internal class PluginErrorNotifierPatch : ModulePatch
|
|
{
|
|
private static bool _messageShown = false;
|
|
|
|
protected override MethodBase GetTargetMethod()
|
|
{
|
|
// We don't really care which "Show" method is returned - either will do
|
|
return typeof(MenuScreen).GetMethods().First(m => m.Name == nameof(MenuScreen.Show));
|
|
}
|
|
|
|
[PatchPostfix]
|
|
private static void PatchPostfix()
|
|
{
|
|
var failedPluginCount = Chainloader.DependencyErrors.Count;
|
|
|
|
// Skip if we've already shown the message, or there are no errors
|
|
if (_messageShown || failedPluginCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Show a toast in the bottom right of the screen indicating how many plugins failed to load
|
|
var consoleHeaderMessage = $"{failedPluginCount} plugin{(failedPluginCount > 1 ? "s" : "")} failed to load due to errors";
|
|
var toastMessage = $"{consoleHeaderMessage}. Please check the console for details.";
|
|
NotificationManagerClass.DisplayMessageNotification(toastMessage, ENotificationDurationType.Infinite, ENotificationIconType.Alert, Color.red);
|
|
|
|
// Build the error message we'll put in the BepInEx and in-game consoles
|
|
var stringBuilder = new StringBuilder();
|
|
stringBuilder.AppendLine($"{consoleHeaderMessage}:");
|
|
foreach (string error in Chainloader.DependencyErrors)
|
|
{
|
|
stringBuilder.AppendLine(error);
|
|
}
|
|
var errorMessage = stringBuilder.ToString();
|
|
|
|
// Show an error in the BepInEx console/log file
|
|
Logger.LogError(errorMessage);
|
|
|
|
// Show errors in the server console
|
|
ServerLog.Error("Aki.Singleplayer", errorMessage);
|
|
|
|
// Show an error in the in-game console, we have to write this in reverse order because the
|
|
// in-game console shows newer messages at the top
|
|
foreach (string line in errorMessage.Split('\n').Reverse())
|
|
{
|
|
if (line.Length > 0)
|
|
{
|
|
ConsoleScreen.LogError(line);
|
|
}
|
|
}
|
|
|
|
_messageShown = true;
|
|
}
|
|
}
|
|
}
|