forked from alterware/s1-mod
init
This commit is contained in:
182
src/client/game/demonware/bit_buffer.cpp
Normal file
182
src/client/game/demonware/bit_buffer.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bit_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output)
|
||||
{
|
||||
return this->read(bytes * 8, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_bool(bool* output)
|
||||
{
|
||||
if (!this->read_data_type(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_uint32(unsigned int* output)
|
||||
{
|
||||
if (!this->read_data_type(8))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->read(32, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_data_type(const char expected)
|
||||
{
|
||||
char data_type = 0;
|
||||
|
||||
if (!this->use_data_types_) return true;
|
||||
if (this->read(5, &data_type))
|
||||
{
|
||||
return (data_type == expected);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bytes(const unsigned int bytes, const char* data)
|
||||
{
|
||||
return this->write_bytes(bytes, reinterpret_cast<const unsigned char*>(data));
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bytes(const unsigned int bytes, const unsigned char* data)
|
||||
{
|
||||
return this->write(bytes * 8, data);
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bool(bool data)
|
||||
{
|
||||
if (this->write_data_type(1))
|
||||
{
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_int32(int data)
|
||||
{
|
||||
if (this->write_data_type(7))
|
||||
{
|
||||
return this->write(32, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_uint32(unsigned int data)
|
||||
{
|
||||
if (this->write_data_type(8))
|
||||
{
|
||||
return this->write(32, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_data_type(char data)
|
||||
{
|
||||
if (!this->use_data_types_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->write(5, &data);
|
||||
}
|
||||
|
||||
bool bit_buffer::read(unsigned int bits, void* output)
|
||||
{
|
||||
if (bits == 0) return false;
|
||||
if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false;
|
||||
|
||||
int cur_byte = this->current_bit_ >> 3;
|
||||
auto cur_out = 0;
|
||||
|
||||
const char* bytes = this->buffer_.data();
|
||||
const auto output_bytes = static_cast<unsigned char*>(output);
|
||||
|
||||
while (bits > 0)
|
||||
{
|
||||
const int min_bit = (bits < 8) ? bits : 8;
|
||||
const auto this_byte = bytes[cur_byte++] & 0xFF;
|
||||
const int remain = this->current_bit_ & 7;
|
||||
|
||||
if ((min_bit + remain) <= 8)
|
||||
{
|
||||
output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain));
|
||||
}
|
||||
else
|
||||
{
|
||||
output_bytes[cur_out] = BYTE(
|
||||
(0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain));
|
||||
}
|
||||
|
||||
cur_out++;
|
||||
this->current_bit_ += min_bit;
|
||||
bits -= min_bit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bit_buffer::write(const unsigned int bits, const void* data)
|
||||
{
|
||||
if (bits == 0) return false;
|
||||
this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1);
|
||||
|
||||
int bit = bits;
|
||||
const auto bytes = const_cast<char*>(this->buffer_.data());
|
||||
const auto* input_bytes = static_cast<const unsigned char*>(data);
|
||||
|
||||
while (bit > 0)
|
||||
{
|
||||
const int bit_pos = this->current_bit_ & 7;
|
||||
auto rem_bit = 8 - bit_pos;
|
||||
const auto this_write = (bit < rem_bit) ? bit : rem_bit;
|
||||
|
||||
const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write)));
|
||||
const int byte_pos = this->current_bit_ >> 3;
|
||||
|
||||
const BYTE temp_byte = (mask & bytes[byte_pos]);
|
||||
const BYTE this_bit = ((bits - bit) & 7);
|
||||
const auto this_byte = (bits - bit) >> 3;
|
||||
|
||||
auto this_data = input_bytes[this_byte];
|
||||
|
||||
const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0;
|
||||
|
||||
this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit));
|
||||
|
||||
const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte);
|
||||
bytes[byte_pos] = out_byte;
|
||||
|
||||
this->current_bit_ += this_write;
|
||||
bit -= this_write;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bit_buffer::set_use_data_types(const bool use_data_types)
|
||||
{
|
||||
this->use_data_types_ = use_data_types;
|
||||
}
|
||||
|
||||
unsigned int bit_buffer::size() const
|
||||
{
|
||||
return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0);
|
||||
}
|
||||
|
||||
std::string& bit_buffer::get_buffer()
|
||||
{
|
||||
this->buffer_.resize(this->size());
|
||||
return this->buffer_;
|
||||
}
|
||||
}
|
40
src/client/game/demonware/bit_buffer.hpp
Normal file
40
src/client/game/demonware/bit_buffer.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bit_buffer final
|
||||
{
|
||||
public:
|
||||
bit_buffer() = default;
|
||||
|
||||
explicit bit_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool read_bytes(unsigned int bytes, unsigned char* output);
|
||||
bool read_bool(bool* output);
|
||||
bool read_uint32(unsigned int* output);
|
||||
bool read_data_type(char expected);
|
||||
|
||||
bool write_bytes(unsigned int bytes, const char* data);
|
||||
bool write_bytes(unsigned int bytes, const unsigned char* data);
|
||||
bool write_bool(bool data);
|
||||
bool write_int32(int data);
|
||||
bool write_uint32(unsigned int data);
|
||||
bool write_data_type(char data);
|
||||
|
||||
bool read(unsigned int bits, void* output);
|
||||
bool write(unsigned int bits, const void* data);
|
||||
|
||||
void set_use_data_types(bool use_data_types);
|
||||
|
||||
unsigned int size() const;
|
||||
|
||||
std::string& get_buffer();
|
||||
|
||||
private:
|
||||
std::string buffer_{};
|
||||
unsigned int current_bit_ = 0;
|
||||
bool use_data_types_ = true;
|
||||
};
|
||||
}
|
308
src/client/game/demonware/byte_buffer.cpp
Normal file
308
src/client/game/demonware/byte_buffer.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <std_include.hpp>
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bool byte_buffer::read_byte(unsigned char* output)
|
||||
{
|
||||
if (!this->read_data_type(3)) return false;
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_bool(bool* output)
|
||||
{
|
||||
if (!this->read_data_type(1)) return false;
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int16(short* output)
|
||||
{
|
||||
if (!this->read_data_type(5)) return false;
|
||||
return this->read(2, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint16(unsigned short* output)
|
||||
{
|
||||
if (!this->read_data_type(6)) return false;
|
||||
return this->read(2, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int32(int* output)
|
||||
{
|
||||
if (!this->read_data_type(7)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint32(unsigned int* output)
|
||||
{
|
||||
if (!this->read_data_type(8)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int64(__int64* output)
|
||||
{
|
||||
if (!this->read_data_type(9)) return false;
|
||||
return this->read(8, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint64(unsigned __int64* output)
|
||||
{
|
||||
if (!this->read_data_type(10)) return false;
|
||||
return this->read(8, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_float(float* output)
|
||||
{
|
||||
if (!this->read_data_type(13)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(std::string* output)
|
||||
{
|
||||
char* out_data;
|
||||
if (this->read_string(&out_data))
|
||||
{
|
||||
output->clear();
|
||||
output->append(out_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(char** output)
|
||||
{
|
||||
if (!this->read_data_type(16)) return false;
|
||||
|
||||
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
this->current_byte_ += strlen(*output) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(char* output, const int length)
|
||||
{
|
||||
if (!this->read_data_type(16)) return false;
|
||||
|
||||
strcpy_s(output, length, const_cast<char*>(this->buffer_.data()) + this->current_byte_);
|
||||
this->current_byte_ += strlen(output) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_blob(std::string* output)
|
||||
{
|
||||
char* out_data;
|
||||
int length;
|
||||
if (this->read_blob(&out_data, &length))
|
||||
{
|
||||
output->clear();
|
||||
output->append(out_data, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_blob(char** output, int* length)
|
||||
{
|
||||
if (!this->read_data_type(0x13))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int size;
|
||||
this->read_uint32(&size);
|
||||
|
||||
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
*length = static_cast<int>(size);
|
||||
|
||||
this->current_byte_ += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_data_type(const char expected)
|
||||
{
|
||||
if (!this->use_data_types_) return true;
|
||||
|
||||
char type;
|
||||
this->read(1, &type);
|
||||
return type == expected;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count,
|
||||
unsigned int* element_size)
|
||||
{
|
||||
if (element_count) *element_count = 0;
|
||||
if (element_size) *element_size = 0;
|
||||
|
||||
if (!this->read_data_type(expected + 100)) return false;
|
||||
|
||||
uint32_t array_size, el_count;
|
||||
if (!this->read_uint32(&array_size)) return false;
|
||||
|
||||
this->set_use_data_types(false);
|
||||
this->read_uint32(&el_count);
|
||||
this->set_use_data_types(true);
|
||||
|
||||
if (element_count) *element_count = el_count;
|
||||
if (element_size) *element_size = array_size / el_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write_byte(char data)
|
||||
{
|
||||
this->write_data_type(3);
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_bool(bool data)
|
||||
{
|
||||
this->write_data_type(1);
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int16(short data)
|
||||
{
|
||||
this->write_data_type(5);
|
||||
return this->write(2, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint16(unsigned short data)
|
||||
{
|
||||
this->write_data_type(6);
|
||||
return this->write(2, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int32(int data)
|
||||
{
|
||||
this->write_data_type(7);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint32(unsigned int data)
|
||||
{
|
||||
this->write_data_type(8);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int64(__int64 data)
|
||||
{
|
||||
this->write_data_type(9);
|
||||
return this->write(8, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint64(unsigned __int64 data)
|
||||
{
|
||||
this->write_data_type(10);
|
||||
return this->write(8, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_data_type(char data)
|
||||
{
|
||||
if (!this->use_data_types_) return true;
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_float(float data)
|
||||
{
|
||||
this->write_data_type(13);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_string(const std::string& data)
|
||||
{
|
||||
return this->write_string(data.data());
|
||||
}
|
||||
|
||||
bool byte_buffer::write_string(const char* data)
|
||||
{
|
||||
this->write_data_type(16);
|
||||
return this->write(static_cast<int>(strlen(data)) + 1, data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_blob(const std::string& data)
|
||||
{
|
||||
return this->write_blob(data.data(), INT(data.size()));
|
||||
}
|
||||
|
||||
bool byte_buffer::write_blob(const char* data, const int length)
|
||||
{
|
||||
this->write_data_type(0x13);
|
||||
this->write_uint32(length);
|
||||
|
||||
return this->write(length, data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count,
|
||||
const unsigned int element_size)
|
||||
{
|
||||
const auto using_types = this->is_using_data_types();
|
||||
this->set_use_data_types(false);
|
||||
|
||||
auto result = this->write_byte(type + 100);
|
||||
|
||||
this->set_use_data_types(true);
|
||||
result &= this->write_uint32(element_count * element_size);
|
||||
this->set_use_data_types(false);
|
||||
|
||||
result &= this->write_uint32(element_count);
|
||||
|
||||
this->set_use_data_types(using_types);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool byte_buffer::read(const int bytes, void* output)
|
||||
{
|
||||
if (bytes + this->current_byte_ > this->buffer_.size()) return false;
|
||||
|
||||
std::memmove(output, this->buffer_.data() + this->current_byte_, bytes);
|
||||
this->current_byte_ += bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write(const int bytes, const void* data)
|
||||
{
|
||||
this->buffer_.append(static_cast<const char*>(data), bytes);
|
||||
this->current_byte_ += bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write(const std::string& data)
|
||||
{
|
||||
return this->write(static_cast<int>(data.size()), data.data());
|
||||
}
|
||||
|
||||
void byte_buffer::set_use_data_types(const bool use_data_types)
|
||||
{
|
||||
this->use_data_types_ = use_data_types;
|
||||
}
|
||||
|
||||
size_t byte_buffer::size() const
|
||||
{
|
||||
return this->buffer_.size();
|
||||
}
|
||||
|
||||
bool byte_buffer::is_using_data_types() const
|
||||
{
|
||||
return use_data_types_;
|
||||
}
|
||||
|
||||
std::string& byte_buffer::get_buffer()
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
|
||||
std::string byte_buffer::get_remaining()
|
||||
{
|
||||
return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end());
|
||||
}
|
||||
|
||||
bool byte_buffer::has_more_data() const
|
||||
{
|
||||
return this->buffer_.size() > this->current_byte_;
|
||||
}
|
||||
}
|
69
src/client/game/demonware/byte_buffer.hpp
Normal file
69
src/client/game/demonware/byte_buffer.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class byte_buffer final
|
||||
{
|
||||
public:
|
||||
byte_buffer() = default;
|
||||
|
||||
explicit byte_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool read_byte(unsigned char* output);
|
||||
bool read_bool(bool* output);
|
||||
bool read_int16(short* output);
|
||||
bool read_uint16(unsigned short* output);
|
||||
bool read_int32(int* output);
|
||||
bool read_uint32(unsigned int* output);
|
||||
bool read_int64(__int64* output);
|
||||
bool read_uint64(unsigned __int64* output);
|
||||
bool read_float(float* output);
|
||||
bool read_string(char** output);
|
||||
bool read_string(char* output, int length);
|
||||
bool read_string(std::string* output);
|
||||
bool read_blob(char** output, int* length);
|
||||
bool read_blob(std::string* output);
|
||||
bool read_data_type(char expected);
|
||||
|
||||
bool read_array_header(unsigned char expected, unsigned int* element_count,
|
||||
unsigned int* element_size = nullptr);
|
||||
|
||||
bool write_byte(char data);
|
||||
bool write_bool(bool data);
|
||||
bool write_int16(short data);
|
||||
bool write_uint16(unsigned short data);
|
||||
bool write_int32(int data);
|
||||
bool write_uint32(unsigned int data);
|
||||
bool write_int64(__int64 data);
|
||||
bool write_uint64(unsigned __int64 data);
|
||||
bool write_data_type(char data);
|
||||
bool write_float(float data);
|
||||
bool write_string(const char* data);
|
||||
bool write_string(const std::string& data);
|
||||
bool write_blob(const char* data, int length);
|
||||
bool write_blob(const std::string& data);
|
||||
|
||||
bool write_array_header(unsigned char type, unsigned int element_count, unsigned int element_size);
|
||||
|
||||
bool read(int bytes, void* output);
|
||||
bool write(int bytes, const void* data);
|
||||
bool write(const std::string& data);
|
||||
|
||||
void set_use_data_types(bool use_data_types);
|
||||
size_t size() const;
|
||||
|
||||
bool is_using_data_types() const;
|
||||
|
||||
std::string& get_buffer();
|
||||
std::string get_remaining();
|
||||
|
||||
bool has_more_data() const;
|
||||
|
||||
private:
|
||||
std::string buffer_;
|
||||
size_t current_byte_ = 0;
|
||||
bool use_data_types_ = true;
|
||||
};
|
||||
}
|
144
src/client/game/demonware/data_types.hpp
Normal file
144
src/client/game/demonware/data_types.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTaskResult
|
||||
{
|
||||
public:
|
||||
virtual ~bdTaskResult() = default;
|
||||
|
||||
virtual void serialize(byte_buffer*)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void deserialize(byte_buffer*)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class bdFileData final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::string file_data;
|
||||
|
||||
explicit bdFileData(std::string buffer) : file_data(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_blob(this->file_data);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_blob(&this->file_data);
|
||||
}
|
||||
};
|
||||
|
||||
class bdFileInfo final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint64_t file_id;
|
||||
uint32_t create_time;
|
||||
uint32_t modified_time;
|
||||
bool priv;
|
||||
uint64_t owner_id;
|
||||
std::string filename;
|
||||
uint32_t file_size;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint32(this->file_size);
|
||||
buffer->write_uint64(this->file_id);
|
||||
buffer->write_uint32(this->create_time);
|
||||
buffer->write_uint32(this->modified_time);
|
||||
buffer->write_bool(this->priv);
|
||||
buffer->write_uint64(this->owner_id);
|
||||
buffer->write_string(this->filename);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint32(&this->file_size);
|
||||
buffer->read_uint64(&this->file_id);
|
||||
buffer->read_uint32(&this->create_time);
|
||||
buffer->read_uint32(&this->modified_time);
|
||||
buffer->read_bool(&this->priv);
|
||||
buffer->read_uint64(&this->owner_id);
|
||||
buffer->read_string(&this->filename);
|
||||
}
|
||||
};
|
||||
|
||||
class bdTimeStamp final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint32_t unix_time;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint32(this->unix_time);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint32(&this->unix_time);
|
||||
}
|
||||
};
|
||||
|
||||
class bdDMLInfo : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::string country_code; // Char [3]
|
||||
std::string country; // Char [65]
|
||||
std::string region; // Char [65]
|
||||
std::string city; // Char [129]
|
||||
float latitude;
|
||||
float longitude;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_string(this->country_code);
|
||||
buffer->write_string(this->country);
|
||||
buffer->write_string(this->region);
|
||||
buffer->write_string(this->city);
|
||||
buffer->write_float(this->latitude);
|
||||
buffer->write_float(this->longitude);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_string(&this->country_code);
|
||||
buffer->read_string(&this->country);
|
||||
buffer->read_string(&this->region);
|
||||
buffer->read_string(&this->city);
|
||||
buffer->read_float(&this->latitude);
|
||||
buffer->read_float(&this->longitude);
|
||||
}
|
||||
};
|
||||
|
||||
class bdDMLRawData final : public bdDMLInfo
|
||||
{
|
||||
public:
|
||||
uint32_t asn; // Autonomous System Number.
|
||||
std::string timezone;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
bdDMLInfo::serialize(buffer);
|
||||
|
||||
buffer->write_uint32(this->asn);
|
||||
buffer->write_string(this->timezone);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
bdDMLInfo::deserialize(buffer);
|
||||
|
||||
buffer->read_uint32(&this->asn);
|
||||
buffer->read_string(&this->timezone);
|
||||
}
|
||||
};
|
||||
}
|
130
src/client/game/demonware/keys.cpp
Normal file
130
src/client/game/demonware/keys.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <std_include.hpp>
|
||||
#include "keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
struct data_t
|
||||
{
|
||||
char m_session_key[24];
|
||||
char m_response[8];
|
||||
char m_hmac_key[20];
|
||||
char m_enc_key[16];
|
||||
char m_dec_key[16];
|
||||
} data{};
|
||||
|
||||
std::string packet_buffer;
|
||||
|
||||
void calculate_hmacs_s1(const char* data_, const unsigned int data_size, const char* key,
|
||||
const unsigned int key_size,
|
||||
char* dst, const unsigned int dst_size)
|
||||
{
|
||||
char buffer[64];
|
||||
unsigned int pos = 0;
|
||||
unsigned int out_offset = 0;
|
||||
char count = 1;
|
||||
std::string result;
|
||||
|
||||
// buffer add key
|
||||
std::memcpy(&buffer[pos], key, key_size);
|
||||
pos += key_size;
|
||||
|
||||
// buffer add count
|
||||
buffer[pos] = count;
|
||||
pos++;
|
||||
|
||||
// calculate hmac
|
||||
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size));
|
||||
|
||||
// save output
|
||||
std::memcpy(dst, result.data(), std::min(20u, (dst_size - out_offset)));
|
||||
out_offset = 20;
|
||||
|
||||
// second loop
|
||||
while (true)
|
||||
{
|
||||
// if we filled the output buffer, exit
|
||||
if (out_offset >= dst_size)
|
||||
break;
|
||||
|
||||
// buffer add last result
|
||||
pos = 0;
|
||||
std::memcpy(&buffer[pos], result.data(), 20);
|
||||
pos += 20;
|
||||
|
||||
// buffer add key
|
||||
std::memcpy(&buffer[pos], key, key_size);
|
||||
pos += key_size;
|
||||
|
||||
// buffer add count
|
||||
count++;
|
||||
buffer[pos] = count;
|
||||
pos++;
|
||||
|
||||
// calculate hmac
|
||||
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(data_, data_size));
|
||||
|
||||
// save output
|
||||
std::memcpy(dst + out_offset, result.data(), std::min(20u, (dst_size - out_offset)));
|
||||
out_offset += 20;
|
||||
}
|
||||
}
|
||||
|
||||
void derive_keys_s1()
|
||||
{
|
||||
const auto out_1 = utils::cryptography::sha1::compute(packet_buffer); // out_1 size 20
|
||||
|
||||
auto data_3 = utils::cryptography::hmac_sha1::compute(data.m_session_key, out_1);
|
||||
|
||||
char out_2[16];
|
||||
calculate_hmacs_s1(data_3.data(), 20, "CLIENTCHAL", 10, out_2, 16);
|
||||
|
||||
char out_3[72];
|
||||
calculate_hmacs_s1(data_3.data(), 20, "BDDATA", 6, out_3, 72);
|
||||
|
||||
std::memcpy(data.m_response, &out_2[8], 8);
|
||||
std::memcpy(data.m_hmac_key, &out_3[20], 20);
|
||||
std::memcpy(data.m_dec_key, &out_3[40], 16);
|
||||
std::memcpy(data.m_enc_key, &out_3[56], 16);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW] Response id: %s\n", utils::string::dump_hex(std::string(&out_2[8], 8)).data());
|
||||
printf("[DW] Hash verify: %s\n", utils::string::dump_hex(std::string(&out_3[20], 20)).data());
|
||||
printf("[DW] AES dec key: %s\n", utils::string::dump_hex(std::string(&out_3[40], 16)).data());
|
||||
printf("[DW] AES enc key: %s\n", utils::string::dump_hex(std::string(&out_3[56], 16)).data());
|
||||
printf("[DW] Bravo 6, going dark.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void queue_packet_to_hash(const std::string& packet)
|
||||
{
|
||||
packet_buffer.append(packet);
|
||||
}
|
||||
|
||||
void set_session_key(const std::string& key)
|
||||
{
|
||||
std::memcpy(data.m_session_key, key.data(), 24);
|
||||
}
|
||||
|
||||
std::string get_decrypt_key()
|
||||
{
|
||||
return std::string(data.m_dec_key, 16);
|
||||
}
|
||||
|
||||
std::string get_encrypt_key()
|
||||
{
|
||||
return std::string(data.m_enc_key, 16);
|
||||
}
|
||||
|
||||
std::string get_hmac_key()
|
||||
{
|
||||
return std::string(data.m_hmac_key, 20);
|
||||
}
|
||||
|
||||
std::string get_response_id()
|
||||
{
|
||||
return std::string(data.m_response, 8);
|
||||
}
|
||||
}
|
12
src/client/game/demonware/keys.hpp
Normal file
12
src/client/game/demonware/keys.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void derive_keys_s1();
|
||||
void queue_packet_to_hash(const std::string& packet);
|
||||
void set_session_key(const std::string& key);
|
||||
std::string get_decrypt_key();
|
||||
std::string get_encrypt_key();
|
||||
std::string get_hmac_key();
|
||||
std::string get_response_id();
|
||||
}
|
87
src/client/game/demonware/reply.cpp
Normal file
87
src/client/game/demonware/reply.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <std_include.hpp>
|
||||
#include "keys.hpp"
|
||||
#include "reply.hpp"
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
std::string unencrypted_reply::data()
|
||||
{
|
||||
byte_buffer result;
|
||||
result.set_use_data_types(false);
|
||||
|
||||
result.write_int32(static_cast<int>(this->buffer_.size()) + 2);
|
||||
result.write_bool(false);
|
||||
result.write_byte(this->type());
|
||||
result.write(this->buffer_);
|
||||
|
||||
return result.get_buffer();
|
||||
}
|
||||
|
||||
std::string encrypted_reply::data()
|
||||
{
|
||||
byte_buffer result;
|
||||
result.set_use_data_types(false);
|
||||
|
||||
byte_buffer enc_buffer;
|
||||
enc_buffer.set_use_data_types(false);
|
||||
|
||||
enc_buffer.write_uint32(static_cast<unsigned int>(this->buffer_.size())); // service data size CHECKTHIS!!
|
||||
enc_buffer.write_byte(this->type()); // TASK_REPLY type
|
||||
enc_buffer.write(this->buffer_); // service data
|
||||
|
||||
auto aligned_data = enc_buffer.get_buffer();
|
||||
auto size = aligned_data.size();
|
||||
size = ~15 & (size + 15); // 16 byte align
|
||||
aligned_data.resize(size);
|
||||
|
||||
// seed
|
||||
std::string seed("\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED", 16);
|
||||
|
||||
// encrypt
|
||||
const auto enc_data = utils::cryptography::aes::encrypt(aligned_data, seed, demonware::get_encrypt_key());
|
||||
|
||||
// header : encrypted service data : hash
|
||||
static auto msg_count = 0;
|
||||
msg_count++;
|
||||
|
||||
byte_buffer response;
|
||||
response.set_use_data_types(false);
|
||||
|
||||
response.write_int32(30 + static_cast<int>(enc_data.size()));
|
||||
response.write_byte(static_cast<char>(0xAB));
|
||||
response.write_byte(static_cast<char>(0x85));
|
||||
response.write_int32(msg_count);
|
||||
response.write(16, seed.data());
|
||||
response.write(enc_data);
|
||||
|
||||
// hash entire packet and append end
|
||||
auto hash_data = utils::cryptography::hmac_sha1::compute(response.get_buffer(), demonware::get_hmac_key());
|
||||
hash_data.resize(8);
|
||||
response.write(8, hash_data.data());
|
||||
|
||||
return response.get_buffer();
|
||||
}
|
||||
|
||||
void remote_reply::send(bit_buffer* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||
|
||||
this->server_->send_reply(reply.get());
|
||||
}
|
||||
|
||||
void remote_reply::send(byte_buffer* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||
|
||||
this->server_->send_reply(reply.get());
|
||||
}
|
||||
}
|
164
src/client/game/demonware/reply.hpp
Normal file
164
src/client/game/demonware/reply.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
|
||||
#include "bit_buffer.hpp"
|
||||
#include "byte_buffer.hpp"
|
||||
#include "data_types.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class reply
|
||||
{
|
||||
public:
|
||||
reply() = default;
|
||||
|
||||
reply(reply&&) = delete;
|
||||
reply(const reply&) = delete;
|
||||
reply& operator=(reply&&) = delete;
|
||||
reply& operator=(const reply&) = delete;
|
||||
|
||||
virtual ~reply() = default;
|
||||
virtual std::string data() = 0;
|
||||
};
|
||||
|
||||
class raw_reply : public reply
|
||||
{
|
||||
protected:
|
||||
std::string buffer_;
|
||||
|
||||
public:
|
||||
raw_reply() = default;
|
||||
|
||||
explicit raw_reply(std::string data) : buffer_(std::move(data))
|
||||
{
|
||||
}
|
||||
|
||||
std::string data() override
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
};
|
||||
|
||||
class typed_reply : public raw_reply
|
||||
{
|
||||
public:
|
||||
typed_reply(const uint8_t _type) : type_(_type)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t type() const { return this->type_; }
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
};
|
||||
|
||||
class encrypted_reply final : public typed_reply
|
||||
{
|
||||
public:
|
||||
encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
std::string data() override;
|
||||
};
|
||||
|
||||
class unencrypted_reply final : public typed_reply
|
||||
{
|
||||
public:
|
||||
unencrypted_reply(const uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
unencrypted_reply(const uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
std::string data() override;
|
||||
};
|
||||
|
||||
class service_server;
|
||||
|
||||
class remote_reply final
|
||||
{
|
||||
public:
|
||||
remote_reply(service_server* server, uint8_t _type) : type_(_type), server_(server)
|
||||
{
|
||||
}
|
||||
|
||||
void send(bit_buffer* buffer, bool encrypted);
|
||||
void send(byte_buffer* buffer, bool encrypted);
|
||||
|
||||
uint8_t type() const { return this->type_; }
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
service_server* server_;
|
||||
};
|
||||
|
||||
class service_reply final
|
||||
{
|
||||
public:
|
||||
service_reply(service_server* _server, const uint8_t _type, const uint32_t _error)
|
||||
: type_(_type), error_(_error), reply_(_server, 1)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t send()
|
||||
{
|
||||
static uint64_t id = 0x0000000000000000;
|
||||
const auto transaction_id = ++id;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.write_uint64(transaction_id);
|
||||
buffer.write_uint32(this->error_);
|
||||
buffer.write_byte(this->type_);
|
||||
|
||||
if (!this->error_)
|
||||
{
|
||||
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||
if (!this->objects_.empty())
|
||||
{
|
||||
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||
|
||||
for (auto& object : this->objects_)
|
||||
{
|
||||
object->serialize(&buffer);
|
||||
}
|
||||
|
||||
this->objects_.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.write_uint64(transaction_id);
|
||||
}
|
||||
|
||||
this->reply_.send(&buffer, true);
|
||||
return transaction_id;
|
||||
}
|
||||
|
||||
void add(const std::shared_ptr<bdTaskResult>& object)
|
||||
{
|
||||
this->objects_.push_back(object);
|
||||
}
|
||||
|
||||
void add(bdTaskResult* object)
|
||||
{
|
||||
this->add(std::shared_ptr<bdTaskResult>(object));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
uint32_t error_;
|
||||
remote_reply reply_;
|
||||
std::vector<std::shared_ptr<bdTaskResult>> objects_;
|
||||
};
|
||||
}
|
60
src/client/game/demonware/server_registry.hpp
Normal file
60
src/client/game/demonware/server_registry.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "servers/base_server.hpp"
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
template <typename T>
|
||||
class server_registry
|
||||
{
|
||||
static_assert(std::is_base_of<base_server, T>::value, "Invalid server registry type");
|
||||
|
||||
public:
|
||||
template <typename S, typename ...Args>
|
||||
void create(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<T, S>::value, "Invalid server type");
|
||||
|
||||
auto server = std::make_unique<S>(std::forward<Args>(args)...);
|
||||
const auto address = server->get_address();
|
||||
servers_[address] = std::move(server);
|
||||
}
|
||||
|
||||
void for_each(const std::function<void(T&)>& callback) const
|
||||
{
|
||||
for (auto& server : servers_)
|
||||
{
|
||||
callback(*server.second);
|
||||
}
|
||||
}
|
||||
|
||||
T* find(const std::string& name)
|
||||
{
|
||||
const auto address = utils::cryptography::jenkins_one_at_a_time::compute(name);
|
||||
return find(address);
|
||||
}
|
||||
|
||||
T* find(const uint32_t address)
|
||||
{
|
||||
const auto it = servers_.find(address);
|
||||
if (it == servers_.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
void frame()
|
||||
{
|
||||
for (auto& server : servers_)
|
||||
{
|
||||
server.second->frame();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32_t, std::unique_ptr<T>> servers_;
|
||||
};
|
||||
}
|
167
src/client/game/demonware/servers/auth3_server.cpp
Normal file
167
src/client/game/demonware/servers/auth3_server.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "auth3_server.hpp"
|
||||
#include "../keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct auth_ticket
|
||||
{
|
||||
unsigned int m_magicNumber;
|
||||
char m_type;
|
||||
unsigned int m_titleID;
|
||||
unsigned int m_timeIssued;
|
||||
unsigned int m_timeExpires;
|
||||
unsigned __int64 m_licenseID;
|
||||
unsigned __int64 m_userID;
|
||||
char m_username[64];
|
||||
char m_sessionKey[24];
|
||||
char m_usingHashMagicNumber[3];
|
||||
char m_hash[4];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
|
||||
void auth3_server::send_reply(reply* data)
|
||||
{
|
||||
if (!data) return;
|
||||
this->send(data->data());
|
||||
}
|
||||
|
||||
void auth3_server::handle(const std::string& packet)
|
||||
{
|
||||
if (packet.starts_with("POST /auth/"))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [auth]: user requested authentication.\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int title_id = 0;
|
||||
unsigned int iv_seed = 0;
|
||||
std::string identity{};
|
||||
std::string token{};
|
||||
|
||||
rapidjson::Document j;
|
||||
const rapidjson::ParseResult parse_result = j.Parse(packet);
|
||||
|
||||
if (!parse_result || !j.IsObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (j.HasMember("title_id") && j["title_id"].IsString())
|
||||
{
|
||||
title_id = std::stoul(j["title_id"].GetString());
|
||||
}
|
||||
|
||||
if (j.HasMember("iv_seed") && j["iv_seed"].IsString())
|
||||
{
|
||||
iv_seed = std::stoul(j["iv_seed"].GetString());
|
||||
}
|
||||
|
||||
if (j.HasMember("extra_data") && j["extra_data"].IsString())
|
||||
{
|
||||
rapidjson::Document extra_data;
|
||||
auto& ed = j["extra_data"];
|
||||
extra_data.Parse(ed.GetString(), ed.GetStringLength());
|
||||
|
||||
if (extra_data.HasMember("token") && extra_data["token"].IsString())
|
||||
{
|
||||
auto& token_field = extra_data["token"];
|
||||
std::string token_b64(token_field.GetString(), token_field.GetStringLength());
|
||||
token = utils::cryptography::base64::decode(token_b64);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [auth]: authenticating user %s\n", token.data() + 64);
|
||||
#endif
|
||||
|
||||
std::string auth_key(reinterpret_cast<char*>(token.data() + 32), 24);
|
||||
std::string session_key(
|
||||
"\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24);
|
||||
|
||||
// client_ticket
|
||||
auth_ticket ticket{};
|
||||
std::memset(&ticket, 0x0, sizeof ticket);
|
||||
ticket.m_magicNumber = 0x0EFBDADDE;
|
||||
ticket.m_type = 0;
|
||||
ticket.m_titleID = title_id;
|
||||
ticket.m_timeIssued = static_cast<uint32_t>(time(nullptr));
|
||||
ticket.m_timeExpires = ticket.m_timeIssued + 30000;
|
||||
ticket.m_licenseID = 0;
|
||||
ticket.m_userID = reinterpret_cast<uint64_t>(token.data() + 56);
|
||||
strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast<char*>(token.data() + 64), 64);
|
||||
std::memcpy(ticket.m_sessionKey, session_key.data(), 24);
|
||||
|
||||
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv_seed), 4));
|
||||
const auto ticket_enc = utils::cryptography::des3::encrypt(
|
||||
std::string(reinterpret_cast<char*>(&ticket), sizeof(ticket)), iv, auth_key);
|
||||
const auto ticket_b64 = utils::cryptography::base64::encode(
|
||||
reinterpret_cast<const unsigned char*>(ticket_enc.data()), 128);
|
||||
|
||||
// server_ticket
|
||||
uint8_t auth_data[128];
|
||||
std::memset(&auth_data, 0, sizeof auth_data);
|
||||
std::memcpy(auth_data, session_key.data(), 24);
|
||||
const auto auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128);
|
||||
|
||||
demonware::set_session_key(session_key);
|
||||
|
||||
// header time
|
||||
char date[64];
|
||||
const auto now = time(nullptr);
|
||||
tm gmtm{};
|
||||
gmtime_s(&gmtm, &now);
|
||||
strftime(date, 64, "%a, %d %b %G %T", &gmtm);
|
||||
|
||||
// json content
|
||||
rapidjson::Document doc;
|
||||
doc.SetObject();
|
||||
|
||||
doc.AddMember("auth_task", "29", doc.GetAllocator());
|
||||
doc.AddMember("code", "700", doc.GetAllocator());
|
||||
|
||||
auto seed = std::to_string(iv_seed);
|
||||
doc.AddMember("iv_seed", rapidjson::StringRef(seed.data(), seed.size()), doc.GetAllocator());
|
||||
doc.AddMember("client_ticket", rapidjson::StringRef(ticket_b64.data(), ticket_b64.size()), doc.GetAllocator());
|
||||
doc.AddMember("server_ticket", rapidjson::StringRef(auth_data_b64.data(), auth_data_b64.size()),
|
||||
doc.GetAllocator());
|
||||
doc.AddMember("client_id", "", doc.GetAllocator());
|
||||
doc.AddMember("account_type", "steam", doc.GetAllocator());
|
||||
doc.AddMember("crossplay_enabled", false, doc.GetAllocator());
|
||||
doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator());
|
||||
|
||||
rapidjson::Value value{};
|
||||
doc.AddMember("lsg_endpoint", value, doc.GetAllocator());
|
||||
|
||||
rapidjson::StringBuffer buffer{};
|
||||
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<>>
|
||||
writer(buffer);
|
||||
doc.Accept(writer);
|
||||
|
||||
// http stuff
|
||||
std::string result;
|
||||
result.append("HTTP/1.1 200 OK\r\n");
|
||||
result.append("Server: TornadoServer/4.5.3\r\n");
|
||||
result.append("Content-Type: application/json\r\n");
|
||||
result.append(utils::string::va("Date: %s GMT\r\n", date));
|
||||
result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength()));
|
||||
result.append(buffer.GetString(), buffer.GetLength());
|
||||
|
||||
raw_reply reply(result);
|
||||
this->send_reply(&reply);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [auth]: user successfully authenticated.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
16
src/client/game/demonware/servers/auth3_server.hpp
Normal file
16
src/client/game/demonware/servers/auth3_server.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "tcp_server.hpp"
|
||||
#include "../reply.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class auth3_server : public tcp_server
|
||||
{
|
||||
public:
|
||||
using tcp_server::tcp_server;
|
||||
|
||||
private:
|
||||
void send_reply(reply* data);
|
||||
void handle(const std::string& packet) override;
|
||||
};
|
||||
}
|
22
src/client/game/demonware/servers/base_server.cpp
Normal file
22
src/client/game/demonware/servers/base_server.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <std_include.hpp>
|
||||
#include "base_server.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
base_server::base_server(std::string name): name_(std::move(name))
|
||||
{
|
||||
this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_);
|
||||
}
|
||||
|
||||
const std::string& base_server::get_name() const
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
uint32_t base_server::get_address() const
|
||||
{
|
||||
return this->address_;
|
||||
}
|
||||
}
|
30
src/client/game/demonware/servers/base_server.hpp
Normal file
30
src/client/game/demonware/servers/base_server.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class base_server
|
||||
{
|
||||
public:
|
||||
using stream_queue = std::queue<char>;
|
||||
using data_queue = std::queue<std::string>;
|
||||
|
||||
base_server(std::string name);
|
||||
|
||||
base_server(base_server&&) = delete;
|
||||
base_server(const base_server&) = delete;
|
||||
base_server& operator=(base_server&&) = delete;
|
||||
base_server& operator=(const base_server&) = delete;
|
||||
|
||||
virtual ~base_server() = default;
|
||||
|
||||
const std::string& get_name() const;
|
||||
|
||||
uint32_t get_address() const;
|
||||
|
||||
virtual void frame() = 0;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::uint32_t address_ = 0;
|
||||
};
|
||||
}
|
176
src/client/game/demonware/servers/lobby_server.cpp
Normal file
176
src/client/game/demonware/servers/lobby_server.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <std_include.hpp>
|
||||
#include "lobby_server.hpp"
|
||||
|
||||
#include "../services.hpp"
|
||||
#include "../keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
lobby_server::lobby_server(std::string name) : tcp_server(std::move(name))
|
||||
{
|
||||
this->register_service<bdAnticheat>();
|
||||
this->register_service<bdContentStreaming>();
|
||||
this->register_service<bdDML>();
|
||||
this->register_service<bdEventLog>();
|
||||
this->register_service<bdGroups>();
|
||||
this->register_service<bdStats>();
|
||||
this->register_service<bdStorage>();
|
||||
this->register_service<bdTitleUtilities>();
|
||||
this->register_service<bdProfiles>();
|
||||
this->register_service<bdRichPresence>();
|
||||
this->register_service<bdFacebook>();
|
||||
this->register_service<bdUNK63>();
|
||||
this->register_service<bdUNK80>();
|
||||
this->register_service<bdPresence>();
|
||||
this->register_service<bdMarketingComms>();
|
||||
this->register_service<bdMatchMaking2>();
|
||||
this->register_service<bdMarketing>();
|
||||
};
|
||||
|
||||
void lobby_server::send_reply(reply* data)
|
||||
{
|
||||
if (!data) return;
|
||||
this->send(data->data());
|
||||
}
|
||||
|
||||
void lobby_server::handle(const std::string& packet)
|
||||
{
|
||||
byte_buffer buffer(packet);
|
||||
buffer.set_use_data_types(false);
|
||||
|
||||
try
|
||||
{
|
||||
while (buffer.has_more_data())
|
||||
{
|
||||
int size;
|
||||
buffer.read_int32(&size);
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
const std::string zero("\x00\x00\x00\x00", 4);
|
||||
raw_reply reply(zero);
|
||||
this->send_reply(&reply);
|
||||
return;
|
||||
}
|
||||
else if (size == 0xC8)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [lobby]: received client_header_ack.\n");
|
||||
#endif
|
||||
|
||||
int c8;
|
||||
buffer.read_int32(&c8);
|
||||
std::string packet_1 = buffer.get_remaining();
|
||||
demonware::queue_packet_to_hash(packet_1);
|
||||
|
||||
const std::string packet_2(
|
||||
"\x16\x00\x00\x00\xab\x81\xd2\x00\x00\x00\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37",
|
||||
26);
|
||||
demonware::queue_packet_to_hash(packet_2);
|
||||
|
||||
raw_reply reply(packet_2);
|
||||
this->send_reply(&reply);
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [lobby]: sending server_header_ack.\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.size() < size_t(size)) return;
|
||||
|
||||
uint8_t check_ab;
|
||||
buffer.read_byte(&check_ab);
|
||||
if (check_ab == 0xAB)
|
||||
{
|
||||
uint8_t type;
|
||||
buffer.read_byte(&type);
|
||||
|
||||
if (type == 0x82)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [lobby]: received client_auth.\n");
|
||||
#endif
|
||||
std::string packet_3(packet.data(), packet.size() - 8); // this 8 are client hash check?
|
||||
|
||||
demonware::queue_packet_to_hash(packet_3);
|
||||
demonware::derive_keys_s1();
|
||||
|
||||
char buff[14] = "\x0A\x00\x00\x00\xAB\x83";
|
||||
std::memcpy(&buff[6], demonware::get_response_id().data(), 8);
|
||||
std::string response(buff, 14);
|
||||
|
||||
raw_reply reply(response);
|
||||
this->send_reply(&reply);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [lobby]: sending server_auth_done.\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (type == 0x85)
|
||||
{
|
||||
uint32_t msg_count;
|
||||
buffer.read_uint32(&msg_count);
|
||||
|
||||
char seed[16];
|
||||
buffer.read(16, &seed);
|
||||
|
||||
std::string enc = buffer.get_remaining();
|
||||
|
||||
char hash[8];
|
||||
std::memcpy(hash, &(enc.data()[enc.size() - 8]), 8);
|
||||
|
||||
std::string dec = utils::cryptography::aes::decrypt(
|
||||
std::string(enc.data(), enc.size() - 8), std::string(seed, 16),
|
||||
demonware::get_decrypt_key());
|
||||
|
||||
byte_buffer serv(dec);
|
||||
serv.set_use_data_types(false);
|
||||
|
||||
uint32_t serv_size;
|
||||
serv.read_uint32(&serv_size);
|
||||
|
||||
uint8_t magic; // 0x86
|
||||
serv.read_byte(&magic);
|
||||
|
||||
uint8_t service_id;
|
||||
serv.read_byte(&service_id);
|
||||
|
||||
this->call_service(service_id, serv.get_remaining());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[DW]: [lobby]: ERROR! received unk message.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void lobby_server::call_service(const uint8_t id, const std::string& data)
|
||||
{
|
||||
const auto& it = this->services_.find(id);
|
||||
|
||||
if (it != this->services_.end())
|
||||
{
|
||||
it->second->exec_task(this, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[DW]: [lobby]: missing service '%s'\n", utils::string::va("%d", id));
|
||||
|
||||
// return no error
|
||||
byte_buffer buffer(data);
|
||||
uint8_t task_id;
|
||||
buffer.read_byte(&task_id);
|
||||
|
||||
this->create_reply(task_id)->send();
|
||||
}
|
||||
}
|
||||
}
|
33
src/client/game/demonware/servers/lobby_server.hpp
Normal file
33
src/client/game/demonware/servers/lobby_server.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.hpp"
|
||||
#include "service_server.hpp"
|
||||
#include "../service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class lobby_server : public tcp_server, service_server
|
||||
{
|
||||
public:
|
||||
lobby_server(std::string name);
|
||||
|
||||
template <typename T>
|
||||
void register_service()
|
||||
{
|
||||
static_assert(std::is_base_of<service, T>::value, "service must inherit from service");
|
||||
|
||||
auto service = std::make_unique<T>();
|
||||
const uint8_t id = service->id();
|
||||
|
||||
this->services_[id] = std::move(service);
|
||||
}
|
||||
|
||||
void send_reply(reply* data) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<uint8_t, std::unique_ptr<service>> services_;
|
||||
|
||||
void handle(const std::string& packet) override;
|
||||
void call_service(uint8_t id, const std::string& data);
|
||||
};
|
||||
}
|
27
src/client/game/demonware/servers/service_server.hpp
Normal file
27
src/client/game/demonware/servers/service_server.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "../reply.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class service_server
|
||||
{
|
||||
public:
|
||||
virtual ~service_server() = default;
|
||||
|
||||
virtual std::shared_ptr<remote_reply> create_message(uint8_t type)
|
||||
{
|
||||
auto reply = std::make_shared<remote_reply>(this, type);
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
||||
virtual std::shared_ptr<service_reply> create_reply(uint8_t type, uint32_t error = 0)
|
||||
{
|
||||
auto reply = std::make_shared<service_reply>(this, type, error);
|
||||
return reply;
|
||||
}
|
||||
|
||||
virtual void send_reply(reply* data) = 0;
|
||||
};
|
||||
}
|
62
src/client/game/demonware/servers/stun_server.cpp
Normal file
62
src/client/game/demonware/servers/stun_server.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <std_include.hpp>
|
||||
#include "stun_server.hpp"
|
||||
|
||||
#include "../byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void stun_server::handle(const endpoint_data& endpoint, const std::string& packet)
|
||||
{
|
||||
uint8_t type, version, padding;
|
||||
|
||||
byte_buffer buffer(packet);
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.read_byte(&type);
|
||||
buffer.read_byte(&version);
|
||||
buffer.read_byte(&padding);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 30:
|
||||
this->ip_discovery(endpoint);
|
||||
break;
|
||||
case 20:
|
||||
this->nat_discovery(endpoint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void stun_server::ip_discovery(const endpoint_data& endpoint)
|
||||
{
|
||||
const uint32_t ip = 0x0100007f;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.write_byte(31); // type
|
||||
buffer.write_byte(2); // version
|
||||
buffer.write_byte(0); // version
|
||||
buffer.write_uint32(ip); // external ip
|
||||
buffer.write_uint16(3074); // port
|
||||
|
||||
this->send(endpoint, buffer.get_buffer());
|
||||
}
|
||||
|
||||
void stun_server::nat_discovery(const endpoint_data& endpoint)
|
||||
{
|
||||
const uint32_t ip = 0x0100007f;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.write_byte(21); // type
|
||||
buffer.write_byte(2); // version
|
||||
buffer.write_byte(0); // version
|
||||
buffer.write_uint32(ip); // external ip
|
||||
buffer.write_uint16(3074); // port
|
||||
buffer.write_uint32(this->get_address()); // server ip
|
||||
buffer.write_uint16(3074); // server port
|
||||
|
||||
this->send(endpoint, buffer.get_buffer());
|
||||
}
|
||||
}
|
18
src/client/game/demonware/servers/stun_server.hpp
Normal file
18
src/client/game/demonware/servers/stun_server.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "udp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class stun_server : public udp_server
|
||||
{
|
||||
public:
|
||||
using udp_server::udp_server;
|
||||
|
||||
private:
|
||||
void handle(const endpoint_data& endpoint, const std::string& packet) override;
|
||||
|
||||
void ip_discovery(const endpoint_data& endpoint);
|
||||
void nat_discovery(const endpoint_data& endpoint);
|
||||
};
|
||||
}
|
84
src/client/game/demonware/servers/tcp_server.cpp
Normal file
84
src/client/game/demonware/servers/tcp_server.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <std_include.hpp>
|
||||
#include "tcp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void tcp_server::handle_input(const char* buf, size_t size)
|
||||
{
|
||||
in_queue_.access([&](data_queue& queue)
|
||||
{
|
||||
queue.emplace(buf, size);
|
||||
});
|
||||
}
|
||||
|
||||
size_t tcp_server::handle_output(char* buf, size_t size)
|
||||
{
|
||||
if (out_queue_.get_raw().empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return out_queue_.access<size_t>([&](stream_queue& queue)
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
buf[i] = queue.front();
|
||||
queue.pop();
|
||||
}
|
||||
|
||||
return size;
|
||||
});
|
||||
}
|
||||
|
||||
bool tcp_server::pending_data()
|
||||
{
|
||||
return !this->out_queue_.get_raw().empty();
|
||||
}
|
||||
|
||||
void tcp_server::frame()
|
||||
{
|
||||
if (this->in_queue_.get_raw().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::string packet{};
|
||||
const auto result = this->in_queue_.access<bool>([&](data_queue& queue)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
packet = std::move(queue.front());
|
||||
queue.pop();
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->handle(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void tcp_server::send(const std::string& data)
|
||||
{
|
||||
out_queue_.access([&](stream_queue& queue)
|
||||
{
|
||||
for (const auto& val : data)
|
||||
{
|
||||
queue.push(val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
27
src/client/game/demonware/servers/tcp_server.hpp
Normal file
27
src/client/game/demonware/servers/tcp_server.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class tcp_server : public base_server
|
||||
{
|
||||
public:
|
||||
using base_server::base_server;
|
||||
|
||||
void handle_input(const char* buf, size_t size);
|
||||
size_t handle_output(char* buf, size_t size);
|
||||
bool pending_data();
|
||||
void frame() override;
|
||||
|
||||
protected:
|
||||
virtual void handle(const std::string& data) = 0;
|
||||
|
||||
void send(const std::string& data);
|
||||
|
||||
private:
|
||||
utils::concurrency::container<data_queue> in_queue_;
|
||||
utils::concurrency::container<stream_queue> out_queue_;
|
||||
};
|
||||
}
|
103
src/client/game/demonware/servers/udp_server.cpp
Normal file
103
src/client/game/demonware/servers/udp_server.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <std_include.hpp>
|
||||
#include "udp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void udp_server::handle_input(const char* buf, size_t size, endpoint_data endpoint)
|
||||
{
|
||||
in_queue_.access([&](in_queue& queue)
|
||||
{
|
||||
in_packet p;
|
||||
p.data = std::string{buf, size};
|
||||
p.endpoint = std::move(endpoint);
|
||||
|
||||
queue.emplace(std::move(p));
|
||||
});
|
||||
}
|
||||
|
||||
size_t udp_server::handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen)
|
||||
{
|
||||
return out_queue_.access<size_t>([&](socket_queue_map& map) -> size_t
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& queue = entry->second;
|
||||
|
||||
if (queue.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto data = std::move(queue.front());
|
||||
queue.pop();
|
||||
|
||||
const auto copy_size = std::min(size, data.data.size());
|
||||
std::memcpy(buf, data.data.data(), copy_size);
|
||||
std::memcpy(address, &data.address, sizeof(data.address));
|
||||
*addrlen = sizeof(data.address);
|
||||
|
||||
return copy_size;
|
||||
});
|
||||
}
|
||||
|
||||
bool udp_server::pending_data(SOCKET socket)
|
||||
{
|
||||
return this->out_queue_.access<bool>([&](const socket_queue_map& map)
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !entry->second.empty();
|
||||
});
|
||||
}
|
||||
|
||||
void udp_server::send(const endpoint_data& endpoint, std::string data)
|
||||
{
|
||||
out_queue_.access([&](socket_queue_map& map)
|
||||
{
|
||||
out_packet p;
|
||||
p.data = std::move(data);
|
||||
p.address = endpoint.address;
|
||||
|
||||
map[endpoint.socket].emplace(std::move(p));
|
||||
});
|
||||
}
|
||||
|
||||
void udp_server::frame()
|
||||
{
|
||||
if (this->in_queue_.get_raw().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
in_packet packet{};
|
||||
const auto result = this->in_queue_.access<bool>([&](in_queue& queue)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
packet = std::move(queue.front());
|
||||
queue.pop();
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->handle(packet.endpoint, std::move(packet.data));
|
||||
}
|
||||
}
|
||||
}
|
62
src/client/game/demonware/servers/udp_server.hpp
Normal file
62
src/client/game/demonware/servers/udp_server.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class udp_server : public base_server
|
||||
{
|
||||
public:
|
||||
struct endpoint_data
|
||||
{
|
||||
SOCKET socket{};
|
||||
sockaddr_in address{};
|
||||
|
||||
endpoint_data() = default;
|
||||
|
||||
endpoint_data(const SOCKET sock, const sockaddr* addr, const int size)
|
||||
{
|
||||
if (size != sizeof(this->address))
|
||||
{
|
||||
throw std::runtime_error("Invalid size");
|
||||
}
|
||||
|
||||
this->socket = sock;
|
||||
std::memcpy(&this->address, addr, sizeof(this->address));
|
||||
}
|
||||
};
|
||||
|
||||
using base_server::base_server;
|
||||
|
||||
void handle_input(const char* buf, size_t size, endpoint_data endpoint);
|
||||
size_t handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen);
|
||||
bool pending_data(SOCKET socket);
|
||||
|
||||
void frame() override;
|
||||
|
||||
protected:
|
||||
virtual void handle(const endpoint_data& endpoint, const std::string& data) = 0;
|
||||
void send(const endpoint_data& endpoint, std::string data);
|
||||
|
||||
private:
|
||||
struct in_packet
|
||||
{
|
||||
std::string data;
|
||||
endpoint_data endpoint;
|
||||
};
|
||||
|
||||
struct out_packet
|
||||
{
|
||||
std::string data;
|
||||
sockaddr_in address;
|
||||
};
|
||||
|
||||
using in_queue = std::queue<in_packet>;
|
||||
using out_queue = std::queue<out_packet>;
|
||||
using socket_queue_map = std::unordered_map<SOCKET, out_queue>;
|
||||
|
||||
utils::concurrency::container<in_queue> in_queue_;
|
||||
utils::concurrency::container<socket_queue_map> out_queue_;
|
||||
};
|
||||
}
|
11
src/client/game/demonware/servers/umbrella_server.cpp
Normal file
11
src/client/game/demonware/servers/umbrella_server.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "umbrella_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void umbrella_server::handle(const std::string& packet)
|
||||
{
|
||||
// TODO:
|
||||
}
|
||||
}
|
14
src/client/game/demonware/servers/umbrella_server.hpp
Normal file
14
src/client/game/demonware/servers/umbrella_server.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "tcp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class umbrella_server : public tcp_server
|
||||
{
|
||||
public:
|
||||
using tcp_server::tcp_server;
|
||||
|
||||
private:
|
||||
void handle(const std::string& packet) override;
|
||||
};
|
||||
}
|
89
src/client/game/demonware/service.hpp
Normal file
89
src/client/game/demonware/service.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include <utils/string.hpp>
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class service
|
||||
{
|
||||
using callback_t = std::function<void(service_server*, byte_buffer*)>;
|
||||
|
||||
uint8_t id_;
|
||||
std::string name_;
|
||||
std::mutex mutex_;
|
||||
uint8_t task_id_;
|
||||
std::map<uint8_t, callback_t> tasks_;
|
||||
|
||||
public:
|
||||
virtual ~service() = default;
|
||||
service(service&&) = delete;
|
||||
service(const service&) = delete;
|
||||
service& operator=(const service&) = delete;
|
||||
|
||||
service(const uint8_t id, std::string name) : id_(id), name_(std::move(name)), task_id_(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t id() const
|
||||
{
|
||||
return this->id_;
|
||||
}
|
||||
|
||||
const std::string& name() const
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
uint8_t task_id() const
|
||||
{
|
||||
return this->task_id_;
|
||||
}
|
||||
|
||||
virtual void exec_task(service_server* server, const std::string& data)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(this->mutex_);
|
||||
|
||||
byte_buffer buffer(data);
|
||||
|
||||
buffer.read_byte(&this->task_id_);
|
||||
|
||||
const auto& it = this->tasks_.find(this->task_id_);
|
||||
|
||||
if (it != this->tasks_.end())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[DW] %s: executing task '%d'\n", name_.data(), this->task_id_);
|
||||
#endif
|
||||
|
||||
it->second(server, &buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[DW] %s: missing task '%d'\n", name_.data(), this->task_id_);
|
||||
|
||||
// return no error
|
||||
server->create_reply(this->task_id_)->send();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
template <typename Class, typename T, typename... Args>
|
||||
void register_task(const uint8_t id, T (Class::* callback)(Args ...) const)
|
||||
{
|
||||
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||
{
|
||||
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Class, typename T, typename... Args>
|
||||
void register_task(const uint8_t id, T (Class::* callback)(Args ...))
|
||||
{
|
||||
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||
{
|
||||
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
34
src/client/game/demonware/services.hpp
Normal file
34
src/client/game/demonware/services.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "bit_buffer.hpp"
|
||||
#include "byte_buffer.hpp"
|
||||
#include "data_types.hpp"
|
||||
#include "reply.hpp"
|
||||
#include "service.hpp"
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
//#include "services/bdTeams.hpp" // 3
|
||||
#include "services/bdStats.hpp" // 4
|
||||
//#include "services/bdMessaging.hpp" // 6
|
||||
#include "services/bdProfiles.hpp" // 8
|
||||
#include "services/bdStorage.hpp" // 10
|
||||
#include "services/bdTitleUtilities.hpp" // 12
|
||||
//#include "services/bdMatchMaking.hpp" // 21
|
||||
#include "services/bdCounters.hpp" // 23
|
||||
#include "services/bdDML.hpp" // 27
|
||||
#include "services/bdGroups.hpp" // 28
|
||||
//#include "services/bdCMail.hpp" // 29
|
||||
#include "services/bdFacebook.hpp" // 36
|
||||
#include "services/bdAnticheat.hpp" // 38
|
||||
#include "services/bdContentStreaming.hpp" // 50
|
||||
//#include "services/bdTags.hpp" // 52
|
||||
#include "services/bdUNK63.hpp" // 63
|
||||
#include "services/bdEventLog.hpp" // 67
|
||||
#include "services/bdRichPresence.hpp" // 68
|
||||
//#include "services/bdTitleUtilities2.hpp" // 72
|
||||
#include "services/bdUNK80.hpp"
|
||||
// AccountLinking // 86
|
||||
#include "services/bdPresence.hpp" //103
|
||||
#include "services/bdMarketingComms.hpp" //104
|
||||
#include "services/bdMatchMaking2.hpp" //138
|
||||
#include "services/bdMarketing.hpp" //139
|
25
src/client/game/demonware/services/bdAnticheat.cpp
Normal file
25
src/client/game/demonware/services/bdAnticheat.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdAnticheat::bdAnticheat() : service(38, "bdAnticheat")
|
||||
{
|
||||
this->register_task(2, &bdAnticheat::unk2);
|
||||
this->register_task(4, &bdAnticheat::report_console_details);
|
||||
}
|
||||
|
||||
void bdAnticheat::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdAnticheat::report_console_details(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdAnticheat.hpp
Normal file
14
src/client/game/demonware/services/bdAnticheat.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdAnticheat final : public service
|
||||
{
|
||||
public:
|
||||
bdAnticheat();
|
||||
|
||||
private:
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
void report_console_details(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdContentStreaming.cpp
Normal file
25
src/client/game/demonware/services/bdContentStreaming.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdContentStreaming::bdContentStreaming() : service(50, "bdContentStreaming")
|
||||
{
|
||||
this->register_task(2, &bdContentStreaming::unk2);
|
||||
this->register_task(3, &bdContentStreaming::unk3);
|
||||
}
|
||||
|
||||
void bdContentStreaming::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdContentStreaming::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdContentStreaming.hpp
Normal file
14
src/client/game/demonware/services/bdContentStreaming.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdContentStreaming final : public service
|
||||
{
|
||||
public:
|
||||
bdContentStreaming();
|
||||
|
||||
private:
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdCounters.cpp
Normal file
25
src/client/game/demonware/services/bdCounters.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdCounters::bdCounters() : service(23, "bdCounters")
|
||||
{
|
||||
this->register_task(1, &bdCounters::unk1);
|
||||
this->register_task(2, &bdCounters::unk2);
|
||||
}
|
||||
|
||||
void bdCounters::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdCounters::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdCounters.hpp
Normal file
14
src/client/game/demonware/services/bdCounters.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdCounters final : public service
|
||||
{
|
||||
public:
|
||||
bdCounters();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
28
src/client/game/demonware/services/bdDML.cpp
Normal file
28
src/client/game/demonware/services/bdDML.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdDML::bdDML() : service(27, "bdDML")
|
||||
{
|
||||
this->register_task(2, &bdDML::get_user_raw_data);
|
||||
}
|
||||
|
||||
void bdDML::get_user_raw_data(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
auto result = new bdDMLRawData;
|
||||
result->country_code = "US";
|
||||
result->country_code = "'Murica";
|
||||
result->region = "New York";
|
||||
result->city = "New York";
|
||||
result->latitude = 0;
|
||||
result->longitude = 0;
|
||||
|
||||
result->asn = 0x2119;
|
||||
result->timezone = "+01:00";
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(result);
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdDML.hpp
Normal file
13
src/client/game/demonware/services/bdDML.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdDML final : public service
|
||||
{
|
||||
public:
|
||||
bdDML();
|
||||
|
||||
private:
|
||||
void get_user_raw_data(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
src/client/game/demonware/services/bdEventLog.cpp
Normal file
17
src/client/game/demonware/services/bdEventLog.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdEventLog::bdEventLog() : service(67, "bdEventLog")
|
||||
{
|
||||
this->register_task(6, &bdEventLog::unk6);
|
||||
}
|
||||
|
||||
void bdEventLog::unk6(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdEventLog.hpp
Normal file
13
src/client/game/demonware/services/bdEventLog.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdEventLog final : public service
|
||||
{
|
||||
public:
|
||||
bdEventLog();
|
||||
|
||||
private:
|
||||
void unk6(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
41
src/client/game/demonware/services/bdFacebook.cpp
Normal file
41
src/client/game/demonware/services/bdFacebook.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdFacebook::bdFacebook() : service(36, "bdFacebook")
|
||||
{
|
||||
this->register_task(1, &bdFacebook::unk1);
|
||||
this->register_task(3, &bdFacebook::unk3);
|
||||
this->register_task(7, &bdFacebook::unk7);
|
||||
this->register_task(8, &bdFacebook::unk8);
|
||||
}
|
||||
|
||||
void bdFacebook::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdFacebook::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdFacebook::unk7(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdFacebook::unk8(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
16
src/client/game/demonware/services/bdFacebook.hpp
Normal file
16
src/client/game/demonware/services/bdFacebook.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdFacebook final : public service
|
||||
{
|
||||
public:
|
||||
bdFacebook();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
void unk7(service_server* server, byte_buffer* buffer) const;
|
||||
void unk8(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdGroups.cpp
Normal file
25
src/client/game/demonware/services/bdGroups.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdGroups::bdGroups() : service(28, "bdGroup")
|
||||
{
|
||||
this->register_task(1, &bdGroups::set_groups);
|
||||
this->register_task(4, &bdGroups::unk4);
|
||||
}
|
||||
|
||||
void bdGroups::set_groups(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdGroups::unk4(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdGroups.hpp
Normal file
14
src/client/game/demonware/services/bdGroups.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdGroups final : public service
|
||||
{
|
||||
public:
|
||||
bdGroups();
|
||||
|
||||
private:
|
||||
void set_groups(service_server* server, byte_buffer* buffer) const;
|
||||
void unk4(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdMarketing.cpp
Normal file
25
src/client/game/demonware/services/bdMarketing.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMarketing::bdMarketing() : service(139, "bdMarketing")
|
||||
{
|
||||
this->register_task(2, &bdMarketing::unk2);
|
||||
this->register_task(3, &bdMarketing::unk3);
|
||||
}
|
||||
|
||||
void bdMarketing::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMarketing::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdMarketing.hpp
Normal file
14
src/client/game/demonware/services/bdMarketing.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdMarketing final : public service
|
||||
{
|
||||
public:
|
||||
bdMarketing();
|
||||
|
||||
private:
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
src/client/game/demonware/services/bdMarketingComms.cpp
Normal file
17
src/client/game/demonware/services/bdMarketingComms.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMarketingComms::bdMarketingComms() : service(104, "bdMarketingComms")
|
||||
{
|
||||
this->register_task(1, &bdMarketingComms::get_messages);
|
||||
}
|
||||
|
||||
void bdMarketingComms::get_messages(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdMarketingComms.hpp
Normal file
13
src/client/game/demonware/services/bdMarketingComms.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdMarketingComms final : public service
|
||||
{
|
||||
public:
|
||||
bdMarketingComms();
|
||||
|
||||
private:
|
||||
void get_messages(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
49
src/client/game/demonware/services/bdMatchMaking2.cpp
Normal file
49
src/client/game/demonware/services/bdMatchMaking2.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMatchMaking2::bdMatchMaking2() : service(138, "bdMatchMaking2")
|
||||
{
|
||||
this->register_task(1, &bdMatchMaking2::unk1);
|
||||
this->register_task(2, &bdMatchMaking2::unk2);
|
||||
this->register_task(3, &bdMatchMaking2::unk3);
|
||||
this->register_task(5, &bdMatchMaking2::unk5);
|
||||
this->register_task(16, &bdMatchMaking2::unk16);
|
||||
}
|
||||
|
||||
void bdMatchMaking2::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMatchMaking2::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMatchMaking2::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMatchMaking2::unk5(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMatchMaking2::unk16(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
17
src/client/game/demonware/services/bdMatchMaking2.hpp
Normal file
17
src/client/game/demonware/services/bdMatchMaking2.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdMatchMaking2 final : public service
|
||||
{
|
||||
public:
|
||||
bdMatchMaking2();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
void unk5(service_server* server, byte_buffer* buffer) const;
|
||||
void unk16(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdPresence.cpp
Normal file
25
src/client/game/demonware/services/bdPresence.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdPresence::bdPresence() : service(103, "bdPresence")
|
||||
{
|
||||
this->register_task(1, &bdPresence::unk1);
|
||||
this->register_task(3, &bdPresence::unk3);
|
||||
}
|
||||
|
||||
void bdPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPresence::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdPresence.hpp
Normal file
14
src/client/game/demonware/services/bdPresence.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdPresence final : public service
|
||||
{
|
||||
public:
|
||||
bdPresence();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
src/client/game/demonware/services/bdProfiles.cpp
Normal file
17
src/client/game/demonware/services/bdProfiles.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdProfiles::bdProfiles() : service(8, "bdProfiles")
|
||||
{
|
||||
this->register_task(3, &bdProfiles::unk3);
|
||||
}
|
||||
|
||||
void bdProfiles::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdProfiles.hpp
Normal file
13
src/client/game/demonware/services/bdProfiles.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdProfiles final : public service
|
||||
{
|
||||
public:
|
||||
bdProfiles();
|
||||
|
||||
private:
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
src/client/game/demonware/services/bdRichPresence.cpp
Normal file
25
src/client/game/demonware/services/bdRichPresence.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdRichPresence::bdRichPresence() : service(68, "bdRichPresence")
|
||||
{
|
||||
this->register_task(1, &bdRichPresence::unk1);
|
||||
this->register_task(2, &bdRichPresence::unk2);
|
||||
}
|
||||
|
||||
void bdRichPresence::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdRichPresence::unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/client/game/demonware/services/bdRichPresence.hpp
Normal file
14
src/client/game/demonware/services/bdRichPresence.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdRichPresence final : public service
|
||||
{
|
||||
public:
|
||||
bdRichPresence();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk2(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
49
src/client/game/demonware/services/bdStats.cpp
Normal file
49
src/client/game/demonware/services/bdStats.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdStats::bdStats() : service(4, "bdStats")
|
||||
{
|
||||
this->register_task(1, &bdStats::unk1);
|
||||
this->register_task(3, &bdStats::unk3); // leaderboards
|
||||
this->register_task(4, &bdStats::unk4);
|
||||
this->register_task(8, &bdStats::unk8);
|
||||
this->register_task(11, &bdStats::unk11);
|
||||
}
|
||||
|
||||
void bdStats::unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::unk4(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::unk8(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::unk11(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
17
src/client/game/demonware/services/bdStats.hpp
Normal file
17
src/client/game/demonware/services/bdStats.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdStats final : public service
|
||||
{
|
||||
public:
|
||||
bdStats();
|
||||
|
||||
private:
|
||||
void unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void unk3(service_server* server, byte_buffer* buffer) const;
|
||||
void unk4(service_server* server, byte_buffer* buffer) const;
|
||||
void unk8(service_server* server, byte_buffer* buffer) const;
|
||||
void unk11(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
211
src/client/game/demonware/services/bdStorage.cpp
Normal file
211
src/client/game/demonware/services/bdStorage.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include <std_include.hpp>
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "../services.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
#include <component/filesystem.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string get_motd_text()
|
||||
{
|
||||
return "This is not a copy & pasted client";
|
||||
}
|
||||
}
|
||||
|
||||
bdStorage::bdStorage() : service(10, "bdStorage")
|
||||
{
|
||||
this->register_task(6, &bdStorage::list_publisher_files);
|
||||
this->register_task(7, &bdStorage::get_publisher_file);
|
||||
this->register_task(10, &bdStorage::set_user_file);
|
||||
this->register_task(12, &bdStorage::get_user_file);
|
||||
this->register_task(13, &bdStorage::unk13);
|
||||
|
||||
this->map_publisher_resource_variant(".*\\motd-.*\\.txt", get_motd_text);
|
||||
this->map_publisher_resource("ffotd-.*\\.ff", "dw/ffotd-1.22.1.ff", DW_FASTFILE);
|
||||
this->map_publisher_resource("playlists(_.+)?\\.aggr", "dw/playlists_tu22.aggr", DW_PLAYLISTS);
|
||||
this->map_publisher_resource("social_[Tt][Uu][0-9]+\\.cfg", "dw/social_tu22.cfg", DW_SOCIAL_CONFIG);
|
||||
this->map_publisher_resource("mm\\.cfg", "dw/mm.cfg", DW_MM_CONFIG);
|
||||
this->map_publisher_resource("entitlement_config\\.info", "dw/entitlement_config.info", DW_ENTITLEMENT_CONFIG);
|
||||
this->map_publisher_resource("lootConfig_[Tt][Uu][0-9]+\\.csv", "dw/lootConfig_tu22.csv", DW_LOOT_CONFIG);
|
||||
this->map_publisher_resource("winStoreConfig_[Tt][Uu][0-9]+\\.csv", "dw/winStoreConfig_tu22.csv", DW_STORE_CONFIG);
|
||||
}
|
||||
|
||||
void bdStorage::map_publisher_resource(const std::string& expression, const std::string& path, const int id)
|
||||
{
|
||||
auto data = filesystem::exists(path)
|
||||
? filesystem::read_file(path)
|
||||
: utils::nt::load_resource(id);
|
||||
|
||||
this->map_publisher_resource_variant(expression, std::move(data));
|
||||
}
|
||||
|
||||
void bdStorage::map_publisher_resource_variant(const std::string& expression, resource_variant resource)
|
||||
{
|
||||
if (resource.valueless_by_exception())
|
||||
{
|
||||
throw std::runtime_error("Publisher resource variant is empty!");
|
||||
}
|
||||
|
||||
this->publisher_resources_.emplace_back(std::regex{expression}, std::move(resource));
|
||||
}
|
||||
|
||||
bool bdStorage::load_publisher_resource(const std::string& name, std::string& buffer) const
|
||||
{
|
||||
for (const auto& resource : this->publisher_resources_)
|
||||
{
|
||||
if (std::regex_match(name, resource.first))
|
||||
{
|
||||
if (std::holds_alternative<std::string>(resource.second))
|
||||
{
|
||||
buffer = std::get<std::string>(resource.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = std::get<callback>(resource.second)();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [bdStorage]: missing publisher file: %s\n", name.data());
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bdStorage::list_publisher_files(service_server* server, byte_buffer* buffer)
|
||||
{
|
||||
uint32_t date;
|
||||
uint16_t num_results, offset;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_uint32(&date);
|
||||
buffer->read_uint16(&num_results);
|
||||
buffer->read_uint16(&offset);
|
||||
buffer->read_string(&filename);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
|
||||
if (this->load_publisher_resource(filename, data))
|
||||
{
|
||||
auto* info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = 0;
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
|
||||
reply->add(info);
|
||||
}
|
||||
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::get_publisher_file(service_server* server, byte_buffer* buffer)
|
||||
{
|
||||
std::string filename;
|
||||
buffer->read_string(&filename);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [bdStorage]: loading publisher file: %s\n", filename.data());
|
||||
#endif
|
||||
|
||||
std::string data;
|
||||
|
||||
if (this->load_publisher_resource(filename, data))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [bdStorage]: sending publisher file: %s, size: %lld\n", filename.data(), data.size());
|
||||
#endif
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(new bdFileData(data));
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->create_reply(this->task_id(), game::BD_NO_FILE)->send();
|
||||
}
|
||||
}
|
||||
|
||||
std::string bdStorage::get_user_file_path(const std::string& name)
|
||||
{
|
||||
return "players2/user/" + name;
|
||||
}
|
||||
|
||||
void bdStorage::set_user_file(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
bool priv;
|
||||
uint64_t owner;
|
||||
std::string game, filename, data;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_bool(&priv);
|
||||
buffer->read_blob(&data);
|
||||
buffer->read_uint64(&owner);
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
utils::io::write_file(path, data);
|
||||
|
||||
auto* info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = owner;
|
||||
info->priv = priv;
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(info);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::get_user_file(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t owner{};
|
||||
std::string game, filename, platform, data;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_uint64(&owner);
|
||||
buffer->read_string(&platform);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DW]: [bdStorage]: user file: %s, %s, %s\n", game.data(), filename.data(), platform.data());
|
||||
#endif
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
if (utils::io::read_file(path, &data))
|
||||
{
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(new bdFileData(data));
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->create_reply(this->task_id(), game::BD_NO_FILE)->send();
|
||||
}
|
||||
}
|
||||
|
||||
void bdStorage::unk13(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
27
src/client/game/demonware/services/bdStorage.hpp
Normal file
27
src/client/game/demonware/services/bdStorage.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdStorage final : public service
|
||||
{
|
||||
public:
|
||||
bdStorage();
|
||||
|
||||
private:
|
||||
using callback = std::function<std::string()>;
|
||||
using resource_variant = std::variant<std::string, callback>;
|
||||
std::vector<std::pair<std::regex, resource_variant>> publisher_resources_;
|
||||
|
||||
void map_publisher_resource(const std::string& expression, const std::string& path, int id);
|
||||
void map_publisher_resource_variant(const std::string& expression, resource_variant resource);
|
||||
bool load_publisher_resource(const std::string& name, std::string& buffer) const;
|
||||
|
||||
void list_publisher_files(service_server* server, byte_buffer* buffer);
|
||||
void get_publisher_file(service_server* server, byte_buffer* buffer);
|
||||
void set_user_file(service_server* server, byte_buffer* buffer) const;
|
||||
void get_user_file(service_server* server, byte_buffer* buffer) const;
|
||||
void unk13(service_server* server, byte_buffer* buffer) const;
|
||||
|
||||
static std::string get_user_file_path(const std::string& name);
|
||||
};
|
||||
}
|
20
src/client/game/demonware/services/bdTitleUtilities.cpp
Normal file
20
src/client/game/demonware/services/bdTitleUtilities.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdTitleUtilities::bdTitleUtilities() : service(12, "bdTitleUtilities")
|
||||
{
|
||||
this->register_task(6, &bdTitleUtilities::get_server_time);
|
||||
}
|
||||
|
||||
void bdTitleUtilities::get_server_time(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
auto* const time_result = new bdTimeStamp;
|
||||
time_result->unix_time = uint32_t(time(nullptr));
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(time_result);
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdTitleUtilities.hpp
Normal file
13
src/client/game/demonware/services/bdTitleUtilities.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTitleUtilities final : public service
|
||||
{
|
||||
public:
|
||||
bdTitleUtilities();
|
||||
|
||||
private:
|
||||
void get_server_time(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
src/client/game/demonware/services/bdUNK63.cpp
Normal file
17
src/client/game/demonware/services/bdUNK63.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdUNK63::bdUNK63() : service(63, "bdUNK63")
|
||||
{
|
||||
//this->register_task(6, "unk6", &bdUNK63::unk6);
|
||||
}
|
||||
|
||||
void bdUNK63::unk(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
src/client/game/demonware/services/bdUNK63.hpp
Normal file
13
src/client/game/demonware/services/bdUNK63.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdUNK63 final : public service
|
||||
{
|
||||
public:
|
||||
bdUNK63();
|
||||
|
||||
private:
|
||||
void unk(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
57
src/client/game/demonware/services/bdUNK80.cpp
Normal file
57
src/client/game/demonware/services/bdUNK80.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdUNK80::bdUNK80() : service(80, "bdUNK80")
|
||||
{
|
||||
this->register_task(42, &bdUNK80::unk42);
|
||||
this->register_task(49, &bdUNK80::unk49);
|
||||
this->register_task(60, &bdUNK80::unk60);
|
||||
this->register_task(130, &bdUNK80::unk130);
|
||||
this->register_task(165, &bdUNK80::unk165);
|
||||
this->register_task(193, &bdUNK80::unk193);
|
||||
}
|
||||
|
||||
void bdUNK80::unk42(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdUNK80::unk49(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdUNK80::unk60(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdUNK80::unk130(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdUNK80::unk165(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdUNK80::unk193(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
18
src/client/game/demonware/services/bdUNK80.hpp
Normal file
18
src/client/game/demonware/services/bdUNK80.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdUNK80 final : public service
|
||||
{
|
||||
public:
|
||||
bdUNK80();
|
||||
|
||||
private:
|
||||
void unk42(service_server* server, byte_buffer* buffer) const;
|
||||
void unk49(service_server* server, byte_buffer* buffer) const;
|
||||
void unk60(service_server* server, byte_buffer* buffer) const;
|
||||
void unk130(service_server* server, byte_buffer* buffer) const;
|
||||
void unk165(service_server* server, byte_buffer* buffer) const;
|
||||
void unk193(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user