diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp index 862ecb8114a7..fb7ecf1c2a49 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp @@ -41,6 +41,7 @@ extern bool g_needInputForFrame; #ifdef LOCAL_TESTING bool isLocalConnected = false; +int localChatMessageId = 0; #endif namespace ExpansionInterface @@ -1884,6 +1885,26 @@ void CEXISlippi::prepareOnlineMatchState() u32 rngOffset = 0; std::string p1Name = ""; std::string p2Name = ""; + u8 chatMessageId = 0; + u8 sentChatMessageId = 0; + +#ifdef LOCAL_TESTING + chatMessageId = localChatMessageId; + localChatMessageId = 0; + // in CSS p1 is always current player and p2 is opponent + p1Name = "Player 1"; + p2Name = "Player 2"; +#endif + + // Set chat message if any + if (slippi_netplay) + { + chatMessageId = slippi_netplay->GetSlippiRemoteChatMessage(); + sentChatMessageId = slippi_netplay->GetSlippiRemoteSentChatMessage(); + // in CSS p1 is always current player and p2 is opponent + p1Name = userInfo.display_name; + p2Name = oppName; + } auto directMode = SlippiMatchmaking::OnlinePlayMode::DIRECT; @@ -1969,6 +1990,10 @@ void CEXISlippi::prepareOnlineMatchState() // Add delay frames to output m_read_queue.push_back((u8)SConfig::GetInstance().m_slippiOnlineDelay); + // Add chat messages id + m_read_queue.push_back((u8)sentChatMessageId); + m_read_queue.push_back((u8)chatMessageId); + // Add names to output p1Name = ConvertStringForGame(p1Name, MAX_NAME_LENGTH); m_read_queue.insert(m_read_queue.end(), p1Name.begin(), p1Name.end()); @@ -2073,6 +2098,28 @@ void CEXISlippi::prepareFileLoad(u8* payload) m_read_queue.insert(m_read_queue.end(), buf.begin(), buf.end()); } +void CEXISlippi::handleChatMessage(u8 *payload) +{ + + int messageId = payload[0]; + INFO_LOG(SLIPPI, "SLIPPI CHAT INPUT: 0x%x", messageId); + +#ifdef LOCAL_TESTING + localChatMessageId = 11; +#endif + + if (slippi_netplay) + { + + auto userInfo = user->GetUserInfo(); + auto packet = std::make_unique(); + // OSD::AddMessage("[Me]: "+ msg, OSD::Duration::VERY_LONG, OSD::Color::YELLOW); + slippi_netplay->remoteSentChatMessageId = messageId; + slippi_netplay->WriteChatMessageToPacket(*packet, messageId); + slippi_netplay->SendAsync(std::move(packet)); + } +} + void CEXISlippi::logMessageFromGame(u8* payload) { if (payload[0] == 0) @@ -2315,6 +2362,9 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) case CMD_LOG_MESSAGE: logMessageFromGame(&memPtr[bufLoc + 1]); break; + case CMD_SEND_CHAT_MESSAGE: + handleChatMessage(&memPtr[bufLoc + 1]); + break; case CMD_UPDATE: handleUpdateAppRequest(); break; diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h index 19782513fd8d..9a7840afad65 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h @@ -70,6 +70,7 @@ class CEXISlippi : public IEXIDevice CMD_UPDATE = 0xB8, CMD_GET_ONLINE_STATUS = 0xB9, CMD_CLEANUP_CONNECTION = 0xBA, + CMD_SEND_CHAT_MESSAGE = 0xBB, CMD_GET_NEW_SEED = 0xBC, // Misc @@ -108,6 +109,7 @@ class CEXISlippi : public IEXIDevice {CMD_GET_MATCH_STATE, 0}, {CMD_FIND_OPPONENT, 19}, {CMD_SET_MATCH_SELECTIONS, 6}, + {CMD_SEND_CHAT_MESSAGE, 2}, {CMD_OPEN_LOGIN, 0}, {CMD_LOGOUT, 0}, {CMD_UPDATE, 0}, @@ -179,6 +181,7 @@ class CEXISlippi : public IEXIDevice void prepareIsFileReady(); // misc stuff + void handleChatMessage(u8 *payload); void logMessageFromGame(u8* payload); void prepareFileLength(u8* payload); void prepareFileLoad(u8* payload); diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index b07b6a3f9f4a..9d83117c7178 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -135,6 +135,7 @@ enum NP_MSG_SLIPPI_PAD_ACK = 0x81, NP_MSG_SLIPPI_MATCH_SELECTIONS = 0x82, NP_MSG_SLIPPI_CONN_SELECTED = 0x83, + NP_MSG_SLIPPI_CHAT_MESSAGE = 0x84, NP_MSG_GOLF_REQUEST = 0x90, NP_MSG_GOLF_SWITCH = 0x91, diff --git a/Source/Core/Core/Slippi/SlippiNetplay.cpp b/Source/Core/Core/Slippi/SlippiNetplay.cpp index a068ef976a49..6dd8f5d2413c 100644 --- a/Source/Core/Core/Slippi/SlippiNetplay.cpp +++ b/Source/Core/Core/Slippi/SlippiNetplay.cpp @@ -271,6 +271,18 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet) } break; + case NetPlay::NP_MSG_SLIPPI_CHAT_MESSAGE: + { + auto playerSelection = ReadChatMessageFromPacket(packet); + auto messageId = playerSelection->messageId; + + // set message id to netplay instance + remoteChatMessageId = messageId; + // Show chat message OSD + INFO_LOG(SLIPPI_ONLINE, "[Netplay] Received chat message from opponent %i", messageId); + } + break; + case NetPlay::NP_MSG_SLIPPI_CONN_SELECTED: { // Currently this is unused but the intent is to support two-way simultaneous connection @@ -295,6 +307,22 @@ void SlippiNetplayClient::writeToPacket(sf::Packet& packet, SlippiPlayerSelectio packet << s.rngOffset; } +void SlippiNetplayClient::WriteChatMessageToPacket(sf::Packet& packet, int messageId) +{ + packet << static_cast(NetPlay::NP_MSG_SLIPPI_CHAT_MESSAGE); + packet << messageId; +} + +std::unique_ptr +SlippiNetplayClient::ReadChatMessageFromPacket(sf::Packet& packet) +{ + auto s = std::make_unique(); + + packet >> s->messageId; + + return std::move(s); +} + std::unique_ptr SlippiNetplayClient::readSelectionsFromPacket(sf::Packet& packet) { @@ -627,6 +655,20 @@ void SlippiNetplayClient::SetMatchSelections(SlippiPlayerSelections& s) SendAsync(std::move(spac)); } +u8 SlippiNetplayClient::GetSlippiRemoteChatMessage() +{ + u8 copiedMessageId = remoteChatMessageId; + remoteChatMessageId = 0; // Clear it out + return copiedMessageId; +} + +u8 SlippiNetplayClient::GetSlippiRemoteSentChatMessage() +{ + u8 copiedMessageId = remoteSentChatMessageId; + remoteSentChatMessageId = 0; // Clear it out + return copiedMessageId; +} + std::unique_ptr SlippiNetplayClient::GetSlippiRemotePad(int32_t curFrame) { std::lock_guard lk(pad_mutex); // TODO: Is this the correct lock? diff --git a/Source/Core/Core/Slippi/SlippiNetplay.h b/Source/Core/Core/Slippi/SlippiNetplay.h index fa5aaf9a8748..225996d7066d 100644 --- a/Source/Core/Core/Slippi/SlippiNetplay.h +++ b/Source/Core/Core/Slippi/SlippiNetplay.h @@ -48,6 +48,8 @@ class SlippiPlayerSelections u32 rngOffset = 0; + int messageId; + void Merge(SlippiPlayerSelections& s) { this->rngOffset = s.rngOffset; @@ -123,9 +125,17 @@ class SlippiNetplayClient std::unique_ptr GetSlippiRemotePad(int32_t curFrame); SlippiMatchInfo* GetMatchInfo(); u64 GetSlippiPing(); - int32_t GetSlippiLatestRemoteFrame(); + s32 GetSlippiLatestRemoteFrame(); + u8 GetSlippiRemoteChatMessage(); + u8 GetSlippiRemoteSentChatMessage(); s32 CalcTimeOffsetUs(); + void WriteChatMessageToPacket(sf::Packet &packet, int messageId); + std::unique_ptr ReadChatMessageFromPacket(sf::Packet &packet); + + u8 remoteChatMessageId = 0; // most recent chat message id from opponent + u8 remoteSentChatMessageId = 0; // most recent chat message id that current player sent + protected: struct {