mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-22 10:19:01 +00:00
even with f68f6f6cbf56b3e4e43f27475763f1d15b6d7c67. playback works, netplay is blank???
This commit is contained in:
parent
ebccf3b2e9
commit
ca80ff04d0
11 changed files with 217 additions and 15 deletions
|
@ -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()
|
||||
|
||||
########################################
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue