// // 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 PlayerManager? _playerManager; private SceneManager? _sceneManager; private PetManagerList? _petManagerList; /// /// Initializes a new instance of the class. /// /// The options for obtaining player manager. /// The scene manager options. /// The pet manager options. public NosBrowserManager ( IOptions playerManagerOptions, IOptions sceneManagerOptions, IOptions petManagerOptions ) : this ( Process.GetCurrentProcess(), playerManagerOptions.Value, sceneManagerOptions.Value, petManagerOptions.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. public NosBrowserManager ( Process process, PlayerManagerOptions playerManagerOptions, SceneManagerOptions sceneManagerOptions, PetManagerOptions petManagerOptions ) { _playerManagerOptions = playerManagerOptions; _sceneManagerOptions = sceneManagerOptions; _petManagerOptions = petManagerOptions; Process = process; 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 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 != IntPtr.Zero; } } /// /// 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 (_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; } return errorResults.Count switch { 0 => Result.FromSuccess(), 1 => errorResults[0], _ => (Result)new AggregateError(errorResults) }; } }