// // NosBrowserManager.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Diagnostics; using Microsoft.Extensions.Options; using NosSmooth.LocalBinding.Errors; using NosSmooth.LocalBinding.Options; using NosSmooth.LocalBinding.Structs; using Reloaded.Memory.Sigscan; using Reloaded.Memory.Sources; using Remora.Results; namespace NosSmooth.LocalBinding; /// /// Used for browsing a nostale process data. /// public class NosBrowserManager { /// /// Checks whether the given process is a NosTale client process. /// /// /// This is just a guess based on presence of "NostaleData" directory. /// /// The process to check. /// Whether the process is a NosTale client. public static bool IsProcessNostaleProcess(Process process) { if (process.MainModule is null) { return false; } var processDirectory = Path.GetDirectoryName(process.MainModule.FileName); if (processDirectory is null) { return false; } return Directory.Exists(Path.Combine(processDirectory, "NostaleData")); } /// /// Get all running nostale processes. /// /// The nostale processes. public static IEnumerable GetAllNostaleProcesses() => Process .GetProcesses() .Where(IsProcessNostaleProcess); private readonly PlayerManagerOptions _playerManagerOptions; private readonly SceneManagerOptions _sceneManagerOptions; private readonly PetManagerOptions _petManagerOptions; private readonly NetworkManagerOptions _networkManagerOptions; private readonly UnitManagerOptions _unitManagerOptions; private readonly NtClientOptions _ntClientOptions; private PlayerManager? _playerManager; private SceneManager? _sceneManager; private PetManagerList? _petManagerList; private NetworkManager? _networkManager; private UnitManager? _unitManager; private NtClient? _ntClient; /// /// Initializes a new instance of the class. /// /// The options for obtaining player manager. /// The scene manager options. /// The pet manager options. /// The network manager options. /// The unit manager options. /// The nt client options. public NosBrowserManager ( IOptionsSnapshot playerManagerOptions, IOptionsSnapshot sceneManagerOptions, IOptionsSnapshot petManagerOptions, IOptionsSnapshot networkManagerOptions, IOptionsSnapshot unitManagerOptions, IOptionsSnapshot ntClientOptions ) : this ( Process.GetCurrentProcess(), playerManagerOptions.Value, sceneManagerOptions.Value, petManagerOptions.Value, networkManagerOptions.Value, unitManagerOptions.Value, ntClientOptions.Value ) { } /// /// Initializes a new instance of the class. /// /// The process to browse. /// The options for obtaining player manager. /// The scene manager options. /// The pet manager options. /// The network manager options. /// The unit manager options. /// The nt client options. public NosBrowserManager ( Process process, PlayerManagerOptions? playerManagerOptions = default, SceneManagerOptions? sceneManagerOptions = default, PetManagerOptions? petManagerOptions = default, NetworkManagerOptions? networkManagerOptions = default, UnitManagerOptions? unitManagerOptions = default, NtClientOptions? ntClientOptions = default ) { _playerManagerOptions = playerManagerOptions ?? new PlayerManagerOptions(); _sceneManagerOptions = sceneManagerOptions ?? new SceneManagerOptions(); _petManagerOptions = petManagerOptions ?? new PetManagerOptions(); _networkManagerOptions = networkManagerOptions ?? new NetworkManagerOptions(); _unitManagerOptions = unitManagerOptions ?? new UnitManagerOptions(); _ntClientOptions = ntClientOptions ?? new NtClientOptions(); Process = process; Memory = Process.Id == Process.GetCurrentProcess().Id ? new Memory() : new ExternalMemory(process); Scanner = new Scanner(process, process.MainModule); } /// /// The NosTale process. /// public Process Process { get; } /// /// Gets the memory scanner. /// internal Scanner Scanner { get; } /// /// Gets the current process memory. /// internal IMemory Memory { get; } /// /// Gets whether this is a NosTale process or not. /// public bool IsNostaleProcess => NosBrowserManager.IsProcessNostaleProcess(Process); /// /// Gets the network manager. /// /// Thrown if the browser is not initialized or there was an error with initialization of network manager. public NetworkManager NetworkManager { get { if (_networkManager is null) { throw new InvalidOperationException ( "Could not get network manager. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _networkManager; } } /// /// Gets the network manager. /// /// Thrown if the browser is not initialized or there was an error with initialization of unit manager. public UnitManager UnitManager { get { if (_unitManager is null) { throw new InvalidOperationException ( "Could not get unit manager. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _unitManager; } } /// /// Gets whether the player is currently in game. /// /// /// It may be unsafe to access some data if the player is not in game. /// public bool IsInGame { get { var player = PlayerManager.Player; return player.Address != nuint.Zero; } } /// /// Gets the nt client. /// /// Thrown if the browser is not initialized or there was an error with initialization of nt client. public NtClient NtClient { get { if (_ntClient is null) { throw new InvalidOperationException ( "Could not get nt client. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _ntClient; } } /// /// Gets the player manager. /// /// Thrown if the browser is not initialized or there was an error with initialization of player manager. public PlayerManager PlayerManager { get { if (_playerManager is null) { throw new InvalidOperationException ( "Could not get player manager. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _playerManager; } } /// /// Gets the scene manager. /// /// Thrown if the browser is not initialized or there was an error with initialization of scene manager. public SceneManager SceneManager { get { if (_sceneManager is null) { throw new InvalidOperationException ( "Could not get scene manager. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _sceneManager; } } /// /// Gets the pet manager list. /// /// Thrown if the browser is not initialized or there was an error with initialization of pet manager list. public PetManagerList PetManagerList { get { if (_petManagerList is null) { throw new InvalidOperationException ( "Could not get pet manager list. The browser manager is not initialized. Did you forget to call NosBrowserManager.Initialize?" ); } return _petManagerList; } } /// /// Initialize the nos browser modules. /// /// /// Needed to use all of the classes from NosTale. /// /// A result that may or may not have succeeded. public IResult Initialize() { if (!IsNostaleProcess) { return (Result)new NotNostaleProcessError(Process); } List errorResults = new List(); if (_unitManager is null) { var unitManagerResult = UnitManager.Create(this, _unitManagerOptions); if (!unitManagerResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(UnitManager), unitManagerResult.Error), unitManagerResult ) ); } _unitManager = unitManagerResult.Entity; } if (_networkManager is null) { var networkManagerResult = NetworkManager.Create(this, _networkManagerOptions); if (!networkManagerResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(NetworkManager), networkManagerResult.Error), networkManagerResult ) ); } _networkManager = networkManagerResult.Entity; } if (_playerManager is null) { var playerManagerResult = PlayerManager.Create(this, _playerManagerOptions); if (!playerManagerResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(PlayerManager), playerManagerResult.Error), playerManagerResult ) ); } _playerManager = playerManagerResult.Entity; } if (_sceneManager is null) { var sceneManagerResult = SceneManager.Create(this, _sceneManagerOptions); if (!sceneManagerResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(SceneManager), sceneManagerResult.Error), sceneManagerResult ) ); } _sceneManager = sceneManagerResult.Entity; } if (_petManagerList is null) { var petManagerResult = PetManagerList.Create(this, _petManagerOptions); if (!petManagerResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(PetManagerList), petManagerResult.Error), petManagerResult ) ); } _petManagerList = petManagerResult.Entity; } if (_ntClient is null) { var ntClientResult = NtClient.Create(this, _ntClientOptions); if (!ntClientResult.IsSuccess) { errorResults.Add ( Result.FromError ( new CouldNotInitializeModuleError(typeof(NtClient), ntClientResult.Error), ntClientResult ) ); } _ntClient = ntClientResult.Entity; } return errorResults.Count switch { 0 => Result.FromSuccess(), 1 => errorResults[0], _ => (Result)new AggregateError(errorResults) }; } }