Commit 471c2134 authored by Chen Bill's avatar Chen Bill Committed by GitHub

Read player names, deck & check script path on OpenReplay (#2776)

parent bfcb4afc
......@@ -359,34 +359,21 @@ bool DeckManager::DeleteCategory(const wchar_t* name) {
return false;
return FileSystem::DeleteDir(localname);
}
bool DeckManager::SaveDeckBuffer(const int deckbuf[], const wchar_t* name) {
bool DeckManager::SaveDeckArray(const DeckArray& deck, const wchar_t* name) {
if (!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false;
FILE* fp = OpenDeckFile(name, "w");
if (!fp)
return false;
int it = 0;
const int mainc = deckbuf[it];
++it;
std::fprintf(fp, "#created by ...\n#main\n");
for (int i = 0; i < mainc; ++i) {
std::fprintf(fp, "%d\n", deckbuf[it]);
++it;
}
const int extrac = deckbuf[it];
++it;
for (const auto& code : deck.main)
std::fprintf(fp, "%u\n", code);
std::fprintf(fp, "#extra\n");
for (int i = 0; i < extrac; ++i) {
std::fprintf(fp, "%d\n", deckbuf[it]);
++it;
}
const int sidec = deckbuf[it];
++it;
for (const auto& code : deck.extra)
std::fprintf(fp, "%u\n", code);
std::fprintf(fp, "!side\n");
for (int i = 0; i < sidec; ++i) {
std::fprintf(fp, "%d\n", deckbuf[it]);
++it;
}
for (const auto& code : deck.side)
std::fprintf(fp, "%u\n", code);
std::fclose(fp);
return true;
}
......
......@@ -35,6 +35,12 @@ struct Deck {
}
};
struct DeckArray {
std::vector<uint32_t> main;
std::vector<uint32_t> extra;
std::vector<uint32_t> side;
};
class DeckManager {
public:
Deck current_deck;
......@@ -49,7 +55,6 @@ public:
unsigned int CheckDeck(const Deck& deck, unsigned int lfhash, int rule);
bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false);
bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname);
bool SaveDeckBuffer(const int deckbuf[], const wchar_t* name);
static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false);
static uint32_t LoadDeckFromStream(Deck& deck, std::istringstream& deckStream, bool is_packlist = false);
......@@ -63,6 +68,7 @@ public:
static bool CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
static bool DeleteCategory(const wchar_t* name);
static bool SaveDeckArray(const DeckArray& deck, const wchar_t* name);
};
extern DeckManager deckManager;
......
......@@ -300,42 +300,23 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
if(selected == -1)
break;
Replay replay;
wchar_t ex_filename[256]{};
wchar_t replay_filename[256]{};
wchar_t namebuf[4][20]{};
wchar_t filename[256]{};
wchar_t replay_path[256]{};
BufferIO::CopyWideString(mainGame->lstReplayList->getListItem(selected), ex_filename);
myswprintf(replay_path, L"./replay/%ls", ex_filename);
BufferIO::CopyWideString(mainGame->lstReplayList->getListItem(selected), replay_filename);
myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path))
break;
const ReplayHeader& rh = replay.pheader;
if(rh.flag & REPLAY_SINGLE_MODE)
if (replay.pheader.flag & REPLAY_SINGLE_MODE)
break;
int player_count = (rh.flag & REPLAY_TAG) ? 4 : 2;
//player name
for(int i = 0; i < player_count; ++i)
replay.ReadName(namebuf[i]);
//skip pre infos
for(int i = 0; i < 4; ++i)
replay.ReadInt32();
//deck
std::vector<int> deckbuf;
for(int i = 0; i < player_count; ++i) {
deckbuf.clear();
int main = replay.ReadInt32();
deckbuf.push_back(main);
for (int j = 0; j < main; ++j) {
deckbuf.push_back(replay.ReadInt32());
}
int extra = replay.ReadInt32();
deckbuf.push_back(extra);
for (int j = 0; j < extra; ++j) {
deckbuf.push_back(replay.ReadInt32());
}
deckbuf.push_back(0);
for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
FileSystem::SafeFileName(namebuf[i]);
myswprintf(filename, L"deck/%ls-%d %ls.ydk", ex_filename, i + 1, namebuf[i]);
deckManager.SaveDeckBuffer(deckbuf.data(), filename);
}
for (size_t i = 0; i < replay.decks.size(); ++i) {
myswprintf(filename, L"./deck/%ls-%d %ls.ydk", replay_filename, i + 1, namebuf[i]);
DeckManager::SaveDeckArray(replay.decks[i], filename);
}
mainGame->stACMessage->setText(dataManager.GetSysString(1335));
mainGame->PopupElement(mainGame->wACMessage, 20);
......@@ -546,7 +527,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t replay_path[256]{};
myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(sel));
if (!ReplayMode::cur_replay.OpenReplay(replay_path)) {
mainGame->stReplayInfo->setText(L"");
mainGame->stReplayInfo->setText(L"Error");
break;
}
wchar_t infobuf[256]{};
......@@ -558,17 +539,17 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
curtime = ReplayMode::cur_replay.pheader.seed;
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf);
wchar_t namebuf[4][20]{};
ReplayMode::cur_replay.ReadName(namebuf[0]);
ReplayMode::cur_replay.ReadName(namebuf[1]);
if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG) {
ReplayMode::cur_replay.ReadName(namebuf[2]);
ReplayMode::cur_replay.ReadName(namebuf[3]);
if (ReplayMode::cur_replay.pheader.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{};
BufferIO::DecodeUTF8(ReplayMode::cur_replay.script_name.c_str(), path);
repinfo.append(path);
repinfo.append(L"\n");
}
const auto& player_names = ReplayMode::cur_replay.players;
if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", namebuf[0], namebuf[1], namebuf[2], namebuf[3]);
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", namebuf[0], namebuf[1]);
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
repinfo.append(infobuf);
mainGame->ebRepStartTurn->setText(L"1");
mainGame->SetStaticText(mainGame->stReplayInfo, 180, mainGame->guiFont, repinfo.c_str());
......
#include "replay.h"
#include "myfilesystem.h"
#include "network.h"
#include "lzma/LzmaLib.h"
namespace ygo {
......@@ -28,9 +29,7 @@ void Replay::BeginRecord() {
if(!fp)
return;
#endif
replay_size = 0;
comp_size = 0;
is_replaying = false;
Reset();
is_recording = true;
}
void Replay::WriteHeader(ReplayHeader& header) {
......@@ -111,11 +110,7 @@ bool Replay::OpenReplay(const wchar_t* name) {
if(!rfp)
return false;
data_position = 0;
is_recording = false;
is_replaying = false;
replay_size = 0;
comp_size = 0;
Reset();
if(std::fread(&pheader, sizeof pheader, 1, rfp) < 1) {
std::fclose(rfp);
return false;
......@@ -138,6 +133,13 @@ bool Replay::OpenReplay(const wchar_t* name) {
comp_size = 0;
}
is_replaying = true;
can_read = true;
if (!ReadInfo()) {
Reset();
return false;
}
info_offset = data_position;
data_position = 0;
return true;
}
bool Replay::CheckReplay(const wchar_t* name) {
......@@ -177,10 +179,6 @@ bool Replay::ReadNextResponse(unsigned char resp[]) {
unsigned char len{};
if (!ReadData(&len, sizeof len))
return false;
if (len > SIZE_RETURN_VALUE) {
is_replaying = false;
return false;
}
if (!ReadData(resp, len))
return false;
return true;
......@@ -197,10 +195,10 @@ void Replay::ReadHeader(ReplayHeader& header) {
header = pheader;
}
bool Replay::ReadData(void* data, size_t length) {
if(!is_replaying)
if (!is_replaying || !can_read)
return false;
if (data_position + length > replay_size) {
is_replaying = false;
can_read = false;
return false;
}
if (length)
......@@ -213,6 +211,73 @@ int32_t Replay::ReadInt32() {
}
void Replay::Rewind() {
data_position = 0;
can_read = true;
}
void Replay::Reset() {
is_recording = false;
is_replaying = false;
can_read = false;
replay_size = 0;
comp_size = 0;
data_position = 0;
info_offset = 0;
players.clear();
params = { 0 };
decks.clear();
script_name.clear();
}
void Replay::SkipInfo(){
data_position += info_offset;
}
bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{};
if (!ReadName(name))
return false;
players.push_back(name);
}
if (!ReadData(&params, sizeof params))
return false;
bool is_tag1 = pheader.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) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
return false;
if (!ReadData(filename, slen))
return false;
filename[slen] = 0;
if (std::strncmp(filename, "./single/", 9))
return false;
script_name = filename + 9;
if (script_name.find_first_of(R"(/\)") != std::string::npos)
return false;
}
else {
for (int p = 0; p < player_count; ++p) {
DeckArray deck;
uint32_t main = Read<uint32_t>();
if (main > MAINC_MAX)
return false;
if (main)
deck.main.resize(main);
if (!ReadData(deck.main.data(), main * sizeof(uint32_t)))
return false;
uint32_t extra = Read<uint32_t>();
if (extra > MAINC_MAX)
return false;
if (extra)
deck.extra.resize(extra);
if (!ReadData(deck.extra.data(), extra * sizeof(uint32_t)))
return false;
decks.push_back(deck);
}
}
return true;
}
}
......@@ -2,6 +2,7 @@
#define REPLAY_H
#include "config.h"
#include "deck_manager.h"
namespace ygo {
......@@ -13,7 +14,7 @@ namespace ygo {
#define REPLAY_UNIFORM 0x10
// max size
constexpr int MAX_REPLAY_SIZE = 0x20000;
constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
struct ReplayHeader {
......@@ -26,6 +27,13 @@ struct ReplayHeader {
uint8_t props[8]{};
};
struct DuelParameters {
int32_t start_lp{};
int32_t start_hand{};
int32_t draw_count{};
uint32_t duel_flag{};
};
class Replay {
public:
Replay();
......@@ -45,10 +53,20 @@ public:
void SaveReplay(const wchar_t* name);
// play
bool OpenReplay(const wchar_t* name);
static bool CheckReplay(const wchar_t* name);
static bool DeleteReplay(const wchar_t* name);
static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname);
static size_t GetDeckPlayer(size_t deck_index) {
switch (deck_index) {
case 2:
return 3;
case 3:
return 2;
default:
return deck_index;
}
}
bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
......@@ -61,6 +79,8 @@ public:
}
int32_t ReadInt32();
void Rewind();
void Reset();
void SkipInfo();
FILE* fp{ nullptr };
#ifdef _WIN32
......@@ -71,12 +91,22 @@ public:
unsigned char* comp_data;
size_t comp_size{};
std::vector<std::wstring> players; // 80 or 160 bytes
DuelParameters params; // 16 bytes
std::vector<DeckArray> decks; // 4 bytes, main deck, 4 bytes, extra deck
std::string script_name; // 2 bytes, script name (max: 256 bytes)
private:
bool ReadInfo();
unsigned char* replay_data;
size_t replay_size{};
size_t data_position{};
size_t info_offset{};
bool is_recording{};
bool is_replaying{};
bool can_read{};
};
}
......
......@@ -158,89 +158,65 @@ bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
cur_replay.SkipInfo();
if(mainGame->dInfo.isTag) {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.hostname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname);
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.hostname_tag);
BufferIO::CopyWideString(cur_replay.players[2].c_str(), mainGame->dInfo.clientname_tag);
BufferIO::CopyWideString(cur_replay.players[3].c_str(), mainGame->dInfo.clientname);
} else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
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());
int start_lp = cur_replay.ReadInt32();
int start_hand = cur_replay.ReadInt32();
int draw_count = cur_replay.ReadInt32();
int opt = cur_replay.ReadInt32();
int duel_rule = opt >> 16;
mainGame->dInfo.duel_rule = duel_rule;
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;
mainGame->dInfo.lp[1] = start_lp;
mainGame->dInfo.start_lp = start_lp;
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);
mainGame->dInfo.lp[0] = cur_replay.params.start_lp;
mainGame->dInfo.lp[1] = cur_replay.params.start_lp;
mainGame->dInfo.start_lp = cur_replay.params.start_lp;
myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]);
myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]);
mainGame->dInfo.turn = 0;
if(!mainGame->dInfo.isSingleMode) {
if(!(opt & DUEL_TAG_MODE)) {
int main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(0), main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(1), main, extra);
if(!(rh.flag & REPLAY_SINGLE_MODE)) {
if(!(rh.flag & REPLAY_TAG)) {
for (int i = 0; i < 2; ++i) {
for (const auto& code : cur_replay.decks[i].main)
new_card(pduel, code, i, i, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
for (const auto& code : cur_replay.decks[i].extra)
new_card(pduel, code, i, i, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(i), cur_replay.decks[i].main.size(), cur_replay.decks[i].extra.size());
}
} else {
int main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(0), main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_EXTRA);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(1), main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_EXTRA);
for (const auto& code : cur_replay.decks[0].main)
new_card(pduel, code, 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
for (const auto& code : cur_replay.decks[0].extra)
new_card(pduel, code, 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(0), cur_replay.decks[0].main.size(), cur_replay.decks[0].extra.size());
for (const auto& code : cur_replay.decks[1].main)
new_tag_card(pduel, code, 0, LOCATION_DECK);
for (const auto& code : cur_replay.decks[1].extra)
new_tag_card(pduel, code, 0, LOCATION_EXTRA);
for (const auto& code : cur_replay.decks[2].main)
new_card(pduel, code, 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
for (const auto& code : cur_replay.decks[2].extra)
new_card(pduel, code, 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(1), cur_replay.decks[2].main.size(), cur_replay.decks[2].extra.size());
for (const auto& code : cur_replay.decks[3].main)
new_tag_card(pduel, code, 1, LOCATION_DECK);
for (const auto& code : cur_replay.decks[3].extra)
new_tag_card(pduel, code, 1, LOCATION_EXTRA);
}
} else {
char filename[256];
auto slen = cur_replay.Read<uint16_t>();
if (slen > sizeof(filename) - 1) {
return false;
}
cur_replay.ReadData(filename, slen);
filename[slen] = 0;
char filename[256]{};
std::snprintf(filename, sizeof filename, "./single/%s", cur_replay.script_name.c_str());
if(!preload_script(pduel, filename)) {
return false;
}
}
if (!(rh.flag & REPLAY_UNIFORM))
opt |= DUEL_OLD_REPLAY;
start_duel(pduel, opt);
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag);
return true;
}
void ReplayMode::EndDuel() {
......
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