Commit 47aa9778 authored by mercury233's avatar mercury233

Merge branch 'master' of https://github.com/Fluorohydride/ygopro into server

parents 7eba35e4 0f73f228
......@@ -2,31 +2,52 @@
#define BUFFERIO_H
#include <cstdint>
#include <cstring>
#include <cwchar>
#include "../ocgcore/buffer.h"
class BufferIO {
public:
static int ReadInt32(unsigned char*& p) {
return buffer_read<int32_t>(p);
template<typename T>
static T Read(unsigned char*& p) {
T ret{};
std::memcpy(&ret, p, sizeof(T));
p += sizeof(T);
return ret;
}
template<typename T>
static void Write(unsigned char*& p, T value) {
std::memcpy(p, &value, sizeof(T));
p += sizeof(T);
}
// for compatibility
[[deprecated]]
static int32_t ReadInt32(unsigned char*& p) {
return Read<int32_t>(p);
}
[[deprecated]]
static short ReadInt16(unsigned char*& p) {
return buffer_read<int16_t>(p);
return Read<int16_t>(p);
}
[[deprecated]]
static char ReadInt8(unsigned char*& p) {
return buffer_read<char>(p);
return Read<char>(p);
}
[[deprecated]]
static unsigned char ReadUInt8(unsigned char*& p) {
return buffer_read<unsigned char>(p);
return Read<unsigned char>(p);
}
static void WriteInt32(unsigned char*& p, int val) {
buffer_write<int32_t>(p, val);
[[deprecated]]
static void WriteInt32(unsigned char*& p, int32_t val) {
Write<int32_t>(p, val);
}
[[deprecated]]
static void WriteInt16(unsigned char*& p, short val) {
buffer_write<int16_t>(p, val);
Write<int16_t>(p, val);
}
[[deprecated]]
static void WriteInt8(unsigned char*& p, char val) {
buffer_write<char>(p, val);
Write<char>(p, val);
}
/**
* @brief Copy a C-style string to another C-style string.
......@@ -61,64 +82,18 @@ public:
return CopyWStr(src, dst, N);
}
template<size_t N>
static void CopyString(const char* src, char(&dst)[N]) {
std::strncpy(dst, src, N - 1);
dst[N - 1] = 0;
static void CopyString(const char* src, char(&dst)[N], size_t len = N - 1) {
if(len >= N)
len = N - 1;
std::strncpy(dst, src, len);
dst[len] = 0;
}
template<size_t N>
static void CopyWideString(const wchar_t* src, wchar_t(&dst)[N]) {
std::wcsncpy(dst, src, N - 1);
dst[N - 1] = 0;
}
template<typename T>
static bool CheckUTF8Byte(const T* str, int len) {
for (int i = 1; i < len; ++i) {
if ((str[i] & 0xc0U) != 0x80U)
return false;
}
return true;
}
static unsigned int ConvertUTF8(const char*& p) {
unsigned int cur = 0;
if ((p[0] & 0x80U) == 0) {
cur = p[0] & 0xffU;
p++;
}
else if ((p[0] & 0xe0U) == 0xc0U) {
if (!CheckUTF8Byte(p, 2)) {
p++;
return UINT32_MAX;
}
cur = ((p[0] & 0x1fU) << 6) | (p[1] & 0x3fU);
p += 2;
if(cur < 0x80U)
return UINT32_MAX;
}
else if ((p[0] & 0xf0U) == 0xe0U) {
if (!CheckUTF8Byte(p, 3)) {
p++;
return UINT32_MAX;
}
cur = ((p[0] & 0xfU) << 12) | ((p[1] & 0x3fU) << 6) | (p[2] & 0x3fU);
p += 3;
if (cur < 0x800U)
return UINT32_MAX;
}
else if ((p[0] & 0xf8U) == 0xf0U) {
if (!CheckUTF8Byte(p, 4)) {
p++;
return UINT32_MAX;
}
cur = ((p[0] & 0x7U) << 18) | ((p[1] & 0x3fU) << 12) | ((p[2] & 0x3fU) << 6) | (p[3] & 0x3fU);
p += 4;
if (cur < 0x10000U)
return UINT32_MAX;
}
else {
p++;
return UINT32_MAX;
}
return cur;
static void CopyWideString(const wchar_t* src, wchar_t(&dst)[N], size_t len = N - 1) {
if(len >= N)
len = N - 1;
std::wcsncpy(dst, src, len);
dst[len] = 0;
}
static bool IsHighSurrogate(unsigned int c) {
return (c >= 0xd800U && c <= 0xdbffU);
......@@ -137,111 +112,31 @@ public:
}
// UTF-16/UTF-32 to UTF-8
// return: string length
static int EncodeUTF8String(const wchar_t* wsrc, char* str, int size) {
auto pw = wsrc;
auto pstr = str;
while (*pw != 0) {
unsigned cur = 0;
int codepoint_size = 0;
if (sizeof(wchar_t) == 2) {
if (IsHighSurrogate(pw[0])) {
if (pw[1] == 0)
break;
if (IsLowSurrogate(pw[1])) {
cur = ((pw[0] & 0x3ffU) << 10) | (pw[1] & 0x3ffU);
cur += 0x10000;
pw += 2;
}
else {
pw++;
continue;
}
}
else if (IsLowSurrogate(pw[0])) {
pw++;
continue;
}
else {
cur = *pw;
pw++;
}
}
else {
cur = *pw;
pw++;
}
if (!IsUnicodeChar(cur))
continue;
if (cur < 0x80U)
codepoint_size = 1;
else if (cur < 0x800U)
codepoint_size = 2;
else if (cur < 0x10000U)
codepoint_size = 3;
else
codepoint_size = 4;
if ((int)(pstr - str) + codepoint_size > size - 1)
break;
switch (codepoint_size) {
case 1:
*pstr = (char)cur;
break;
case 2:
pstr[0] = ((cur >> 6) & 0x1f) | 0xc0;
pstr[1] = (cur & 0x3f) | 0x80;
break;
case 3:
pstr[0] = ((cur >> 12) & 0xf) | 0xe0;
pstr[1] = ((cur >> 6) & 0x3f) | 0x80;
pstr[2] = (cur & 0x3f) | 0x80;
break;
case 4:
pstr[0] = ((cur >> 18) & 0x7) | 0xf0;
pstr[1] = ((cur >> 12) & 0x3f) | 0x80;
pstr[2] = ((cur >> 6) & 0x3f) | 0x80;
pstr[3] = (cur & 0x3f) | 0x80;
break;
default:
break;
}
pstr += codepoint_size;
static int EncodeUTF8String(const wchar_t* wsrc, char* str, size_t len) {
if (len == 0) {
str[0] = 0;
return 0;
}
*pstr = 0;
return (int)(pstr - str);
std::mbstate_t state{};
size_t result_len = std::wcsrtombs(str, &wsrc, len - 1, &state);
if (result_len == static_cast<size_t>(-1))
result_len = 0;
str[result_len] = 0;
return static_cast<int>(result_len);
}
// UTF-8 to UTF-16/UTF-32
// return: string length
static int DecodeUTF8String(const char* src, wchar_t* wstr, int size) {
const char* p = src;
wchar_t* wp = wstr;
while(*p != 0) {
unsigned int cur = ConvertUTF8(p);
int codepoint_size = 0;
if (!IsUnicodeChar(cur))
continue;
if (cur >= 0x10000) {
if (sizeof(wchar_t) == 2)
codepoint_size = 2;
else
codepoint_size = 1;
}
else
codepoint_size = 1;
if ((int)(wp - wstr) + codepoint_size > size - 1)
break;
if (codepoint_size == 1) {
wp[0] = cur;
wp++;
}
else {
cur -= 0x10000U;
wp[0] = (cur >> 10) | 0xd800;
wp[1] = (cur & 0x3ff) | 0xdc00;
wp += 2;
}
static int DecodeUTF8String(const char* src, wchar_t* wstr, size_t len) {
if (len == 0) {
wstr[0] = 0;
return 0;
}
*wp = 0;
return wp - wstr;
std::mbstate_t state{};
size_t result_len = std::mbsrtowcs(wstr, &src, len - 1, &state);
if (result_len == static_cast<size_t>(-1))
result_len = 0;
wstr[result_len] = 0;
return static_cast<int>(result_len);
}
template<size_t N>
static int EncodeUTF8(const wchar_t* src, char(&dst)[N]) {
......
......@@ -39,13 +39,13 @@ void ClientCard::SetCode(unsigned int x) {
code = x;
}
void ClientCard::UpdateInfo(unsigned char* buf) {
int flag = BufferIO::ReadInt32(buf);
int flag = BufferIO::Read<int32_t>(buf);
if (flag == 0) {
ClearData();
return;
}
if(flag & QUERY_CODE) {
int pdata = BufferIO::ReadInt32(buf);
int pdata = BufferIO::Read<int32_t>(buf);
if (!pdata)
ClearData();
if((location == LOCATION_HAND) && ((unsigned int)pdata != code)) {
......@@ -55,7 +55,7 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
code = pdata;
}
if(flag & QUERY_POSITION) {
int pdata = (BufferIO::ReadInt32(buf) >> 24) & 0xff;
int pdata = (BufferIO::Read<int32_t>(buf) >> 24) & 0xff;
if((location & (LOCATION_EXTRA | LOCATION_REMOVED)) && pdata != position) {
position = pdata;
mainGame->dField.MoveCard(this, 1);
......@@ -63,29 +63,29 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
position = pdata;
}
if(flag & QUERY_ALIAS)
alias = BufferIO::ReadInt32(buf);
alias = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_TYPE)
type = BufferIO::ReadInt32(buf);
type = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_LEVEL) {
int pdata = BufferIO::ReadInt32(buf);
int pdata = BufferIO::Read<int32_t>(buf);
if(level != (unsigned int)pdata) {
level = pdata;
myswprintf(lvstring, L"L%d", level);
}
}
if(flag & QUERY_RANK) {
int pdata = BufferIO::ReadInt32(buf);
int pdata = BufferIO::Read<int32_t>(buf);
if(pdata && rank != (unsigned int)pdata) {
rank = pdata;
myswprintf(lvstring, L"R%d", rank);
}
}
if(flag & QUERY_ATTRIBUTE)
attribute = BufferIO::ReadInt32(buf);
attribute = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_RACE)
race = BufferIO::ReadInt32(buf);
race = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_ATTACK) {
attack = BufferIO::ReadInt32(buf);
attack = BufferIO::Read<int32_t>(buf);
if(attack < 0) {
atkstring[0] = '?';
atkstring[1] = 0;
......@@ -93,7 +93,7 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
myswprintf(atkstring, L"%d", attack);
}
if(flag & QUERY_DEFENSE) {
defense = BufferIO::ReadInt32(buf);
defense = BufferIO::Read<int32_t>(buf);
if(type & TYPE_LINK) {
defstring[0] = '-';
defstring[1] = 0;
......@@ -104,18 +104,18 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
myswprintf(defstring, L"%d", defense);
}
if(flag & QUERY_BASE_ATTACK)
base_attack = BufferIO::ReadInt32(buf);
base_attack = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_BASE_DEFENSE)
base_defense = BufferIO::ReadInt32(buf);
base_defense = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_REASON)
reason = BufferIO::ReadInt32(buf);
reason = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_REASON_CARD)
buf += 4;
if(flag & QUERY_EQUIP_CARD) {
int c = BufferIO::ReadUInt8(buf);
unsigned int l = BufferIO::ReadUInt8(buf);
int s = BufferIO::ReadUInt8(buf);
BufferIO::ReadUInt8(buf);
int c = BufferIO::Read<uint8_t>(buf);
unsigned int l = BufferIO::Read<uint8_t>(buf);
int s = BufferIO::Read<uint8_t>(buf);
BufferIO::Read<uint8_t>(buf);
ClientCard* ecard = mainGame->dField.GetCard(mainGame->LocalPlayer(c), l, s);
if (ecard) {
equipTarget = ecard;
......@@ -123,12 +123,12 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
}
}
if(flag & QUERY_TARGET_CARD) {
int count = BufferIO::ReadInt32(buf);
int count = BufferIO::Read<int32_t>(buf);
for(int i = 0; i < count; ++i) {
int c = BufferIO::ReadUInt8(buf);
unsigned int l = BufferIO::ReadUInt8(buf);
int s = BufferIO::ReadUInt8(buf);
BufferIO::ReadUInt8(buf);
int c = BufferIO::Read<uint8_t>(buf);
unsigned int l = BufferIO::Read<uint8_t>(buf);
int s = BufferIO::Read<uint8_t>(buf);
BufferIO::Read<uint8_t>(buf);
ClientCard* tcard = mainGame->dField.GetCard(mainGame->LocalPlayer(c), l, s);
if (tcard) {
cardTarget.insert(tcard);
......@@ -137,38 +137,38 @@ void ClientCard::UpdateInfo(unsigned char* buf) {
}
}
if(flag & QUERY_OVERLAY_CARD) {
int count = BufferIO::ReadInt32(buf);
int count = BufferIO::Read<int32_t>(buf);
for(int i = 0; i < count; ++i) {
overlayed[i]->SetCode(BufferIO::ReadInt32(buf));
overlayed[i]->SetCode(BufferIO::Read<int32_t>(buf));
}
}
if(flag & QUERY_COUNTERS) {
int count = BufferIO::ReadInt32(buf);
int count = BufferIO::Read<int32_t>(buf);
for(int i = 0; i < count; ++i) {
int ctype = BufferIO::ReadInt16(buf);
int ccount = BufferIO::ReadInt16(buf);
int ctype = BufferIO::Read<uint16_t>(buf);
int ccount = BufferIO::Read<uint16_t>(buf);
counters[ctype] = ccount;
}
}
if(flag & QUERY_OWNER)
owner = BufferIO::ReadInt32(buf);
owner = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_STATUS)
status = BufferIO::ReadInt32(buf);
status = BufferIO::Read<int32_t>(buf);
if(flag & QUERY_LSCALE) {
lscale = BufferIO::ReadInt32(buf);
lscale = BufferIO::Read<int32_t>(buf);
myswprintf(lscstring, L"%d", lscale);
}
if(flag & QUERY_RSCALE) {
rscale = BufferIO::ReadInt32(buf);
rscale = BufferIO::Read<int32_t>(buf);
myswprintf(rscstring, L"%d", rscale);
}
if(flag & QUERY_LINK) {
int pdata = BufferIO::ReadInt32(buf);
int pdata = BufferIO::Read<int32_t>(buf);
if (link != (unsigned int)pdata) {
link = pdata;
}
myswprintf(linkstring, L"L\x2012%d", link);
pdata = BufferIO::ReadInt32(buf);
pdata = BufferIO::Read<int32_t>(buf);
if (link_marker != (unsigned int)pdata) {
link_marker = pdata;
}
......
......@@ -317,7 +317,7 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) {
}
void ClientField::UpdateCard(int controler, int location, int sequence, unsigned char* data) {
ClientCard* pcard = GetCard(controler, location, sequence);
int len = BufferIO::ReadInt32(data);
int len = BufferIO::Read<int32_t>(data);
if (pcard && len > LEN_HEADER)
pcard->UpdateInfo(data);
}
......@@ -350,7 +350,7 @@ void ClientField::UpdateFieldCard(int controler, int location, unsigned char* da
return;
int len;
for(auto cit = lst->begin(); cit != lst->end(); ++cit) {
len = BufferIO::ReadInt32(data);
len = BufferIO::Read<int32_t>(data);
if(len > LEN_HEADER)
(*cit)->UpdateInfo(data);
data += len - 4;
......@@ -1402,7 +1402,8 @@ bool ClientField::check_sum_trib(std::set<ClientCard*>::const_iterator index, st
|| check_sum_trib(index, end, acc + l2)
|| check_sum_trib(index, end, acc);
}
static bool is_declarable(const CardData& cd, const std::vector<unsigned int>& opcode) {
template <class T>
static bool is_declarable(const T& cd, const std::vector<unsigned int>& opcode) {
std::stack<int> stack;
for(auto it = opcode.begin(); it != opcode.end(); ++it) {
switch(*it) {
......@@ -1492,9 +1493,15 @@ static bool is_declarable(const CardData& cd, const std::vector<unsigned int>& o
}
case OPCODE_ISSETCARD: {
if (stack.size() >= 1) {
int set_code = stack.top();
uint32_t set_code = stack.top();
stack.pop();
bool res = cd.is_setcode(set_code);
bool res = false;
for (const auto& x : cd.setcode) {
if(check_setcode(x, set_code)) {
res = true;
break;
}
}
stack.push(res);
}
break;
......@@ -1538,12 +1545,12 @@ static bool is_declarable(const CardData& cd, const std::vector<unsigned int>& o
void ClientField::UpdateDeclarableList() {
const wchar_t* pname = mainGame->ebANCard->getText();
int trycode = BufferIO::GetVal(pname);
CardString cstr;
CardData cd;
if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, declare_opcodes)) {
if (dataManager.GetData(trycode, &cd) && is_declarable(cd, declare_opcodes)) {
auto it = dataManager.GetStringPointer(trycode);
mainGame->lstANCard->clear();
ancard.clear();
mainGame->lstANCard->addItem(cstr.name.c_str());
mainGame->lstANCard->addItem(it->second.name.c_str());
ancard.push_back(trycode);
return;
}
......
......@@ -23,33 +23,21 @@ bool DataManager::ReadDB(sqlite3* pDB) {
#else
const char* sql = "select * from datas,texts where datas.id=texts.id";
#endif
if (sqlite3_prepare_v2(pDB, sql, -1, &pStmt, 0) != SQLITE_OK)
if (sqlite3_prepare_v2(pDB, sql, -1, &pStmt, nullptr) != SQLITE_OK)
return Error(pDB, pStmt);
#ifndef YGOPRO_SERVER_MODE
wchar_t strBuffer[4096];
#endif
int step = 0;
do {
CardDataC cd;
CardString cs;
step = sqlite3_step(pStmt);
if (step == SQLITE_ROW) {
cd.code = sqlite3_column_int(pStmt, 0);
for (int step = sqlite3_step(pStmt); step != SQLITE_DONE; step = sqlite3_step(pStmt)) {
if (step != SQLITE_ROW)
return Error(pDB, pStmt);
uint32_t code = static_cast<uint32_t>(sqlite3_column_int64(pStmt, 0));
auto& cd = _datas[code];
cd.code = code;
cd.ot = sqlite3_column_int(pStmt, 1);
cd.alias = sqlite3_column_int(pStmt, 2);
uint64_t setcode = static_cast<uint64_t>(sqlite3_column_int64(pStmt, 3));
if (setcode) {
auto it = extra_setcode.find(cd.code);
if (it != extra_setcode.end()) {
int len = it->second.size();
if (len > SIZE_SETCODE)
len = SIZE_SETCODE;
if (len)
std::memcpy(cd.setcode, it->second.data(), len * sizeof(uint16_t));
}
else
cd.set_setcode(setcode);
}
write_setcode(cd.setcode, setcode);
cd.type = static_cast<decltype(cd.type)>(sqlite3_column_int64(pStmt, 4));
cd.attack = sqlite3_column_int(pStmt, 5);
cd.defense = sqlite3_column_int(pStmt, 6);
......@@ -59,15 +47,15 @@ bool DataManager::ReadDB(sqlite3* pDB) {
}
else
cd.link_marker = 0;
uint32_t level = static_cast<uint32_t>(sqlite3_column_int(pStmt, 7));
uint32_t level = static_cast<uint32_t>(sqlite3_column_int64(pStmt, 7));
cd.level = level & 0xff;
cd.lscale = (level >> 24) & 0xff;
cd.rscale = (level >> 16) & 0xff;
cd.race = static_cast<decltype(cd.race)>(sqlite3_column_int64(pStmt, 8));
cd.attribute = static_cast<decltype(cd.attribute)>(sqlite3_column_int64(pStmt, 9));
cd.category = static_cast<decltype(cd.category)>(sqlite3_column_int64(pStmt, 10));
_datas[cd.code] = cd;
#ifndef YGOPRO_SERVER_MODE
auto& cs = _strings[code];
if (const char* text = (const char*)sqlite3_column_text(pStmt, 12)) {
BufferIO::DecodeUTF8(text, strBuffer);
cs.name = strBuffer;
......@@ -83,13 +71,19 @@ bool DataManager::ReadDB(sqlite3* pDB) {
cs.desc[i] = strBuffer;
}
}
_strings[cd.code] = cs;
#endif //YGOPRO_SERVER_MODE
}
else if (step != SQLITE_DONE)
return Error(pDB, pStmt);
} while (step == SQLITE_ROW);
sqlite3_finalize(pStmt);
for (const auto& entry : extra_setcode) {
const auto& code = entry.first;
const auto& list = entry.second;
if (list.size() > SIZE_SETCODE || list.empty())
continue;
auto it = _datas.find(code);
if (it == _datas.end())
continue;
std::memcpy(it->second.setcode, list.data(), list.size() * sizeof(uint16_t));
}
return true;
}
bool DataManager::LoadDB(const wchar_t* wfile) {
......@@ -189,42 +183,32 @@ void DataManager::ReadStringConfLine(const char* linebuf) {
}
#endif //YGOPRO_SERVER_MODE
bool DataManager::Error(sqlite3* pDB, sqlite3_stmt* pStmt) {
std::snprintf(errmsg, sizeof errmsg, "%s", sqlite3_errmsg(pDB));
if(pStmt)
if (const char* msg = sqlite3_errmsg(pDB))
std::snprintf(errmsg, sizeof errmsg, "%s", msg);
else
errmsg[0] = '\0';
sqlite3_finalize(pStmt);
return false;
}
code_pointer DataManager::GetCodePointer(unsigned int code) const {
code_pointer DataManager::GetCodePointer(uint32_t code) const {
return _datas.find(code);
}
#ifndef YGOPRO_SERVER_MODE
string_pointer DataManager::GetStringPointer(unsigned int code) const {
string_pointer DataManager::GetStringPointer(uint32_t code) const {
return _strings.find(code);
}
code_pointer DataManager::datas_begin() const {
return _datas.cbegin();
}
code_pointer DataManager::datas_end() const {
return _datas.cend();
}
string_pointer DataManager::strings_begin() const {
return _strings.cbegin();
}
string_pointer DataManager::strings_end() const {
return _strings.cend();
}
#endif //YGOPRO_SERVER_MODE
bool DataManager::GetData(unsigned int code, CardData* pData) const {
bool DataManager::GetData(uint32_t code, CardData* pData) const {
auto cdit = _datas.find(code);
if(cdit == _datas.end())
return false;
if (pData) {
*pData = cdit->second;
std::memcpy(pData, &cdit->second, sizeof(CardData));
}
return true;
}
#ifndef YGOPRO_SERVER_MODE
bool DataManager::GetString(unsigned int code, CardString* pStr) const {
bool DataManager::GetString(uint32_t code, CardString* pStr) const {
auto csit = _strings.find(code);
if(csit == _strings.end()) {
pStr->name = unknown_string;
......@@ -234,7 +218,7 @@ bool DataManager::GetString(unsigned int code, CardString* pStr) const {
*pStr = csit->second;
return true;
}
const wchar_t* DataManager::GetName(unsigned int code) const {
const wchar_t* DataManager::GetName(uint32_t code) const {
auto csit = _strings.find(code);
if(csit == _strings.end())
return unknown_string;
......@@ -242,7 +226,7 @@ const wchar_t* DataManager::GetName(unsigned int code) const {
return csit->second.name.c_str();
return unknown_string;
}
const wchar_t* DataManager::GetText(unsigned int code) const {
const wchar_t* DataManager::GetText(uint32_t code) const {
auto csit = _strings.find(code);
if(csit == _strings.end())
return unknown_string;
......@@ -250,7 +234,7 @@ const wchar_t* DataManager::GetText(unsigned int code) const {
return csit->second.text.c_str();
return unknown_string;
}
const wchar_t* DataManager::GetDesc(unsigned int strCode) const {
const wchar_t* DataManager::GetDesc(uint32_t strCode) const {
if (strCode < (MIN_CARD_ID << 4))
return GetSysString(strCode);
unsigned int code = (strCode >> 4) & 0x0fffffff;
......
......@@ -16,19 +16,35 @@ namespace irr {
namespace ygo {
constexpr int MAX_STRING_ID = 0x7ff;
constexpr unsigned int MIN_CARD_ID = (unsigned int)(MAX_STRING_ID + 1) >> 4;
constexpr unsigned int MAX_CARD_ID = 0x0fffffffU;
constexpr uint32_t MIN_CARD_ID = (uint32_t)(MAX_STRING_ID + 1) >> 4;
constexpr uint32_t MAX_CARD_ID = 0x0fffffffU;
using CardData = card_data;
struct CardDataC : card_data {
struct CardDataC {
uint32_t code{};
uint32_t alias{};
uint16_t setcode[SIZE_SETCODE]{};
uint32_t type{};
uint32_t level{};
uint32_t attribute{};
uint32_t race{};
int32_t attack{};
int32_t defense{};
uint32_t lscale{};
uint32_t rscale{};
uint32_t link_marker{};
uint32_t ot{};
uint32_t category{};
bool is_setcodes(const std::vector<unsigned int>& values) const {
for (auto& value : values) {
if (is_setcode(value))
for (const auto& x : setcode) {
if(!x)
break;
if(check_setcode(x, value))
return true;
}
}
return false;
}
};
......@@ -37,8 +53,8 @@ struct CardString {
std::wstring text;
std::wstring desc[16];
};
using code_pointer = std::unordered_map<unsigned int, CardDataC>::const_iterator;
using string_pointer = std::unordered_map<unsigned int, CardString>::const_iterator;
using code_pointer = std::unordered_map<uint32_t, CardDataC>::const_iterator;
using string_pointer = std::unordered_map<uint32_t, CardString>::const_iterator;
class DataManager {
public:
......@@ -52,20 +68,28 @@ public:
#endif
bool Error(sqlite3* pDB, sqlite3_stmt* pStmt = nullptr);
code_pointer GetCodePointer(unsigned int code) const;
code_pointer GetCodePointer(uint32_t code) const;
#ifndef YGOPRO_SERVER_MODE
string_pointer GetStringPointer(unsigned int code) const;
code_pointer datas_begin() const;
code_pointer datas_end() const;
string_pointer strings_begin() const;
string_pointer strings_end() const;
#endif
bool GetData(unsigned int code, CardData* pData) const;
string_pointer GetStringPointer(uint32_t code) const;
code_pointer datas_begin() const noexcept {
return _datas.cbegin();
}
code_pointer datas_end() const noexcept {
return _datas.cend();
}
string_pointer strings_begin() const noexcept {
return _strings.cbegin();
}
string_pointer strings_end() const noexcept {
return _strings.cend();
}
#endif //YGOPRO_SERVER_MODE
bool GetData(uint32_t code, CardData* pData) const;
#ifndef YGOPRO_SERVER_MODE
bool GetString(unsigned int code, CardString* pStr) const;
const wchar_t* GetName(unsigned int code) const;
const wchar_t* GetText(unsigned int code) const;
const wchar_t* GetDesc(unsigned int strCode) const;
bool GetString(uint32_t code, CardString* pStr) const;
const wchar_t* GetName(uint32_t code) const;
const wchar_t* GetText(uint32_t code) const;
const wchar_t* GetDesc(uint32_t strCode) const;
const wchar_t* GetSysString(int code) const;
const wchar_t* GetVictoryString(int code) const;
const wchar_t* GetCounterName(int code) const;
......@@ -110,9 +134,9 @@ public:
#endif
private:
std::unordered_map<unsigned int, CardDataC> _datas;
std::unordered_map<unsigned int, CardString> _strings;
std::unordered_map<unsigned int, std::vector<uint16_t>> extra_setcode;
std::unordered_map<uint32_t, CardDataC> _datas;
std::unordered_map<uint32_t, CardString> _strings;
std::unordered_map<uint32_t, std::vector<uint16_t>> extra_setcode;
};
extern DataManager dataManager;
......
......@@ -696,16 +696,16 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break;
}
mainGame->ClearCardInfo();
unsigned char deckbuf[1024];
unsigned char deckbuf[1024]{};
auto pdeck = deckbuf;
BufferIO::WriteInt32(pdeck, deckManager.current_deck.main.size() + deckManager.current_deck.extra.size());
BufferIO::WriteInt32(pdeck, deckManager.current_deck.side.size());
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.main.size() + deckManager.current_deck.extra.size()));
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.side.size()));
for(size_t i = 0; i < deckManager.current_deck.main.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.main[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.main[i]->first);
for(size_t i = 0; i < deckManager.current_deck.extra.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.extra[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.extra[i]->first);
for(size_t i = 0; i < deckManager.current_deck.side.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.side[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.side[i]->first);
DuelClient::SendBufferToServer(CTOS_UPDATE_DECK, deckbuf, pdeck - deckbuf);
break;
}
......@@ -1472,7 +1472,7 @@ void DeckBuilder::FilterCards() {
auto strpointer = dataManager.GetStringPointer(ptr->first);
if (strpointer == dataManager.strings_end())
continue;
const CardString& text = strpointer->second;
const CardString& strings = strpointer->second;
if(data.type & TYPE_TOKEN)
continue;
switch(filter_type) {
......@@ -1548,14 +1548,14 @@ void DeckBuilder::FilterCards() {
for (auto elements_iterator = query_elements.begin(); elements_iterator != query_elements.end(); ++elements_iterator) {
bool match = false;
if (elements_iterator->type == element_t::type_t::name) {
match = CardNameContains(text.name.c_str(), elements_iterator->keyword.c_str());
match = CardNameContains(strings.name.c_str(), elements_iterator->keyword.c_str());
} else if (elements_iterator->type == element_t::type_t::setcode) {
match = data.is_setcodes(elements_iterator->setcodes);
} else if (trycode && (data.code == trycode || data.alias == trycode && data.is_alternative())){
} else if (trycode && (data.code == trycode || data.alias == trycode && is_alternative(data.code, data.alias))){
match = true;
} else {
match = CardNameContains(text.name.c_str(), elements_iterator->keyword.c_str())
|| text.text.find(elements_iterator->keyword) != std::wstring::npos
match = CardNameContains(strings.name.c_str(), elements_iterator->keyword.c_str())
|| strings.text.find(elements_iterator->keyword) != std::wstring::npos
|| data.is_setcodes(elements_iterator->setcodes);
}
if(elements_iterator->exclude)
......@@ -1871,7 +1871,7 @@ void DeckBuilder::pop_side(int seq) {
GetHoveredCard();
}
bool DeckBuilder::check_limit(code_pointer pointer) {
unsigned int limitcode = pointer->second.alias ? pointer->second.alias : pointer->first;
auto limitcode = pointer->second.alias ? pointer->second.alias : pointer->first;
int limit = 3;
auto flit = filterList->content.find(limitcode);
if(flit != filterList->content.end())
......
......@@ -15,7 +15,6 @@ void DeckManager::LoadLFListSingle(const char* path) {
FILE* fp = myfopen(path, "r");
char linebuf[256]{};
wchar_t strBuffer[256]{};
char str1[16]{};
if(fp) {
while(std::fgets(linebuf, sizeof linebuf, fp)) {
if(linebuf[0] == '#')
......@@ -33,13 +32,20 @@ void DeckManager::LoadLFListSingle(const char* path) {
}
if (cur == _lfList.rend())
continue;
unsigned int code = 0;
int count = -1;
if (std::sscanf(linebuf, "%10s%*[ ]%1d", str1, &count) != 2)
char* pos = linebuf;
errno = 0;
auto result = std::strtoul(pos, &pos, 10);
if (errno || result > UINT32_MAX)
continue;
if (pos == linebuf || *pos != ' ')
continue;
uint32_t code = static_cast<uint32_t>(result);
errno = 0;
int count = std::strtol(pos, &pos, 10);
if (errno)
continue;
if (count < 0 || count > 2)
continue;
code = std::strtoul(str1, nullptr, 10);
cur->content[code] = count;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
}
......@@ -201,8 +207,9 @@ uint32_t DeckManager::LoadDeckFromStream(Deck& deck, std::istringstream& deckStr
}
if (linebuf[0] < '0' || linebuf[0] > '9')
continue;
errno = 0;
auto code = std::strtoul(linebuf.c_str(), nullptr, 10);
if (code >= UINT32_MAX)
if (errno || code > UINT32_MAX)
continue;
cardlist[ct++] = code;
if (is_side)
......
......@@ -29,10 +29,13 @@ namespace ygo {
constexpr int SIDE_MAX_SIZE = YGOPRO_MAX_SIDE;
constexpr int PACK_MAX_SIZE = 1000;
constexpr int MAINC_MAX = 250; // the limit of card_state
constexpr int SIDEC_MAX = MAINC_MAX;
struct LFList {
unsigned int hash{};
std::wstring listName;
std::unordered_map<unsigned int, int> content;
std::unordered_map<uint32_t, int> content;
};
struct Deck {
std::vector<code_pointer> main;
......
......@@ -1121,7 +1121,7 @@ void Game::WaitFrameSignal(int frame) {
frameSignal.Wait();
}
void Game::DrawThumb(code_pointer cp, irr::core::vector2di pos, const LFList* lflist, bool drag) {
int code = cp->first;
auto code = cp->first;
auto lcode = cp->second.alias;
if(lcode == 0)
lcode = code;
......
This diff is collapsed.
......@@ -4,6 +4,7 @@
#include <vector>
#include <set>
#include <random>
#include "config.h"
#include "network.h"
namespace ygo {
......@@ -49,16 +50,16 @@ public:
static void SendResponse();
static void SendPacketToServer(unsigned char proto) {
auto p = duel_client_write;
buffer_write<uint16_t>(p, 1);
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, 1);
BufferIO::Write<uint8_t>(p, proto);
bufferevent_write(client_bev, duel_client_write, 3);
}
template<typename ST>
static void SendPacketToServer(unsigned char proto, const ST& st) {
auto p = duel_client_write;
static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
BufferIO::Write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST));
bufferevent_write(client_bev, duel_client_write, sizeof(ST) + 3);
}
......@@ -66,8 +67,8 @@ public:
auto p = duel_client_write;
if (len > MAX_DATA_SIZE)
len = MAX_DATA_SIZE;
buffer_write<uint16_t>(p, (uint16_t)(1 + len));
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, (uint16_t)(1 + len));
BufferIO::Write<uint8_t>(p, proto);
std::memcpy(p, buffer, len);
bufferevent_write(client_bev, duel_client_write, len + 3);
}
......
......@@ -1301,11 +1301,8 @@ void Game::RefreshDeck(const wchar_t* deckpath, const std::function<void(const w
}
FileSystem::TraversalDir(deckpath, [additem](const wchar_t* name, bool isdir) {
if (!isdir && IsExtension(name, L".ydk")) {
size_t len = std::wcslen(name);
wchar_t deckname[256]{};
size_t count = std::min(len - 4, sizeof deckname / sizeof deckname[0] - 1);
std::wcsncpy(deckname, name, count);
deckname[count] = 0;
BufferIO::CopyWideString(name, deckname, std::wcslen(name) - 4);
additem(deckname);
}
});
......@@ -1611,7 +1608,7 @@ void Game::ShowCardInfo(int code, bool resize) {
imgCard->setImage(imageManager.GetTexture(code, true));
if (is_valid) {
auto& cd = cit->second;
if (cd.is_alternative())
if (is_alternative(cd.code,cd.alias))
myswprintf(formatBuffer, L"%ls[%08d]", dataManager.GetName(cd.alias), cd.alias);
else
myswprintf(formatBuffer, L"%ls[%08d]", dataManager.GetName(code), code);
......
......@@ -17,14 +17,14 @@ void UpdateDeck() {
BufferIO::CopyWideString(mainGame->cbDeckSelect->getText(), mainGame->gameConf.lastdeck);
unsigned char deckbuf[1024]{};
auto pdeck = deckbuf;
BufferIO::WriteInt32(pdeck, deckManager.current_deck.main.size() + deckManager.current_deck.extra.size());
BufferIO::WriteInt32(pdeck, deckManager.current_deck.side.size());
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.main.size() + deckManager.current_deck.extra.size()));
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.side.size()));
for(size_t i = 0; i < deckManager.current_deck.main.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.main[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.main[i]->first);
for(size_t i = 0; i < deckManager.current_deck.extra.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.extra[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.extra[i]->first);
for(size_t i = 0; i < deckManager.current_deck.side.size(); ++i)
BufferIO::WriteInt32(pdeck, deckManager.current_deck.side[i]->first);
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.side[i]->first);
DuelClient::SendBufferToServer(CTOS_UPDATE_DECK, deckbuf, pdeck - deckbuf);
}
bool MenuHandler::OnEvent(const irr::SEvent& event) {
......@@ -428,8 +428,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t *dot = std::wcsrchr(open_file_name, L'.');
if(dash && dot && !mywcsncasecmp(dot, L".ydk", 4)) { // full path
wchar_t deck_name[256];
std::wcsncpy(deck_name, dash + 1, dot - dash - 1);
deck_name[dot - dash - 1] = L'\0';
BufferIO::CopyWideString(dash + 1, deck_name, dot - dash - 1);
mainGame->ebDeckname->setText(deck_name);
mainGame->cbDBCategory->setSelected(-1);
mainGame->cbDBDecks->setSelected(-1);
......@@ -438,7 +437,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->cbDBDecks->setEnabled(false);
} else if(dash) { // has category
wchar_t deck_name[256];
std::wcsncpy(deck_name, dash + 1, 256);
BufferIO::CopyWideString(dash + 1, deck_name);
for(size_t i = 0; i < mainGame->cbDBDecks->getItemCount(); ++i) {
if(!std::wcscmp(mainGame->cbDBDecks->getItem(i), deck_name)) {
BufferIO::CopyWideString(deck_name, mainGame->gameConf.lastdeck);
......
......@@ -268,7 +268,7 @@ void NetServer::DisconnectPlayer(DuelPlayer* dp) {
}
void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
auto pdata = data;
unsigned char pktType = BufferIO::ReadUInt8(pdata);
unsigned char pktType = BufferIO::Read<uint8_t>(pdata);
#ifdef YGOPRO_SERVER_MODE
if((pktType != CTOS_SURRENDER) && (pktType != CTOS_CHAT) && (pktType != CTOS_REQUEST_FIELD) && (dp->state == 0xff || (dp->state && dp->state != pktType)))
#else
......@@ -348,7 +348,7 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
// for other server & reverse proxy use only
/*
wchar_t hostname[LEN_HOSTNAME];
uint32_t real_ip = ntohl(BufferIO::ReadInt32(pdata));
uint32_t real_ip = ntohl(BufferIO::Read<int32_t>(pdata));
BufferIO::CopyCharArray((uint16_t*)pdata, hostname);
*/
break;
......@@ -484,8 +484,9 @@ size_t NetServer::CreateChatPacket(unsigned char* src, int src_size, unsigned ch
return 0;
// STOC_Chat packet
auto pdst = dst;
buffer_write<uint16_t>(pdst, dst_player_type);
buffer_write_block(pdst, src_msg, src_size);
BufferIO::Write<uint16_t>(pdst, dst_player_type);
std::memcpy(pdst, src_msg, src_size);
pdst += src_size;
return sizeof(dst_player_type) + src_size;
}
......
#ifndef NETSERVER_H
#define NETSERVER_H
#include "network.h"
#include <unordered_map>
#include "config.h"
#include "network.h"
namespace ygo {
......@@ -43,8 +44,8 @@ public:
static size_t CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type);
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto) {
auto p = net_server_write;
buffer_write<uint16_t>(p, 1);
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, 1);
BufferIO::Write<uint8_t>(p, proto);
last_sent = 3;
if (dp)
bufferevent_write(dp->bev, net_server_write, 3);
......@@ -53,8 +54,8 @@ public:
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, const ST& st) {
auto p = net_server_write;
static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
BufferIO::Write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST));
last_sent = sizeof(ST) + 3;
if (dp)
......@@ -64,8 +65,8 @@ public:
auto p = net_server_write;
if (len > MAX_DATA_SIZE)
len = MAX_DATA_SIZE;
buffer_write<uint16_t>(p, (uint16_t)(1 + len));
buffer_write<uint8_t>(p, proto);
BufferIO::Write<uint16_t>(p, (uint16_t)(1 + len));
BufferIO::Write<uint8_t>(p, proto);
std::memcpy(p, buffer, len);
last_sent = len + 3;
if (dp)
......
......@@ -9,14 +9,13 @@
#include <event2/buffer.h>
#include <event2/thread.h>
#include <type_traits>
#include "deck_manager.h"
#define check_trivially_copyable(T) static_assert(std::is_trivially_copyable<T>::value == true && std::is_standard_layout<T>::value == true, "not trivially copyable")
namespace ygo {
constexpr int SIZE_NETWORK_BUFFER = 0x20000;
constexpr int MAX_DATA_SIZE = UINT16_MAX - 1;
constexpr int MAINC_MAX = 250; // the limit of card_state
constexpr int SIDEC_MAX = MAINC_MAX;
struct HostInfo {
uint32_t lflist{};
......
#include "config.h"
#include "replay.h"
#include "myfilesystem.h"
#include "network.h"
#include "lzma/LzmaLib.h"
namespace ygo {
......@@ -23,23 +23,6 @@ void Replay::BeginRecord() {
#endif
if(!FileSystem::IsDirExists(L"./replay") && !FileSystem::MakeDir(L"./replay"))
return;
#ifdef _WIN32
if(is_recording)
CloseHandle(recording_fp);
#ifdef YGOPRO_SERVER_MODE
time_t nowtime = time(NULL);
struct tm *localedtime = localtime(&nowtime);
wchar_t tmppath[80];
wcsftime(tmppath, 80, L"./replay/%Y-%m-%d %H-%M-%S %%u.yrp", localedtime);
wchar_t path[80];
myswprintf(path, tmppath, server_port);
recording_fp = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
#else
recording_fp = CreateFileW(L"./replay/_LastReplay.yrp", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, nullptr);
#endif //YGOPRO_SERVER_MODE
if(recording_fp == INVALID_HANDLE_VALUE)
return;
#else
if(is_recording)
std::fclose(fp);
#ifdef YGOPRO_SERVER_MODE
......@@ -55,7 +38,6 @@ void Replay::BeginRecord() {
#endif //YGOPRO_SERVER_MODE
if(!fp)
return;
#endif
#ifdef YGOPRO_SERVER_MODE
}
#endif //YGOPRO_SERVER_MODE
......@@ -67,13 +49,8 @@ void Replay::WriteHeader(ExtendedReplayHeader& header) {
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
#endif
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, &header, sizeof(header), &size, nullptr);
#else
std::fwrite(&header, sizeof(header), 1, fp);
std::fwrite(&header, sizeof header, 1, fp);
std::fflush(fp);
#endif
}
void Replay::WriteData(const void* data, size_t length, bool flush) {
if(!is_recording)
......@@ -85,14 +62,9 @@ void Replay::WriteData(const void* data, size_t length, bool flush) {
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
#endif
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, data, length, &size, nullptr);
#else
std::fwrite(data, length, 1, fp);
if(flush)
std::fflush(fp);
#endif
}
void Replay::WriteInt32(int32_t data, bool flush) {
Write<int32_t>(data, flush);
......@@ -103,10 +75,7 @@ void Replay::Flush() {
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
#endif
#ifdef _WIN32
#else
std::fflush(fp);
#endif
}
void Replay::EndRecord() {
if(!is_recording)
......@@ -114,11 +83,7 @@ void Replay::EndRecord() {
#ifdef YGOPRO_SERVER_MODE
if(replay_mode & REPLAY_MODE_SAVE_IN_SERVER) {
#endif
#ifdef _WIN32
CloseHandle(recording_fp);
#else
std::fclose(fp);
#endif
#ifdef YGOPRO_SERVER_MODE
}
#endif
......
#ifndef REPLAY_H
#define REPLAY_H
#include "config.h"
#include <cstdio>
#include <vector>
#include <string>
#include "../ocgcore/ocgapi.h"
#include "deck_manager.h"
namespace ygo {
......@@ -105,10 +108,6 @@ public:
#endif // YGOPRO_SERVER_MODE
FILE* fp{ nullptr };
#ifdef _WIN32
HANDLE recording_fp{ nullptr };
#endif
ExtendedReplayHeader pheader;
unsigned char* comp_data;
size_t comp_size{};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment