Skip to content

Instantly share code, notes, and snippets.

@ariankordi
Created December 4, 2025 02:11
Show Gist options
  • Select an option

  • Save ariankordi/3dcad495ede2c29d5150934ca61ba154 to your computer and use it in GitHub Desktop.

Select an option

Save ariankordi/3dcad495ede2c29d5150934ca61ba154 to your computer and use it in GitHub Desktop.
Patches for Cemu's source that allow using its built-in NEX client for the Wii U Friends List standalone, along with an example
Have you ever wanted to access the Nintendo- or, now Pretendo Network friends list server, but you don't want to use the same old NintendoClients/examples/wiiu/friends.py being used for years and is kinda stinky and yucky because it's Python?
Well, Cemu has (I believe) the only NEX client that's not in Python, like NintendoClients. Because it's in C++, it should be much easier/painless to use and call from.. whatever else.
NOTE that the library is async and multi-threaded, but the example above does not properly await yet. Ooooooooops!
Compile command (Works on my macOS):
- Change: Boost platform, Boost/fmt includes, potentially the output target, potentially remove test.cpp from being built if you do not need it
clang++ -DBOOST_OS_MACOS=1 -Wno-macro-redefined -std=c++20 -I /opt/homebrew/Cellar/boost/1.89.0_1/include/ -I /opt/homebrew/Cellar/fmt/12.1.0/include/ -I ../../ -include ../../Common/precompiled.h ../../Common/unix/platform.cpp ./nex.cpp ./nexFriends.cpp ./nexThread.cpp ./prudp.cpp ../../util/crypto/md5.cpp -fno-rtti -fno-threadsafe-statics -g ./test.cpp -o cemu-nex-friends
Emscripten??? (Make same changes to include as above):
em++ -DBOOST_OS_LINUX=1 -Wno-macro-redefined -std=c++20 -I /opt/homebrew/Cellar/boost/1.89.0_1/include/ -I /opt/homebrew/Cellar/fmt/12.1.0/include/ -I ../../ -include ../../Common/precompiled.h ../../Common/unix/platform.cpp *.cpp ../../util/crypto/md5.cpp -fno-rtti -fno-threadsafe-statics -g -shared -o cemu-nex-friends
- I thought it'd be nice to use this along with Embind to use the code from Node.js.
- However, this uses sockets which don't "just work" in WASM so that would have to be worked around.
- I've thought of using function pointers? for the socket functions, and either assigning them in Node.js from the system libraries, or potentially using this to bridge it with Node's native addon API: https://github.com/toyobayashi/emnapi
diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h
index 5b2e5fa..3294194 100644
--- a/src/Cemu/Logging/CemuLogging.h
+++ b/src/Cemu/Logging/CemuLogging.h
@@ -1,6 +1,6 @@
#pragma once
-extern uint64 s_loggingFlagMask;
+//extern uint64 s_loggingFlagMask;
enum class LogType : sint32
{
@@ -71,13 +71,34 @@ inline uint64 cemuLog_getFlag(LogType type)
inline bool cemuLog_isLoggingEnabled(LogType type)
{
- return (s_loggingFlagMask & cemuLog_getFlag(type)) != 0;
+ return true;
+ //return (s_loggingFlagMask & cemuLog_getFlag(type)) != 0;
}
bool cemuLog_log(LogType type, std::string_view text);
bool cemuLog_log(LogType type, std::u8string_view text);
void cemuLog_waitForFlush(); // wait until all log lines are written
+inline bool cemuLog_log(LogType type, std::string_view text)
+{
+ if (!cemuLog_isLoggingEnabled(type))
+ return false;
+
+ //if (LaunchSettings::Verbose())
+ std::cout << text << std::endl;
+/*
+ cemuLog_writeLineToLog(text);
+
+ const auto it = std::find_if(g_logging_window_mapping.cbegin(), g_logging_window_mapping.cend(),
+ [type](const auto& entry) { return entry.first == type; });
+ if (it == g_logging_window_mapping.cend())
+ s_loggingDispatcher.Log(text);
+ else
+ s_loggingDispatcher.Log(it->second, text);
+*/
+ return true;
+}
+
template<typename T, typename ... TArgs>
bool cemuLog_log(LogType type, std::basic_string<T> formatStr, TArgs&&... args)
{
diff --git a/src/Cemu/nex/nexFriends.cpp b/src/Cemu/nex/nexFriends.cpp
index 36ba4a5..326a122 100644
--- a/src/Cemu/nex/nexFriends.cpp
+++ b/src/Cemu/nex/nexFriends.cpp
@@ -1,7 +1,7 @@
#include "prudp.h"
#include "nex.h"
#include "nexFriends.h"
-#include "Cafe/CafeSystem.h"
+//#include "Cafe/CafeSystem.h"
static const int NOTIFICATION_SRV_FRIEND_OFFLINE = 0x0A; // the opposite event (friend online) is notified via _PRESENCE_CHANGE
static const int NOTIFICATION_SRV_FRIEND_PRESENCE_CHANGE = 0x18;
@@ -937,7 +937,7 @@ void NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 coun
void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
{
this->myPresence = myPresence;
-
+/*
if (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) == 0x00050000)
{
myPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();
@@ -945,9 +945,9 @@ void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
}
else
{
- myPresence.gameKey.titleId = 0; // icon will not be ??? or invalid to others
+*/ myPresence.gameKey.titleId = 0; // icon will not be ??? or invalid to others
myPresence.gameKey.ukn = 0;
- }
+// }
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
diff --git a/src/Common/platform.h b/src/Common/platform.h
index 3f480f4..ca83733 100644
--- a/src/Common/platform.h
+++ b/src/Common/platform.h
@@ -14,4 +14,7 @@
#elif BOOST_OS_MACOS
#include <libkern/OSByteOrder.h>
#include "Common/unix/platform.h"
+#elif 1
+#include <byteswap.h>
+#include "Common/unix/platform.h"
#endif
diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h
index bda75ce..1e220b8 100644
--- a/src/Common/precompiled.h
+++ b/src/Common/precompiled.h
@@ -79,10 +79,10 @@
#include <boost/predef.h>
#include <boost/nowide/convert.hpp>
#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
-#include <glm/glm.hpp>
+//#include <boost/asio.hpp>
+/*#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
-
+*/
namespace fs = std::filesystem;
#include "enumFlags.h"
@@ -379,7 +379,7 @@ inline void cemu_assert_error()
#define assert_dbg() DEBUG_BREAK // old style unconditional generic assert
// MEMPTR
-#include "Common/MemPtr.h"
+//#include "Common/MemPtr.h"
template <typename T1, typename T2>
constexpr bool HAS_FLAG(T1 flags, T2 test_flag) { return (flags & (T1)test_flag) == (T1)test_flag; }
@@ -556,12 +556,14 @@ inline uint32 GetTitleIdLow(uint64 titleId)
#endif
// PPC context and memory functions
+/*
#include "Cafe/HW/MMU/MMU.h"
#include "Cafe/HW/Espresso/PPCState.h"
#include "Cafe/HW/Espresso/PPCCallback.h"
// PPC stack trace printer
void DebugLogStackTrace(struct OSThread_t* thread, MPTR sp, bool printSymbols = false);
+*/
// generic formatter for enums (to underlying)
template <typename Enum>
diff --git a/src/Common/socket.h b/src/Common/socket.h
index 37d53c0..873ab69 100644
--- a/src/Common/socket.h
+++ b/src/Common/socket.h
@@ -7,6 +7,10 @@ typedef int socklen_t;
#else
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <fcntl.h>
+
#include <sys/socket.h>
#define SOCKET int
#define closesocket close
#include "prudp.h"
#include "nex.h"
#include "nexFriends.h"
#include <cstdio>
#include <arpa/inet.h>
#include <unistd.h>
// see cemu source: src/Cafe/IOSU/legacy/iosu_fpd.cpp
int getIpFromHostname(const char* hostname) {
struct in_addr addr = {0};
if (inet_pton(AF_INET, hostname, &addr) != 1) // 0 = invalid, -1 = error
{
return -1; // Invalid IP format.
}
return addr.s_addr;
}
#include <csignal> // JUST for adding a breakpoint
int main()
{
unsigned char* miiData = (unsigned char*)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
nexPresenceV2 presence = {0};
const int ip = getIpFromHostname("138.201.49.123");
if (ip == -1)
{
printf("ip could not be resolved.\n");
return 1;
}
NexFriends friends(
/*authServerIp=*/ ip,
/*authServerPort=*/ 30100,
/*accessKey=*/ "ridfebb9", // constant for all accounts
/*pid=*/ 1435495150,
/*nexPassword=*/ "your nex password",
// the token changes, where the pid/password does not
/*nexToken=*/ "lol no nex token for you",
/*nnid=*/ ".arian.",
/*miiData=*/ miiData, /*miiNickname=*/ L"mii name",
/*country=*/ 0, presence);
friends.update();
sleep(5); // TODO: NEED TO PROPERLY AWAIT!
printf("finished waiting for friends.update(), add breakpoint here\n");
raise(SIGTRAP); // breakpoint
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment