Commit 3a597afc authored by edo9300's avatar edo9300

New replay system

parent 6880af21
......@@ -121,6 +121,27 @@ public:
return ret;
return 0;
}
struct ReplayPacket {
int message;
int length;
unsigned char data[0x2000];
ReplayPacket() {}
ReplayPacket(char * buf, int len) {
message = ReadInt8(buf);
length = len;
memcpy(data, buf, length);
}
ReplayPacket(int msg, char * buf, int len) {
message = msg;
length = len;
memcpy(data, buf, length);
}
void Set(int msg, char * buf, int len) {
message = msg;
length = len;
memcpy(data, buf, length);
}
};
};
#endif //BUFFERIO_H
......@@ -53,7 +53,8 @@ ClientCard::ClientCard() {
void ClientCard::SetCode(int code) {
if((location == LOCATION_HAND) && (this->code != (unsigned int)code)) {
this->code = code;
mainGame->dField.MoveCard(this, 5);
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->dField.MoveCard(this, 5);
} else
this->code = code;
}
......@@ -66,7 +67,8 @@ void ClientCard::UpdateInfo(char* buf) {
pdata = BufferIO::ReadInt32(buf);
if((location == LOCATION_HAND) && ((unsigned int)pdata != code)) {
code = pdata;
mainGame->dField.MoveCard(this, 5);
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->dField.MoveCard(this, 5);
} else
code = pdata;
}
......
......@@ -26,6 +26,10 @@ u64 DuelClient::select_hint = 0;
wchar_t DuelClient::event_string[256];
mtrandom DuelClient::rnd;
std::vector<BufferIO::ReplayPacket> DuelClient::replay_stream;
Replay DuelClient::last_replay;
bool DuelClient::old_replay = true;
bool DuelClient::is_refreshing = false;
int DuelClient::match_kill = 0;
std::vector<HostPacket> DuelClient::hosts;
......@@ -693,43 +697,7 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->btnSideReload->setVisible(false);
mainGame->wChat->setVisible(true);
mainGame->device->setEventReceiver(&mainGame->dField);
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval & 0x1) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
mainGame->SetPhaseButtons();
if(!mainGame->dInfo.isTag) {
if(selftype > 1) {
mainGame->dInfo.player_type = 7;
......@@ -767,6 +735,7 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
}
mainGame->gMutex.Unlock();
match_kill = 0;
replay_stream.clear();
break;
}
case STOC_DUEL_END: {
......@@ -823,16 +792,28 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->gMutex.Unlock();
mainGame->replaySignal.Reset();
mainGame->replaySignal.Wait();
if(mainGame->actionParam || !is_host) {
if(mainGame->saveReplay || !is_host) {
char* prep = pdata;
Replay new_replay;
memcpy(&new_replay.pheader, prep, sizeof(ReplayHeader));
prep += sizeof(ReplayHeader);
memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1;
if(mainGame->actionParam)
new_replay.SaveReplay(mainGame->ebRSName->getText());
else new_replay.SaveReplay(L"_LastReplay");
ReplayHeader pheader;
memcpy(&pheader, prep, sizeof(ReplayHeader));
replay_stream.push_back(BufferIO::ReplayPacket(OLD_REPLAY_SYSTEM, prep, len - 1));
if(old_replay && mainGame->saveReplay) {
last_replay.BeginRecord();
last_replay.WriteHeader(pheader);
last_replay.pheader.id = 0x58707279;
last_replay.WriteData(mainGame->dInfo.hostname, 40, false);
last_replay.WriteData(mainGame->dInfo.clientname, 40, false);
if (last_replay.pheader.flag & REPLAY_TAG) {
last_replay.WriteData(mainGame->dInfo.hostname_tag, 40, false);
last_replay.WriteData(mainGame->dInfo.clientname_tag, 40, false);
}
last_replay.WriteInt32(mainGame->dInfo.duel_field | mainGame->dInfo.extraval);
last_replay.WriteStream(replay_stream);
last_replay.EndRecord();
}
if (mainGame->saveReplay)
last_replay.SaveReplay(mainGame->ebRSName->getText());
else last_replay.SaveReplay(L"_LastReplay");
}
break;
}
......@@ -975,12 +956,30 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->gMutex.Unlock();
break;
}
case STOC_NEW_REPLAY: {
char* prep = pdata;
memcpy(&last_replay.pheader, prep, sizeof(ReplayHeader));
prep += sizeof(ReplayHeader);
memcpy(last_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
last_replay.comp_size = len - sizeof(ReplayHeader) - 1;
old_replay = false;
break;
}
}
}
int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
char* pbuf = msg;
wchar_t textBuffer[256];
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
if(!mainGame->dInfo.isReplay) {
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
if(mainGame->dInfo.curMsg != MSG_WAITING) {
BufferIO::ReplayPacket p;
p.message = mainGame->dInfo.curMsg;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
replay_stream.push_back(p);
}
}
mainGame->wCmdMenu->setVisible(false);
if(!mainGame->dInfo.isReplay && mainGame->dInfo.curMsg != MSG_WAITING && mainGame->dInfo.curMsg != MSG_CARD_SELECTED) {
mainGame->waitFrame = -1;
......@@ -1164,15 +1163,17 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
return true;
}
case MSG_START: {
mainGame->showcardcode = 11;
mainGame->showcarddif = 30;
mainGame->showcardp = 0;
mainGame->showcard = 101;
mainGame->WaitFrameSignal(40);
mainGame->showcard = 0;
mainGame->gMutex.Lock();
int playertype = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.isFirst = (playertype & 0xf) ? false : true;
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping) {
mainGame->showcardcode = 11;
mainGame->showcarddif = 30;
mainGame->showcardp = 0;
mainGame->showcard = 101;
mainGame->WaitFrameSignal(40);
mainGame->showcard = 0;
mainGame->gMutex.Lock();
mainGame->dInfo.isFirst = (playertype & 0xf) ? false : true;
}
if(playertype & 0xf0)
mainGame->dInfo.player_type = 7;
if(mainGame->dInfo.isTag) {
......@@ -1197,24 +1198,29 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->dField.Initial(mainGame->LocalPlayer(1), deckc, extrac);
mainGame->dInfo.turn = 0;
mainGame->dInfo.is_shuffling = false;
mainGame->gMutex.Unlock();
if (!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
return true;
}
case MSG_UPDATE_DATA: {
int player = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int location = BufferIO::ReadInt8(pbuf);
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.UpdateFieldCard(player, location, pbuf);
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
return true;
}
case MSG_UPDATE_CARD: {
int player = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int loc = BufferIO::ReadInt8(pbuf);
int seq = BufferIO::ReadInt8(pbuf);
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.UpdateCard(player, loc, seq, pbuf);
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
break;
}
case MSG_SELECT_BATTLECMD: {
......@@ -3728,11 +3734,13 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
break;
}
case MSG_RELOAD_FIELD: {
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.Clear();
int field = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.duel_field = field & 0xf;
mainGame->dInfo.extraval = field >> 4;
mainGame->SetPhaseButtons();
int val = 0;
for(int i = 0; i < 2; ++i) {
int p = mainGame->LocalPlayer(i);
......@@ -3847,7 +3855,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
myswprintf(event_string, dataManager.GetSysString(1609), dataManager.GetName(mainGame->dField.current_chain.code));
mainGame->dField.last_chain = true;
}
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
break;
}
}
......@@ -3913,10 +3922,11 @@ void DuelClient::SendResponse() {
break;
}
}
replay_stream.pop_back();
if(mainGame->dInfo.isSingleMode) {
SingleMode::SetResponse(response_buf, response_len);
mainGame->singleSignal.Set();
} else {
} else if (!mainGame->dInfo.isReplay) {
mainGame->dInfo.time_player = 2;
SendBufferToServer(CTOS_RESPONSE, response_buf, response_len);
}
......
......@@ -13,6 +13,7 @@
#include "data_manager.h"
#include "deck_manager.h"
#include "../ocgcore/mtrandom.h"
#include "replay.h"
namespace ygo {
......@@ -45,6 +46,9 @@ public:
static void ClientEvent(bufferevent *bev, short events, void *ctx);
static int ClientThread(void* param);
static void HandleSTOCPacketLan(char* data, unsigned int len);
static std::vector<BufferIO::ReplayPacket> replay_stream;
static Replay last_replay;
static bool old_replay;
static int ClientAnalyze(char* msg, unsigned int len);
static void SetResponseI(int respI);
static void SetResponseB(void* respB, unsigned char len);
......
......@@ -95,13 +95,13 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case BUTTON_REPLAY_SAVE: {
if(mainGame->ebRSName->getText()[0] == 0)
break;
mainGame->actionParam = 1;
mainGame->saveReplay = 1;
mainGame->HideElement(mainGame->wReplaySave);
mainGame->replaySignal.Set();
break;
}
case BUTTON_REPLAY_CANCEL: {
mainGame->actionParam = 0;
mainGame->saveReplay = 0;
mainGame->HideElement(mainGame->wReplaySave);
mainGame->replaySignal.Set();
break;
......
......@@ -1228,7 +1228,7 @@ bool Game::PlayChant(unsigned int code) {
return false;
}
void Game::PlaySoundEffect(char* sound) {
if(chkEnableSound->isChecked()) {
if(chkEnableSound->isChecked() && (!dInfo.isReplay || !dInfo.isReplaySkiping)) {
engineSound->play2D(sound);
engineSound->setSoundVolume(gameConf.volume);
}
......@@ -1563,8 +1563,46 @@ int Game::GetMasterRule(uint32 param, uint32 forbiddentypes, int* truerule) {
}
}
}
void Game::OnResize()
{
void Game::SetPhaseButtons() {
// reset master rule 4 phase button position
wPhase->setRelativePosition(Resize(480, 310, 855, 330));
if (dInfo.extraval & 0x1) {
if (dInfo.duel_field >= 4) {
wPhase->setRelativePosition(Resize(480, 290, 855, 350));
btnShuffle->setRelativePosition(Resize(0, 40, 50, 60));
btnDP->setRelativePosition(Resize(0, 40, 50, 60));
btnSP->setRelativePosition(Resize(0, 40, 50, 60));
btnM1->setRelativePosition(Resize(160, 20, 210, 40));
btnBP->setRelativePosition(Resize(160, 20, 210, 40));
btnM2->setRelativePosition(Resize(160, 20, 210, 40));
btnEP->setRelativePosition(Resize(310, 0, 360, 20));
} else {
btnShuffle->setRelativePosition(Resize(65, 0, 115, 20));
btnDP->setRelativePosition(Resize(65, 0, 115, 20));
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
btnEP->setRelativePosition(Resize(260, 0, 310, 20));
}
} else {
btnDP->setRelativePosition(Resize(0, 0, 50, 20));
if (dInfo.duel_field >= 4) {
btnSP->setRelativePosition(Resize(0, 0, 50, 20));
btnM1->setRelativePosition(Resize(160, 0, 210, 20));
btnBP->setRelativePosition(Resize(160, 0, 210, 20));
btnM2->setRelativePosition(Resize(160, 0, 210, 20));
} else {
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
}
btnEP->setRelativePosition(Resize(320, 0, 370, 20));
btnShuffle->setRelativePosition(Resize(0, 0, 50, 20));
}
}
void Game::OnResize() {
wMainMenu->setRelativePosition(ResizeWin(370, 200, 650, 415));
wDeckEdit->setRelativePosition(Resize(309, 8, 605, 130));
cbDBLFList->setRelativePosition(Resize(80, 5, 220, 30));
......@@ -1662,42 +1700,7 @@ void Game::OnResize()
btnReplaySwap->setRelativePosition(Resize(5, 30, 85, 50));
btnReplayExit->setRelativePosition(Resize(5, 105, 85, 125));
wPhase->setRelativePosition(Resize(480, 310, 855, 330));
if(dInfo.extraval & 0x1) {
if(dInfo.duel_field >= 4) {
wPhase->setRelativePosition(Resize(480, 290, 855, 350));
btnShuffle->setRelativePosition(Resize(0, 40, 50, 60));
btnDP->setRelativePosition(Resize(0, 40, 50, 60));
btnSP->setRelativePosition(Resize(0, 40, 50, 60));
btnM1->setRelativePosition(Resize(160, 20, 210, 40));
btnBP->setRelativePosition(Resize(160, 20, 210, 40));
btnM2->setRelativePosition(Resize(160, 20, 210, 40));
btnEP->setRelativePosition(Resize(310, 0, 360, 20));
} else {
btnShuffle->setRelativePosition(Resize(65, 0, 115, 20));
btnDP->setRelativePosition(Resize(65, 0, 115, 20));
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
btnEP->setRelativePosition(Resize(260, 0, 310, 20));
}
} else {
btnDP->setRelativePosition(Resize(0, 0, 50, 20));
if(dInfo.duel_field >= 4) {
btnSP->setRelativePosition(Resize(0, 0, 50, 20));
btnM1->setRelativePosition(Resize(160, 0, 210, 20));
btnBP->setRelativePosition(Resize(160, 0, 210, 20));
btnM2->setRelativePosition(Resize(160, 0, 210, 20));
} else {
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
}
btnEP->setRelativePosition(Resize(320, 0, 370, 20));
btnShuffle->setRelativePosition(Resize(0, 0, 50, 20));
}
SetPhaseButtons();
btnSpectatorSwap->setRelativePosition(Resize(205, 100, 295, 135));
btnChainAlways->setRelativePosition(Resize(205, 140, 295, 175));
btnChainIgnore->setRelativePosition(Resize(205, 100, 295, 135));
......
......@@ -134,6 +134,7 @@ public:
const wchar_t* LocalName(int local_player);
void UpdateDuelParam();
int GetMasterRule(uint32 param, uint32 forbidden, int* truerule = 0);
void SetPhaseButtons();
bool HasFocus(EGUI_ELEMENT_TYPE type) const {
irr::gui::IGUIElement* focus = env->getFocus();
......@@ -170,7 +171,7 @@ public:
unsigned short linePattern;
int waitFrame;
int signalFrame;
int actionParam;
int saveReplay;
const wchar_t* showingtext;
int showcard;
int showcardcode;
......
......@@ -215,6 +215,9 @@ public:
#define STOC_HS_PLAYER_CHANGE 0x21
#define STOC_HS_WATCH_CHANGE 0x22
#define STOC_NEW_REPLAY 0x30
#define PLAYERCHANGE_OBSERVE 0x8
#define PLAYERCHANGE_READY 0x9
#define PLAYERCHANGE_NOTREADY 0xa
......
......@@ -33,6 +33,33 @@ void Replay::BeginRecord() {
pdata = replay_data;
is_recording = true;
}
void Replay::BeginRecord2() {
#ifdef _WIN32
if(is_recording)
CloseHandle(recording_fp);
recording_fp = CreateFileW(L"./replay/_LastReplay2.yrp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
if(recording_fp == INVALID_HANDLE_VALUE)
return;
#else
if(is_recording)
fclose(fp);
fp = fopen("./replay/_LastReplay2.yrp", "wb");
if(!fp)
return;
#endif
pdata = replay_data;
is_recording = true;
}
void Replay::WritePacket(BufferIO::ReplayPacket p) {
WriteInt8(p.message, false);
WriteInt32(p.length, false);
WriteData((char*)p.data, p.length);
}
void Replay::WriteStream(std::vector<BufferIO::ReplayPacket> stream) {
if(stream.size())
for(auto it = stream.begin(); it != stream.end(); it++)
WritePacket((*it));
}
void Replay::WriteHeader(ReplayHeader& header) {
pheader = header;
#ifdef _WIN32
......@@ -118,7 +145,7 @@ void Replay::EndRecord() {
pheader.datasize = pdata - replay_data;
pheader.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
comp_size = 0x1000;
comp_size = 0x20000;
LzmaCompress(comp_data, &comp_size, replay_data, pdata - replay_data, pheader.props, &propsize, 5, 1 << 24, 3, 0, 2, 32, 1);
is_recording = false;
}
......@@ -161,7 +188,7 @@ bool Replay::OpenReplay(const wchar_t* name) {
return false;
fread(&pheader, sizeof(pheader), 1, fp);
if(pheader.flag & REPLAY_COMPRESSED) {
comp_size = fread(comp_data, 1, 0x1000, fp);
comp_size = fread(comp_data, 1, 0x20000, fp);
fclose(fp);
replay_size = pheader.datasize;
if(LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
......@@ -190,7 +217,15 @@ bool Replay::CheckReplay(const wchar_t* name) {
ReplayHeader rheader;
fread(&rheader, sizeof(ReplayHeader), 1, rfp);
fclose(rfp);
return rheader.id == 0x31707279 && rheader.version >= 0x12d0;
return (rheader.id == 0x31707279 || rheader.id == 0x58707279) && rheader.version >= 0x12d0;
}
bool Replay::ReadNextPacket(BufferIO::ReplayPacket* packet) {
if (pdata - replay_data >= (int)replay_size)
return false;
packet->message = *pdata++;
packet->length = ReadInt32();
ReadData((char*)&packet->data, packet->length);
return true;
}
bool Replay::ReadNextResponse(unsigned char resp[64]) {
if(pdata - replay_data >= (int)replay_size)
......
......@@ -27,6 +27,9 @@ public:
Replay();
~Replay();
void BeginRecord();
void BeginRecord2();
void WriteStream(std::vector<BufferIO::ReplayPacket> stream);
void WritePacket(BufferIO::ReplayPacket p);
void WriteHeader(ReplayHeader& header);
void WriteData(const void* data, unsigned int length, bool flush = true);
void WriteInt32(int data, bool flush = true);
......@@ -37,6 +40,7 @@ public:
void SaveReplay(const wchar_t* name);
bool OpenReplay(const wchar_t* name);
static bool CheckReplay(const wchar_t* name);
bool ReadNextPacket(BufferIO::ReplayPacket* packet);
bool ReadNextResponse(unsigned char resp[64]);
void ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
......
......@@ -10,11 +10,12 @@ namespace ygo {
long ReplayMode::pduel = 0;
Replay ReplayMode::cur_replay;
std::vector<BufferIO::ReplayPacket> ReplayMode::current_stream;
bool ReplayMode::is_continuing = true;
bool ReplayMode::is_closing = false;
bool ReplayMode::is_pausing = false;
bool ReplayMode::is_paused = false;
bool ReplayMode::is_swaping = false;
bool ReplayMode::is_swapping = false;
bool ReplayMode::is_restarting = false;
bool ReplayMode::exit_pending = false;
int ReplayMode::skip_turn = 0;
......@@ -39,7 +40,7 @@ void ReplayMode::SwapField() {
if(is_paused)
mainGame->dField.ReplaySwap();
else
is_swaping = true;
is_swapping = true;
}
void ReplayMode::Pause(bool is_pause, bool is_step) {
if(is_pause)
......@@ -62,75 +63,56 @@ int ReplayMode::ReplayThread(void* param) {
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
mainGame->dInfo.isSingleMode = !!(rh.flag & REPLAY_SINGLE_MODE);
mainGame->dInfo.lua64 = !!(rh.flag & REPLAY_LUA64);
mainGame->dInfo.lua64 = true;
mainGame->dInfo.tag_player[0] = false;
mainGame->dInfo.tag_player[1] = false;
if(mainGame->dInfo.isSingleMode) {
set_script_reader((script_reader)SingleMode::ScriptReader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
} else {
set_script_reader(default_script_reader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
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);
}
else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
if(!StartDuel()) {
EndDuel();
return 0;
int opt = cur_replay.ReadInt32();
mainGame->dInfo.duel_field = opt & 0xff;
mainGame->dInfo.extraval = (opt >> 8);
mainGame->SetPhaseButtons();
BufferIO::ReplayPacket p;
current_stream.clear();
while (cur_replay.ReadNextPacket(&p)) {
current_stream.push_back(p);
}
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplay = true;
mainGame->dInfo.isReplaySkiping = (skip_turn > 0);
char engineBuffer[0x1000];
is_continuing = true;
skip_step = 0;
if(mainGame->dInfo.isSingleMode) {
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0)
is_continuing = ReplayAnalyze(engineBuffer, len);
} else {
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
ReplayRefreshExtra(0);
ReplayRefreshExtra(1);
}
exit_pending = false;
current_step = 0;
if(mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
while (is_continuing && !exit_pending) {
int result = process(pduel);
int len = result & 0xffff;
/*int flag = result >> 16;*/
if (len > 0) {
get_message(pduel, (byte*)engineBuffer);
is_continuing = ReplayAnalyze(engineBuffer, len);
if(is_restarting) {
is_restarting = false;
int step = current_step - 1;
if(step < 0)
step = 0;
if(mainGame->dInfo.isSingleMode) {
is_continuing = true;
skip_step = 0;
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0) {
mainGame->gMutex.Unlock();
is_continuing = ReplayAnalyze(engineBuffer, len);
mainGame->gMutex.Lock();
}
}
if(step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
skip_step = step;
current_step = 0;
for(auto it = current_stream.begin(); is_continuing && !exit_pending && it != current_stream.end();) {
is_continuing = ReplayAnalyze((*it));
if(is_restarting) {
it = current_stream.begin();
is_restarting = false;
int step = current_step - 1;
if (step < 0)
step = 0;
if (step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
}
skip_step = step;
current_step = 0;
} else
it++;
}
if(mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
......@@ -140,163 +122,7 @@ int ReplayMode::ReplayThread(void* param) {
EndDuel();
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
mtrandom rnd;
int seed = rh.seed;
rnd.reset(seed);
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);
} else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
pduel = create_duel(rnd.rand());
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;
int rule = opt >> 16; //backwards compatibility with master rule replays
if(rule)
switch (rule) {
case 1: {
opt |= MASTER_RULE_1;
break;
}
case 2: {
opt |= MASTER_RULE_2;
break;
}
case 3: {
opt |= MASTER_RULE_3;
break;
}
case 4: {
opt |= MASTER_RULE_4;
break;
}
}
//pre mr4 replay compatibility
if(opt & DUEL_OBSOLETE_RULING) {
opt &= ~DUEL_OBSOLETE_RULING;
opt |= MASTER_RULE_1;
} else if (!(opt & 0xff80))
opt |= MASTER_RULE_3;
mainGame->dInfo.duel_field = 2;
if ((opt & DUEL_PZONE) && (opt & DUEL_SEPARATE_PZONE) && (opt & DUEL_EMZONE))
mainGame->dInfo.duel_field = 5;
else if (opt & DUEL_EMZONE)
mainGame->dInfo.duel_field = 4;
else if(opt & DUEL_PZONE)
mainGame->dInfo.duel_field = 3;
mainGame->dInfo.extraval = !!(opt & SPEED_DUEL);
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
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.startlp = 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(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(1, main, extra);
} 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(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(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);
}
} else {
char filename[256];
size_t slen = cur_replay.ReadInt16();
cur_replay.ReadData(filename, slen);
filename[slen] = 0;
if(!preload_script(pduel, filename, slen)) {
return false;
}
}
start_duel(pduel, opt);
return true;
}
void ReplayMode::EndDuel() {
end_duel(pduel);
if(!is_closing) {
mainGame->actionSignal.Reset();
mainGame->gMutex.Lock();
......@@ -323,21 +149,13 @@ void ReplayMode::EndDuel() {
}
}
void ReplayMode::Restart(bool refresh) {
end_duel(pduel);
mainGame->dInfo.isStarted = false;
mainGame->dField.Clear();
//mainGame->device->setEventReceiver(&mainGame->dField);
cur_replay.Rewind();
//mainGame->dInfo.isFirst = true;
mainGame->dInfo.tag_player[0] = false;
mainGame->dInfo.tag_player[1] = false;
if(!StartDuel()) {
EndDuel();
}
if(refresh) {
mainGame->dField.RefreshAllCards();
mainGame->dInfo.isStarted = true;
//mainGame->dInfo.isReplay = true;
}
skip_turn = 0;
is_restarting = true;
......@@ -350,26 +168,21 @@ void ReplayMode::Undo() {
mainGame->gMutex.Lock();
Pause(false, false);
}
bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
char* pbuf = msg;
int player, count;
bool ReplayMode::ReplayAnalyze(BufferIO::ReplayPacket p) {
is_restarting = false;
while (pbuf - msg < (int)len) {
while(true) {
if(is_closing)
return false;
if(is_restarting) {
//is_restarting = false;
return true;
}
if(is_swaping) {
if(is_restarting)
break;
if(is_swapping) {
mainGame->gMutex.Lock();
mainGame->dField.ReplaySwap();
mainGame->gMutex.Unlock();
is_swaping = false;
is_swapping = false;
}
char* offset = pbuf;
bool pauseable = true;
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
mainGame->dInfo.curMsg = p.message;
switch (mainGame->dInfo.curMsg) {
case MSG_RETRY: {
if(mainGame->dInfo.isReplaySkiping) {
......@@ -385,188 +198,40 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
mainGame->actionSignal.Wait();
return false;
}
case MSG_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_WIN: {
if(mainGame->dInfo.isReplaySkiping) {
if (mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
DuelClient::ClientAnalyze((char*)p.data, p.length);
return false;
}
case MSG_SELECT_BATTLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8 + 2;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_IDLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11 + 3;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_EFFECTYN: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 16 : 12;
return ReadReplayResponse();
}
case MSG_SELECT_YESNO: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_OPTION: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_CARD:
case MSG_SELECT_TRIBUTE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 3;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_UNSELECT_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += 10 + count * (mainGame->dInfo.lua64) ? 17 : 13;
return ReadReplayResponse();
}
case MSG_SELECT_PLACE:
case MSG_SELECT_DISFIELD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_POSITION: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_COUNTER: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 9;
return ReadReplayResponse();
}
case MSG_SELECT_SUM: {
pbuf++;
player = BufferIO::ReadInt8(pbuf);
pbuf += 6;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
return ReadReplayResponse();
}
case MSG_SORT_CARD:
case MSG_SORT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
return ReadReplayResponse();
}
case MSG_CONFIRM_DECKTOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_EXTRATOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_EXTRA: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REFRESH_DECK: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SWAP_GRAVE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshGrave(player);
break;
}
case MSG_REVERSE_DECK: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
pbuf += 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_SET_CARD: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
case MSG_START:
case MSG_UPDATE_DATA:
case MSG_UPDATE_CARD:
case MSG_SET:
case MSG_SWAP:
case MSG_FIELD_DISABLED:
case MSG_SUMMONING:
case MSG_SPSUMMONING:
case MSG_FLIPSUMMONING:
case MSG_CHAIN_SOLVING:
case MSG_CHAIN_SOLVED:
case MSG_CHAIN_END:
case MSG_CARD_SELECTED:
case MSG_RANDOM_SELECTED:
case MSG_EQUIP:
case MSG_UNEQUIP:
case MSG_CARD_TARGET:
case MSG_CANCEL_TARGET:
case MSG_BATTLE:
case MSG_ATTACK_DISABLED:
case MSG_DAMAGE_STEP_START:
case MSG_DAMAGE_STEP_END:
case MSG_TAG_SWAP:
case MSG_RELOAD_FIELD: {
pauseable = false;
break;
}
case MSG_NEW_TURN: {
......@@ -578,335 +243,12 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
mainGame->gMutex.Unlock();
}
}
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_NEW_PHASE: {
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_MOVE: {
int pc = pbuf[4];
int pl = pbuf[5];
/*int ps = pbuf[6];*/
/*int pp = pbuf[7];*/
int cc = pbuf[8];
int cl = pbuf[9];
int cs = pbuf[10];
/*int cp = pbuf[11];*/
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
if(cl && !(cl & 0x80) && (pl != cl || pc != cc))
ReplayRefreshSingle(cc, cl, cs);
break;
}
case MSG_POS_CHANGE: {
pbuf += 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SWAP: {
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_FIELD_DISABLED: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_SPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
case OLD_REPLAY_MODE:
break;
}
case MSG_SPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_FLIPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_FLIPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAINING: {
pbuf += (mainGame->dInfo.lua64) ? 20 : 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAINED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAIN_SOLVING: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CHAIN_SOLVED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_NEGATED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAIN_DISABLED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CARD_SELECTED:
case MSG_RANDOM_SELECTED: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_BECOME_TARGET: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DRAW: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DAMAGE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_RECOVER: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_EQUIP: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_LPUPDATE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_UNEQUIP: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CARD_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CANCEL_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_PAY_LPCOST: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ADD_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REMOVE_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ATTACK: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_BATTLE: {
pbuf += 26;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_ATTACK_DISABLED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_START: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_MISSED_EFFECT: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_COIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_DICE: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ROCK_PAPER_SCISSORS: {
player = BufferIO::ReadInt8(pbuf);
return ReadReplayResponse();
}
case MSG_HAND_RES: {
pbuf += 1;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ANNOUNCE_RACE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_ATTRIB: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4 * count;
return ReadReplayResponse();
}
case MSG_CARD_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 13 : 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_PLAYER_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_MATCH_KILL: {
pbuf += 4;
break;
}
case MSG_TAG_SWAP: {
player = pbuf[0];
pbuf += pbuf[2] * 4 + pbuf[4] * 4 + 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
ReplayRefreshExtra(player);
break;
}
case MSG_RELOAD_FIELD: {
pbuf++;
for(int p = 0; p < 2; ++p) {
pbuf += 4;
for(int seq = 0; seq < 7; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if(val)
pbuf += 2;
}
for(int seq = 0; seq < 8; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if(val)
pbuf++;
}
pbuf += 6;
}
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayReload();
mainGame->dField.RefreshAllCards();
break;
}
case MSG_AI_NAME: {
int len = BufferIO::ReadInt16(pbuf);
pbuf += len + 1;
break;
}
case MSG_SHOW_HINT: {
int len = BufferIO::ReadInt16(pbuf);
pbuf += len + 1;
break;
}
}
DuelClient::ClientAnalyze((char*)p.data, p.length);
if(pauseable) {
current_step++;
if(skip_step) {
......@@ -926,88 +268,9 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
is_paused = false;
}
}
break;
}
return true;
}
void ReplayMode::ReplayRefresh(int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshHand(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshGrave(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_GRAVE, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshDeck(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_DECK, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshExtra(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_EXTRA, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshSingle(int player, int location, int sequence, int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
mainGame->dField.UpdateCard(mainGame->LocalPlayer(player), location, sequence, (char*)queryBuffer);
}
void ReplayMode::ReplayReload() {
unsigned char queryBuffer[0x4000];
unsigned int flag = 0xffdfff;
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_REMOVED, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_REMOVED, (char*)queryBuffer);
}
int ReplayMode::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
char msgbuf[1024];
get_log_message(fduel, (byte*)msgbuf);
mainGame->AddDebugMsg(msgbuf);
return 0;
}
}
......@@ -16,8 +16,9 @@ private:
static bool is_closing;
static bool is_pausing;
static bool is_paused;
static bool is_swaping;
static bool is_swapping;
static bool is_restarting;
static bool undo;
static bool exit_pending;
static int skip_turn;
static int current_step;
......@@ -25,6 +26,7 @@ private:
public:
static Replay cur_replay;
static std::vector<BufferIO::ReplayPacket> ReplayMode::current_stream;
public:
static bool StartReplay(int skipturn);
......@@ -37,17 +39,7 @@ public:
static void EndDuel();
static void Restart(bool refresh);
static void Undo();
static bool ReplayAnalyze(char* msg, unsigned int len);
static void ReplayRefresh(int flag = 0xf81fff);
static void ReplayRefreshHand(int player, int flag = 0x781fff);
static void ReplayRefreshGrave(int player, int flag = 0x181fff);
static void ReplayRefreshDeck(int player, int flag = 0x181fff);
static void ReplayRefreshExtra(int player, int flag = 0x181fff);
static void ReplayRefreshSingle(int player, int location, int sequence, int flag = 0xf81fff);
static void ReplayReload();
static int MessageHandler(long fduel, int type);
static bool ReplayAnalyze(BufferIO::ReplayPacket p);
};
}
......
......@@ -9,6 +9,8 @@
namespace ygo {
std::vector<BufferIO::ReplayPacket> SingleDuel::replay_stream;
SingleDuel::SingleDuel(bool is_match) {
game_started = false;
match_mode = is_match;
......@@ -185,6 +187,8 @@ void SingleDuel::LeaveGame(DuelPlayer* dp) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
BufferIO::ReplayPacket p((char*)wbuf, 3);
replay_stream.push_back(p);
EndDuel();
NetServer::SendPacketToPlayer(players[0], STOC_DUEL_END);
NetServer::ReSendToPlayer(players[1]);
......@@ -401,6 +405,13 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
rnd.reset(seed);
last_replay.WriteData(players[0]->name, 40, false);
last_replay.WriteData(players[1]->name, 40, false);
//records the replay with the new system
new_replay.BeginRecord2();
rh.id = 0x58707279;
new_replay.WriteHeader(rh);
new_replay.WriteData(players[0]->name, 40, false);
new_replay.WriteData(players[1]->name, 40);
replay_stream.clear();
if(!host_info.no_shuffle_deck) {
for(size_t i = pdeck[0].main.size() - 1; i > 0; --i) {
int swap = rnd.real() * (i + 1);
......@@ -425,6 +436,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
opt |= DUEL_PSEUDO_SHUFFLE;
if(host_info.speed)
opt |= SPEED_DUEL;
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
last_replay.WriteInt32(host_info.start_lp, false);
last_replay.WriteInt32(host_info.start_hand, false);
last_replay.WriteInt32(host_info.draw_count, false);
......@@ -516,8 +528,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
else startbuf[1] = 0x11;
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::SendBufferToPlayer(*oit, STOC_GAME_MSG, startbuf, 18);
startbuf[1] = 0;
BufferIO::ReplayPacket p((char*)startbuf, 17);
replay_stream.push_back(p);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
RefreshExtra(0);
RefreshExtra(1);
new_replay.WriteStream(replay_stream);
start_duel(pduel, opt);
Process();
}
......@@ -592,6 +610,8 @@ void SingleDuel::Surrender(DuelPlayer* dp) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
BufferIO::ReplayPacket p((char*)wbuf, 3);
replay_stream.push_back(p);
if(players[player] == pplayer[player]) {
match_result[duel_count++] = 1 - player;
tp_player = player;
......@@ -607,12 +627,19 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
char* offset, *pbufw, *pbuf = msgbuffer;
int player, count, type;
while (pbuf - msgbuffer < (int)len) {
replay_stream.clear();
bool record = true;
BufferIO::ReplayPacket p;
offset = pbuf;
unsigned char engType = BufferIO::ReadUInt8(pbuf);
p.message = engType;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (engType) {
case MSG_RETRY: {
WaitforResponse(last_response);
NetServer::SendBufferToPlayer(players[last_response], STOC_GAME_MSG, offset, pbuf - offset);
replay_stream.push_back(p);
return 1;
}
case MSG_HINT: {
......@@ -625,6 +652,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
case 3:
case 5: {
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset);
record = false;
break;
}
case 4:
......@@ -664,6 +692,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
match_result[duel_count++] = 1 - player;
tp_player = player;
}
replay_stream.push_back(p);
EndDuel();
return 2;
}
......@@ -870,6 +899,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
......@@ -918,6 +948,8 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
......@@ -1430,6 +1462,12 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return 0;
}
......@@ -1456,6 +1494,23 @@ void SingleDuel::EndDuel() {
memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
replay_stream.push_back(BufferIO::ReplayPacket(OLD_REPLAY_SYSTEM, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size));
//in case of remaining packets, e.g. MSG_WIN
new_replay.WriteStream(replay_stream);
new_replay.EndRecord();
char nreplaybuf[0x2000], *npbuf = nreplaybuf;
memcpy(npbuf, &new_replay.pheader, sizeof(ReplayHeader));
npbuf += sizeof(ReplayHeader);
memcpy(npbuf, new_replay.comp_data, new_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_NEW_REPLAY, nreplaybuf, sizeof(ReplayHeader) + new_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for (auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
......@@ -1495,8 +1550,10 @@ void SingleDuel::RefreshMzone(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
int len = query_field_card(pduel, player, LOCATION_MZONE, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
while (qlen < len) {
int clen = BufferIO::ReadInt32(qbuf);
qlen += clen;
if (clen == 4)
......@@ -1517,8 +1574,10 @@ void SingleDuel::RefreshSzone(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
int len = query_field_card(pduel, player, LOCATION_SZONE, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
while (qlen < len) {
int clen = BufferIO::ReadInt32(qbuf);
qlen += clen;
if (clen == 4)
......@@ -1556,6 +1615,8 @@ void SingleDuel::RefreshHand(int player, int flag, int use_cache) {
NetServer::SendBufferToPlayer(players[1 - player], STOC_GAME_MSG, query_buffer, len + 3);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshGrave(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1568,6 +1629,8 @@ void SingleDuel::RefreshGrave(int player, int flag, int use_cache) {
NetServer::ReSendToPlayer(players[1]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshExtra(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1577,6 +1640,8 @@ void SingleDuel::RefreshExtra(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
int len = query_field_card(pduel, player, LOCATION_EXTRA, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag) {
char query_buffer[0x2000];
......@@ -1587,6 +1652,8 @@ void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag)
BufferIO::WriteInt8(qbuf, sequence);
int len = query_card(pduel, player, location, sequence, flag, (unsigned char*)qbuf, 0);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 4);
BufferIO::ReplayPacket p((char*)query_buffer, len + 3);
replay_stream.push_back(p);
if(location == LOCATION_REMOVED && (qbuf[15] & POS_FACEDOWN))
return;
if ((location & 0x90) || ((location & 0x2c) && (qbuf[15] & POS_FACEUP))) {
......@@ -1595,6 +1662,16 @@ void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag)
NetServer::ReSendToPlayer(*pit);
}
}
void SingleDuel::PseudoRefreshDeck(int player, int flag) {
char query_buffer[0x2000];
char* qbuf = query_buffer;
BufferIO::WriteInt8(qbuf, MSG_UPDATE_DATA);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
int len = query_field_card(pduel, player, LOCATION_DECK, flag, (unsigned char*)qbuf, 0);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
int SingleDuel::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
......@@ -1616,6 +1693,8 @@ void SingleDuel::SingleTimer(evutil_socket_t fd, short events, void* arg) {
NetServer::ReSendToPlayer(sd->players[1]);
for(auto oit = sd->observers.begin(); oit != sd->observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
BufferIO::ReplayPacket p((char*)wbuf, 3);
sd->replay_stream.push_back(p);
if(sd->players[player] == sd->pplayer[player]) {
sd->match_result[sd->duel_count++] = 1 - player;
sd->tp_player = player;
......
......@@ -40,6 +40,9 @@ public:
static int MessageHandler(long fduel, int type);
static void SingleTimer(evutil_socket_t fd, short events, void* arg);
void PseudoRefreshDeck(int player, int flag = 0x181fff);
static std::vector<BufferIO::ReplayPacket> replay_stream;
protected:
DuelPlayer* players[2];
......@@ -51,6 +54,7 @@ protected:
unsigned char last_response;
std::set<DuelPlayer*> observers;
Replay last_replay;
Replay new_replay;
bool match_mode;
int match_kill;
bool game_started;
......
......@@ -11,6 +11,8 @@ long SingleMode::pduel = 0;
bool SingleMode::is_closing = false;
bool SingleMode::is_continuing = false;
Replay SingleMode::last_replay;
Replay SingleMode::new_replay;
std::vector<BufferIO::ReplayPacket> SingleMode::replay_stream;
static byte buffer[0x20000];
......@@ -106,16 +108,20 @@ int SingleMode::SinglePlayThread(void* param) {
char engineBuffer[0x1000];
is_closing = false;
is_continuing = true;
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0)
is_continuing = SinglePlayAnalyze(engineBuffer, len);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
//records the replay with the new system
new_replay.BeginRecord2();
rh.id = 0x58707279;
new_replay.WriteHeader(rh);
replay_stream.clear();
unsigned short buffer[20];
BufferIO::CopyWStr(mainGame->dInfo.hostname, buffer, 20);
last_replay.WriteData(buffer, 40, false);
new_replay.WriteData(buffer, 40, false);
BufferIO::CopyWStr(mainGame->dInfo.clientname, buffer, 20);
last_replay.WriteData(buffer, 40, false);
new_replay.WriteData(buffer, 40, false);
last_replay.WriteInt32(start_lp, false);
last_replay.WriteInt32(start_hand, false);
last_replay.WriteInt32(draw_count, false);
......@@ -123,6 +129,11 @@ int SingleMode::SinglePlayThread(void* param) {
last_replay.WriteInt16(slen, false);
last_replay.WriteData(filename, slen, false);
last_replay.Flush();
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0){
is_continuing = SinglePlayAnalyze(engineBuffer, len);
}
start_duel(pduel, opt);
while (is_continuing) {
int result = process(pduel);
......@@ -134,6 +145,7 @@ int SingleMode::SinglePlayThread(void* param) {
}
}
last_replay.EndRecord();
new_replay.EndRecord();
time_t nowtime = time(NULL);
struct tm *localedtime = localtime(&nowtime);
char timebuf[40];
......@@ -146,8 +158,8 @@ int SingleMode::SinglePlayThread(void* param) {
mainGame->gMutex.Unlock();
mainGame->replaySignal.Reset();
mainGame->replaySignal.Wait();
if(mainGame->actionParam)
last_replay.SaveReplay(mainGame->ebRSName->getText());
if(mainGame->saveReplay)
new_replay.SaveReplay(mainGame->ebRSName->getText());
end_duel(pduel);
if(!is_closing) {
mainGame->gMutex.Lock();
......@@ -171,10 +183,16 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
char* offset, *pbuf = msg;
int player, count;
while (pbuf - msg < (int)len) {
replay_stream.clear();
bool record = true;
if(is_closing || !is_continuing)
return false;
offset = pbuf;
BufferIO::ReplayPacket p;
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
p.message = mainGame->dInfo.curMsg;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (mainGame->dInfo.curMsg) {
case MSG_RETRY: {
mainGame->gMutex.Lock();
......@@ -186,16 +204,19 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
return false;
}
case MSG_HINT: {
/*int type = */BufferIO::ReadInt8(pbuf);
int type = BufferIO::ReadInt8(pbuf);
int player = BufferIO::ReadInt8(pbuf);
/*int data = */BufferIO::ReadInt64(pbuf);
if(player == 0)
DuelClient::ClientAnalyze(offset, pbuf - offset);
if (type > 0 && type < 6 && type != 4)
record = false;
break;
}
case MSG_WIN: {
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
replay_stream.push_back(p);
return false;
}
case MSG_SELECT_BATTLECMD: {
......@@ -209,6 +230,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_IDLECMD: {
......@@ -230,6 +252,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_EFFECTYN: {
......@@ -240,6 +263,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_YESNO: {
......@@ -249,6 +273,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_OPTION: {
......@@ -259,6 +284,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_CARD:
......@@ -271,6 +297,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_UNSELECT_CARD: {
......@@ -284,6 +311,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_CHAIN: {
......@@ -294,6 +322,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_PLACE:
......@@ -304,6 +333,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_POSITION: {
......@@ -313,6 +343,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_COUNTER: {
......@@ -324,6 +355,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_SUM: {
......@@ -338,6 +370,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SORT_CARD:
......@@ -349,6 +382,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_CONFIRM_DECKTOP: {
......@@ -655,6 +689,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_HAND_RES: {
......@@ -669,6 +704,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_ATTRIB: {
......@@ -678,6 +714,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_CARD: {
......@@ -687,6 +724,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_NUMBER:
......@@ -698,6 +736,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_CARD_HINT: {
......@@ -728,43 +767,6 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
int rule = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.duel_field = rule & 0xf;
mainGame->dInfo.extraval = rule >> 4;
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
int val = 0;
for(int p = 0; p < 2; ++p) {
mainGame->dInfo.lp[p] = BufferIO::ReadInt32(pbuf);
......@@ -839,6 +841,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
memcpy(namebuf, begin, len + 1);
BufferIO::DecodeUTF8(namebuf, wname);
BufferIO::CopyWStr(wname, mainGame->dInfo.clientname, 20);
record = false;
break;
}
case MSG_SHOW_HINT: {
......@@ -858,80 +861,282 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return is_continuing;
}
void SingleMode::SinglePlayRefresh(int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
BufferIO::ReplayPacket p;
int len = query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefreshHand(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_HAND, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
memcpy(qbuf, (char*)queryBuffer, len);
BufferIO::ReplayPacket p(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefreshGrave(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_GRAVE, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_GRAVE);
memcpy(qbuf, (char*)queryBuffer, len);
BufferIO::ReplayPacket p(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefreshDeck(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_DECK, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
memcpy(qbuf, (char*)queryBuffer, len);
BufferIO::ReplayPacket p(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefreshExtra(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_EXTRA, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
memcpy(qbuf, (char*)queryBuffer, len);
BufferIO::ReplayPacket p(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefreshSingle(int player, int location, int sequence, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
mainGame->dField.UpdateCard(mainGame->LocalPlayer(player), location, sequence, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, location);
BufferIO::WriteInt8(qbuf, sequence);
memcpy(qbuf, (char*)queryBuffer, len);
BufferIO::ReplayPacket p(MSG_UPDATE_CARD, queryBuffer2, len + 3);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayReload() {
unsigned char queryBuffer[0x2000];
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
unsigned int flag = 0xffdfff;
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
BufferIO::ReplayPacket p;
int len = query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_GRAVE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_GRAVE);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_REMOVED, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
BufferIO::WriteInt8(qbuf, 0);
BufferIO::WriteInt8(qbuf, LOCATION_REMOVED);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
qbuf = queryBuffer2;
len = query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_REMOVED, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, 1);
BufferIO::WriteInt8(qbuf, LOCATION_REMOVED);
memcpy(qbuf, (char*)queryBuffer, len);
p.Set(MSG_UPDATE_DATA, queryBuffer2, len + 2);
replay_stream.push_back(p);
}
byte* SingleMode::ScriptReader(const char* script_name, int* slen) {
FILE *fp;
......@@ -960,4 +1165,4 @@ int SingleMode::MessageHandler(long fduel, int type) {
return 0;
}
}
}
\ No newline at end of file
......@@ -31,6 +31,8 @@ public:
protected:
static Replay last_replay;
static Replay new_replay;
static std::vector<BufferIO::ReplayPacket> replay_stream;
};
}
......
......@@ -9,6 +9,8 @@
namespace ygo {
std::vector<BufferIO::ReplayPacket> TagDuel::replay_stream;
TagDuel::TagDuel() {
game_started = false;
for(int i = 0; i < 4; ++i) {
......@@ -362,6 +364,15 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
last_replay.WriteData(players[1]->name, 40, false);
last_replay.WriteData(players[2]->name, 40, false);
last_replay.WriteData(players[3]->name, 40, false);
//records the replay with the new system
new_replay.BeginRecord2();
rh.id = 0x58707279;
new_replay.WriteHeader(rh);
new_replay.WriteData(players[0]->name, 40, false);
new_replay.WriteData(players[1]->name, 40, false);
new_replay.WriteData(players[2]->name, 40, false);
new_replay.WriteData(players[3]->name, 40);
replay_stream.clear();
if(!host_info.no_shuffle_deck) {
for(size_t i = pdeck[0].main.size() - 1; i > 0; --i) {
int swap = rnd.real() * (i + 1);
......@@ -395,6 +406,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
if(host_info.speed)
opt |= SPEED_DUEL;
opt |= DUEL_TAG_MODE;
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
last_replay.WriteInt32(host_info.start_lp, false);
last_replay.WriteInt32(host_info.start_hand, false);
last_replay.WriteInt32(host_info.draw_count, false);
......@@ -519,8 +531,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
else startbuf[1] = 0x11;
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::SendBufferToPlayer(*oit, STOC_GAME_MSG, startbuf, 18);
startbuf[1] = 0;
BufferIO::ReplayPacket p((char*)startbuf, 17);
replay_stream.push_back(p);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
RefreshExtra(0);
RefreshExtra(1);
new_replay.WriteStream(replay_stream);
start_duel(pduel, opt);
Process();
}
......@@ -558,12 +576,19 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
char* offset, *pbufw, *pbuf = msgbuffer;
int player, count, type;
while (pbuf - msgbuffer < (int)len) {
replay_stream.clear();
bool record = true;
BufferIO::ReplayPacket p;
offset = pbuf;
unsigned char engType = BufferIO::ReadUInt8(pbuf);
p.message = engType;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (engType) {
case MSG_RETRY: {
WaitforResponse(last_response);
NetServer::SendBufferToPlayer(cur_player[last_response], STOC_GAME_MSG, offset, pbuf - offset);
replay_stream.push_back(p);
return 1;
}
case MSG_HINT: {
......@@ -577,6 +602,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
case 5:
case 10: {
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset);
record = false;
break;
}
case 4:
......@@ -603,6 +629,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
replay_stream.push_back(p);
EndDuel();
return 2;
}
......@@ -817,6 +844,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
......@@ -875,6 +903,8 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
......@@ -1499,6 +1529,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::SendBufferToPlayer(players[p], STOC_GAME_MSG, offset, pbuf - offset);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
RefreshExtra(player);
RefreshMzone(0, 0x81fff, 0);
RefreshMzone(1, 0x81fff, 0);
......@@ -1513,6 +1544,12 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return 0;
}
......@@ -1535,6 +1572,21 @@ void TagDuel::GetResponse(DuelPlayer* dp, void* pdata, unsigned int len) {
void TagDuel::EndDuel() {
if(!pduel)
return;
//in case of remaining packets, e.g. MSG_WIN
new_replay.WriteStream(replay_stream);
new_replay.EndRecord();
char nreplaybuf[0x2000], *npbuf = nreplaybuf;
memcpy(npbuf, &new_replay.pheader, sizeof(ReplayHeader));
npbuf += sizeof(ReplayHeader);
memcpy(npbuf, new_replay.comp_data, new_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_NEW_REPLAY, nreplaybuf, sizeof(ReplayHeader) + new_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]);
NetServer::ReSendToPlayer(players[3]);
for (auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
......@@ -1586,6 +1638,8 @@ void TagDuel::RefreshMzone(int player, int flag, int use_cache) {
int len = query_field_card(pduel, player, LOCATION_MZONE, flag, (unsigned char*)qbuf, use_cache);
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
NetServer::ReSendToPlayer(players[pid + 1]);
int qlen = 0;
while(qlen < len) {
......@@ -1612,6 +1666,8 @@ void TagDuel::RefreshSzone(int player, int flag, int use_cache) {
int len = query_field_card(pduel, player, LOCATION_SZONE, flag, (unsigned char*)qbuf, use_cache);
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
NetServer::ReSendToPlayer(players[pid + 1]);
int qlen = 0;
while(qlen < len) {
......@@ -1637,6 +1693,8 @@ void TagDuel::RefreshHand(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
int len = query_field_card(pduel, player, LOCATION_HAND, flag | QUERY_IS_PUBLIC, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
int slen = BufferIO::ReadInt32(qbuf);
......@@ -1670,6 +1728,8 @@ void TagDuel::RefreshGrave(int player, int flag, int use_cache) {
NetServer::ReSendToPlayer(players[3]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void TagDuel::RefreshExtra(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1679,6 +1739,8 @@ void TagDuel::RefreshExtra(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
int len = query_field_card(pduel, player, LOCATION_EXTRA, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, query_buffer, len + 3);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
char query_buffer[0x2000];
......@@ -1688,6 +1750,8 @@ void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
BufferIO::WriteInt8(qbuf, location);
BufferIO::WriteInt8(qbuf, sequence);
int len = query_card(pduel, player, location, sequence, flag, (unsigned char*)qbuf, 0);
BufferIO::ReplayPacket p((char*)query_buffer, len + 3);
replay_stream.push_back(p);
if(location & LOCATION_ONFIELD) {
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 4);
......@@ -1714,6 +1778,16 @@ void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
}
}
}
void TagDuel::PseudoRefreshDeck(int player, int flag) {
char query_buffer[0x2000];
char* qbuf = query_buffer;
BufferIO::WriteInt8(qbuf, MSG_UPDATE_DATA);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
int len = query_field_card(pduel, player, LOCATION_DECK, flag, (unsigned char*)qbuf, 0);
BufferIO::ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
int TagDuel::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
......@@ -1735,6 +1809,8 @@ void TagDuel::TagTimer(evutil_socket_t fd, short events, void* arg) {
NetServer::ReSendToPlayer(sd->players[1]);
NetServer::ReSendToPlayer(sd->players[2]);
NetServer::ReSendToPlayer(sd->players[3]);
BufferIO::ReplayPacket p((char*)wbuf, 3);
sd->replay_stream.push_back(p);
sd->EndDuel();
sd->DuelEndProc();
event_del(sd->etimer);
......
......@@ -40,6 +40,9 @@ public:
static int MessageHandler(long fduel, int type);
static void TagTimer(evutil_socket_t fd, short events, void* arg);
void PseudoRefreshDeck(int player, int flag = 0x181fff);
static std::vector<BufferIO::ReplayPacket> replay_stream;
protected:
DuelPlayer* players[4];
......@@ -52,6 +55,7 @@ protected:
unsigned char hand_result[2];
unsigned char last_response;
Replay last_replay;
Replay new_replay;
bool game_started;
unsigned char turn_count;
unsigned short time_limit[2];
......
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