This commit is contained in:
Nikhil Narayana 2021-12-01 20:30:09 -08:00
commit 2964a86b9b
8 changed files with 715 additions and 695 deletions

View file

@ -1620,6 +1620,17 @@ void CEXISlippi::handleSendInputs(u8* payload)
int32_t frame = payload[0] << 24 | payload[1] << 16 | payload[2] << 8 | payload[3];
u8 delay = payload[4];
// On the first frame sent, we need to queue up empty dummy pads for as many
// frames as we have delay
if (frame == 1)
{
for (int i = 1; i <= delay; i++)
{
auto empty = std::make_unique<SlippiPad>(i);
slippi_netplay->SendSlippiPad(std::move(empty));
}
}
auto pad = std::make_unique<SlippiPad>(frame + delay, &payload[5]);
slippi_netplay->SendSlippiPad(std::move(pad));
@ -1662,13 +1673,14 @@ void CEXISlippi::prepareOpponentInputs(u8* payload)
int32_t latestFrame = results[i]->latestFrame;
if (latestFrame > frame)
latestFrame = frame;
appendWordToBuffer(&m_read_queue, *(u32 *)&latestFrame);
// INFO_LOG(SLIPPI_ONLINE, "Sending frame num %d for pIdx %d (offset: %d)", latestFrame, i, offset[i]);
appendWordToBuffer(&m_read_queue, *(u32*)&latestFrame);
// INFO_LOG(SLIPPI_ONLINE, "Sending frame num %d for pIdx %d (offset: %d)", latestFrame, i,
// offset[i]);
}
// Send the current frame for any unused player slots.
for (int i = remotePlayerCount; i < SLIPPI_REMOTE_PLAYER_MAX; i++)
{
appendWordToBuffer(&m_read_queue, *(u32 *)&frame);
appendWordToBuffer(&m_read_queue, *(u32*)&frame);
}
// copy pad data over
@ -1821,27 +1833,30 @@ void CEXISlippi::startFindMatch(u8* payload)
void CEXISlippi::prepareOnlineMatchState()
{
// This match block is a VS match with P1 Red Falco vs P2 Red Bowser vs P3 Young Link vs P4 Young Link
// on Battlefield. The proper values will be overwritten
// This match block is a VS match with P1 Red Falco vs P2 Red Bowser vs P3 Young Link vs P4 Young
// Link on Battlefield. The proper values will be overwritten
static std::vector<u8> onlineMatchBlock = {
0x32, 0x01, 0x86, 0x4C, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6E, 0x00, 0x1F, 0x00, 0x00,
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x15, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x15, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
0x32, 0x01, 0x86, 0x4C, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6E, 0x00,
0x1F, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F,
0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09,
0x00, 0x78, 0x00, 0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x05, 0x00, 0x04,
0x01, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0xC0, 0x00, 0x04, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F,
0x80, 0x00, 0x00, 0x15, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00,
0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x15, 0x03, 0x04, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0x40, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09,
0x00, 0x78, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
};
m_read_queue.clear();
@ -2109,16 +2124,17 @@ void CEXISlippi::prepareOnlineMatchState()
stageId = rps[0].isStageSelected ? rps[0].stageId : lps.stageId;
}
u16 *stage = (u16 *)&onlineMatchBlock[0xE];
u16* stage = (u16*)&onlineMatchBlock[0xE];
*stage = Common::swap16(stageId);
// Set rng offset
rngOffset = isDecider ? lps.rngOffset : rps[0].rngOffset;
WARN_LOG(SLIPPI_ONLINE, "Rng Offset: 0x%x", rngOffset);
WARN_LOG(SLIPPI_ONLINE, "P1 Char: 0x%X, P2 Char: 0x%X", onlineMatchBlock[0x60], onlineMatchBlock[0x84]);
WARN_LOG(SLIPPI_ONLINE, "P1 Char: 0x%X, P2 Char: 0x%X", onlineMatchBlock[0x60],
onlineMatchBlock[0x84]);
// Turn pause on in direct, off in everything else
u8 *gameBitField3 = (u8 *)&onlineMatchBlock[2];
u8* gameBitField3 = (u8*)&onlineMatchBlock[2];
*gameBitField3 = lastSearch.mode >= directMode ? *gameBitField3 & 0xF7 : *gameBitField3 | 0x8;
//*gameBitField3 = *gameBitField3 | 0x8;
@ -2148,7 +2164,7 @@ void CEXISlippi::prepareOnlineMatchState()
// Add chat messages id
m_read_queue.push_back((u8)sentChatMessageId);
m_read_queue.push_back((u8)chatMessageId);
m_read_queue.push_back((u8)chatMessagePlayerIdx);
m_read_queue.push_back((u8)chatMessagePlayerIdx);
// Add player groupings for VS splash screen
leftTeamPlayers.resize(4, 0);
@ -2251,8 +2267,8 @@ void CEXISlippi::setMatchSelections(u8* payload)
s.stageId = getRandomStage();
}
INFO_LOG(SLIPPI, "LPS set char: %d, iSS: %d, %d, stage: %d, team: %d", s.isCharacterSelected, stageSelectOption,
s.isStageSelected, s.stageId, s.teamId);
INFO_LOG(SLIPPI, "LPS set char: %d, iSS: %d, %d, stage: %d, team: %d", s.isCharacterSelected,
stageSelectOption, s.isStageSelected, s.stageId, s.teamId);
s.rngOffset = generator() % 0xFFFF;
@ -2451,12 +2467,12 @@ void CEXISlippi::prepareNewSeed()
appendWordToBuffer(&m_read_queue, newSeed);
}
void CEXISlippi::handleReportGame(u8 *payload)
void CEXISlippi::handleReportGame(u8* payload)
{
SlippiGameReporter::GameReport r;
r.duration_frames = Common::swap32(&payload[0]);
//ERROR_LOG(SLIPPI_ONLINE, "Frames: %d", r.duration_frames);
// ERROR_LOG(SLIPPI_ONLINE, "Frames: %d", r.duration_frames);
for (auto i = 0; i < 2; ++i)
{
@ -2465,9 +2481,9 @@ void CEXISlippi::handleReportGame(u8 *payload)
p.stocks_remaining = payload[5 + offset];
auto swappedDamageDone = Common::swap32(&payload[6 + offset]);
p.damage_done = *(float *)&swappedDamageDone;
p.damage_done = *(float*)&swappedDamageDone;
//ERROR_LOG(SLIPPI_ONLINE, "Stocks: %d, DamageDone: %f", p.stocks_remaining, p.damage_done);
// ERROR_LOG(SLIPPI_ONLINE, "Stocks: %d, DamageDone: %f", p.stocks_remaining, p.damage_done);
r.players.push_back(p);
}

View file

@ -16,21 +16,21 @@
#include <json.hpp>
using json = nlohmann::json;
static size_t receive(char *ptr, size_t size, size_t nmemb, void *rcvBuf)
static size_t receive(char* ptr, size_t size, size_t nmemb, void* rcvBuf)
{
size_t len = size * nmemb;
INFO_LOG(SLIPPI_ONLINE, "[User] Received data: %d", len);
std::string *buf = (std::string *)rcvBuf;
std::string* buf = (std::string*)rcvBuf;
buf->insert(buf->end(), ptr, ptr + len);
return len;
}
SlippiGameReporter::SlippiGameReporter(SlippiUser *user)
SlippiGameReporter::SlippiGameReporter(SlippiUser* user)
{
CURL *curl = curl_easy_init();
CURL* curl = curl_easy_init();
if (curl)
{
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &receive);

View file

@ -1,19 +1,19 @@
#pragma once
#include "Common/CommonTypes.h"
#include "Core/Slippi/SlippiUser.h"
#include <atomic>
#include <condition_variable> // std::condition_variable
#include <curl/curl.h>
#include <mutex> // std::mutex, std::unique_lock
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include <queue>
#include "Common/CommonTypes.h"
#include "Core/Slippi/SlippiUser.h"
class SlippiGameReporter
{
public:
public:
struct PlayerReport
{
float damage_done;
@ -25,22 +25,22 @@ class SlippiGameReporter
std::vector<PlayerReport> players;
};
SlippiGameReporter(SlippiUser *user);
SlippiGameReporter(SlippiUser* user);
~SlippiGameReporter();
void StartReport(GameReport report);
void StartNewSession(std::vector<std::string> player_uids);
void ReportThreadHandler();
protected:
protected:
const std::string REPORT_URL = "https://rankings-dot-slippi.uc.r.appspot.com/report";
CURL *m_curl = nullptr;
struct curl_slist *m_curl_header_list = nullptr;
CURL* m_curl = nullptr;
struct curl_slist* m_curl_header_list = nullptr;
u32 gameIndex = 1;
std::vector<std::string> player_uids;
SlippiUser *m_user;
SlippiUser* m_user;
std::queue<GameReport> game_report_queue;
std::thread reportingThread;
std::mutex mtx;

View file

@ -244,8 +244,9 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
// Check that the packet actually contains the data it claims to
if ((5 + inputsToCopy * SLIPPI_PAD_DATA_SIZE) > (int)packet.getDataSize())
{
ERROR_LOG(SLIPPI_ONLINE,
"Netplay packet too small to read pad buffer. Size: %d, Inputs: %d, MinSize: %d",
ERROR_LOG_FMT(
SLIPPI_ONLINE,
"Netplay packet too small to read pad buffer. Size: {}, Inputs: {}, MinSize: {}",
(int)packet.getDataSize(), inputsToCopy, 5 + inputsToCopy * SLIPPI_PAD_DATA_SIZE);
break;
}

View file

@ -19,7 +19,7 @@ SlippiPad::SlippiPad(int32_t frame, u8* padBuf) : SlippiPad(frame)
memcpy(this->padBuf, padBuf, SLIPPI_PAD_DATA_SIZE);
}
SlippiPad::SlippiPad(int32_t frame, u8 playerIdx, u8 *padBuf) : SlippiPad(frame)
SlippiPad::SlippiPad(int32_t frame, u8 playerIdx, u8* padBuf) : SlippiPad(frame)
{
this->frame = frame;
this->playerIdx = playerIdx;

View file

@ -10,7 +10,7 @@ class SlippiPad
public:
SlippiPad(int32_t frame);
SlippiPad(int32_t frame, u8* padBuf);
SlippiPad(int32_t frame, u8 playerIdx, u8 *padBuf);
SlippiPad(int32_t frame, u8 playerIdx, u8* padBuf);
~SlippiPad();
int32_t frame;

View file

@ -1,9 +1,9 @@
#include "SlippiSpectate.h"
#include <Core/ConfigManager.h>
#include "Common/Base64.hpp"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/Version.h"
#include <Core/ConfigManager.h>
// Networking
#ifdef _WIN32
@ -24,9 +24,10 @@ SlippiSpectateServer& SlippiSpectateServer::getInstance()
return instance;
}
void SlippiSpectateServer::write(u8 *payload, u32 length)
void SlippiSpectateServer::write(u8* payload, u32 length)
{
if (isSpectatorEnabled()) {
if (isSpectatorEnabled())
{
std::string str_payload((char*)payload, length);
m_event_queue.Push(str_payload);
}
@ -56,7 +57,8 @@ void SlippiSpectateServer::writeEvents(u16 peer_id)
// Send menu events
if (!m_in_game && (m_sockets[peer_id]->m_menu_cursor != m_menu_cursor))
{
ENetPacket *packet = enet_packet_create(m_menu_event.data(), m_menu_event.length(), ENET_PACKET_FLAG_RELIABLE);
ENetPacket* packet =
enet_packet_create(m_menu_event.data(), m_menu_event.length(), ENET_PACKET_FLAG_RELIABLE);
// Batch for sending
enet_peer_send(m_sockets[peer_id]->m_peer, 0, packet);
// Record for the peer that it was sent
@ -76,8 +78,8 @@ void SlippiSpectateServer::writeEvents(u16 peer_id)
for (u64 i = m_sockets[peer_id]->m_cursor; i < m_event_buffer.size(); i++)
{
ENetPacket *packet =
enet_packet_create(m_event_buffer[i].data(), m_event_buffer[i].size(), ENET_PACKET_FLAG_RELIABLE);
ENetPacket* packet = enet_packet_create(m_event_buffer[i].data(), m_event_buffer[i].size(),
ENET_PACKET_FLAG_RELIABLE);
// Batch for sending
enet_peer_send(m_sockets[peer_id]->m_peer, 0, packet);
m_sockets[peer_id]->m_cursor++;
@ -186,10 +188,10 @@ SlippiSpectateServer::~SlippiSpectateServer()
}
// CALLED FROM SERVER THREAD
void SlippiSpectateServer::handleMessage(u8 *buffer, u32 length, u16 peer_id)
void SlippiSpectateServer::handleMessage(u8* buffer, u32 length, u16 peer_id)
{
// Unpack the message
std::string message((char *)buffer, length);
std::string message((char*)buffer, length);
json json_message = json::parse(message);
if (!json_message.is_discarded() && (json_message.find("type") != json_message.end()))
{
@ -215,7 +217,8 @@ void SlippiSpectateServer::handleMessage(u8 *buffer, u32 length, u16 peer_id)
// Set the user's cursor position
if (requested_cursor >= m_cursor_offset)
{
// If the requested cursor is past what events we even have, then just tell them to start over
// If the requested cursor is past what events we even have, then just tell them to start
// over
if (requested_cursor > m_event_buffer.size() + m_cursor_offset)
{
m_sockets[peer_id]->m_cursor = 0;
@ -249,8 +252,8 @@ void SlippiSpectateServer::handleMessage(u8 *buffer, u32 length, u16 peer_id)
std::string packet_buffer = reply.dump();
ENetPacket *packet =
enet_packet_create(packet_buffer.data(), (u32)packet_buffer.length(), ENET_PACKET_FLAG_RELIABLE);
ENetPacket* packet = enet_packet_create(packet_buffer.data(), (u32)packet_buffer.length(),
ENET_PACKET_FLAG_RELIABLE);
// Batch for sending
enet_peer_send(m_sockets[peer_id]->m_peer, 0, packet);
@ -277,7 +280,7 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
// or for some period of time after it closes down. You basically have to just
// retry until the OS lets go of the port and we can claim it again
// This typically only takes a few seconds
ENetHost *server = enet_host_create(&server_address, MAX_CLIENTS, 2, 0, 0);
ENetHost* server = enet_host_create(&server_address, MAX_CLIENTS, 2, 0, 0);
int tries = 0;
while (server == nullptr && tries < 20)
{
@ -323,7 +326,6 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
{
case ENET_EVENT_TYPE_CONNECT:
{
INFO_LOG(SLIPPI, "A new spectator connected from %x:%u.\n", event.peer->address.host,
event.peer->address.port);
@ -334,7 +336,8 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
}
case ENET_EVENT_TYPE_RECEIVE:
{
handleMessage(event.packet->data, (u32)event.packet->dataLength, event.peer->incomingPeerID);
handleMessage(event.packet->data, (u32)event.packet->dataLength,
event.peer->incomingPeerID);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);

View file

@ -5,9 +5,9 @@
#include <map>
#include <thread>
#include <enet/enet.h>
#include "Common/SPSCQueue.h"
#include "nlohmann/json.hpp"
#include <enet/enet.h>
using json = nlohmann::json;
// Sockets in windows are unsigned