Commit f2f9be5a authored by wind2009's avatar wind2009

Merge remote-tracking branch 'upstream/master'

parents 495485f2 b824c77e
......@@ -59,7 +59,6 @@ Xyz materials:
### Directories:
* pics: .jpg card images(177*254).
* pics\thumbnail: .jpg thumbnail images(44*64).
* script: .lua script files.
* textures: Other image files.
* deck: .ydk deck files.
......
......@@ -4,6 +4,7 @@
#include <cstdint>
#include <cstring>
#include <cwchar>
#include <vector>
class BufferIO {
public:
......@@ -15,11 +16,21 @@ public:
return ret;
}
template<typename T>
static void Write(unsigned char*& p, T value) {
static void Write(unsigned char*& p, const T& value) {
std::memcpy(p, &value, sizeof(T));
p += sizeof(T);
}
static void VectorWriteBlock(std::vector<unsigned char>& buffer, const void* src, size_t size) {
const auto len = buffer.size();
buffer.resize(len + size);
std::memcpy(buffer.data() + len, src, size);
}
template<typename T>
static void VectorWrite(std::vector<unsigned char>& buffer, const T& value) {
VectorWriteBlock(buffer, &value, sizeof(T));
}
// for compatibility
[[deprecated]]
static int32_t ReadInt32(unsigned char*& p) {
......
......@@ -32,14 +32,15 @@ ClientCard::~ClientCard() {
overlayed.clear();
}
void ClientCard::SetCode(unsigned int x) {
if((location == LOCATION_HAND) && (code != x)) {
code = x;
if (code == x) {
return;
}
if (x == 0) {
chain_code = code;
}
code = x;
if (location == LOCATION_HAND) {
mainGame->dField.MoveCard(this, 5);
} else {
if (x == 0 && code != 0) {
chain_code = code;
}
code = x;
}
}
void ClientCard::UpdateInfo(unsigned char* buf) {
......
......@@ -456,17 +456,15 @@ void ClientField::ShowSelectCard(bool buttonok, bool is_continuous) {
if(mainGame->dInfo.curMsg != MSG_SORT_CARD) {
// text
wchar_t formatBuffer[2048];
if(select_continuous)
if (select_continuous)
myswprintf(formatBuffer, L"%ls", dataManager.unknown_string);
else if(cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
else if (cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
myswprintf(formatBuffer, L"%ls", dataManager.FormatLocation(selectable_cards[i]->location, 0));
else if(selectable_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i]->overlayTarget->location, selectable_cards[i]->overlayTarget->sequence),
selectable_cards[i]->overlayTarget->sequence + 1, selectable_cards[i]->sequence + 1);
else if (selectable_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i]->overlayTarget), selectable_cards[i]->overlayTarget->sequence + 1, selectable_cards[i]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]->location, selectable_cards[i]->sequence),
selectable_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]), selectable_cards[i]->sequence + 1);
mainGame->stCardPos[i]->setText(formatBuffer);
// color
if (selectable_cards[i]->is_selected)
......@@ -542,8 +540,7 @@ void ClientField::ShowChainCard() {
mainGame->btnCardSelect[i]->setPressed(false);
mainGame->btnCardSelect[i]->setVisible(true);
wchar_t formatBuffer[2048];
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]->location, selectable_cards[i]->sequence),
selectable_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]), selectable_cards[i]->sequence + 1);
mainGame->stCardPos[i]->setText(formatBuffer);
if(selectable_cards[i]->location == LOCATION_OVERLAY) {
if(selectable_cards[i]->owner != selectable_cards[i]->overlayTarget->controler)
......@@ -597,13 +594,11 @@ void ClientField::ShowLocationCard() {
mainGame->btnCardDisplay[i]->setPressed(false);
mainGame->btnCardDisplay[i]->setVisible(true);
wchar_t formatBuffer[2048];
if(display_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i]->overlayTarget->location, display_cards[i]->overlayTarget->sequence),
display_cards[i]->overlayTarget->sequence + 1, display_cards[i]->sequence + 1);
if (display_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i]->overlayTarget), display_cards[i]->overlayTarget->sequence + 1, display_cards[i]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i]->location, display_cards[i]->sequence),
display_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i]), display_cards[i]->sequence + 1);
mainGame->stDisplayPos[i]->setText(formatBuffer);
if(display_cards[i]->location == LOCATION_OVERLAY) {
if(display_cards[i]->owner != display_cards[i]->overlayTarget->controler)
......
#include "data_manager.h"
#include "game.h"
#include "client_card.h"
#include "spmemvfs/spmemvfs.h"
namespace ygo {
......@@ -220,34 +221,26 @@ const wchar_t* DataManager::GetDesc(uint32_t strCode) const {
return csit->second.desc[offset].c_str();
return unknown_string;
}
const wchar_t* DataManager::GetSysString(int code) const {
if (code < 0 || code > MAX_STRING_ID)
return unknown_string;
auto csit = _sysStrings.find(code);
if(csit == _sysStrings.end())
const wchar_t* DataManager::GetMapString(const wstring_map& table, uint32_t code) const {
auto csit = table.find(code);
if (csit == table.end())
return unknown_string;
return csit->second.c_str();
}
const wchar_t* DataManager::GetVictoryString(int code) const {
auto csit = _victoryStrings.find(code);
if(csit == _victoryStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetSysString(uint32_t code) const {
return GetMapString(_sysStrings, code);
}
const wchar_t* DataManager::GetCounterName(int code) const {
auto csit = _counterStrings.find(code);
if(csit == _counterStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetVictoryString(uint32_t code) const {
return GetMapString(_victoryStrings, code);
}
const wchar_t* DataManager::GetSetName(int code) const {
auto csit = _setnameStrings.find(code);
if(csit == _setnameStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetCounterName(uint32_t code) const {
return GetMapString(_counterStrings, code);
}
const wchar_t* DataManager::GetSetName(uint32_t code) const {
return GetMapString(_setnameStrings, code);
}
std::vector<unsigned int> DataManager::GetSetCodes(std::wstring setname) const {
std::vector<unsigned int> matchingCodes;
std::vector<uint32_t> DataManager::GetSetCodes(std::wstring setname) const {
std::vector<uint32_t> matchingCodes;
for(auto csit = _setnameStrings.begin(); csit != _setnameStrings.end(); ++csit) {
auto xpos = csit->second.find_first_of(L'|');//setname|another setname or extra info
if(setname.size() < 2) {
......@@ -280,11 +273,10 @@ const wchar_t* DataManager::FormatLocation(int location, int sequence) const {
else
return GetSysString(1009);
}
int i = 1000;
int string_id = 0;
for (unsigned filter = LOCATION_DECK; filter <= LOCATION_PZONE; filter <<= 1, ++i) {
if (filter == location) {
string_id = i;
for (int i = 0; i < 10; ++i) {
if ((0x1U << i) == location) {
string_id = STRING_ID_LOCATION + i;
break;
}
}
......@@ -293,6 +285,11 @@ const wchar_t* DataManager::FormatLocation(int location, int sequence) const {
else
return unknown_string;
}
const wchar_t* DataManager::FormatLocation(ClientCard* card) const {
if (!card)
return unknown_string;
return FormatLocation(card->location, card->sequence);
}
std::wstring DataManager::FormatAttribute(unsigned int attribute) const {
std::wstring buffer;
for (int i = 0; i < ATTRIBUTES_COUNT; ++i) {
......@@ -303,7 +300,7 @@ std::wstring DataManager::FormatAttribute(unsigned int attribute) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatRace(unsigned int race) const {
......@@ -316,7 +313,7 @@ std::wstring DataManager::FormatRace(unsigned int race) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatType(unsigned int type) const {
......@@ -329,7 +326,7 @@ std::wstring DataManager::FormatType(unsigned int type) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatSetName(const uint16_t setcode[]) const {
......@@ -343,7 +340,7 @@ std::wstring DataManager::FormatSetName(const uint16_t setcode[]) const {
buffer.append(setname);
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatLinkMarker(unsigned int link_marker) const {
......
......@@ -57,6 +57,9 @@ struct CardString {
};
using code_pointer = std::unordered_map<uint32_t, CardDataC>::const_iterator;
using string_pointer = std::unordered_map<uint32_t, CardString>::const_iterator;
using wstring_map = std::unordered_map<uint32_t, std::wstring>;
class ClientCard;
class DataManager {
public:
......@@ -81,30 +84,32 @@ public:
const wchar_t* GetName(uint32_t code) const;
const wchar_t* GetText(uint32_t code) const;
const wchar_t* GetDesc(uint32_t strCode) const;
const wchar_t* GetSysString(int code) const;
const wchar_t* GetVictoryString(int code) const;
const wchar_t* GetCounterName(int code) const;
const wchar_t* GetSetName(int code) const;
std::vector<unsigned int> GetSetCodes(std::wstring setname) const;
const wchar_t* GetSysString(uint32_t code) const;
const wchar_t* GetVictoryString(uint32_t code) const;
const wchar_t* GetCounterName(uint32_t code) const;
const wchar_t* GetSetName(uint32_t code) const;
std::vector<uint32_t> GetSetCodes(std::wstring setname) const;
std::wstring GetNumString(int num, bool bracket = false) const;
const wchar_t* FormatLocation(int location, int sequence) const;
const wchar_t* FormatLocation(ClientCard* card) const;
std::wstring FormatAttribute(unsigned int attribute) const;
std::wstring FormatRace(unsigned int race) const;
std::wstring FormatType(unsigned int type) const;
std::wstring FormatSetName(const uint16_t setcode[]) const;
std::wstring FormatLinkMarker(unsigned int link_marker) const;
std::unordered_map<unsigned int, std::wstring> _counterStrings;
std::unordered_map<unsigned int, std::wstring> _victoryStrings;
std::unordered_map<unsigned int, std::wstring> _setnameStrings;
std::unordered_map<unsigned int, std::wstring> _sysStrings;
wstring_map _counterStrings;
wstring_map _victoryStrings;
wstring_map _setnameStrings;
wstring_map _sysStrings;
char errmsg[512]{};
const wchar_t* unknown_string{ L"???" };
irr::io::IFileSystem* FileSystem{};
static constexpr int STRING_ID_ATTRIBUTE = 1010;
static constexpr int STRING_ID_RACE = 1020;
static constexpr int STRING_ID_TYPE = 1050;
static constexpr uint32_t STRING_ID_LOCATION = 1000;
static constexpr uint32_t STRING_ID_ATTRIBUTE = 1010;
static constexpr uint32_t STRING_ID_RACE = 1020;
static constexpr uint32_t STRING_ID_TYPE = 1050;
static constexpr int TYPES_COUNT = 27;
static unsigned char scriptBuffer[0x100000];
......@@ -122,6 +127,7 @@ public:
static bool deck_sort_name(code_pointer l1, code_pointer l2);
private:
const wchar_t* GetMapString(const wstring_map& table, uint32_t code) const;
std::unordered_map<uint32_t, CardDataC> _datas;
std::unordered_map<uint32_t, CardString> _strings;
std::unordered_map<uint32_t, std::vector<uint16_t>> extra_setcode;
......
......@@ -179,10 +179,12 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
std::sort(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), DataManager::deck_sort_lv);
std::sort(deckManager.current_deck.extra.begin(), deckManager.current_deck.extra.end(), DataManager::deck_sort_lv);
std::sort(deckManager.current_deck.side.begin(), deckManager.current_deck.side.end(), DataManager::deck_sort_lv);
is_modified = true;
break;
}
case BUTTON_SHUFFLE_DECK: {
std::shuffle(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), rnd);
is_modified = true;
break;
}
case BUTTON_SAVE_DECK: {
......@@ -702,17 +704,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break;
}
mainGame->ClearCardInfo();
unsigned char deckbuf[1024]{};
auto pdeck = deckbuf;
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.main.size() + deckManager.current_deck.extra.size()));
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.side.size()));
for(size_t i = 0; i < deckManager.current_deck.main.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.main[i]->first);
for(size_t i = 0; i < deckManager.current_deck.extra.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.extra[i]->first);
for(size_t i = 0; i < deckManager.current_deck.side.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.side[i]->first);
DuelClient::SendBufferToServer(CTOS_UPDATE_DECK, deckbuf, pdeck - deckbuf);
DuelClient::SendUpdateDeck(deckManager.current_deck);
break;
}
case BUTTON_SIDE_RELOAD: {
......@@ -750,6 +742,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
is_modified = true;
} else if(prev_operation == BUTTON_DELETE_DECK) {
int sel = prev_sel;
mainGame->cbDBDecks->setSelected(sel);
......@@ -1093,6 +1086,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
is_starting_dragging = false;
irr::gui::IGUIElement* root = mainGame->env->getRootGUIElement();
if(!is_draging && !mainGame->is_siding && root->getElementFromPoint(mouse_pos) == mainGame->imgCard) {
soundManager.PlaySoundEffect(SOUND_CARD_DROP);
ShowBigCard(mainGame->showingcode, 1);
break;
}
......@@ -1122,6 +1116,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
case irr::EMIE_LMOUSE_DOUBLE_CLICK: {
irr::gui::IGUIElement* root = mainGame->env->getRootGUIElement();
if(!is_draging && !mainGame->is_siding && root->getElementFromPoint(mouse_pos) == root && hovered_code) {
soundManager.PlaySoundEffect(SOUND_CARD_DROP);
ShowBigCard(hovered_code, 1);
break;
}
......@@ -1381,8 +1376,6 @@ void DeckBuilder::GetHoveredCard() {
if(!is_draging && pre_code != hovered_code) {
if(hovered_code)
mainGame->ShowCardInfo(hovered_code);
if(pre_code)
imageManager.RemoveTexture(pre_code);
}
}
void DeckBuilder::StartFilter() {
......@@ -1403,7 +1396,7 @@ void DeckBuilder::FilterCards() {
results.clear();
struct element_t {
std::wstring keyword;
std::vector<unsigned int> setcodes;
std::vector<uint32_t> setcodes;
enum class type_t {
all,
name,
......
......@@ -829,11 +829,11 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break;
}
case STOC_HS_PLAYER_ENTER: {
if (len < 1 + STOC_HS_PlayerEnter_size)
if (len < 1 + sizeof(STOC_HS_PlayerEnter))
return;
soundManager.PlaySoundEffect(SOUND_PLAYER_ENTER);
STOC_HS_PlayerEnter packet;
std::memcpy(&packet, pdata, STOC_HS_PlayerEnter_size);
std::memcpy(&packet, pdata, sizeof(STOC_HS_PlayerEnter));
auto pkt = &packet;
if(pkt->pos > 3)
break;
......@@ -2942,7 +2942,7 @@ bool DuelClient::ClientAnalyze(unsigned char* msg, int len) {
pcard->SetCode(code);
pcard->position = cp;
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping) {
soundManager.PlaySoundEffect(SOUND_FILP);
soundManager.PlaySoundEffect(SOUND_FLIP);
myswprintf(event_string, dataManager.GetSysString(1607), dataManager.GetName(code));
mainGame->dField.MoveCard(pcard, 10);
mainGame->WaitFrameSignal(11);
......@@ -4067,6 +4067,19 @@ void DuelClient::SendResponse() {
SendBufferToServer(CTOS_RESPONSE, response_buf, response_len);
}
}
void DuelClient::SendUpdateDeck(const Deck& deck) {
std::vector<unsigned char> deckbuf;
deckbuf.reserve(1024);
BufferIO::VectorWrite<int32_t>(deckbuf, static_cast<int32_t>(deck.main.size() + deck.extra.size()));
BufferIO::VectorWrite<int32_t>(deckbuf, static_cast<int32_t>(deck.side.size()));
for (const auto& card: deck.main)
BufferIO::VectorWrite<uint32_t>(deckbuf, card->first);
for (const auto& card: deck.extra)
BufferIO::VectorWrite<uint32_t>(deckbuf, card->first);
for (const auto& card: deck.side)
BufferIO::VectorWrite<uint32_t>(deckbuf, card->first);
SendBufferToServer(CTOS_UPDATE_DECK, deckbuf.data(), deckbuf.size());
}
void DuelClient::BeginRefreshHost() {
if(is_refreshing)
return;
......
......@@ -5,6 +5,7 @@
#include <set>
#include <random>
#include "config.h"
#include "deck_manager.h"
#include "network.h"
namespace ygo {
......@@ -48,6 +49,7 @@ public:
static void SetResponseI(int32_t respI);
static void SetResponseB(void* respB, size_t len);
static void SendResponse();
static void SendUpdateDeck(const Deck& deck);
static void SendPacketToServer(unsigned char proto) {
auto p = duel_client_write;
BufferIO::Write<uint16_t>(p, 1);
......
......@@ -905,17 +905,15 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
else
myswprintf(formatBuffer, L"");
} else {
if(select_continuous)
if (select_continuous)
myswprintf(formatBuffer, L"%ls", dataManager.unknown_string);
else if(cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
else if (cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
myswprintf(formatBuffer, L"%ls", dataManager.FormatLocation(selectable_cards[i]->location, 0));
else if(selectable_cards[i + pos]->location == LOCATION_OVERLAY)
else if (selectable_cards[i + pos]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i + pos]->overlayTarget->location, selectable_cards[i + pos]->overlayTarget->sequence),
selectable_cards[i + pos]->overlayTarget->sequence + 1, selectable_cards[i + pos]->sequence + 1);
dataManager.FormatLocation(selectable_cards[i + pos]->overlayTarget), selectable_cards[i + pos]->overlayTarget->sequence + 1, selectable_cards[i + pos]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i + pos]->location, selectable_cards[i + pos]->sequence),
selectable_cards[i + pos]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i + pos]), selectable_cards[i + pos]->sequence + 1);
}
mainGame->stCardPos[i]->setText(formatBuffer);
// color
......@@ -961,13 +959,11 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
mainGame->btnCardDisplay[i]->setImage(imageManager.tCover[display_cards[i + pos]->controler + 2]);
mainGame->btnCardDisplay[i]->setRelativePosition(irr::core::rect<irr::s32>(30 + i * 125, 55, 30 + 120 + i * 125, 225));
wchar_t formatBuffer[2048];
if(display_cards[i + pos]->location == LOCATION_OVERLAY) {
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i + pos]->overlayTarget->location, display_cards[i + pos]->overlayTarget->sequence),
display_cards[i + pos]->overlayTarget->sequence + 1, display_cards[i + pos]->sequence + 1);
} else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i + pos]->location, display_cards[i + pos]->sequence),
display_cards[i + pos]->sequence + 1);
if(display_cards[i + pos]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i + pos]->overlayTarget), display_cards[i + pos]->overlayTarget->sequence + 1, display_cards[i + pos]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i + pos]), display_cards[i + pos]->sequence + 1);
mainGame->stDisplayPos[i]->setText(formatBuffer);
if(display_cards[i + pos]->location == LOCATION_OVERLAY) {
if(display_cards[i + pos]->owner != display_cards[i + pos]->overlayTarget->controler)
......
......@@ -1089,16 +1089,13 @@ void Game::InitStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, i
scrCardText->setPos(0);
}
std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::gui::CGUITTFont* font, const wchar_t* text, irr::u32 pos) {
size_t pbuffer = 0;
irr::u32 _width = 0, _height = 0;
wchar_t prev = 0;
wchar_t strBuffer[4096]{};
constexpr size_t buffer_len = sizeof strBuffer / sizeof strBuffer[0] - 1;
std::wstring result;
result.reserve(4096);
const size_t text_len = std::wcslen(text);
for(size_t i = 0; i < text_len ; ++i) {
if (pbuffer >= buffer_len)
break;
wchar_t c = text[i];
irr::u32 w = font->getCharDimension(c).Width + font->getKerningWidth(c, prev);
prev = c;
......@@ -1106,31 +1103,28 @@ std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cW
continue;
}
if (c == L'\n') {
strBuffer[pbuffer++] = L'\n';
result.push_back(L'\n');
_width = 0;
_height++;
prev = 0;
if (_height == pos)
pbuffer = 0;
result.clear();
continue;
}
if (_width > 0 && _width + w > cWidth) {
strBuffer[pbuffer++] = L'\n';
result.push_back(L'\n');
_width = 0;
_height++;
prev = 0;
if (_height == pos)
pbuffer = 0;
result.clear();
}
if (pbuffer >= buffer_len)
break;
_width += w;
strBuffer[pbuffer++] = c;
result.push_back(c);
}
strBuffer[pbuffer] = 0;
if (pControl)
pControl->setText(strBuffer);
return std::wstring(strBuffer);
pControl->setText(result.c_str());
return result;
}
void Game::LoadExpansions() {
FileSystem::TraversalDir(L"./expansions", [](const wchar_t* name, bool isdir) {
......@@ -1330,8 +1324,6 @@ void Game::LoadConfig() {
gameConf.antialias = std::strtol(valbuf, nullptr, 10);
} else if(!std::strcmp(strbuf, "use_d3d")) {
gameConf.use_d3d = std::strtol(valbuf, nullptr, 10) > 0;
} else if(!std::strcmp(strbuf, "use_image_scale")) {
gameConf.use_image_scale = std::strtol(valbuf, nullptr, 10) > 0;
} else if (!std::strcmp(strbuf, "use_image_scale_multi_thread")) {
gameConf.use_image_scale_multi_thread = std::strtol(valbuf, nullptr, 10) > 0;
} else if (!std::strcmp(strbuf, "use_image_load_background_thread")) {
......@@ -1466,7 +1458,6 @@ void Game::SaveConfig() {
std::fprintf(fp, "#config file\n#nickname & gamename should be less than 20 characters\n");
char linebuf[CONFIG_LINE_SIZE];
std::fprintf(fp, "use_d3d = %d\n", gameConf.use_d3d ? 1 : 0);
std::fprintf(fp, "use_image_scale = %d\n", gameConf.use_image_scale ? 1 : 0);
std::fprintf(fp, "use_image_scale_multi_thread = %d\n", gameConf.use_image_scale_multi_thread ? 1 : 0);
std::fprintf(fp, "use_image_load_background_thread = %d\n", gameConf.use_image_load_background_thread ? 1 : 0);
std::fprintf(fp, "antialias = %d\n", gameConf.antialias);
......
......@@ -48,7 +48,6 @@ bool IsExtension(const char* filename, const char(&extension)[N]) {
struct Config {
bool use_d3d{ false };
bool use_image_scale{ true };
bool use_image_scale_multi_thread{ true };
#ifdef _OPENMP
bool use_image_load_background_thread{ false };
......
This diff is collapsed.
......@@ -10,13 +10,17 @@
namespace ygo {
class ImageManager {
private:
void resizeImage(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
irr::video::ITexture* addTexture(const char* name, irr::video::IImage* srcimg, irr::s32 width, irr::s32 height);
public:
bool Initial();
void SetDevice(irr::IrrlichtDevice* dev);
void ClearTexture();
void RemoveTexture(int code);
void ResizeTexture();
irr::video::ITexture* GetTextureFromFile(const char* file, irr::s32 width, irr::s32 height);
irr::video::IImage* GetImage(int code);
irr::video::ITexture* GetTexture(int code, irr::s32 width, irr::s32 height);
irr::video::ITexture* GetTexture(int code, bool fit = false);
irr::video::ITexture* GetBigPicture(int code, float zoom);
irr::video::ITexture* GetTextureThumb(int code);
......
#include "image_resizer.h"
#include <cmath>
#ifdef _OPENMP
#include <omp.h>
#endif
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
#include "stb_image_resize2.h"
namespace ygo {
ImageResizer imageResizer;
struct StbSamplerCache {
STBIR_RESIZE resize{};
int in_w = 0;
int in_h = 0;
int out_w = 0;
int out_h = 0;
stbir_pixel_layout layout = STBIR_BGRA;
bool samplers_built = false;
~StbSamplerCache() {
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
}
void reset_if_needed(int new_in_w, int new_in_h, int new_out_w, int new_out_h, stbir_pixel_layout new_layout) {
if(new_in_w == in_w && new_in_h == in_h && new_out_w == out_w && new_out_h == out_h && new_layout == layout)
return;
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
in_w = new_in_w;
in_h = new_in_h;
out_w = new_out_w;
out_h = new_out_h;
layout = new_layout;
resize = STBIR_RESIZE{};
}
};
/**
* Scale image using stb_image_resize2.
* Returns true on success, false on failure or unsupported format.
*/
bool ImageResizer::imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest) {
if(!src || !dest)
return false;
const auto srcDim = src->getDimension();
const auto destDim = dest->getDimension();
if(srcDim.Width == 0 || srcDim.Height == 0 || destDim.Width == 0 || destDim.Height == 0)
return false;
if(src->getColorFormat() != dest->getColorFormat())
return false;
stbir_pixel_layout layout = STBIR_BGRA;
// Fast-paths (8-bit per channel only):
// - ECF_A8R8G8B8: Irrlicht stores as BGRA in memory on little-endian.
// - ECF_R8G8B8: common for JPEGs (3 channels).
switch(src->getColorFormat()) {
case irr::video::ECF_A8R8G8B8:
layout = STBIR_BGRA;
break;
case irr::video::ECF_R8G8B8:
layout = STBIR_RGB;
break;
default:
return false;
}
void* srcPtr = src->lock();
if(!srcPtr)
return false;
void* destPtr = dest->lock();
if(!destPtr) {
src->unlock();
return false;
}
const int srcStride = (int)src->getPitch();
const int destStride = (int)dest->getPitch();
thread_local StbSamplerCache cache;
cache.reset_if_needed((int)srcDim.Width, (int)srcDim.Height, (int)destDim.Width, (int)destDim.Height, layout);
if(!cache.samplers_built) {
stbir_resize_init(&cache.resize,
srcPtr, (int)srcDim.Width, (int)srcDim.Height, srcStride,
destPtr, (int)destDim.Width, (int)destDim.Height, destStride,
layout, STBIR_TYPE_UINT8);
stbir_set_edgemodes(&cache.resize, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP);
// Use box filters to reduce aliasing when downscaling.
stbir_set_filters(&cache.resize, STBIR_FILTER_BOX, STBIR_FILTER_BOX);
cache.samplers_built = (stbir_build_samplers(&cache.resize) != 0);
if(!cache.samplers_built) {
dest->unlock();
src->unlock();
return false;
}
} else {
// Reuse samplers but update buffer pointers for the current images
stbir_set_buffer_ptrs(&cache.resize, srcPtr, srcStride, destPtr, destStride);
}
const int ok = stbir_resize_extended(&cache.resize);
dest->unlock();
src->unlock();
return ok != 0;
}
/**
* Scale image using nearest neighbor anti-aliasing.
* Function by Warr1024, from https://github.com/minetest/minetest/issues/2419, modified.
*/
void ImageResizer::imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
const auto& srcDim = src->getDimension();
const auto& destDim = dest->getDimension();
if (destDim.Width == 0 || destDim.Height == 0)
return;
// Cache scale ratios.
const double rx = (double)srcDim.Width / destDim.Width;
const double ry = (double)srcDim.Height / destDim.Height;
#pragma omp parallel if(use_threading)
{
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < (irr::s32)destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < (irr::s32)destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds.
double minsx = dx * rx;
double maxsx = minsx + rx;
double minsy = dy * ry;
double maxsy = minsy + ry;
irr::u32 sx_begin = (irr::u32)std::floor(minsx);
irr::u32 sx_end = (irr::u32)std::ceil(maxsx);
if (sx_end > srcDim.Width)
sx_end = srcDim.Width;
irr::u32 sy_begin = (irr::u32)std::floor(minsy);
irr::u32 sy_end = (irr::u32)std::ceil(maxsy);
if (sy_end > srcDim.Height)
sy_end = srcDim.Height;
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.
double area = 0, ra = 0, ga = 0, ba = 0, aa = 0;
irr::video::SColor pxl, npxl;
// Loop over the integral pixel positions described by those bounds.
for(irr::u32 sy = sy_begin; sy < sy_end; sy++) {
for(irr::u32 sx = sx_begin; sx < sx_end; sx++) {
// Calculate width, height, then area of dest pixel
// that's covered by this source pixel.
double pw = 1;
if(minsx > sx)
pw += sx - minsx;
if(maxsx < (sx + 1))
pw += maxsx - sx - 1;
double ph = 1;
if(minsy > sy)
ph += sy - minsy;
if(maxsy < (sy + 1))
ph += maxsy - sy - 1;
double pa = pw * ph;
// Get source pixel and add it to totals, weighted
// by covered area and alpha.
pxl = src->getPixel(sx, sy);
area += pa;
ra += pa * pxl.getRed();
ga += pa * pxl.getGreen();
ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha();
}
}
// Set the destination image pixel to the average color.
if(area > 0) {
npxl.set((irr::u32)(aa / area + 0.5),
(irr::u32)(ra / area + 0.5),
(irr::u32)(ga / area + 0.5),
(irr::u32)(ba / area + 0.5));
} else {
npxl.set(0);
}
dest->setPixel(dx, dy, npxl);
}
}
} // end of parallel region
}
void ImageResizer::resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
if(imageScaleSTB(src, dest))
return;
imageScaleNNAA(src, dest, use_threading);
}
} // namespace ygo
#ifndef IMAGE_RESIZER_H
#define IMAGE_RESIZER_H
#include <irrlicht.h>
namespace ygo {
class ImageResizer {
private:
bool imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest);
void imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
public:
void resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
};
extern ImageResizer imageResizer;
} // namespace ygo
#endif // IMAGE_RESIZER_H
......@@ -15,17 +15,7 @@ namespace ygo {
void UpdateDeck() {
BufferIO::CopyWideString(mainGame->cbCategorySelect->getText(), mainGame->gameConf.lastcategory);
BufferIO::CopyWideString(mainGame->cbDeckSelect->getText(), mainGame->gameConf.lastdeck);
unsigned char deckbuf[1024]{};
auto pdeck = deckbuf;
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.main.size() + deckManager.current_deck.extra.size()));
BufferIO::Write<int32_t>(pdeck, static_cast<int32_t>(deckManager.current_deck.side.size()));
for(size_t i = 0; i < deckManager.current_deck.main.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.main[i]->first);
for(size_t i = 0; i < deckManager.current_deck.extra.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.extra[i]->first);
for(size_t i = 0; i < deckManager.current_deck.side.size(); ++i)
BufferIO::Write<uint32_t>(pdeck, deckManager.current_deck.side[i]->first);
DuelClient::SendBufferToServer(CTOS_UPDATE_DECK, deckbuf, pdeck - deckbuf);
DuelClient::SendUpdateDeck(deckManager.current_deck);
}
bool MenuHandler::OnEvent(const irr::SEvent& event) {
if(mainGame->dField.OnCommonEvent(event))
......
......@@ -8,8 +8,10 @@
#ifndef _WIN32
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <string>
#endif
#ifdef _WIN32
......@@ -182,7 +184,7 @@ public:
bool success = true;
TraversalDir(dir, [dir, &success](const char *name, bool isdir) {
char full_path[1024];
int len = mysnprintf(full_path, "%s/%s", dir, name);
int len = std::snprintf(full_path, sizeof(full_path), "%s/%s", dir, name);
if (len < 0 || len >= (int)(sizeof full_path)) {
success = false;
return;
......@@ -228,7 +230,7 @@ public:
while((dirp = readdir(dir)) != nullptr) {
file_unit funit;
char fname[1024];
int len = mysnprintf(fname, "%s/%s", path, dirp->d_name);
int len = std::snprintf(fname, sizeof(fname), "%s/%s", path, dirp->d_name);
if (len < 0 || len >= (int)(sizeof fname))
continue;
stat(fname, &fileStat);
......
......@@ -172,14 +172,14 @@ constexpr int LEN_CHAT_PLAYER = 1;
constexpr int LEN_CHAT_MSG = 256;
constexpr int SIZE_STOC_CHAT = (LEN_CHAT_PLAYER + LEN_CHAT_MSG) * sizeof(uint16_t);
#pragma pack(push, 1)
struct STOC_HS_PlayerEnter {
uint16_t name[20]{};
uint8_t pos{};
// byte padding[1]
};
#pragma pack(pop)
check_trivially_copyable(STOC_HS_PlayerEnter);
//static_assert(sizeof(STOC_HS_PlayerEnter) == 42, "size mismatch: STOC_HS_PlayerEnter");
constexpr int STOC_HS_PlayerEnter_size = 41; //workwround
static_assert(sizeof(STOC_HS_PlayerEnter) == 41, "size mismatch: STOC_HS_PlayerEnter");
struct STOC_HS_PlayerChange {
//pos<<4 | state
......
......@@ -88,143 +88,142 @@ void SoundManager::PlaySoundEffect(int sound) {
#ifdef YGOPRO_USE_AUDIO
if(!mainGame->chkEnableSound->isChecked())
return;
char soundName[32];
std::string soundName;
switch(sound) {
case SOUND_SUMMON: {
strcpy(soundName, "summon");
soundName = "summon";
break;
}
case SOUND_SPECIAL_SUMMON: {
strcpy(soundName, "specialsummon");
soundName = "specialsummon";
break;
}
case SOUND_ACTIVATE: {
strcpy(soundName, "activate");
soundName = "activate";
break;
}
case SOUND_SET: {
strcpy(soundName, "set");
soundName = "set";
break;
}
case SOUND_FILP: {
strcpy(soundName, "flip");
case SOUND_FLIP: {
soundName = "flip";
break;
}
case SOUND_REVEAL: {
strcpy(soundName, "reveal");
soundName = "reveal";
break;
}
case SOUND_EQUIP: {
strcpy(soundName, "equip");
soundName = "equip";
break;
}
case SOUND_DESTROYED: {
strcpy(soundName, "destroyed");
soundName = "destroyed";
break;
}
case SOUND_BANISHED: {
strcpy(soundName, "banished");
soundName = "banished";
break;
}
case SOUND_TOKEN: {
strcpy(soundName, "token");
soundName = "token";
break;
}
case SOUND_NEGATE: {
strcpy(soundName, "negate");
soundName = "negate";
break;
}
case SOUND_ATTACK: {
strcpy(soundName, "attack");
soundName = "attack";
break;
}
case SOUND_DIRECT_ATTACK: {
strcpy(soundName, "directattack");
soundName = "directattack";
break;
}
case SOUND_DRAW: {
strcpy(soundName, "draw");
soundName = "draw";
break;
}
case SOUND_SHUFFLE: {
strcpy(soundName, "shuffle");
soundName = "shuffle";
break;
}
case SOUND_DAMAGE: {
strcpy(soundName, "damage");
soundName = "damage";
break;
}
case SOUND_RECOVER: {
strcpy(soundName, "gainlp");
soundName = "gainlp";
break;
}
case SOUND_COUNTER_ADD: {
strcpy(soundName, "addcounter");
soundName = "addcounter";
break;
}
case SOUND_COUNTER_REMOVE: {
strcpy(soundName, "removecounter");
soundName = "removecounter";
break;
}
case SOUND_COIN: {
strcpy(soundName, "coinflip");
soundName = "coinflip";
break;
}
case SOUND_DICE: {
strcpy(soundName, "diceroll");
soundName = "diceroll";
break;
}
case SOUND_NEXT_TURN: {
strcpy(soundName, "nextturn");
soundName = "nextturn";
break;
}
case SOUND_PHASE: {
strcpy(soundName, "phase");
soundName = "phase";
break;
}
case SOUND_MENU: {
strcpy(soundName, "menu");
soundName = "menu";
break;
}
case SOUND_BUTTON: {
strcpy(soundName, "button");
soundName = "button";
break;
}
case SOUND_INFO: {
strcpy(soundName, "info");
soundName = "info";
break;
}
case SOUND_QUESTION: {
strcpy(soundName, "question");
soundName = "question";
break;
}
case SOUND_CARD_PICK: {
strcpy(soundName, "cardpick");
soundName = "cardpick";
break;
}
case SOUND_CARD_DROP: {
strcpy(soundName, "carddrop");
soundName = "carddrop";
break;
}
case SOUND_PLAYER_ENTER: {
strcpy(soundName, "playerenter");
soundName = "playerenter";
break;
}
case SOUND_CHAT: {
strcpy(soundName, "chatmessage");
soundName = "chatmessage";
break;
}
default:
break;
return;
}
char soundPath[40];
mysnprintf(soundPath, "./sound/%s.wav", soundName);
std::string soundPath = "./sound/" + soundName + ".wav";
SetSoundVolume(mainGame->gameConf.sound_volume);
#ifdef YGOPRO_USE_MINIAUDIO
ma_engine_play_sound(&engineSound, soundPath, nullptr);
ma_engine_play_sound(&engineSound, soundPath.c_str(), nullptr);
#endif
#ifdef YGOPRO_USE_IRRKLANG
engineSound->play2D(soundPath);
engineSound->play2D(soundPath.c_str());
#endif
#endif // YGOPRO_USE_AUDIO
}
......
......@@ -54,7 +54,7 @@ extern SoundManager soundManager;
#define SOUND_SPECIAL_SUMMON 102
#define SOUND_ACTIVATE 103
#define SOUND_SET 104
#define SOUND_FILP 105
#define SOUND_FLIP 105
#define SOUND_REVEAL 106
#define SOUND_EQUIP 107
#define SOUND_DESTROYED 108
......
This diff is collapsed.
This diff is collapsed.
......@@ -671,6 +671,7 @@
!counter 0x70 盘子指示物
!counter 0x71 纠罪指示物
!counter 0x1072 少女指示物
!counter 0x73 T指示物
#setnames, using tab for comment
!setname 0x1 正义盟军 AOJ
!setname 0x2 次世代 ジェネクス
......@@ -832,7 +833,7 @@
!setname 0x106e 魔导书 魔導書
!setname 0x6f 英豪 ヒロイック
!setname 0x106f 英豪挑战者 HC
#setname 0x206f 英豪冠军 H-C
!setname 0x206f 英豪冠军 HC
!setname 0x70 先史遗产 先史遺産
!setname 0x71 魔偶甜点 マドルチェ
!setname 0x72 齿轮齿轮 ギアギア
......@@ -1278,3 +1279,6 @@
!setname 0x1d8 耀圣 エルフェンノーツ
!setname 0x1d9 磁力 マグネット
!setname 0x1da 世界末日 エンド・オブ・ザ・ワールド
!setname 0x1db 妖精传姬 妖精伝姫
!setname 0x1dc 道化一座 道化の一座
!setname 0x1dd GMX
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