-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for sending game memory changes to outside processes #3403
Conversation
// (without the "0x"). The output to the socket is two words long, the first | ||
// containing the address, and the second containing the data as stored in | ||
// game memory. | ||
namespace MW |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
da97d8d
to
e3c6aae
Compare
if (!File::Exists(locations_path)) | ||
return false; | ||
|
||
std::ifstream locations(locations_path.c_str()); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
s_running = true; | ||
while (s_running) | ||
{ | ||
for (auto iter = s_values.begin(); iter != s_values.end(); iter++) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
8665204
to
d1392c2
Compare
|
||
static bool LoadAddresses() | ||
{ | ||
std::string locations_path = File::GetUserPath(F_MEMORYWATCHERLOCATIONS_IDX); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
The idea is good, but the design seems a bit annoying and limited to work with. For the tool programmer that would use this memory watcher interface, the setup would require a special build of dolphin as well as some folder setup to get things going. It would also be nice if the api allowed for changing the addrs being watched at runtime, as well as a size parameter to specify how many bytes the tool would like to watch for each address. These extra requirements give me some ideas.
What are you planning on using this mem watcher for anyways? |
Also, I'd suggest changing the mem watcher code to be a class instead of a namespace. The compile may be faster when using statics like that, but it's generally better practice to have it as an object, then create an instance of it where it is used (in this case, core). If you're worried about visibility of the member vars in the header, there's always the pImp idiom. |
It doesn't require a special build, just that you're on a unix system. It does require some folder setup. |
While it would be nice to have a more powerful API for setting addresses to watch, I shied away from this for a few reasons. I wanted to keep it as simple as possible, and didn't want to add JSON requirements or similar. I also didn't want to have to deal with synchronization, and if I read a hundred bytes at a time it will be possible that the cpu messes with it halfway through the read. If we only read a word at a time this can't happen. Individual packets are going to be consistent, and I make no guarantees about the consistency of anything more than that. I'm going to start working on an AI for SSBM. Another user has already started on a similar project over here. |
Did you see PR #3031 ? It tries to get the same kind of utility. |
@SizzlingCalamari I took your changes to the code, thanks :) (Well except for the broad design ones, but we can talk about that more). |
@@ -109,6 +112,10 @@ static bool s_request_refresh_info = false; | |||
static int s_pause_and_lock_depth = 0; | |||
static bool s_is_framelimiter_temp_disabled = false; | |||
|
|||
#ifdef USE_MEMORYWATCHER | |||
static MemoryWatcher* s_memory_watcher = nullptr; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
return; | ||
if (!OpenSocket(File::GetUserPath(F_MEMORYWATCHERSOCKET_IDX))) | ||
return; | ||
m_watcher_thread = std::thread(std::bind(&MemoryWatcher::WatcherThread, this)); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
I think I applied your suggestions properly, thanks. |
} | ||
|
||
bool MemoryWatcher::LoadAddresses(const std::string& path) | ||
{ |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This PR is probably fine for what you need from it. My only concern is the usefulness of this for others.
If these aren't issues for others, then merge away. |
That's fair. It's pretty similar to the named pipe controller input in that regard (unix-only, awkward setup), but that one's been useful for at least a few other people. I'm under the impression that Windows named pipes can do this, but I don't have a Windows box to develop on. I'm not too attached to this, so if someone does a better job sometime in the future using a different method then I won't mind deleting this. That's part of why I want to keep it simple :) |
Ok, I'll merge this. Someone remember to delete it if there is a better method in the future. |
Add support for sending game memory changes to outside processes
I previously added support for sending controller inputs from another process to Dolphin, and here I add support for sending game memory pieces to other processes. Currently only supported on Unix, but porting to Windows isn't too big of a deal, although Windows uses named pipes for this. Use it like this:
Create a folder in the user directory called
MemoryWatcher
, and a file in it calledLocations.txt
. To that file, write out the memory locations that you want to watch. If this file isn't found or is empty, the polling thread won't be started. For SSBM, for instance, to watch player one and two percent, put in:Now listen to
MemoryWatcher/MemoryWatcher
like so (C code, but this will work with other languages of course):Every time the locations you specified change in game memory, the address and the new value will be sent to that socket. I've currently set it to poll every 10 ms.
I am not sure that this is the right way to do this, but it works. Please suggest alternatives. Also, where should I document this + the controller inputs?