146 lines
5.2 KiB
C++
146 lines
5.2 KiB
C++
#include "classic/classic_mark_client.h"
|
|
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
using namespace mtnet::classic;
|
|
|
|
static std::vector<uint8_t> take_all(ClassicStream &stream) {
|
|
std::vector<uint8_t> out(stream.outgoing_pending());
|
|
if (!out.empty()) {
|
|
assert(stream.take_outgoing(out.data(), out.size()) == out.size());
|
|
}
|
|
return out;
|
|
}
|
|
|
|
static void put_u16(std::vector<uint8_t> &p, size_t off, uint16_t v) {
|
|
p[off] = static_cast<uint8_t>(v);
|
|
p[off + 1] = static_cast<uint8_t>(v >> 8);
|
|
}
|
|
|
|
static void put_u32(std::vector<uint8_t> &p, size_t off, uint32_t v) {
|
|
p[off] = static_cast<uint8_t>(v);
|
|
p[off + 1] = static_cast<uint8_t>(v >> 8);
|
|
p[off + 2] = static_cast<uint8_t>(v >> 16);
|
|
p[off + 3] = static_cast<uint8_t>(v >> 24);
|
|
}
|
|
|
|
static void test_mark_download() {
|
|
ClassicMarkClient client(0x11223344u, 0x55667788u);
|
|
Handshake handshake{};
|
|
handshake.header = HDR_HANDSHAKE;
|
|
handshake.handshake = 7;
|
|
handshake.time = 100;
|
|
client.stream().feed(&handshake, sizeof(handshake));
|
|
std::vector<uint8_t> login = take_all(client.stream());
|
|
assert(login.size() == sizeof(Handshake) + sizeof(CGMarkLogin));
|
|
assert(login[sizeof(Handshake)] == HDR_CG_MARK_LOGIN);
|
|
uint32_t handle = 0;
|
|
std::memcpy(&handle, login.data() + sizeof(Handshake) + 1, sizeof(handle));
|
|
assert(handle == 0x11223344u);
|
|
uint32_t random_key = 0;
|
|
std::memcpy(&random_key, login.data() + sizeof(Handshake) + 5, sizeof(random_key));
|
|
assert(random_key == 0x55667788u);
|
|
|
|
Handshake resync = handshake;
|
|
resync.time = 200;
|
|
resync.delta = 3;
|
|
client.stream().feed(&resync, sizeof(resync));
|
|
std::vector<uint8_t> repeated_login = take_all(client.stream());
|
|
assert(repeated_login.size() == sizeof(Handshake) + sizeof(CGMarkLogin));
|
|
assert(repeated_login[0] == HDR_HANDSHAKE);
|
|
assert(repeated_login[sizeof(Handshake)] == HDR_CG_MARK_LOGIN);
|
|
|
|
std::vector<uint8_t> phase{HDR_GC_PHASE, PHASE_LOGIN};
|
|
client.stream().feed(phase.data(), phase.size());
|
|
std::vector<uint8_t> request = take_all(client.stream());
|
|
assert(request.size() == sizeof(CGMarkIDXList));
|
|
assert(request[0] == HDR_CG_MARK_IDXLIST);
|
|
|
|
// One guild maps to image zero, position one. Feed the whole-size frame in
|
|
// two chunks to exercise the custom raw framing path.
|
|
std::vector<uint8_t> idx(sizeof(GCMarkIDXList) + 4);
|
|
idx[0] = HDR_GC_MARK_IDXLIST;
|
|
put_u32(idx, 1, static_cast<uint32_t>(idx.size()));
|
|
put_u16(idx, 5, 1);
|
|
put_u16(idx, 7, 42);
|
|
put_u16(idx, 9, 1);
|
|
client.stream().feed(idx.data(), 6);
|
|
assert(client.stream().outgoing_pending() == 0);
|
|
client.stream().feed(idx.data() + 6, idx.size() - 6);
|
|
request = take_all(client.stream());
|
|
assert(request.size() == sizeof(CGMarkCRCList));
|
|
assert(request[0] == HDR_CG_MARK_CRCLIST && request[1] == 0);
|
|
assert(client.marks().has_mark(42));
|
|
|
|
// A valid zero-block image response advances the image state and completes
|
|
// the download without requiring LZO data in this framing test.
|
|
std::vector<uint8_t> block(sizeof(GCMarkBlock));
|
|
block[0] = HDR_GC_MARK_BLOCK;
|
|
put_u32(block, 1, static_cast<uint32_t>(block.size()));
|
|
block[5] = 0;
|
|
put_u32(block, 6, 0);
|
|
client.stream().feed(block.data(), block.size());
|
|
assert(client.complete());
|
|
}
|
|
|
|
static void test_symbol_download() {
|
|
ClassicMarkClient client(0x11u, 0x22u);
|
|
client.set_download_symbol(42);
|
|
std::vector<uint8_t> phase{HDR_GC_PHASE, PHASE_LOGIN};
|
|
client.stream().feed(phase.data(), phase.size());
|
|
std::vector<uint8_t> request = take_all(client.stream());
|
|
assert(request.size() == sizeof(CGSymbolCRC));
|
|
assert(request[0] == HDR_CG_SYMBOL_CRC);
|
|
uint32_t gid = 0;
|
|
std::memcpy(&gid, request.data() + 1, sizeof(gid));
|
|
assert(gid == 42);
|
|
|
|
const std::vector<uint8_t> payload{0xAA, 0xBB, 0xCC};
|
|
std::vector<uint8_t> symbol(sizeof(GCSymbolData) + payload.size());
|
|
symbol[0] = HDR_GC_SYMBOL_DATA;
|
|
put_u16(symbol, 1, static_cast<uint16_t>(symbol.size()));
|
|
put_u32(symbol, 3, 42);
|
|
std::memcpy(symbol.data() + sizeof(GCSymbolData), payload.data(), payload.size());
|
|
client.stream().feed(symbol.data(), symbol.size());
|
|
assert(client.complete());
|
|
assert(client.symbol_guild_id() == 42);
|
|
assert(client.symbol_data() == payload);
|
|
}
|
|
|
|
static void test_upload_layouts() {
|
|
uint32_t px[GUILD_MARK_WIDTH * GUILD_MARK_HEIGHT] = {};
|
|
px[0] = 0x44332211u;
|
|
ClassicMarkClient mark(1, 2);
|
|
mark.set_upload_mark(42, px);
|
|
std::vector<uint8_t> phase{HDR_GC_PHASE, PHASE_LOGIN};
|
|
mark.stream().feed(phase.data(), phase.size());
|
|
std::vector<uint8_t> packet = take_all(mark.stream());
|
|
assert(packet.size() == sizeof(CGMarkUpload));
|
|
assert(packet[0] == HDR_CG_MARK_UPLOAD);
|
|
uint32_t gid = 0;
|
|
std::memcpy(&gid, packet.data() + 1, sizeof(gid));
|
|
assert(gid == 42);
|
|
assert(packet[5] == 0x11 && packet[6] == 0x22 && packet[7] == 0x33 && packet[8] == 0x44);
|
|
|
|
ClassicMarkClient symbol(3, 4);
|
|
symbol.set_upload_symbol(99, std::vector<uint8_t>{1, 2, 3});
|
|
symbol.stream().feed(phase.data(), phase.size());
|
|
packet = take_all(symbol.stream());
|
|
assert(packet.size() == sizeof(CGGuildSymbolUpload) + 3);
|
|
assert(packet[0] == HDR_CG_GUILD_SYMBOL_UPLOAD);
|
|
assert(packet[1] == packet.size() && packet[2] == 0);
|
|
std::memcpy(&gid, packet.data() + 3, sizeof(gid));
|
|
assert(gid == 99);
|
|
assert(packet[7] == 1 && packet[8] == 2 && packet[9] == 3);
|
|
}
|
|
|
|
int main() {
|
|
test_mark_download();
|
|
test_symbol_download();
|
|
test_upload_layouts();
|
|
return 0;
|
|
}
|