even with f68f6f6cbf56b3e4e43f27475763f1d15b6d7c67. playback works, netplay is blank???

This commit is contained in:
R2DLiu 2023-08-01 17:25:20 -04:00
commit ca80ff04d0
11 changed files with 217 additions and 15 deletions

View file

@ -657,7 +657,7 @@ endif()
set(SLIPPI_PLAYBACK TRUE)
if(SLIPPI_PLAYBACK)
# Slippi Playback build option
add_definitions(-DIS_PLAYBACK=1)
# add_definitions(-DIS_PLAYBACK=1)
endif()
########################################

View file

@ -611,11 +611,25 @@ std::string UTF16BEToUTF8(const char16_t* str, size_t max_size)
#else
template <typename T>
std::string CodeTo(const char* tocode, const char* fromcode, std::basic_string_view<T> input)
#ifdef __APPLE__
std::string CodeToWithFallbacks(const char* tocode, const char* fromcode,
const std::basic_string<T>& input, iconv_fallbacks* fallbacks)
#else
std::string CodeTo(const char* tocode, const char* fromcode, const std::basic_string<T>& input)
#endif
{
std::string result;
iconv_t const conv_desc = iconv_open(tocode, fromcode);
// Only on OS X can we call iconvctl, it isn't found on Linux
#ifdef __APPLE__
if (fallbacks)
{
iconvctl(conv_desc, ICONV_SET_FALLBACKS, fallbacks);
}
#endif
if ((iconv_t)-1 == conv_desc)
{
ERROR_LOG_FMT(COMMON, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno));
@ -671,6 +685,14 @@ std::string CodeTo(const char* tocode, const char* fromcode, std::basic_string_v
return result;
}
#ifdef __APPLE__
template <typename T>
std::string CodeTo(const char* tocode, const char* fromcode, const std::basic_string<T>& input)
{
return CodeToWithFallbacks(tocode, fromcode, input, nullptr);
}
#endif
template <typename T>
std::string CodeToUTF8(const char* fromcode, std::basic_string_view<T> input)
{
@ -690,9 +712,74 @@ std::string SHIFTJISToUTF8(std::string_view input)
return CodeToUTF8("SJIS", input);
}
std::string UTF8ToSHIFTJIS(std::string_view input)
#ifdef __APPLE__
void uc_to_mb_fb(unsigned int code,
void (*write_replacement)(const char* buf, size_t buflen, void* callback_arg),
void* callback_arg, void* data)
{
return CodeTo("SJIS", "UTF-8", input);
static std::unordered_map<unsigned int, const char*> specialCharConvert = {
{'!', (const char*)"\x81\x49"},
{'"', (const char*)"\x81\x68"},
{'#', (const char*)"\x81\x94"},
{'$', (const char*)"\x81\x90"},
{'%', (const char*)"\x81\x93"},
{'&', (const char*)"\x81\x95"},
{'\'', (const char*)"\x81\x66"},
{'(', (const char*)"\x81\x69"},
{')', (const char*)"\x81\x6a"},
{'*', (const char*)"\x81\x96"},
{'+', (const char*)"\x81\x7b"},
{',', (const char*)"\x81\x43"},
{'-', (const char*)"\x81\x7c"},
{'.', (const char*)"\x81\x44"},
{'/', (const char*)"\x81\x5e"},
{':', (const char*)"\x81\x46"},
{';', (const char*)"\x81\x47"},
{'<', (const char*)"\x81\x83"},
{'=', (const char*)"\x81\x81"},
{'>', (const char*)"\x81\x84"},
{'?', (const char*)"\x81\x48"},
{'@', (const char*)"\x81\x97"},
{'[', (const char*)"\x81\x6d"},
{'\\', (const char*)"\x81\x5f"},
{']', (const char*)"\x81\x6e"},
{'^', (const char*)"\x81\x4f"},
{'_', (const char*)"\x81\x51"},
{'`', (const char*)"\x81\x4d"},
{'{', (const char*)"\x81\x6f"},
{'|', (const char*)"\x81\x62"},
{'}', (const char*)"\x81\x70"},
{'~', (const char*)"\x81\x60"},
{U'¥', "\x81\x8f"},
{U'', "\x81\x45"},
{U'', "\x81\x7C"}};
bool hasConversion = specialCharConvert.count(code);
if (!hasConversion)
return;
auto newChar = specialCharConvert[code];
// Add new chars to pos to replace
write_replacement(newChar, 2, callback_arg);
}
#endif
std::string UTF8ToSHIFTJIS(const std::string& input)
{
#ifdef __APPLE__
// Set SHIFTJIS callbacks only if converting to shift jis
auto fallbacks = new iconv_fallbacks();
fallbacks->uc_to_mb_fallback = uc_to_mb_fb;
fallbacks->mb_to_uc_fallback = nullptr;
fallbacks->mb_to_wc_fallback = nullptr;
fallbacks->wc_to_mb_fallback = nullptr;
fallbacks->data = nullptr;
auto str = CodeToWithFallbacks("SJIS", "UTF-8", input, fallbacks);
free(fallbacks);
#else
auto str = CodeTo("SJIS", "UTF-8", input);
#endif
return str;
}
std::string WStringToUTF8(std::wstring_view input)

View file

@ -188,6 +188,17 @@ std::string UTF16BEToUTF8(const char16_t* str, size_t max_size); // Stops at \0
std::string UTF16ToUTF8(std::u16string_view str);
std::u16string UTF8ToUTF16(std::string_view str);
#ifdef __APPLE__
/**
* Callback Implementation used for iconv when a unicode character could not be automatically
* converted. This callback is used specifically for SHIFTJIS failures when converting some special
* wide characters for melee.
*/
void uc_to_mb_fb(unsigned int code,
void (*write_replacement)(const char* buf, size_t buflen, void* callback_arg),
void* callback_arg, void* data);
#endif
#ifdef _WIN32
std::wstring UTF8ToWString(std::string_view str);

View file

@ -2084,7 +2084,7 @@ void CEXISlippi::prepareOnlineMatchState()
chatMessagePlayerIdx = 0;
localChatMessageId = 0;
// in CSS p1 is always current player and p2 is opponent
localPlayerName = p1Name = "Player 1";
localPlayerName = p1Name = userInfo.display_name;
oppName = p2Name = "Player 2";
#endif
@ -2949,6 +2949,44 @@ void CEXISlippi::handleCompleteSet(const SlippiExiTypes::ReportSetCompletionQuer
}
}
void CEXISlippi::handleGetPlayerSettings()
{
m_read_queue.clear();
SlippiExiTypes::GetPlayerSettingsResponse resp = {};
std::vector<std::vector<std::string>> messagesByPlayer = {
SlippiUser::default_chat_messages, SlippiUser::default_chat_messages,
SlippiUser::default_chat_messages, SlippiUser::default_chat_messages};
// These chat messages will be used when previewing messages
auto userChatMessages = user->GetUserInfo().chat_messages;
if (userChatMessages.size() == 16)
{
messagesByPlayer[0] = userChatMessages;
}
// These chat messages will be set when we have an opponent. We load their and our messages
auto playerInfo = matchmaking->GetPlayerInfo();
for (auto& player : playerInfo)
{
messagesByPlayer[player.port - 1] = player.chat_messages;
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 16; j++)
{
auto str = ConvertStringForGame(messagesByPlayer[i][j], MAX_MESSAGE_LENGTH);
sprintf(resp.settings[i].chatMessages[j], "%s", str.c_str());
}
}
auto data_ptr = (u8*)&resp;
m_read_queue.insert(m_read_queue.end(), data_ptr,
data_ptr + sizeof(SlippiExiTypes::GetPlayerSettingsResponse));
}
void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
{
auto& system = Core::System::GetInstance();
@ -3123,6 +3161,9 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
handleCompleteSet(
SlippiExiTypes::Convert<SlippiExiTypes::ReportSetCompletionQuery>(&memPtr[bufLoc]));
break;
case CMD_GET_PLAYER_SETTINGS:
handleGetPlayerSettings();
break;
default:
writeToFileAsync(&memPtr[bufLoc], payloadLen + 1, "");
SlippiSpectateServer::getInstance().write(&memPtr[bufLoc], payloadLen + 1);

View file

@ -23,6 +23,7 @@
#define ROLLBACK_MAX_FRAMES 7
#define MAX_NAME_LENGTH 15
#define MAX_MESSAGE_LENGTH 25
#define CONNECT_CODE_LENGTH 8
namespace ExpansionInterface
@ -80,6 +81,7 @@ private:
CMD_GP_COMPLETE_STEP = 0xC0,
CMD_GP_FETCH_STEP = 0xC1,
CMD_REPORT_SET_COMPLETE = 0xC2,
CMD_GET_PLAYER_SETTINGS = 0xC3,
// Misc
CMD_LOG_MESSAGE = 0xD0,
@ -137,6 +139,7 @@ private:
{CMD_GP_FETCH_STEP, static_cast<u32>(sizeof(SlippiExiTypes::GpFetchStepQuery) - 1)},
{CMD_REPORT_SET_COMPLETE,
static_cast<u32>(sizeof(SlippiExiTypes::ReportSetCompletionQuery) - 1)},
{CMD_GET_PLAYER_SETTINGS, 0},
// Misc
{CMD_LOG_MESSAGE, 0xFFFF}, // Variable size... will only work if by itself
@ -203,6 +206,7 @@ private:
void handleGamePrepStepComplete(const SlippiExiTypes::GpCompleteStepQuery& query);
void prepareGamePrepOppStep(const SlippiExiTypes::GpFetchStepQuery& query);
void handleCompleteSet(const SlippiExiTypes::ReportSetCompletionQuery& query);
void handleGetPlayerSettings();
// replay playback stuff
void prepareGameInfo(u8* payload);

View file

@ -80,6 +80,15 @@ struct OverwriteSelectionsQuery
OverwriteCharSelections chars[4];
};
struct PlayerSettings
{
char chatMessages[16][51];
};
struct GetPlayerSettingsResponse
{
PlayerSettings settings[4];
};
// Not sure if resetting is strictly needed, might be contained to the file
#pragma pack()

View file

@ -123,9 +123,6 @@ SlippiGameReporter::SlippiGameReporter(SlippiUser* user, const std::string curre
INFO_LOG_FMT(SLIPPI_ONLINE, "MD5 Hash: {}", this->m_iso_hash);
});
m_md5_thread.detach();
run_thread = true;
reporting_thread = std::thread(&SlippiGameReporter::ReportThreadHandler, this);
}
SlippiGameReporter::~SlippiGameReporter()

View file

@ -507,6 +507,15 @@ void SlippiMatchmaking::handleMatchmaking()
playerInfo.display_name = el.value("displayName", "");
playerInfo.connect_code = el.value("connectCode", "");
playerInfo.port = el.value("port", 0);
playerInfo.chat_messages = SlippiUser::default_chat_messages;
if (el["chatMessages"].is_array())
{
playerInfo.chat_messages = el.value("chatMessages", SlippiUser::default_chat_messages);
if (playerInfo.chat_messages.size() != 16)
{
playerInfo.chat_messages = SlippiUser::default_chat_messages;
}
}
m_playerInfo.push_back(playerInfo);
if (isLocal)

View file

@ -22,6 +22,28 @@
#include <json.hpp>
using json = nlohmann::json;
const std::vector<std::string> SlippiUser::default_chat_messages = {
"ggs",
"one more",
"brb",
"good luck",
"well played",
"that was fun",
"thanks",
"too good",
"sorry",
"my b",
"lol",
"wow",
"gotta go",
"one sec",
"let's play again later",
"bad connection",
};
#ifdef _WIN32
#define MAX_SYSTEM_PROGRAM (4096)
static void system_hidden(const char* cmd)
@ -173,17 +195,17 @@ void SlippiUser::OpenLogInPage()
void SlippiUser::UpdateApp()
{
std::string url = "https://slippi.gg/downloads?update=true";
std::string url = "https://slippi.gg/downloads?update=true";
#ifdef _WIN32
std::string command = "explorer \"" + url + "\"";
std::string command = "explorer \"" + url + "\"";
#elif defined(__APPLE__)
std::string command = "open \"" + url + "\"";
std::string command = "open \"" + url + "\"";
#else
std::string command = "xdg-open \"" + url + "\""; // Linux
std::string command = "xdg-open \"" + url + "\""; // Linux
#endif
RunSystemCommand(command);
RunSystemCommand(command);
}
void SlippiUser::ListenForLogIn()
@ -279,6 +301,15 @@ SlippiUser::UserInfo SlippiUser::parseFile(std::string file_contents)
info.play_key = readString(res, "playKey");
info.connect_code = readString(res, "connectCode");
info.latest_version = readString(res, "latestVersion");
info.chat_messages = SlippiUser::default_chat_messages;
if (res["chatMessages"].is_array())
{
info.chat_messages = res.value("chatMessages", SlippiUser::default_chat_messages);
if (info.chat_messages.size() != 16)
{
info.chat_messages = SlippiUser::default_chat_messages;
}
}
return info;
}
@ -296,7 +327,8 @@ void SlippiUser::overwriteFromServer()
// Perform curl request
std::string resp;
curl_easy_setopt(m_curl, CURLOPT_URL, (URL_START + "/" + m_user_info.uid).c_str());
curl_easy_setopt(m_curl, CURLOPT_URL,
(URL_START + "/" + m_user_info.uid + "?additionalFields=chatMessages").c_str());
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &resp);
CURLcode res = curl_easy_perform(m_curl);
@ -320,4 +352,12 @@ void SlippiUser::overwriteFromServer()
m_user_info.connect_code = r.value("connectCode", m_user_info.connect_code);
m_user_info.latest_version = r.value("latestVersion", m_user_info.latest_version);
m_user_info.display_name = r.value("displayName", m_user_info.display_name);
if (r["chatMessages"].is_array())
{
m_user_info.chat_messages = r.value("chatMessages", SlippiUser::default_chat_messages);
if (m_user_info.chat_messages.size() != 16)
{
m_user_info.chat_messages = SlippiUser::default_chat_messages;
}
}
}

View file

@ -21,6 +21,8 @@ public:
std::string file_contents = "";
int port;
std::vector<std::string> chat_messages;
};
SlippiUser();
@ -36,6 +38,8 @@ public:
bool IsLoggedIn();
void FileListenThread();
const static std::vector<std::string> default_chat_messages;
protected:
std::string getUserFilePath();
UserInfo parseFile(std::string file_contents);

View file

@ -513,7 +513,7 @@ bool TriggerSTMPowerEvent()
#ifdef HAVE_X11
void InhibitScreenSaver(Window win, bool inhibit)
#else
void InhibitScreenSaver(bool inhibit)
void InhibitScreenSaver(bool inhibit)
#endif
{
// Inhibit the screensaver. Depending on the operating system this may also