Let's use rapidjson instead of roll-your-own json. Added helpers to keep allocations minimized.
This commit is contained in:
parent
12054246a2
commit
79d70b8bae
6 changed files with 234 additions and 224 deletions
|
@ -1,6 +1,6 @@
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
set(BASE_RPC_SRC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc.cpp rpc_connection.h rpc_connection.cpp yolojson.h connection.h backoff.h)
|
set(BASE_RPC_SRC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc.cpp rpc_connection.h rpc_connection.cpp serialization.h serialization.cpp connection.h backoff.h)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_win.cpp)
|
add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_win.cpp)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
#include "discord-rpc.h"
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
#include "rpc_connection.h"
|
|
||||||
#include "yolojson.h"
|
|
||||||
#include "backoff.h"
|
#include "backoff.h"
|
||||||
|
#include "rpc_connection.h"
|
||||||
#include "rapidjson/document.h"
|
#include "serialization.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -126,7 +124,7 @@ extern "C" void Discord_Initialize(const char* applicationId, DiscordEventHandle
|
||||||
};
|
};
|
||||||
Connection->onDisconnect = [](int err, const char* message) {
|
Connection->onDisconnect = [](int err, const char* message) {
|
||||||
LastErrorCode = err;
|
LastErrorCode = err;
|
||||||
StringCopy(LastErrorMessage, message, sizeof(LastErrorMessage));
|
StringCopy(LastErrorMessage, message);
|
||||||
WasJustDisconnected.exchange(true);
|
WasJustDisconnected.exchange(true);
|
||||||
UpdateReconnectTime();
|
UpdateReconnectTime();
|
||||||
};
|
};
|
||||||
|
@ -155,9 +153,7 @@ extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||||
{
|
{
|
||||||
auto qmessage = SendQueueGetNextAddMessage();
|
auto qmessage = SendQueueGetNextAddMessage();
|
||||||
if (qmessage) {
|
if (qmessage) {
|
||||||
char* jsonWrite = qmessage->buffer;
|
qmessage->length = JsonWriteRichPresenceObj(qmessage->buffer, sizeof(qmessage->buffer), presence);
|
||||||
JsonWriteRichPresenceObj(jsonWrite, presence);
|
|
||||||
qmessage->length = jsonWrite - qmessage->buffer;
|
|
||||||
SendQueueCommitMessage();
|
SendQueueCommitMessage();
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "rpc_connection.h"
|
#include "rpc_connection.h"
|
||||||
#include "yolojson.h"
|
#include "serialization.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ static RpcConnection Instance;
|
||||||
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId)
|
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId)
|
||||||
{
|
{
|
||||||
Instance.connection = BaseConnection::Create();
|
Instance.connection = BaseConnection::Create();
|
||||||
StringCopy(Instance.appId, applicationId, sizeof(Instance.appId));
|
StringCopy(Instance.appId, applicationId);
|
||||||
return &Instance;
|
return &Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +35,7 @@ void RpcConnection::Open()
|
||||||
}
|
}
|
||||||
|
|
||||||
sendFrame.opcode = Opcode::Handshake;
|
sendFrame.opcode = Opcode::Handshake;
|
||||||
char* json = sendFrame.message;
|
sendFrame.length = JsonWriteHandshakeObj(sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId);
|
||||||
JsonWriteHandshakeObj(json, RpcVersion, appId);
|
|
||||||
sendFrame.length = json - sendFrame.message;
|
|
||||||
|
|
||||||
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
|
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
|
||||||
state = State::Connected;
|
state = State::Connected;
|
||||||
|
@ -97,7 +95,7 @@ bool RpcConnection::Read(rapidjson::Document& message)
|
||||||
message.ParseInsitu(readFrame.message);
|
message.ParseInsitu(readFrame.message);
|
||||||
lastErrorCode = message["code"].GetInt();
|
lastErrorCode = message["code"].GetInt();
|
||||||
const auto& m = message["message"];
|
const auto& m = message["message"];
|
||||||
StringCopy(lastErrorMessage, m.GetString(), sizeof(lastErrorMessage));
|
StringCopy(lastErrorMessage, m.GetString());
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -105,13 +103,11 @@ bool RpcConnection::Read(rapidjson::Document& message)
|
||||||
message.ParseInsitu(readFrame.message);
|
message.ParseInsitu(readFrame.message);
|
||||||
return true;
|
return true;
|
||||||
case Opcode::Ping:
|
case Opcode::Ping:
|
||||||
{
|
|
||||||
readFrame.opcode = Opcode::Pong;
|
readFrame.opcode = Opcode::Pong;
|
||||||
if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) {
|
if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case Opcode::Pong:
|
case Opcode::Pong:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
202
src/serialization.cpp
Normal file
202
src/serialization.cpp
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#include "connection.h"
|
||||||
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
|
||||||
|
// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need to supply some of
|
||||||
|
// your own allocators for stuff rather than use the defaults
|
||||||
|
|
||||||
|
class LinearAllocator {
|
||||||
|
public:
|
||||||
|
char* buffer_;
|
||||||
|
char* end_;
|
||||||
|
LinearAllocator() {
|
||||||
|
assert(0); // needed for some default case in rapidjson, should not use
|
||||||
|
}
|
||||||
|
LinearAllocator(char* buffer, size_t size) : buffer_(buffer), end_(buffer + size) {}
|
||||||
|
static const bool kNeedFree = false;
|
||||||
|
void* Malloc(size_t size)
|
||||||
|
{
|
||||||
|
char* res = buffer_;
|
||||||
|
buffer_ += size;
|
||||||
|
if (buffer_ > end_) {
|
||||||
|
buffer_ = res;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
|
||||||
|
{
|
||||||
|
if (newSize == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// allocate how much you need in the first place
|
||||||
|
assert(!originalPtr && !originalSize);
|
||||||
|
return Malloc(newSize);
|
||||||
|
}
|
||||||
|
static void Free(void* ptr) { /* shrug */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int Size>
|
||||||
|
class FixedLinearAllocator : public LinearAllocator {
|
||||||
|
public:
|
||||||
|
char fixedBuffer_[Size];
|
||||||
|
FixedLinearAllocator() : LinearAllocator(fixedBuffer_, Size) {}
|
||||||
|
static const bool kNeedFree = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// wonder why this isn't a thing already, maybe I missed it
|
||||||
|
class DirectStringBuffer {
|
||||||
|
public:
|
||||||
|
typedef typename char Ch;
|
||||||
|
char* buffer_;
|
||||||
|
char* end_;
|
||||||
|
char* current_;
|
||||||
|
|
||||||
|
DirectStringBuffer(char* buffer, size_t maxLen)
|
||||||
|
: buffer_(buffer)
|
||||||
|
, end_(buffer + maxLen)
|
||||||
|
, current_(buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Put(char c)
|
||||||
|
{
|
||||||
|
if (current_ < end_) {
|
||||||
|
*current_++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Flush() {}
|
||||||
|
size_t GetSize() const
|
||||||
|
{
|
||||||
|
return current_ - buffer_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Encoding = rapidjson::UTF8<char>;
|
||||||
|
// Writer appears to need about 16 bytes per nested object level (with 64bit size_t)
|
||||||
|
using WriterAllocator = FixedLinearAllocator<2048>;
|
||||||
|
constexpr size_t WriterNestingLevels = 2048 / 16;
|
||||||
|
using JsonWriter = rapidjson::Writer<DirectStringBuffer, Encoding, Encoding, WriterAllocator, rapidjson::kWriteNoFlags>;
|
||||||
|
|
||||||
|
// it's ever so slightly faster to not have to strlen the key
|
||||||
|
template<typename T>
|
||||||
|
void WriteKey(JsonWriter& w, T& k) {
|
||||||
|
w.Key(k, sizeof(T) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void WriteOptionalString(JsonWriter& w, T& k, const char* value) {
|
||||||
|
if (value) {
|
||||||
|
w.Key(k, sizeof(T) - 1);
|
||||||
|
w.String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, const DiscordRichPresence* presence)
|
||||||
|
{
|
||||||
|
DirectStringBuffer sb(dest, maxLen);
|
||||||
|
WriterAllocator wa;
|
||||||
|
JsonWriter writer(sb, &wa, WriterNestingLevels);
|
||||||
|
|
||||||
|
// const args = {pid, activity};
|
||||||
|
// this.socket.write(encode(OPCODES.FRAME, { nonce: uuid(), cmd : 'SET_ACTIVITY', args })
|
||||||
|
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteKey(writer, "args");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteKey(writer, "activity");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteOptionalString(writer, "state", presence->state);
|
||||||
|
WriteOptionalString(writer, "details", presence->details);
|
||||||
|
|
||||||
|
if (presence->startTimestamp || presence->endTimestamp) {
|
||||||
|
WriteKey(writer, "timestamps");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
if (presence->startTimestamp) {
|
||||||
|
WriteKey(writer, "start");
|
||||||
|
writer.Int64(presence->startTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presence->endTimestamp) {
|
||||||
|
WriteKey(writer, "end");
|
||||||
|
writer.Int64(presence->endTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presence->largeImageKey || presence->largeImageText || presence->smallImageKey || presence->smallImageText) {
|
||||||
|
WriteKey(writer, "assets");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteOptionalString(writer, "large_image", presence->largeImageKey);
|
||||||
|
WriteOptionalString(writer, "large_text", presence->largeImageText);
|
||||||
|
WriteOptionalString(writer, "small_image", presence->smallImageKey);
|
||||||
|
WriteOptionalString(writer, "small_text", presence->smallImageText);
|
||||||
|
|
||||||
|
writer.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presence->partyId || presence->partySize || presence->partyMax) {
|
||||||
|
WriteKey(writer, "party");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteOptionalString(writer, "id", presence->partyId);
|
||||||
|
if (presence->partySize) {
|
||||||
|
writer.StartArray();
|
||||||
|
|
||||||
|
writer.Int(presence->partySize);
|
||||||
|
if (0 < presence->partyMax) {
|
||||||
|
writer.Int(presence->partyMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.EndArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presence->matchSecret || presence->joinSecret || presence->spectateSecret) {
|
||||||
|
WriteKey(writer, "secrets");
|
||||||
|
writer.StartObject();
|
||||||
|
|
||||||
|
WriteOptionalString(writer, "match", presence->matchSecret);
|
||||||
|
WriteOptionalString(writer, "join", presence->joinSecret);
|
||||||
|
WriteOptionalString(writer, "spectate", presence->spectateSecret);
|
||||||
|
|
||||||
|
writer.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Key("instance");
|
||||||
|
writer.Bool(presence->instance != 0);
|
||||||
|
|
||||||
|
writer.EndObject(); // activity
|
||||||
|
|
||||||
|
writer.EndObject(); // args
|
||||||
|
|
||||||
|
writer.EndObject(); // top level
|
||||||
|
|
||||||
|
return sb.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId)
|
||||||
|
{
|
||||||
|
DirectStringBuffer sb(dest, maxLen);
|
||||||
|
WriterAllocator wa;
|
||||||
|
JsonWriter writer(sb, &wa, WriterNestingLevels);
|
||||||
|
|
||||||
|
writer.StartObject();
|
||||||
|
WriteKey(writer, "v");
|
||||||
|
writer.Int(version);
|
||||||
|
WriteKey(writer, "client_id");
|
||||||
|
writer.String(applicationId);
|
||||||
|
writer.EndObject();
|
||||||
|
|
||||||
|
return sb.GetSize();
|
||||||
|
}
|
||||||
|
|
23
src/serialization.h
Normal file
23
src/serialization.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// if only there was a standard library function for this
|
||||||
|
template<size_t Len>
|
||||||
|
inline size_t StringCopy(char (&dest)[Len], const char* src) {
|
||||||
|
if (!dest || !src || !Len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t copied;
|
||||||
|
char* out = dest;
|
||||||
|
for (copied = 1; *src && copied < Len; ++copied) {
|
||||||
|
*out++ = *src++;
|
||||||
|
}
|
||||||
|
*out = 0;
|
||||||
|
return copied - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DiscordRichPresence;
|
||||||
|
|
||||||
|
size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, const DiscordRichPresence* presence);
|
||||||
|
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId);
|
207
src/yolojson.h
207
src/yolojson.h
|
@ -1,207 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "connection.h"
|
|
||||||
#include "discord-rpc.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is as simple of a json writing thing as possible; does not try to keep you
|
|
||||||
from overflowing buffer, so make sure you have room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// if only there was a standard library function for this
|
|
||||||
inline size_t StringCopy(char* dest, const char* src, size_t maxBytes = UINT32_MAX) {
|
|
||||||
if (!dest || !src || !maxBytes) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t copied;
|
|
||||||
for (copied = 1; *src && copied < maxBytes; ++copied) {
|
|
||||||
*dest++ = *src++;
|
|
||||||
}
|
|
||||||
*dest = 0;
|
|
||||||
return copied - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWriteEscapedString(char*& dest, const char* src)
|
|
||||||
{
|
|
||||||
for (char c = *src++; c; c = *src++) {
|
|
||||||
switch (c) {
|
|
||||||
case '\"':
|
|
||||||
case '\\':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = c;
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'b';
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'f';
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'n';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'r';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 't';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*dest++ = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void JsonWriteNumber(char*& dest, T number)
|
|
||||||
{
|
|
||||||
if (!number) {
|
|
||||||
*dest++ = '0';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (number < 0) {
|
|
||||||
*dest++ = '-';
|
|
||||||
number = -number;
|
|
||||||
}
|
|
||||||
char temp[32];
|
|
||||||
int place = 0;
|
|
||||||
while (number) {
|
|
||||||
auto digit = number % 10;
|
|
||||||
number = number / 10;
|
|
||||||
temp[place++] = '0' + (char)digit;
|
|
||||||
}
|
|
||||||
for (--place; place >= 0; --place) {
|
|
||||||
*dest++ = temp[place];
|
|
||||||
}
|
|
||||||
*dest = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWritePropName(char*& dest, const char* name)
|
|
||||||
{
|
|
||||||
*dest++ = '"';
|
|
||||||
dest += StringCopy(dest, name);
|
|
||||||
*dest++ = '"';
|
|
||||||
*dest++ = ':';
|
|
||||||
*dest++ = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWritePropSep(char*& dest)
|
|
||||||
{
|
|
||||||
*dest++ = ',';
|
|
||||||
*dest++ = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWriteStringProp(char*& dest, const char* name, const char* value)
|
|
||||||
{
|
|
||||||
JsonWritePropName(dest, name);
|
|
||||||
*dest++ = '"';
|
|
||||||
JsonWriteEscapedString(dest, value);
|
|
||||||
*dest++ = '"';
|
|
||||||
JsonWritePropSep(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void JsonWriteNumberAsStringProp(char*& dest, const char* name, T value)
|
|
||||||
{
|
|
||||||
JsonWritePropName(dest, name);
|
|
||||||
*dest++ = '"';
|
|
||||||
JsonWriteNumber(dest, value);
|
|
||||||
*dest++ = '"';
|
|
||||||
JsonWritePropSep(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void JsonWriteNumberProp(char*& dest, const char* name, T value)
|
|
||||||
{
|
|
||||||
JsonWritePropName(dest, name);
|
|
||||||
JsonWriteNumber(dest, value);
|
|
||||||
JsonWritePropSep(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWriteBoolProp(char*& dest, const char* name, bool value)
|
|
||||||
{
|
|
||||||
JsonWritePropName(dest, name);
|
|
||||||
dest += StringCopy(dest, value ? "true" : "false");
|
|
||||||
JsonWritePropSep(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWriteRichPresenceObj(char*& dest, const DiscordRichPresence* presence)
|
|
||||||
{
|
|
||||||
*dest++ = '{';
|
|
||||||
|
|
||||||
if (presence->state) {
|
|
||||||
JsonWriteStringProp(dest, "state", presence->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->details) {
|
|
||||||
JsonWriteStringProp(dest, "details", presence->details);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->startTimestamp) {
|
|
||||||
JsonWriteNumberAsStringProp(dest, "start_timestamp", presence->startTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->endTimestamp) {
|
|
||||||
JsonWriteNumberAsStringProp(dest, "end_timestamp", presence->endTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->largeImageKey) {
|
|
||||||
JsonWriteStringProp(dest, "large_image_key", presence->largeImageKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->largeImageText) {
|
|
||||||
JsonWriteStringProp(dest, "large_image_text", presence->largeImageText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->smallImageKey) {
|
|
||||||
JsonWriteStringProp(dest, "small_image_key", presence->smallImageKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->smallImageText) {
|
|
||||||
JsonWriteStringProp(dest, "small_image_text", presence->smallImageText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->partyId) {
|
|
||||||
JsonWriteStringProp(dest, "party_id", presence->partyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->partyMax) {
|
|
||||||
JsonWriteNumberProp(dest, "party_size", presence->partySize);
|
|
||||||
JsonWriteNumberProp(dest, "party_max", presence->partyMax);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->matchSecret) {
|
|
||||||
JsonWriteStringProp(dest, "match_secret", presence->matchSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->joinSecret) {
|
|
||||||
JsonWriteStringProp(dest, "join_secret", presence->joinSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->spectateSecret) {
|
|
||||||
JsonWriteStringProp(dest, "spectate_secret", presence->spectateSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonWriteBoolProp(dest, "instance", presence->instance != 0);
|
|
||||||
|
|
||||||
dest -= 1;
|
|
||||||
*(dest - 1) = '}';
|
|
||||||
*dest = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JsonWriteHandshakeObj(char*& dest, int version, const char* applicationId)
|
|
||||||
{
|
|
||||||
*dest++ = '{';
|
|
||||||
|
|
||||||
JsonWriteNumberProp(dest, "v", version);
|
|
||||||
JsonWriteStringProp(dest, "client_id", applicationId);
|
|
||||||
|
|
||||||
dest -= 1;
|
|
||||||
*(dest - 1) = '}';
|
|
||||||
*dest = 0;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue