// // SceneManager.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 NosSmooth.LocalBinding.Errors; using NosSmooth.LocalBinding.Extensions; using NosSmooth.LocalBinding.Options; using Reloaded.Memory.Sources; using Remora.Results; namespace NosSmooth.LocalBinding.Structs; /// /// Represents nostale scene manager struct. /// public class SceneManager { /// /// Create instance. /// /// The NosTale process browser. /// The options. /// The player manager or an error. public static Result Create(NosBrowserManager nosBrowserManager, SceneManagerOptions options) { var characterObjectAddress = nosBrowserManager.Scanner.FindPattern(options.SceneManagerObjectPattern); if (!characterObjectAddress.Found) { return new BindingNotFoundError(options.SceneManagerObjectPattern, "SceneManager"); } if (nosBrowserManager.Process.MainModule is null) { return new NotFoundError("Cannot find the main module of the target process."); } int staticManagerAddress = (int)nosBrowserManager.Process.MainModule.BaseAddress + characterObjectAddress.Offset; return new SceneManager(nosBrowserManager.Memory, staticManagerAddress, options.SceneManagerOffsets); } private readonly int[] _sceneManagerOffsets; private readonly IMemory _memory; private readonly int _staticSceneManagerAddress; /// /// Initializes a new instance of the class. /// /// The memory. /// The pointer to the scene manager. /// The offsets from the static scene manager address. public SceneManager(IMemory memory, int staticSceneManagerAddress, int[] sceneManagerOffsets) { _memory = memory; _staticSceneManagerAddress = staticSceneManagerAddress; _sceneManagerOffsets = sceneManagerOffsets; } /// /// Gets the address of the scene manager. /// public nuint Address => _memory.FollowStaticAddressOffsets(_staticSceneManagerAddress, _sceneManagerOffsets); /// /// Gets the player list. /// public NostaleList PlayerList => new MapBaseList(_memory, ReadPtr(Address + 0xC)); /// /// Gets the monster list. /// public NostaleList MonsterList => new MapBaseList(_memory, ReadPtr(Address + 0x10)); /// /// Gets the npc list. /// public NostaleList NpcList => new MapBaseList(_memory, ReadPtr(Address + 0x14)); /// /// Gets the item list. /// public NostaleList ItemList => new MapBaseList(_memory, ReadPtr(Address + 0x18)); /// /// Gets the entity that is currently being followed by the player. /// public MapBaseObj? FollowEntity { get { var ptr = ReadPtr(Address + 0x48); if (ptr == nuint.Zero) { return null; } return new MapBaseObj(_memory, ptr); } } /// /// Gets the lock on target marked address. /// public nuint LockOnTargetMarkedAddress { get { var ptr = ReadPtr(Address + 0x1C); ptr = ReadPtr(ptr + 0x04); ptr = ReadPtr(ptr + 0x00); return ptr; } } private nuint ReadPtr(nuint ptr) { _memory.Read(ptr, out int read); return (nuint)read; } /// /// Find the given entity address. /// /// The id of the entity. /// The pointer to the entity or an error. public Result FindEntity(long id) { if (id == 0) { return Result.FromSuccess(null); } var item = ItemList.FirstOrDefault(x => x.Id == id); if (item is not null) { return item; } var monster = MonsterList.FirstOrDefault(x => x.Id == id); if (monster is not null) { return monster; } var npc = NpcList.FirstOrDefault(x => x.Id == id); if (npc is not null) { return npc; } var player = PlayerList.FirstOrDefault(x => x.Id == id); if (player is not null) { return player; } return new NotFoundError($"Could not find entity with id {id}"); } }