FFXIVAPP/sharlayan

Using ffxivapp-memory in custom project - no data returned

Closed this issue · 13 comments

I have been experimenting with your library lately but unfortunately you haven't updated the signatures for 64bit yet so I have tried accessing the data from the 32bit version of the game hence I have tried accesing something really basic with this piece of code:

var processes = Process.GetProcessesByName("ffxiv");
if(processes.Length > 0) {
    var process = processes[0];
    var processModel = new ProcessModel
    {
        Process = process,
        IsWin64 = false
    };
    MemoryHandler.Instance.SetProcess(processModel);
    var readResult = Reader.GetPlayerInfo().PlayerEntity;
    Console.WriteLine("Name: " + readResult.Name);
}

Unfortunately the code returns an empty string but the GetPlayerInfo() returns a result object with default values of 0 everywhere and does not trigger an error. I was wondering what might be the issue accessing the data - any suggestions?

Furthermore, do you know when you will be able to update offsets and signatures? I guess you have those already running in the Aetherflow framework which you're working on as well if I am not mistaken?

I'm having the same problem when trying to read the in-game chat, but with 64-bit.
The ChatLogReadResult returns 0 ChatLogEntries.
I realize this is an old post, but any help would be appreciated.

Windows10 64bit Dx11
Test:
Simple program

    private void button1_Click(object sender, EventArgs e)
    {
        Process[] processes = Process.GetProcessesByName("ffxiv_dx11");
        if (processes.Length>0)
        {
            // supported: English, Chinese, Japanese, French, German, Korean
            string gameLanguage = "English";
            Process process = processes[0];
            ProcessModel processModel = new ProcessModel
            {
                Process = process,
                IsWin64 = true
            };
            MemoryHandler.Instance.SetProcess(processModel, gameLanguage);
        }
        PlayerInfoReadResult readResult = Reader.GetPlayerInfo();
    }

Return 0...

I know this is super old, but I believe GetPlayerInfo() does not work, I need to look into how it's done.

The other way is:

ActorReadResult readResult = Reader.GetActors();
ActorEntity player = readResult.PCEntities.FirstOrDefault().Value.CurrentUser;

// player.Name .. etc

You can also get it through the party list, you will always be party member 0, but that doesn't provide as much information as you get a PartyEntity, could probably convert to ActorEntity but no need when the above code is enough.

This fix: c7123d4

(And general updates to memory) will now fix this issue. Can be closed.

@viion
Besides no available x64 signatures, the D9 version still does not work in any way for me. Could you please try to create a generic C# console application which loads the player data and displays its name for testing purposes? Maybe there are more things to setup or reference than I do.

I tried your different ways of acquiring the data from memory but I am constantly getting internal NullPointerExceptions or empty structs and nothing useful at all.

@ChristianIvicevic

I built a helper:

using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;

using FFXIVAPP.Memory;
using FFXIVAPP.Memory.Models;
using FFXIVAPP.Memory.Core;
using System.Threading;

namespace XIVDB.Helpers
{
    static class GameMemory
    {
        /// <summary>
        /// Set the game process
        /// </summary>
        /// <returns></returns>
        public static bool setGameProcess()
        {
            Logger.add("getting game process");
            Process[] processes = Process.GetProcessesByName("ffxiv");
            if (processes.Length > 0) {
                Process process = processes[0];
                ProcessModel processModel = new ProcessModel {
                    Process = process
                };

                MemoryHandler.Instance.SetProcess(processModel, "English");
                Logger.add("hooked into game");
                return true;
            }

            Logger.add("could not find ffxiv process");
            return false;
        }

        /// <summary>
        /// Get the current player actor
        /// </summary>
        /// <returns></returns>
        public static ActorEntity getPlayer()
        {     
            ActorReadResult readResult = Reader.GetActors();
            return readResult.PCEntities.FirstOrDefault().Value.CurrentUser;
        }

        /// <summary>
        /// Get the current target actor
        /// </summary>
        /// <returns></returns>
        public static ActorEntity getCurrentTarget()
        {
            try
            {
                TargetReadResult readResult = Reader.GetTargetInfo();
                return readResult.TargetEntity.CurrentTarget;
            }
            catch { }

            return getPlayer();
        }

        /// <summary>
        /// Get all monsters around the player in memory
        /// </summary>
        /// <returns></returns>
        public static List<ActorEntity> getMonstersAroundPlayer()
        {
            ActorReadResult readResult = Reader.GetActors();
            return readResult.MonsterEntities.Select(e => e.Value).ToList();
        }

        /// <summary>
        /// Get all npcs around the player in memory
        /// </summary>
        /// <returns></returns>
        public static List<ActorEntity> getNpcsAroundPlayer()
        {
            ActorReadResult readResult = Reader.GetActors();
            return readResult.NPCEntities.Select(e => e.Value).ToList();
        }
    }
}

With this I can do:

ActorEntity player = GameMemory.getPlayer();
player.Name ...

@viion
Actually the hook returns true but my second line fails with a NullPointerException no matter whether I run it as an administrator or not. The readResult is empty hence return readResult.PCEntities.FirstOrDefault().Value.CurrentUser; fails.

static void Main(string[] args) {
    GameMemory.setGameProcess();
    ActorEntity player = GameMemory.getPlayer();
    Console.ReadLine();
}

Surprisingly enough, the ffxivapp itself works for the 32bit client without issues! Do you have an idea what else could be causing trouble?

@ChristianIvicevic I'm not sure to be honest :( - it works for me and several others who have used my mapping app that i used to populate XIVDB, so might be something very specific to the client.

@viion
I have something VERY intriguing. After some code that has been failing I have been looking through the original code of ffxivapp and the plugins and noticed something I tried to recreate with the following snippet:

while (true)
{
	var readResult = Reader.GetActors();
	if (readResult != null && readResult.NewPC.Any())
	{
		try
		{
			Console.WriteLine(readResult.PCEntities.FirstOrDefault().Value.CurrentUser.Name);
		}
		catch(Exception _)
		{
			Console.WriteLine("Fail.");
		}
	}
	Thread.Sleep(200);
}

Apparently the library takes a while to load and respond - the app itself works similiar like this and responds to new data/events. This has in the end worked for me as well. I guess your app/plugin is based on ffxivapp and not from scratch as I am attempting it? If so then it is obvious why you did not struggle as I did ;-)

For future reference I found the approch in the linked source code.

That's odd, but no I didn't use ffxiv app, I built from scratch and only using the memory module. Make sure the json files downloaded as they contain the structs and offsets, delete them if they look bugged. Also yes you need to give it a second to connect but the thread should wait.

Here my app working https://m.youtube.com/watch?v=7CbrovOG9y4

I only use the memory module

Well checking the NewPC list for example can help unnecessary checks and overhead every now and then, but what it really comes down to was to give the library some time to load. How to do you wait until it is fully loaded since just hooking isn't enough on its own - do you use something fancy or poke until you are not getting a NullPointer?

I have a 2 second timer, not that smart lol but worked! Forgot I did that

Alright, thanks for helping me out anyways - we both learned something new that definitely has to be fixed/refactored! ;-)