Commit 060950a9 authored by nanahira's avatar nanahira

Merge branch 'pre-20250620' into develop

parents a98914c5 4abefff8
Pipeline #37862 passed with stages
in 12 minutes and 43 seconds
......@@ -99,28 +99,28 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua
run: |
tar xf ${{ steps.lua.outputs.filepath }}
move lua-5.4.7 lua
move lua-5.4.8 lua
- name: Download sqlite
id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite
run: |
7z x ${{ steps.sqlite.outputs.filepath }}
move sqlite-amalgamation-3490100 sqlite3
move sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio
if: matrix.audiolib == 'miniaudio'
run: |
git clone --depth=1 --branch 0.11.22 https://github.com/mackron/miniaudio
git clone --depth=1 https://github.com/mercury233/miniaudio
cd miniaudio
xcopy /Y extras\miniaudio_split\miniaudio.* .
cd ..
......@@ -345,29 +345,29 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua
run: |
tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua
mv lua-5.4.8 lua
- name: Download sqlite
if: matrix.static-link == true
id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite
if: matrix.static-link == true
run: |
7z x ${{ steps.sqlite.outputs.filepath }}
mv sqlite-amalgamation-3490100 sqlite3
mv sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio
run: |
git clone --depth=1 --branch 0.11.22 https://github.com/mackron/miniaudio
git clone --depth=1 https://github.com/mercury233/miniaudio
cd miniaudio
cp extras/miniaudio_split/miniaudio.* .
cd ..
......@@ -585,29 +585,29 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua
run: |
tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua
mv lua-5.4.8 lua
- name: Download sqlite
if: matrix.static-link == true
id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite
if: matrix.static-link == true
run: |
7z x ${{ steps.sqlite.outputs.filepath }}
mv sqlite-amalgamation-3490100 sqlite3
mv sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio
run: |
git clone --depth=1 --branch 0.11.22 https://github.com/mackron/miniaudio
git clone --depth=1 https://github.com/mercury233/miniaudio
cd miniaudio
cp extras/miniaudio_split/miniaudio.* .
cd ..
......
......@@ -6,7 +6,6 @@
#include "image_manager.h"
#include "game.h"
#include "materials.h"
#include "../ocgcore/common.h"
namespace ygo {
......@@ -15,7 +14,7 @@ ClientField::ClientField() {
mzone[p].resize(7, 0);
szone[p].resize(8, 0);
}
rnd.reset((uint_fast32_t)std::random_device()());
rnd.seed(std::random_device()());
}
ClientField::~ClientField() {
for (int i = 0; i < 2; ++i) {
......@@ -408,7 +407,7 @@ void ClientField::ShowSelectCard(bool buttonok, bool chain) {
}
}
if(has_card_in_grave) {
rnd.shuffle_vector(selectable_cards);
std::shuffle(selectable_cards.begin(), selectable_cards.end(), rnd);
}
}
int startpos;
......@@ -1149,6 +1148,14 @@ bool ClientField::ShowSelectSum(bool panelmode) {
}
return false;
}
static void get_sum_params(irr::u32 opParam, int& op1, int& op2) {
op1 = opParam & 0xffff;
op2 = (opParam >> 16) & 0xffff;
if(op2 & 0x8000) {
op1 = opParam & 0x7fffffff;
op2 = 0;
}
}
bool ClientField::CheckSelectSum() {
std::set<ClientCard*> selable;
for(auto sc : selectsum_all) {
......@@ -1189,8 +1196,8 @@ bool ClientField::CheckSelectSum() {
int mm = -1, mx = -1, max = 0, sumc = 0;
bool ret = false;
for (auto sc : selected_cards) {
int op1 = sc->opParam & 0xffff;
int op2 = sc->opParam >> 16;
int op1, op2;
get_sum_params(sc->opParam, op1, op2);
int opmin = (op2 > 0 && op1 > op2) ? op2 : op1;
int opmax = op2 > op1 ? op2 : op1;
if (mm == -1 || opmin < mm)
......@@ -1205,8 +1212,8 @@ bool ClientField::CheckSelectSum() {
if (select_sumval <= max && select_sumval > max - mx)
ret = true;
for(auto sc : selable) {
int op1 = sc->opParam & 0xffff;
int op2 = sc->opParam >> 16;
int op1, op2;
get_sum_params(sc->opParam, op1, op2);
int m = op1;
int sums = sumc;
sums += m;
......@@ -1275,8 +1282,8 @@ bool ClientField::CheckSelectTribute() {
bool ClientField::check_min(const std::set<ClientCard*>& left, std::set<ClientCard*>::const_iterator index, int min, int max) {
if (index == left.end())
return false;
int op1 = (*index)->opParam & 0xffff;
int op2 = (*index)->opParam >> 16;
int op1, op2;
get_sum_params((*index)->opParam, op1, op2);
int m = (op2 > 0 && op1 > op2) ? op2 : op1;
if (m >= min && m <= max)
return true;
......@@ -1295,9 +1302,8 @@ bool ClientField::check_sel_sum_s(const std::set<ClientCard*>& left, int index,
check_sel_sum_t(left, acc);
return false;
}
int l = selected_cards[index]->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params(selected_cards[index]->opParam, l1, l2);
bool res1 = false, res2 = false;
res1 = check_sel_sum_s(left, index + 1, acc - l1);
if (l2 > 0)
......@@ -1311,9 +1317,8 @@ void ClientField::check_sel_sum_t(const std::set<ClientCard*>& left, int acc) {
continue;
std::set<ClientCard*> testlist(left);
testlist.erase(*sit);
int l = (*sit)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*sit)->opParam, l1, l2);
if (check_sum(testlist.begin(), testlist.end(), acc - l1, count)
|| (l2 > 0 && check_sum(testlist.begin(), testlist.end(), acc - l2, count))) {
selectsum_cards.insert(*sit);
......@@ -1325,9 +1330,8 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se
return count >= select_min && count <= select_max;
if (acc < 0 || index == end)
return false;
int l = (*index)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*index)->opParam, l1, l2);
if ((l1 == acc || (l2 > 0 && l2 == acc)) && (count + 1 >= select_min) && (count + 1 <= select_max))
return true;
++index;
......@@ -1342,9 +1346,8 @@ bool ClientField::check_sel_sum_trib_s(const std::set<ClientCard*>& left, int in
check_sel_sum_trib_t(left, acc);
return acc >= select_min && acc <= select_max;
}
int l = selected_cards[index]->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params(selected_cards[index]->opParam, l1, l2);
bool res1 = false, res2 = false;
res1 = check_sel_sum_trib_s(left, index + 1, acc + l1);
if(l2 > 0)
......@@ -1357,9 +1360,8 @@ void ClientField::check_sel_sum_trib_t(const std::set<ClientCard*>& left, int ac
continue;
std::set<ClientCard*> testlist(left);
testlist.erase(*sit);
int l = (*sit)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*sit)->opParam, l1, l2);
if(check_sum_trib(testlist.begin(), testlist.end(), acc + l1)
|| (l2 > 0 && check_sum_trib(testlist.begin(), testlist.end(), acc + l2))) {
selectsum_cards.insert(*sit);
......@@ -1371,9 +1373,8 @@ bool ClientField::check_sum_trib(std::set<ClientCard*>::const_iterator index, st
return true;
if(acc > select_max || index == end)
return false;
int l = (*index)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*index)->opParam, l1, l2);
if((acc + l1 >= select_min && acc + l1 <= select_max) || (acc + l2 >= select_min && acc + l2 <= select_max))
return true;
++index;
......
......@@ -2,7 +2,7 @@
#define CLIENT_FIELD_H
#include "config.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <vector>
#include <set>
#include <map>
......@@ -90,7 +90,7 @@ public:
bool cant_check_grave{ false };
bool tag_surrender{ false };
bool tag_teammate_surrender{ false };
mt19937 rnd;
std::mt19937 rnd;
ClientField();
~ClientField();
......
#include <array>
#include "config.h"
#include "deck_con.h"
#include "myfilesystem.h"
#include "data_manager.h"
#include "deck_manager.h"
#include "image_manager.h"
#include "sound_manager.h"
#include "game.h"
......@@ -54,6 +53,14 @@ static inline void load_current_deck(irr::gui::IGUIComboBox* cbCategory, irr::gu
deckManager.LoadCurrentDeck(cbCategory->getSelected(), cbCategory->getText(), cbDeck->getText());
}
DeckBuilder::DeckBuilder() {
std::random_device rd;
std::array<uint32_t, 8> seed{};
for (auto& x : seed)
x = rd();
std::seed_seq seq(seed.begin(), seed.end());
rnd.seed(seq);
}
void DeckBuilder::Initialize() {
mainGame->is_building = true;
mainGame->is_siding = false;
......@@ -82,7 +89,6 @@ void DeckBuilder::Initialize() {
filterList = &deckManager._lfList.back();
}
ClearSearch();
rnd.reset((uint_fast32_t)std::time(nullptr));
mouse_pos.set(0, 0);
hovered_code = 0;
hovered_pos = 0;
......@@ -175,7 +181,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_SHUFFLE_DECK: {
rnd.shuffle_vector(deckManager.current_deck.main);
std::shuffle(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), rnd);
break;
}
case BUTTON_SAVE_DECK: {
......@@ -388,6 +394,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
prev_operation = id;
break;
}
case BUTTON_IMPORT_DECK_CODE: {
time_t nowtime = std::time(nullptr);
wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&nowtime));
mainGame->gMutex.lock();
mainGame->stDMMessage->setText(dataManager.GetSysString(1471));
mainGame->ebDMName->setVisible(true);
mainGame->ebDMName->setText(timetext);
mainGame->PopupElement(mainGame->wDMQuery);
mainGame->gMutex.unlock();
prev_operation = id;
break;
}
case BUTTON_EXPORT_DECK_CODE: {
std::stringstream textStream;
deckManager.SaveDeck(deckManager.current_deck, textStream);
wchar_t text[0x10000];
BufferIO::DecodeUTF8(textStream.str().c_str(), text);
mainGame->env->getOSOperator()->copyToClipboard(text);
mainGame->stACMessage->setText(dataManager.GetSysString(1480));
mainGame->PopupElement(mainGame->wACMessage, 20);
break;
}
case BUTTON_DM_OK: {
switch(prev_operation) {
case BUTTON_NEW_CATEGORY: {
......@@ -464,7 +493,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
}
break;
}
case BUTTON_NEW_DECK: {
case BUTTON_NEW_DECK:
case BUTTON_IMPORT_DECK_CODE: {
const wchar_t* deckname = mainGame->ebDMName->getText();
wchar_t catepath[256];
DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText());
......@@ -472,9 +502,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname);
bool res = false;
if(!FileSystem::IsFileExists(filepath)) {
deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
} else {
const wchar_t* txt = mainGame->env->getOSOperator()->getTextFromClipboard();
if(txt) {
char text[0x10000];
BufferIO::EncodeUTF8(txt, text);
std::istringstream textStream(text);
deckManager.LoadCurrentDeck(textStream);
}
}
res = DeckManager::SaveDeck(deckManager.current_deck, filepath);
RefreshDeckList();
ChangeCategory(mainGame->lstCategories->getSelected());
......
......@@ -3,15 +3,16 @@
#include <unordered_map>
#include <vector>
#include <random>
#include <irrlicht.h>
#include "data_manager.h"
#include "deck_manager.h"
#include "../ocgcore/mtrandom.h"
namespace ygo {
class DeckBuilder: public irr::IEventReceiver {
public:
DeckBuilder();
bool OnEvent(const irr::SEvent& event) override;
void Initialize();
void Terminate();
......@@ -80,7 +81,7 @@ public:
bool is_modified{};
bool readonly{};
bool showing_pack{};
mt19937 rnd;
std::mt19937 rnd;
const LFList* filterList{};
std::vector<code_pointer> results;
......
......@@ -277,6 +277,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#endif
return reader;
}
bool DeckManager::LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist) {
LoadDeckFromStream(current_deck, deckStream, is_packlist);
return true; // the above LoadDeck has return value but we ignore it here for now
}
bool DeckManager::LoadCurrentDeck(const wchar_t* file, bool is_packlist) {
current_deck.clear();
auto reader = OpenDeckReader(file);
......@@ -311,21 +315,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na
mainGame->deckBuilder.RefreshPackListScroll();
return res;
}
void DeckManager::SaveDeck(const Deck& deck, std::stringstream& deckStream) {
deckStream << "#created by ..." << std::endl;
deckStream << "#main" << std::endl;
for(size_t i = 0; i < deck.main.size(); ++i)
deckStream << deck.main[i]->first << std::endl;
deckStream << "#extra" << std::endl;
for(size_t i = 0; i < deck.extra.size(); ++i)
deckStream << deck.extra[i]->first << std::endl;
deckStream << "!side" << std::endl;
for(size_t i = 0; i < deck.side.size(); ++i)
deckStream << deck.side[i]->first << std::endl;
}
bool DeckManager::SaveDeck(const Deck& deck, const wchar_t* file) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false;
FILE* fp = OpenDeckFile(file, "w");
if(!fp)
return false;
std::fprintf(fp, "#created by ...\n#main\n");
for(size_t i = 0; i < deck.main.size(); ++i)
std::fprintf(fp, "%u\n", deck.main[i]->first);
std::fprintf(fp, "#extra\n");
for(size_t i = 0; i < deck.extra.size(); ++i)
std::fprintf(fp, "%u\n", deck.extra[i]->first);
std::fprintf(fp, "!side\n");
for(size_t i = 0; i < deck.side.size(); ++i)
std::fprintf(fp, "%u\n", deck.side[i]->first);
std::stringstream deckStream;
SaveDeck(deck, deckStream);
std::fwrite(deckStream.str().c_str(), 1, deckStream.str().length(), fp);
std::fclose(fp);
return true;
}
......
......@@ -55,6 +55,7 @@ public:
unsigned int CheckDeck(const Deck& deck, unsigned int lfhash, int rule);
bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false);
bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname);
bool LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist = false);
static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false);
static uint32_t LoadDeckFromStream(Deck& deck, std::istringstream& deckStream, bool is_packlist = false);
......@@ -64,6 +65,7 @@ public:
static FILE* OpenDeckFile(const wchar_t* file, const char* mode);
static irr::io::IReadFile* OpenDeckReader(const wchar_t* file);
static bool SaveDeck(const Deck& deck, const wchar_t* file);
static void SaveDeck(const Deck& deck, std::stringstream& deckStream);
static bool DeleteDeck(const wchar_t* file);
static bool CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
......
......@@ -5,7 +5,6 @@
#include "deck_manager.h"
#include "sound_manager.h"
#include "duelclient.h"
#include "../ocgcore/common.h"
namespace ygo {
......
This diff is collapsed.
......@@ -3,8 +3,8 @@
#include <vector>
#include <set>
#include <random>
#include "network.h"
#include "../ocgcore/mtrandom.h"
namespace ygo {
......@@ -26,7 +26,8 @@ private:
static unsigned char last_successful_msg[SIZE_NETWORK_BUFFER];
static size_t last_successful_msg_length;
static wchar_t event_string[256];
static mt19937 rnd;
static std::mt19937 rnd;
static std::uniform_real_distribution<float> real_dist;
static bool is_refreshing;
static int match_kill;
static event* resp_event;
......
#include "event_handler.h"
#include "client_field.h"
#include "math.h"
#include "network.h"
#include "game.h"
#include "duelclient.h"
......@@ -11,7 +10,6 @@
#include "replay_mode.h"
#include "single_mode.h"
#include "materials.h"
#include "../ocgcore/common.h"
namespace ygo {
......@@ -377,9 +375,9 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) {
if (activatable_cards[i] == menu_card) {
if(activatable_descs[i].second == EDESC_OPERATION)
if(activatable_descs[i].second & EDESC_OPERATION)
continue;
else if(activatable_descs[i].second == EDESC_RESET) {
else if(activatable_descs[i].second & EDESC_RESET) {
if(id == BUTTON_CMD_ACTIVATE) continue;
} else {
if(id == BUTTON_CMD_RESET) continue;
......@@ -660,7 +658,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) {
if (activatable_cards[i] == command_card) {
if(activatable_descs[i].second == EDESC_OPERATION) {
if(activatable_descs[i].second & EDESC_OPERATION) {
if(list_command == COMMAND_ACTIVATE) continue;
} else {
if(list_command == COMMAND_OPERATION) continue;
......
......@@ -645,10 +645,10 @@ bool Game::Initialize() {
wDeckEdit->setVisible(false);
btnManageDeck = env->addButton(irr::core::rect<irr::s32>(225, 5, 290, 30), wDeckEdit, BUTTON_MANAGE_DECK, dataManager.GetSysString(1328));
//deck manage
wDeckManage = env->addWindow(irr::core::rect<irr::s32>(310, 135, 800, 465), false, dataManager.GetSysString(1460), 0, WINDOW_DECK_MANAGE);
wDeckManage = env->addWindow(irr::core::rect<irr::s32>(310, 135, 800, 515), false, dataManager.GetSysString(1460), 0, WINDOW_DECK_MANAGE);
wDeckManage->setVisible(false);
lstCategories = env->addListBox(irr::core::rect<irr::s32>(10, 30, 140, 320), wDeckManage, LISTBOX_CATEGORIES, true);
lstDecks = env->addListBox(irr::core::rect<irr::s32>(150, 30, 340, 320), wDeckManage, LISTBOX_DECKS, true);
lstCategories = env->addListBox(irr::core::rect<irr::s32>(10, 30, 140, 370), wDeckManage, LISTBOX_CATEGORIES, true);
lstDecks = env->addListBox(irr::core::rect<irr::s32>(150, 30, 340, 370), wDeckManage, LISTBOX_DECKS, true);
posY = 30;
btnNewCategory = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_NEW_CATEGORY, dataManager.GetSysString(1461));
posY += 35;
......@@ -665,6 +665,10 @@ bool Game::Initialize() {
btnMoveDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_MOVE_DECK, dataManager.GetSysString(1467));
posY += 35;
btnCopyDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_COPY_DECK, dataManager.GetSysString(1468));
posY += 35;
btnImportDeckCode = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_IMPORT_DECK_CODE, dataManager.GetSysString(1478));
posY += 35;
btnExportDeckCode = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_EXPORT_DECK_CODE, dataManager.GetSysString(1479));
//deck manage query
wDMQuery = env->addWindow(irr::core::rect<irr::s32>(400, 200, 710, 320), false, dataManager.GetSysString(1460));
wDMQuery->getCloseButton()->setVisible(false);
......@@ -1897,7 +1901,7 @@ void Game::OnResize() {
ebDeckname->setRelativePosition(Resize(80, 65, 220, 90));
cbDBCategory->setRelativePosition(Resize(80, 5, 220, 30));
btnManageDeck->setRelativePosition(Resize(225, 5, 290, 30));
wDeckManage->setRelativePosition(ResizeWin(310, 135, 800, 465));
wDeckManage->setRelativePosition(ResizeWin(310, 135, 800, 515));
scrPackCards->setRelativePosition(Resize(775, 161, 795, 629));
wSort->setRelativePosition(Resize(930, 132, 1020, 156));
......
......@@ -317,7 +317,7 @@ public:
irr::gui::CGUITTFont* numFont;
irr::gui::CGUITTFont* adFont;
irr::gui::CGUITTFont* lpcFont;
std::map<irr::gui::CGUIImageButton*, int> imageLoading;
std::unordered_map<irr::gui::CGUIImageButton*, int> imageLoading;
//card image
irr::gui::IGUIStaticText* wCardImg;
irr::gui::IGUIImage* imgCard;
......@@ -574,6 +574,8 @@ public:
irr::gui::IGUIButton* btnDMDeleteDeck;
irr::gui::IGUIButton* btnMoveDeck;
irr::gui::IGUIButton* btnCopyDeck;
irr::gui::IGUIButton* btnImportDeckCode;
irr::gui::IGUIButton* btnExportDeckCode;
irr::gui::IGUIWindow* wDMQuery;
irr::gui::IGUIStaticText* stDMMessage;
irr::gui::IGUIStaticText* stDMMessage2;
......@@ -827,6 +829,8 @@ extern Game* mainGame;
#define LISTBOX_DECKS 340
#define BUTTON_DM_OK 341
#define BUTTON_DM_CANCEL 342
#define BUTTON_IMPORT_DECK_CODE 343
#define BUTTON_EXPORT_DECK_CODE 344
#define COMBOBOX_LFLIST 349
#define BUTTON_CLEAR_LOG 350
......
......@@ -309,7 +309,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path))
break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE)
if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break;
for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
......@@ -537,24 +537,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{};
std::wstring repinfo;
time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM)
curtime = temp_replay.pheader.start_time;
const auto& rh = temp_replay.pheader.base;
if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
curtime = rh.start_time;
else{
curtime = temp_replay.pheader.seed;
curtime = rh.seed;
wchar_t version_info[256]{};
myswprintf(version_info, L"version 0x%X\n", temp_replay.pheader.version);
myswprintf(version_info, L"version 0x%X\n", rh.version);
repinfo.append(version_info);
}
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) {
if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path);
repinfo.append(L"\n");
}
const auto& player_names = temp_replay.players;
if(temp_replay.pheader.flag & REPLAY_TAG)
if(rh.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str());
else
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
......
......@@ -206,7 +206,11 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
case CTOS_CHAT: {
if(!dp->game)
return;
if (len < 1 + (int)sizeof(unsigned char))
if (len < 1 + sizeof(uint16_t) * 1)
return;
if (len > 1 + sizeof(uint16_t) * LEN_CHAT_MSG)
return;
if ((len - 1) % sizeof(uint16_t))
return;
duel_mode->Chat(dp, pdata, len - 1);
break;
......@@ -253,6 +257,15 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
BufferIO::CopyCharArray(pkt->name, dp->name);
break;
}
case CTOS_EXTERNAL_ADDRESS: {
// for other server & reverse proxy use only
/*
wchar_t hostname[LEN_HOSTNAME];
uint32_t real_ip = ntohl(BufferIO::ReadInt32(pdata));
BufferIO::CopyCharArray((uint16_t*)pdata, hostname);
*/
break;
}
case CTOS_CREATE_GAME: {
if(dp->game || duel_mode)
return;
......@@ -361,8 +374,6 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
}
}
size_t NetServer::CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type) {
if (!check_msg_size(src_size))
return 0;
uint16_t src_msg[LEN_CHAT_MSG];
std::memcpy(src_msg, src, src_size);
const int src_len = src_size / sizeof(uint16_t);
......
......@@ -103,6 +103,14 @@ struct CTOS_Kick {
check_trivially_copyable(CTOS_Kick);
static_assert(sizeof(CTOS_Kick) == 1, "size mismatch: CTOS_Kick");
/*
* CTOS_ExternalAddress
* uint32_t real_ip; (IPv4 address, BE, alway 0 in normal client)
* uint16_t hostname[256]; (UTF-16 string)
*/
constexpr int LEN_HOSTNAME = 256;
// STOC
struct STOC_ErrorMsg {
uint8_t msg{};
......@@ -196,17 +204,6 @@ struct DuelPlayer {
bufferevent* bev{};
};
inline bool check_msg_size(int size) {
// empty string is not allowed
if (size < 2 * sizeof(uint16_t))
return false;
if (size > LEN_CHAT_MSG * sizeof(uint16_t))
return false;
if (size % sizeof(uint16_t) != 0)
return false;
return true;
}
inline unsigned int GetPosition(unsigned char* qbuf, size_t offset) {
unsigned int info = 0;
std::memcpy(&info, qbuf + offset, sizeof info);
......@@ -269,6 +266,7 @@ public:
#define CTOS_SURRENDER 0x14 // no data
#define CTOS_TIME_CONFIRM 0x15 // no data
#define CTOS_CHAT 0x16 // uint16_t array
#define CTOS_EXTERNAL_ADDRESS 0x17 // CTOS_ExternalAddress
#define CTOS_HS_TODUELIST 0x20 // no data
#define CTOS_HS_TOOBSERVER 0x21 // no data
#define CTOS_HS_READY 0x22 // no data
......@@ -292,7 +290,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // no data
#define STOC_DUEL_END 0x16 // no data
#define STOC_REPLAY 0x17 // ReplayHeader + byte array
#define STOC_REPLAY 0x17 // ExtendedReplayHeader + byte array
#define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit
#define STOC_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
......@@ -32,7 +32,7 @@ void Replay::BeginRecord() {
Reset();
is_recording = true;
}
void Replay::WriteHeader(ReplayHeader& header) {
void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header;
#ifdef _WIN32
DWORD size;
......@@ -77,11 +77,11 @@ void Replay::EndRecord() {
#else
std::fclose(fp);
#endif
pheader.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED;
pheader.base.datasize = replay_size;
pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
comp_size = MAX_COMP_SIZE;
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.base.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
if (ret != SZ_OK) {
std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret;
......@@ -112,27 +112,31 @@ bool Replay::OpenReplay(const wchar_t* name) {
Reset();
bool correct_header = true;
if (std::fread(&pheader, sizeof pheader, 1, rfp) < 1)
if (std::fread(&pheader, sizeof pheader.base, 1, rfp) < 1)
correct_header = false;
else if (pheader.id != 0x31707279)
else if (pheader.base.id != REPLAY_ID_YRP1 && pheader.base.id != REPLAY_ID_YRP2)
correct_header = false;
else if (pheader.version < 0x12d0u)
else if (pheader.base.version < 0x12d0u)
correct_header = false;
else if (pheader.version >= 0x1353u && !(pheader.flag & REPLAY_UNIFORM))
else if (pheader.base.version >= 0x1353u && !(pheader.base.flag & REPLAY_UNIFORM))
correct_header = false;
if (!correct_header) {
std::fclose(rfp);
return false;
}
if(pheader.flag & REPLAY_COMPRESSED) {
if (pheader.base.id == REPLAY_ID_YRP2 && std::fread(reinterpret_cast<unsigned char*>(&pheader) + sizeof pheader.base, sizeof pheader - sizeof pheader.base, 1, rfp) < 1) {
std::fclose(rfp);
return false;
}
if(pheader.base.flag & REPLAY_COMPRESSED) {
comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp);
std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE)
if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false;
replay_size = pheader.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false;
if (replay_size != pheader.datasize) {
if (replay_size != pheader.base.datasize) {
replay_size = 0;
return false;
}
......@@ -189,7 +193,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20);
return true;
}
void Replay::ReadHeader(ReplayHeader& header) {
void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader;
}
bool Replay::ReadData(void* data, size_t length) {
......@@ -232,7 +236,7 @@ bool Replay::IsReplaying() const {
return is_replaying;
}
bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2;
int player_count = (pheader.base.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{};
if (!ReadName(name))
......@@ -241,11 +245,11 @@ bool Replay::ReadInfo() {
}
if (!ReadData(&params, sizeof params))
return false;
bool is_tag1 = pheader.flag & REPLAY_TAG;
bool is_tag1 = pheader.base.flag & REPLAY_TAG;
bool is_tag2 = params.duel_flag & DUEL_TAG_MODE;
if (is_tag1 != is_tag2)
return false;
if (pheader.flag & REPLAY_SINGLE_MODE) {
if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
......
......@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size
constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
......@@ -27,6 +30,15 @@ struct ReplayHeader {
uint8_t props[8]{};
};
struct ExtendedReplayHeader {
ReplayHeader base;
uint32_t seed_sequence[SEED_COUNT]{};
uint32_t header_version{ 1 };
uint32_t value1{};
uint32_t value2{};
uint32_t value3{};
};
struct DuelParameters {
int32_t start_lp{};
int32_t start_hand{};
......@@ -41,7 +53,7 @@ public:
// record
void BeginRecord();
void WriteHeader(ReplayHeader& header);
void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true);
template<typename T>
void Write(T data, bool flush = true) {
......@@ -68,7 +80,7 @@ public:
bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length);
template<typename T>
T Read() {
......@@ -87,7 +99,7 @@ public:
HANDLE recording_fp{ nullptr };
#endif
ReplayHeader pheader;
ExtendedReplayHeader pheader;
unsigned char* comp_data;
size_t comp_size{};
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result;
}
int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader;
const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
......@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
const auto& rh = cur_replay.pheader.base;
cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
......@@ -168,7 +166,12 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
}
pduel = create_duel(rnd());
if(rh.id == REPLAY_ID_YRP1) {
std::mt19937 rnd(rh.seed);
pduel = create_duel(rnd());
} else {
pduel = create_duel_v2(cur_replay.pheader.seed_sequence);
}
mainGame->dInfo.duel_rule = cur_replay.params.duel_flag >> 16;
set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
......@@ -214,8 +217,6 @@ bool ReplayMode::StartDuel() {
return false;
}
}
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag);
return true;
}
......@@ -392,7 +393,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
return ReadReplayResponse();
}
case MSG_SELECT_PLACE:
......@@ -445,6 +446,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
......
......@@ -411,15 +411,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
}
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -433,7 +432,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(SingleDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
set_player_info(pduel, 0, host_info.start_lp, host_info.start_hand, host_info.draw_count);
set_player_info(pduel, 1, host_info.start_lp, host_info.start_hand, host_info.draw_count);
unsigned int opt = (unsigned int)host_info.duel_rule << 16;
......@@ -751,7 +750,7 @@ int SingleDuel::Analyze(unsigned char* msgbuffer, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
WaitforResponse(player);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1;
......@@ -822,6 +821,7 @@ int SingleDuel::Analyze(unsigned char* msgbuffer, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
if(pbuf[5] != LOCATION_DECK) {
pbuf += count * 7;
......@@ -1426,10 +1426,10 @@ void SingleDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -36,12 +36,22 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear();
int opt = 0;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
std::seed_seq seed(rh.seed_sequence, rh.seed_sequence + SEED_COUNT);
std::mt19937 rnd(seed);
uint32_t duel_seed[SEED_COUNT]{};
for (auto& x : duel_seed)
x = rnd();
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(SingleMode::MessageHandler);
pduel = create_duel(rnd.rand());
pduel = create_duel_v2(duel_seed);
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
mainGame->dInfo.lp[0] = start_lp;
......@@ -79,12 +89,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel);
return 0;
}
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
mainGame->gMutex.lock();
mainGame->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo();
......@@ -297,7 +301,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
if(!DuelClient::ClientAnalyze(offset, pbuf - offset)) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
......@@ -374,6 +378,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
......
......@@ -16,7 +16,7 @@ bool SoundManager::Init() {
#ifdef YGOPRO_USE_AUDIO
bgm_scene = -1;
RefreshBGMList();
rnd.reset((unsigned int)std::time(nullptr));
rnd.seed(std::random_device()());
#ifdef YGOPRO_USE_MINIAUDIO
engineConfig = ma_engine_config_init();
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
......@@ -304,7 +304,7 @@ void SoundManager::PlayBGM(int scene) {
if(count <= 0)
return;
bgm_scene = scene;
int bgm = rnd.get_random_integer(0, count -1);
int bgm = (count > 1) ? std::uniform_int_distribution<>(0, count - 1)(rnd) : 0;
auto name = BGMList[scene][bgm].c_str();
wchar_t BGMName[1024];
myswprintf(BGMName, L"./sound/BGM/%ls", name);
......
......@@ -2,7 +2,7 @@
#define SOUNDMANAGER_H
#include "game.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#ifdef YGOPRO_USE_MINIAUDIO
#include <miniaudio.h>
#endif
......@@ -16,7 +16,7 @@ class SoundManager {
private:
std::vector<std::wstring> BGMList[8];
int bgm_scene{};
mt19937 rnd;
std::mt19937 rnd;
#ifdef YGOPRO_USE_MINIAUDIO
ma_engine_config engineConfig;
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
......
......@@ -384,15 +384,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
cur_player[1] = players[3];
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -410,7 +409,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(TagDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
set_player_info(pduel, 0, host_info.start_lp, host_info.start_hand, host_info.draw_count);
set_player_info(pduel, 1, host_info.start_lp, host_info.start_hand, host_info.draw_count);
unsigned int opt = (unsigned int)host_info.duel_rule << 16;
......@@ -707,7 +706,7 @@ int TagDuel::Analyze(unsigned char* msgbuffer, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
WaitforResponse(player);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1;
......@@ -782,6 +781,7 @@ int TagDuel::Analyze(unsigned char* msgbuffer, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
if(pbuf[5] != LOCATION_DECK) {
pbuf += count * 7;
......@@ -1529,10 +1529,10 @@ void TagDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]);
NetServer::ReSendToPlayer(players[3]);
......
Subproject commit d750174f6943d7941db16db6a598c625f315d376
Subproject commit 0631e6b01a090db0eb78bc3c6ea6a4becde4ec14
Subproject commit 2134e8af15961ccc3aeeab4feba0464f8f5c6eac
Subproject commit 656ce97e7e8dc7458be66ee7cdca4002d7c491c2
......@@ -493,6 +493,9 @@
!system 1475 已存在同名卡组
!system 1476 删除失败
!system 1477 卡片数:
!system 1478 导入卡组码
!system 1479 导出卡组码
!system 1480 已导出到剪贴板
!system 1481 OCG
!system 1482 TCG
!system 1483 简体中文
......
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