Commit b3482765 authored by Chen Bill's avatar Chen Bill Committed by GitHub

fix: seeding std::mt19937 with only 1 uint32_t (#2820)

parent b9e1089f
......@@ -715,7 +715,7 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break;
}
case STOC_REPLAY: {
if (len < 1 + (int)sizeof(ReplayHeader))
if (len < 1 + (int)sizeof(ExtendedReplayHeader))
return;
mainGame->gMutex.lock();
mainGame->wPhase->setVisible(false);
......@@ -726,10 +726,10 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
Replay new_replay;
std::memcpy(&new_replay.pheader, prep, sizeof(new_replay.pheader));
time_t starttime;
if (new_replay.pheader.flag & REPLAY_UNIFORM)
starttime = new_replay.pheader.start_time;
if (new_replay.pheader.base.flag & REPLAY_UNIFORM)
starttime = new_replay.pheader.base.start_time;
else
starttime = new_replay.pheader.seed;
starttime = new_replay.pheader.base.seed;
wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&starttime));
......@@ -751,9 +751,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
mainGame->WaitFrameSignal(30);
}
if(mainGame->actionParam || !is_host) {
prep += sizeof(ReplayHeader);
std::memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1;
prep += sizeof new_replay.pheader;
std::memcpy(new_replay.comp_data, prep, len - sizeof new_replay.pheader - 1);
new_replay.comp_size = len - sizeof new_replay.pheader - 1;
if(mainGame->actionParam)
new_replay.SaveReplay(mainGame->ebRSName->getText());
else
......
......@@ -309,7 +309,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path))
break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE)
if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break;
for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
......@@ -537,24 +537,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{};
std::wstring repinfo;
time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM)
curtime = temp_replay.pheader.start_time;
const auto& rh = temp_replay.pheader.base;
if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
curtime = rh.start_time;
else{
curtime = temp_replay.pheader.seed;
curtime = rh.seed;
wchar_t version_info[256]{};
myswprintf(version_info, L"version 0x%X\n", temp_replay.pheader.version);
myswprintf(version_info, L"version 0x%X\n", rh.version);
repinfo.append(version_info);
}
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) {
if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path);
repinfo.append(L"\n");
}
const auto& player_names = temp_replay.players;
if(temp_replay.pheader.flag & REPLAY_TAG)
if(rh.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str());
else
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
......
......@@ -281,7 +281,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // no data
#define STOC_DUEL_END 0x16 // no data
#define STOC_REPLAY 0x17 // ReplayHeader + byte array
#define STOC_REPLAY 0x17 // ExtendedReplayHeader + byte array
#define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit
#define STOC_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
......@@ -32,7 +32,7 @@ void Replay::BeginRecord() {
Reset();
is_recording = true;
}
void Replay::WriteHeader(ReplayHeader& header) {
void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header;
#ifdef _WIN32
DWORD size;
......@@ -77,11 +77,11 @@ void Replay::EndRecord() {
#else
std::fclose(fp);
#endif
pheader.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED;
pheader.base.datasize = replay_size;
pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
comp_size = MAX_COMP_SIZE;
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.base.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
if (ret != SZ_OK) {
std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret;
......@@ -112,27 +112,31 @@ bool Replay::OpenReplay(const wchar_t* name) {
Reset();
bool correct_header = true;
if (std::fread(&pheader, sizeof pheader, 1, rfp) < 1)
if (std::fread(&pheader, sizeof pheader.base, 1, rfp) < 1)
correct_header = false;
else if (pheader.id != 0x31707279)
else if (pheader.base.id != REPLAY_ID_YRP1 && pheader.base.id != REPLAY_ID_YRP2)
correct_header = false;
else if (pheader.version < 0x12d0u)
else if (pheader.base.version < 0x12d0u)
correct_header = false;
else if (pheader.version >= 0x1353u && !(pheader.flag & REPLAY_UNIFORM))
else if (pheader.base.version >= 0x1353u && !(pheader.base.flag & REPLAY_UNIFORM))
correct_header = false;
if (!correct_header) {
std::fclose(rfp);
return false;
}
if(pheader.flag & REPLAY_COMPRESSED) {
if (pheader.base.id == REPLAY_ID_YRP2 && std::fread(&pheader.seed_sequence, sizeof pheader.seed_sequence, 1, rfp) < 1) {
std::fclose(rfp);
return false;
}
if(pheader.base.flag & REPLAY_COMPRESSED) {
comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp);
std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE)
if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false;
replay_size = pheader.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false;
if (replay_size != pheader.datasize) {
if (replay_size != pheader.base.datasize) {
replay_size = 0;
return false;
}
......@@ -189,7 +193,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20);
return true;
}
void Replay::ReadHeader(ReplayHeader& header) {
void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader;
}
bool Replay::ReadData(void* data, size_t length) {
......@@ -232,7 +236,7 @@ bool Replay::IsReplaying() const {
return is_replaying;
}
bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2;
int player_count = (pheader.base.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{};
if (!ReadName(name))
......@@ -241,11 +245,11 @@ bool Replay::ReadInfo() {
}
if (!ReadData(&params, sizeof params))
return false;
bool is_tag1 = pheader.flag & REPLAY_TAG;
bool is_tag1 = pheader.base.flag & REPLAY_TAG;
bool is_tag2 = params.duel_flag & DUEL_TAG_MODE;
if (is_tag1 != is_tag2)
return false;
if (pheader.flag & REPLAY_SINGLE_MODE) {
if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
......
......@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size
constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
......@@ -27,6 +30,15 @@ struct ReplayHeader {
uint8_t props[8]{};
};
struct ExtendedReplayHeader {
ReplayHeader base;
uint32_t seed_sequence[SEED_COUNT]{};
uint32_t header_version{ 1 };
uint32_t value1{};
uint32_t value2{};
uint32_t value3{};
};
struct DuelParameters {
int32_t start_lp{};
int32_t start_hand{};
......@@ -41,7 +53,7 @@ public:
// record
void BeginRecord();
void WriteHeader(ReplayHeader& header);
void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true);
template<typename T>
void Write(T data, bool flush = true) {
......@@ -68,7 +80,7 @@ public:
bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length);
template<typename T>
T Read() {
......@@ -87,7 +99,7 @@ public:
HANDLE recording_fp{ nullptr };
#endif
ReplayHeader pheader;
ExtendedReplayHeader pheader;
unsigned char* comp_data;
size_t comp_size{};
......
......@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result;
}
int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader;
const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
......@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
const auto& rh = cur_replay.pheader.base;
cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
......@@ -168,7 +166,12 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
}
pduel = create_duel(rnd());
if(rh.id == REPLAY_ID_YRP1) {
std::mt19937 rnd(rh.seed);
pduel = create_duel(rnd());
} else {
pduel = create_duel_v2(cur_replay.pheader.seed_sequence);
}
mainGame->dInfo.duel_rule = cur_replay.params.duel_flag >> 16;
set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
......@@ -214,8 +217,6 @@ bool ReplayMode::StartDuel() {
return false;
}
}
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag);
return true;
}
......
......@@ -411,15 +411,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
}
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -433,7 +432,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(SingleDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
set_player_info(pduel, 0, host_info.start_lp, host_info.start_hand, host_info.draw_count);
set_player_info(pduel, 1, host_info.start_lp, host_info.start_hand, host_info.draw_count);
unsigned int opt = (unsigned int)host_info.duel_rule << 16;
......@@ -1426,10 +1425,10 @@ void SingleDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -36,12 +36,22 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear();
int opt = 0;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
std::seed_seq seed(rh.seed_sequence, rh.seed_sequence + SEED_COUNT);
std::mt19937 rnd(seed);
uint32_t duel_seed[SEED_COUNT]{};
for (auto& x : duel_seed)
x = rnd();
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(SingleMode::MessageHandler);
pduel = create_duel(rnd.rand());
pduel = create_duel_v2(duel_seed);
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
mainGame->dInfo.lp[0] = start_lp;
......@@ -79,12 +89,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel);
return 0;
}
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
mainGame->gMutex.lock();
mainGame->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo();
......
......@@ -384,15 +384,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
cur_player[1] = players[3];
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -410,7 +409,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(TagDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
set_player_info(pduel, 0, host_info.start_lp, host_info.start_hand, host_info.draw_count);
set_player_info(pduel, 1, host_info.start_lp, host_info.start_hand, host_info.draw_count);
unsigned int opt = (unsigned int)host_info.duel_rule << 16;
......@@ -1529,10 +1528,10 @@ void TagDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]);
NetServer::ReSendToPlayer(players[3]);
......
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