Fixing minor bugs in texts, encoding, UI
This commit is contained in:
1 parent
79413e7319
commit
d4365728fe
87 files changed
+883
-404
No files matched your search
@@ -1,4 +1,4 @@
|
||||
#include "AudioPlayerAsync.h"
|
||||
#include "AudioPlayerAsync.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "BoneAnimatedModelNew.h"
|
||||
#include "BoneAnimatedModelNew.h"
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "render/Renderer.h"
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "Character.h"
|
||||
#include "Character.h"
|
||||
#include "render/TextRenderer.h"
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "CharacterState.h"
|
||||
#include "BoneAnimatedModelNew.h"
|
||||
#include "render/Renderer.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "CharacterState.h"
|
||||
#include "CharacterState.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
+9
-5
@@ -412,13 +412,15 @@ namespace ZL
|
||||
nlohmann::json root;
|
||||
gameState.save(root);
|
||||
const std::string path = "resources/config/start_state.json";
|
||||
/*
|
||||
std::ofstream file(path);
|
||||
if (file.is_open()) {
|
||||
file << root.dump(2);
|
||||
std::cout << "[reset] Saved initial state snapshot to " << path << std::endl;
|
||||
} else {
|
||||
std::cerr << "[reset] Could not open " << path << " for writing" << std::endl;
|
||||
}
|
||||
}*/
|
||||
saveJsonToFile(root, path);
|
||||
}
|
||||
|
||||
void Game::createLocations()
|
||||
@@ -1664,7 +1666,7 @@ namespace ZL
|
||||
SaveSlotInfo Game::readSlotInfo(int slot) const
|
||||
{
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::string content = ZL::readTextFile(path);
|
||||
std::string content = ZL::readSavedTextFile(path);
|
||||
if (content.empty()) return {};
|
||||
try {
|
||||
nlohmann::json root = nlohmann::json::parse(content);
|
||||
@@ -1683,18 +1685,20 @@ namespace ZL
|
||||
nlohmann::json root;
|
||||
gameState.save(root);
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::ofstream file(path);
|
||||
|
||||
/*std::ofstream file(path);
|
||||
if (file.is_open()) {
|
||||
file << root.dump(2);
|
||||
} else {
|
||||
std::cerr << "[save] Could not open " << path << " for writing" << std::endl;
|
||||
}
|
||||
}*/
|
||||
saveJsonToFile(root, path);
|
||||
}
|
||||
|
||||
void Game::loadGame(int slot)
|
||||
{
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::string content = ZL::readTextFile(path);
|
||||
std::string content = ZL::readSavedTextFile(path);
|
||||
if (content.empty()) {
|
||||
std::cerr << "[save] Save file not found or empty: " << path << std::endl;
|
||||
return;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "GameState.h"
|
||||
#include "GameState.h"
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "items/Item.h"
|
||||
#include "quest/QuestJournal.h"
|
||||
#include "Location.h"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
+54
-3
@@ -1,9 +1,16 @@
|
||||
#include "Localization.h"
|
||||
#include "Localization.h"
|
||||
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "utils/Utils.h"
|
||||
#include <iostream>
|
||||
|
||||
// Платформозависимые инклюды для детекции языка
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
namespace ZL {
|
||||
|
||||
Language g_currentLanguage = Language::Russian;
|
||||
@@ -55,8 +62,15 @@ std::string readLocalizedConfigFile(const std::string& basePath, const std::stri
|
||||
}
|
||||
|
||||
void loadLanguageSetting() {
|
||||
const std::string content = readTextFile("settings.json");
|
||||
if (content.empty()) return;
|
||||
const std::string content = readSavedTextFile("settings.json");
|
||||
|
||||
// Если файла настроек нет (content пустой), определяем язык системы и выходим
|
||||
if (content.empty()) {
|
||||
g_currentLanguage = detectSystemLanguage();
|
||||
std::cout << "[settings] No settings.json found. System language detected: "
|
||||
<< languageToCode(g_currentLanguage) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const nlohmann::json root = nlohmann::json::parse(content);
|
||||
@@ -68,4 +82,41 @@ void loadLanguageSetting() {
|
||||
}
|
||||
}
|
||||
|
||||
Language detectSystemLanguage() {
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// Получаем первые два символа языка из браузера (0 - English, 1 - Russian, -1 - другой)
|
||||
int res = EM_ASM_INT({
|
||||
var lang = (navigator.language || navigator.userLanguage || 'en').toLowerCase();
|
||||
if (lang.startsWith('ru')) return 1;
|
||||
if (lang.startsWith('en')) return 0;
|
||||
return -1;
|
||||
});
|
||||
if (res == 1) return Language::Russian;
|
||||
if (res == 0) return Language::English;
|
||||
|
||||
#elif defined(_WIN32)
|
||||
LANGID langId = GetUserDefaultUILanguage();
|
||||
WORD primaryLang = PRIMARYLANGID(langId);
|
||||
if (primaryLang == LANG_RUSSIAN) return Language::Russian;
|
||||
if (primaryLang == LANG_ENGLISH) return Language::English;
|
||||
|
||||
#else
|
||||
// Linux / SteamOS
|
||||
const char* langEnv = std::getenv("LC_ALL");
|
||||
if (!langEnv || *langEnv == '\0') {
|
||||
langEnv = std::getenv("LANG");
|
||||
}
|
||||
|
||||
if (langEnv && *langEnv != '\0') {
|
||||
std::string langStr(langEnv);
|
||||
// Ищем префиксы "ru" или "en" в начале строки (например, ru_RU.UTF-8)
|
||||
if (langStr.rfind("ru", 0) == 0) return Language::Russian;
|
||||
if (langStr.rfind("en", 0) == 0) return Language::English;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Дефолтный фоллбек, если язык системы не поддерживается игрой (например, немецкий)
|
||||
return Language::English;
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace ZL {
|
||||
@@ -29,4 +29,6 @@ std::string readLocalizedConfigFile(const std::string& basePath, const std::stri
|
||||
// location scripts start dialogues eagerly as soon as they're loaded.
|
||||
void loadLanguageSetting();
|
||||
|
||||
Language detectSystemLanguage();
|
||||
|
||||
} // namespace ZL
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
#include "Location.h"
|
||||
#include "Location.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include <iostream>
|
||||
@@ -20,11 +20,15 @@ namespace ZL
|
||||
{
|
||||
extern const char* CONST_ZIP_FILE;
|
||||
|
||||
|
||||
|
||||
static constexpr float CAMERA_FOV_Y = 1.0f / 1.5f;
|
||||
// How close the player needs to be to a peaceful NPC before the
|
||||
// on_npc_interact callback fires and the conversation begins.
|
||||
static constexpr float NPC_TALK_DISTANCE = 1.35f;
|
||||
|
||||
static constexpr float RENDER_DISTRANCE = 50.f;
|
||||
|
||||
static float distancePointToSegmentXZ(const Eigen::Vector3f& p,
|
||||
const Eigen::Vector3f& a,
|
||||
const Eigen::Vector3f& b)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "render/Renderer.h"
|
||||
#include "Environment.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "LocationEditor.h"
|
||||
#include "LocationEditor.h"
|
||||
#include "Location.h"
|
||||
#include "Character.h"
|
||||
#include "utils/Utils.h"
|
||||
@@ -415,6 +415,7 @@ namespace ZL
|
||||
}
|
||||
|
||||
const std::string filename = baseName + ".json";
|
||||
/*
|
||||
std::ofstream out(filename);
|
||||
if (out.is_open()) {
|
||||
out << j.dump(4);
|
||||
@@ -422,7 +423,8 @@ namespace ZL
|
||||
<< " interactive object(s) to " << filename << "\n";
|
||||
} else {
|
||||
std::cerr << "[IO_EDITOR] Failed to open " << filename << " for writing\n";
|
||||
}
|
||||
}*/
|
||||
saveJsonToFile(j, filename);
|
||||
}
|
||||
|
||||
void LocationEditor::saveAll()
|
||||
@@ -522,14 +524,15 @@ namespace ZL
|
||||
}
|
||||
|
||||
const std::string filename = baseName + ".json";
|
||||
std::ofstream out(filename);
|
||||
/*std::ofstream out(filename);
|
||||
if (out.is_open()) {
|
||||
out << j.dump(4);
|
||||
std::cout << "[GAME_EDITOR] Saved " << editorPlacedObjects.size()
|
||||
<< " object(s) to " << filename << "\n";
|
||||
} else {
|
||||
std::cerr << "[GAME_EDITOR] Failed to open " << filename << " for writing\n";
|
||||
}
|
||||
}*/
|
||||
saveJsonToFile(j, filename);
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "LocationState.h"
|
||||
#include "LocationState.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "ISaveable.h"
|
||||
|
||||
|
||||
+47
-13
@@ -1,4 +1,4 @@
|
||||
#include "MenuManager.h"
|
||||
#include "MenuManager.h"
|
||||
#include "Game.h"
|
||||
#include "Localization.h"
|
||||
#include "items/ItemRegistry.h"
|
||||
@@ -672,10 +672,16 @@ namespace ZL {
|
||||
const bool portrait = isPortraitMode();
|
||||
uiManager.pushMenuFromSavedRoot(portrait ? portraitInventoryListRoot : newInventoryRoot);
|
||||
|
||||
uiManager.setButtonCallback("inventoryExitButton", [this](const std::string&) {
|
||||
uiManager.setButtonCallback("inventoryExitButton2", [this](const std::string&) {
|
||||
closeInventory();
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("inventoryExitButton", [this](const std::string&) {
|
||||
closeInventory();
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("inventoryMain", [this](const std::string&) {});
|
||||
|
||||
const auto& items = inventory->getItems();
|
||||
const int maxSlots = 9;
|
||||
for (int i = 0; i < maxSlots; ++i) {
|
||||
@@ -772,6 +778,15 @@ namespace ZL {
|
||||
audioPlayer_.playSoundAsync("audio/656126__itsthegoodstuff__paging-through-book.ogg");
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("journalExitButton2", [this](const std::string&) {
|
||||
closeQuestJournal();
|
||||
audioPlayer_.playSoundAsync("audio/656126__itsthegoodstuff__paging-through-book.ogg");
|
||||
});
|
||||
|
||||
|
||||
uiManager.setButtonCallback("journalMain", [this](const std::string&) {});
|
||||
|
||||
|
||||
static const char* kItemNames[9] = {
|
||||
"item1name","item2name","item3name",
|
||||
"item4name","item5name","item6name",
|
||||
@@ -1576,6 +1591,14 @@ namespace ZL {
|
||||
audioPlayer_.playSoundAsync("audio/sound_bag001.ogg");
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("inventoryExitButton2", [this](const std::string&) {
|
||||
closePortraitInventoryItem();
|
||||
audioPlayer_.playSoundAsync("audio/sound_bag001.ogg");
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("inventoryMain", [this](const std::string&) {});
|
||||
|
||||
|
||||
const auto& item = items[index];
|
||||
|
||||
auto img = uiManager.findStaticImage("selectedItemPic");
|
||||
@@ -1604,6 +1627,15 @@ namespace ZL {
|
||||
audioPlayer_.playSoundAsync("audio/255571__stradie__flipping-paper.ogg");
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("journalItemExitButton2", [this](const std::string&) {
|
||||
closeQuestJournal();
|
||||
audioPlayer_.playSoundAsync("audio/656126__itsthegoodstuff__paging-through-book.ogg");
|
||||
});
|
||||
|
||||
|
||||
uiManager.setButtonCallback("journalMain", [this](const std::string&) {});
|
||||
|
||||
|
||||
Quest::QuestState* quest = gameState_.questJournal.findQuest(visibleQuestIds[index]);
|
||||
if (!quest) return;
|
||||
const auto& def = quest->definition;
|
||||
@@ -1665,6 +1697,13 @@ namespace ZL {
|
||||
uiManager.updateAllLayouts();
|
||||
refreshQuestJournalUi();
|
||||
}
|
||||
/*
|
||||
void MenuManager::closePortraitJournalItemCompletely() {
|
||||
journalMenuStackDepth_ = 1;
|
||||
uiManager.popMenu();
|
||||
uiManager.updateAllLayouts();
|
||||
refreshQuestJournalUi();
|
||||
}*/
|
||||
|
||||
void MenuManager::resetPhoneChatNodes() {
|
||||
static const char* kChatNodes[] = {
|
||||
@@ -2054,19 +2093,14 @@ namespace ZL {
|
||||
|
||||
void MenuManager::saveSettings() {
|
||||
nlohmann::json root;
|
||||
root["musicVolume"] = audioPlayer_.getMusicVolume();
|
||||
root["soundVolume"] = audioPlayer_.getSoundVolume();
|
||||
root["musicVolume"] = audioPlayer_.getMusicVolume();
|
||||
root["soundVolume"] = audioPlayer_.getSoundVolume();
|
||||
root["musicEnabled"] = audioPlayer_.isMusicEnabled();
|
||||
root["soundEnabled"] = audioPlayer_.isSoundEnabled();
|
||||
root["fullscreen"] = Environment::isFullscreen;
|
||||
root["language"] = ZL::languageToCode(ZL::g_currentLanguage);
|
||||
root["fullscreen"] = Environment::isFullscreen;
|
||||
root["language"] = ZL::languageToCode(ZL::g_currentLanguage);
|
||||
|
||||
std::ofstream file("settings.json");
|
||||
if (file.is_open()) {
|
||||
file << root.dump(2);
|
||||
} else {
|
||||
std::cerr << "[settings] Could not open settings.json for writing" << std::endl;
|
||||
}
|
||||
saveJsonToFile(root, "settings.json");
|
||||
}
|
||||
|
||||
void MenuManager::loadSettings() {
|
||||
@@ -2079,7 +2113,7 @@ namespace ZL {
|
||||
// loaded, before this function ever runs.
|
||||
ZL::loadLanguageSetting();
|
||||
|
||||
const std::string content = ZL::readTextFile("settings.json");
|
||||
const std::string content = ZL::readSavedTextFile("settings.json");
|
||||
if (content.empty()) return;
|
||||
try {
|
||||
const nlohmann::json root = nlohmann::json::parse(content);
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "render/Renderer.h"
|
||||
#include "Environment.h"
|
||||
#include "render/TextureManager.h"
|
||||
@@ -164,6 +164,7 @@ namespace ZL {
|
||||
void closePortraitInventoryItem();
|
||||
void openPortraitQuestJournalItem(int index);
|
||||
void closePortraitJournalItem();
|
||||
//void closePortraitJournalItemCompletely();
|
||||
|
||||
void showAboutScreen();
|
||||
void showSettingsScreen();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ScriptEngine.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Game.h"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "TeleportZone.h"
|
||||
#include "TeleportZone.h"
|
||||
#include "render/Renderer.h"
|
||||
#include "render/TextureManager.h"
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <Eigen/Core>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "cutscene/CutsceneDatabase.h"
|
||||
#include "cutscene/CutsceneDatabase.h"
|
||||
|
||||
#include "utils/Utils.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/CutsceneTypes.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "cutscene/CutsceneOverlay.h"
|
||||
#include "cutscene/CutsceneOverlay.h"
|
||||
#include "dialogue/DialogueTypes.h"
|
||||
|
||||
#include "Environment.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/CutsceneTypes.h"
|
||||
#include "dialogue/DialogueTypes.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "cutscene/CutsceneRuntime.h"
|
||||
#include "cutscene/CutsceneRuntime.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/CutsceneDatabase.h"
|
||||
#include "dialogue/DialogueTypes.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogue/DialogueDatabase.h"
|
||||
#include "dialogue/DialogueDatabase.h"
|
||||
|
||||
#include "utils/Utils.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "dialogue/DialogueTypes.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogue/DialogueOverlay.h"
|
||||
#include "dialogue/DialogueOverlay.h"
|
||||
#include "dialogue/DialogueTypes.h"
|
||||
|
||||
#include "GameConstants.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "dialogue/DialogueRuntime.h"
|
||||
#include "render/Renderer.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogue/DialogueRuntime.h"
|
||||
#include "dialogue/DialogueRuntime.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "dialogue/DialogueDatabase.h"
|
||||
#include "dialogue/TranslationDatabase.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogue/DialogueSystem.h"
|
||||
#include "dialogue/DialogueSystem.h"
|
||||
|
||||
namespace ZL::Dialogue {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "dialogue/DialogueOverlay.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/CutsceneTypes.h"
|
||||
#include <string>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogue/TranslationDatabase.h"
|
||||
#include "dialogue/TranslationDatabase.h"
|
||||
|
||||
#include "utils/Utils.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Localization.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "GameObjectLoader.h"
|
||||
#include "GameObjectLoader.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "InteractiveObject.h"
|
||||
#include "InteractiveObject.h"
|
||||
#include "render/Renderer.h"
|
||||
#include "render/TextureManager.h"
|
||||
#include "../TextModel.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "Item.h"
|
||||
#include "Item.h"
|
||||
#include "ItemRegistry.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ItemRegistry.h"
|
||||
#include "ItemRegistry.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "Localization.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "Item.h"
|
||||
|
||||
+3
-1
@@ -132,6 +132,8 @@ int main(int argc, char* argv[]) {
|
||||
// since we now handle SDL_FINGERDOWN directly for multi-touch support.
|
||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||
|
||||
ZL::emscriptenInitFileSystem();
|
||||
|
||||
emscripten_set_main_loop(MainLoop, 0, 1);
|
||||
|
||||
|
||||
@@ -252,7 +254,7 @@ int main(int argc, char *argv[]) {
|
||||
// window, so it opens directly in the right mode instead of flashing
|
||||
// windowed -> fullscreen once settings are loaded later during setupPart2().
|
||||
{
|
||||
const std::string settingsContent = ZL::readTextFile("settings.json");
|
||||
const std::string settingsContent = ZL::readSavedTextFile("settings.json");
|
||||
if (!settingsContent.empty()) {
|
||||
try {
|
||||
const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "navigation/PathFinder.h"
|
||||
#include "navigation/PathFinder.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "utils/Utils.h"
|
||||
#include <algorithm>
|
||||
@@ -584,16 +584,20 @@ bool PathFinder::saveConfig(const std::string& path) const
|
||||
}
|
||||
root["obstacles"] = obstArr;
|
||||
|
||||
/*
|
||||
std::ofstream f(path);
|
||||
if (!f.is_open()) {
|
||||
return false;
|
||||
}
|
||||
f << root.dump(2);
|
||||
return f.good();
|
||||
return f.good();*/
|
||||
|
||||
return saveJsonToFile(root, path);
|
||||
}
|
||||
|
||||
bool PathFinder::saveGrid(const std::string& path) const
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (!ready) return false;
|
||||
std::ofstream f(path);
|
||||
if (!f.is_open()) return false;
|
||||
@@ -615,6 +619,9 @@ bool PathFinder::saveGrid(const std::string& path) const
|
||||
f << '\n';
|
||||
}
|
||||
return f.good();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PathFinder::loadGrid(const std::string& path, const std::string& zipPath)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "render/Renderer.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "quest/QuestJournal.h"
|
||||
#include "quest/QuestJournal.h"
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "utils/Utils.h"
|
||||
#include "Localization.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "quest/QuestTypes.h"
|
||||
#include "ISaveable.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include "utils/Utils.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ShadowMap.h"
|
||||
#include "ShadowMap.h"
|
||||
#include "Environment.h"
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "render/Renderer.h"
|
||||
#include "UiManager.h"
|
||||
|
||||
+228
-85
@@ -16,126 +16,133 @@
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
std::string readTextFile(const std::string &filename) {
|
||||
std::string readTextFile(const std::string& filename) {
|
||||
#ifdef __ANDROID__
|
||||
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
||||
if (!file) {
|
||||
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
||||
if (!file) {
|
||||
#ifdef DEBUG
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Utils",
|
||||
"Failed to open: %s", filename.c_str());
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Utils",
|
||||
"Failed to open: %s", filename.c_str());
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Sint64 size = SDL_RWsize(file);
|
||||
if (size <= 0) {
|
||||
SDL_RWclose(file);
|
||||
return "";
|
||||
}
|
||||
Sint64 size = SDL_RWsize(file);
|
||||
if (size <= 0) {
|
||||
SDL_RWclose(file);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string content(size, '\0');
|
||||
if (SDL_RWread(file, &content[0], size, 1) != 1) {
|
||||
SDL_RWclose(file);
|
||||
return "";
|
||||
}
|
||||
std::string content(size, '\0');
|
||||
if (SDL_RWread(file, &content[0], size, 1) != 1) {
|
||||
SDL_RWclose(file);
|
||||
return "";
|
||||
}
|
||||
|
||||
SDL_RWclose(file);
|
||||
return content;
|
||||
SDL_RWclose(file);
|
||||
return content;
|
||||
#else
|
||||
std::ifstream f(filename);
|
||||
if (!f.is_open()) {
|
||||
return "";
|
||||
}
|
||||
return std::string((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
std::ifstream f(filename);
|
||||
if (!f.is_open()) {
|
||||
return "";
|
||||
}
|
||||
return std::string((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> readFile(const std::string &filename) {
|
||||
std::vector<char> readFile(const std::string& filename) {
|
||||
#ifdef __ANDROID__
|
||||
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Sint64 size = SDL_RWsize(file);
|
||||
if (size <= 0) {
|
||||
SDL_RWclose(file);
|
||||
return {};
|
||||
}
|
||||
Sint64 size = SDL_RWsize(file);
|
||||
if (size <= 0) {
|
||||
SDL_RWclose(file);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<char> data(size);
|
||||
if (SDL_RWread(file, data.data(), size, 1) != 1) {
|
||||
SDL_RWclose(file);
|
||||
return {};
|
||||
}
|
||||
std::vector<char> data(size);
|
||||
if (SDL_RWread(file, data.data(), size, 1) != 1) {
|
||||
SDL_RWclose(file);
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_RWclose(file);
|
||||
return data;
|
||||
SDL_RWclose(file);
|
||||
return data;
|
||||
#else
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize size = file.tellg();
|
||||
if (size <= 0) {
|
||||
return {};
|
||||
}
|
||||
std::streamsize size = file.tellg();
|
||||
if (size <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<char> buffer(size);
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<char> buffer(size);
|
||||
|
||||
if (!file.read(buffer.data(), size)) {
|
||||
return {};
|
||||
}
|
||||
if (!file.read(buffer.data(), size)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> readFileFromZIP(const std::string& filename, const std::string& zipfilename) {
|
||||
#ifdef EMSCRIPTEN
|
||||
int zipErr = 0;
|
||||
zip_t* archive = zip_open(zipfilename.c_str(), ZIP_RDONLY, &zipErr);
|
||||
if (!archive) {
|
||||
int zipErr = 0;
|
||||
zip_t* archive = zip_open(zipfilename.c_str(), ZIP_RDONLY, &zipErr);
|
||||
if (!archive) {
|
||||
std::cout << "Failed to open ZIP: " << zipfilename << " (error code " << zipErr << ")" << std::endl;
|
||||
throw std::runtime_error("Failed to open ZIP: " + zipfilename);
|
||||
}
|
||||
throw std::runtime_error("Failed to open ZIP: " + zipfilename);
|
||||
}
|
||||
|
||||
std::string cleanFilename = filename;
|
||||
if (cleanFilename.rfind("./", 0) == 0) cleanFilename = cleanFilename.substr(2);
|
||||
std::string cleanFilename = filename;
|
||||
if (cleanFilename.rfind("./", 0) == 0) cleanFilename = cleanFilename.substr(2);
|
||||
|
||||
zip_stat_t fileStat;
|
||||
zip_stat_init(&fileStat);
|
||||
if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0 || !(fileStat.valid & ZIP_STAT_SIZE)) {
|
||||
zip_close(archive);
|
||||
zip_stat_t fileStat;
|
||||
zip_stat_init(&fileStat);
|
||||
if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0 || !(fileStat.valid & ZIP_STAT_SIZE)) {
|
||||
zip_close(archive);
|
||||
std::cout << "Failed to stat file in ZIP: " << cleanFilename << " in " << zipfilename << std::endl;
|
||||
throw std::runtime_error("Can't stat file in ZIP: " + cleanFilename);
|
||||
}
|
||||
throw std::runtime_error("Can't stat file in ZIP: " + cleanFilename);
|
||||
}
|
||||
|
||||
zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0);
|
||||
if (!zipFile) {
|
||||
zip_close(archive);
|
||||
zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0);
|
||||
if (!zipFile) {
|
||||
zip_close(archive);
|
||||
std::cout << "Failed to open file in ZIP: " << cleanFilename << std::endl;
|
||||
throw std::runtime_error("Can't open file in ZIP: " + cleanFilename);
|
||||
}
|
||||
throw std::runtime_error("Can't open file in ZIP: " + cleanFilename);
|
||||
}
|
||||
|
||||
std::vector<char> fileData(static_cast<size_t>(fileStat.size));
|
||||
zip_int64_t bytesRead = zip_fread(zipFile, fileData.data(), fileStat.size);
|
||||
std::vector<char> fileData(static_cast<size_t>(fileStat.size));
|
||||
zip_int64_t bytesRead = zip_fread(zipFile, fileData.data(), fileStat.size);
|
||||
|
||||
// Обязательно закрываем всё перед проверкой результата или throw
|
||||
zip_fclose(zipFile);
|
||||
zip_close(archive);
|
||||
// Обязательно закрываем всё перед проверкой результата или throw
|
||||
zip_fclose(zipFile);
|
||||
zip_close(archive);
|
||||
|
||||
if (bytesRead < 0 || static_cast<zip_uint64_t>(bytesRead) != fileStat.size) {
|
||||
if (bytesRead < 0 || static_cast<zip_uint64_t>(bytesRead) != fileStat.size) {
|
||||
std::cout << "Failed to read file from ZIP: " << cleanFilename << " (bytes read: " << bytesRead << ", expected: " << fileStat.size << ")" << std::endl;
|
||||
throw std::runtime_error("Error reading data from ZIP: " + cleanFilename);
|
||||
}
|
||||
throw std::runtime_error("Error reading data from ZIP: " + cleanFilename);
|
||||
}
|
||||
|
||||
return fileData;
|
||||
return fileData;
|
||||
#else
|
||||
|
||||
if (zipfilename.empty()) {
|
||||
@@ -205,4 +212,140 @@ namespace ZL
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveJsonToFile(const nlohmann::json& root, const std::string& filename) {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
try {
|
||||
fs::path dir = getSaveDirectory();
|
||||
fs::create_directories(dir);
|
||||
|
||||
fs::path filePath = dir / filename;
|
||||
std::ofstream file(filePath);
|
||||
|
||||
if (file.is_open()) {
|
||||
file << root.dump(2);
|
||||
file.close(); // Явно закрываем стрим перед синхронизацией
|
||||
|
||||
emscriptenSyncFs();
|
||||
|
||||
return file.good();
|
||||
}
|
||||
else {
|
||||
std::cerr << "[settings] Could not open " << filePath << " for writing" << std::endl;
|
||||
}
|
||||
}
|
||||
catch (const fs::filesystem_error& e) {
|
||||
std::cerr << "[settings] Filesystem error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::filesystem::path getSaveDirectory() {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
fs::path baseDir;
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// Для Web монтируем IDBFS обычно в локальную папку /offline или /home/webuser
|
||||
// Чтобы не усложнять иерархию в IndexedDB, можно использовать фиксированный корень
|
||||
baseDir = "/offline";
|
||||
#elif defined(_WIN32)
|
||||
wchar_t* appDataPath = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &appDataPath))) {
|
||||
baseDir = appDataPath;
|
||||
CoTaskMemFree(appDataPath);
|
||||
}
|
||||
else {
|
||||
const char* envAppData = std::getenv("APPDATA");
|
||||
baseDir = envAppData ? envAppData : fs::current_path();
|
||||
}
|
||||
#else
|
||||
const char* xdgConfig = std::getenv("XDG_CONFIG_HOME");
|
||||
if (xdgConfig && *xdgConfig != '\0') {
|
||||
baseDir = xdgConfig;
|
||||
}
|
||||
else {
|
||||
const char* home = std::getenv("HOME");
|
||||
baseDir = home ? fs::path(home) / ".config" : fs::current_path();
|
||||
}
|
||||
#endif
|
||||
|
||||
// На Web-платформе можно опустить имя разработчика, либо оставить для единообразия.
|
||||
// Если в EMSCRIPTEN монтируется `/offline`, структура останется чистой.
|
||||
return baseDir / "Fish Run Games" / "Shadow Over Bishkek Demo";
|
||||
}
|
||||
|
||||
std::string readSavedTextFile(const std::string& filename) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
try {
|
||||
fs::path dir = getSaveDirectory();
|
||||
fs::path filePath = dir / filename;
|
||||
|
||||
// Быстрая проверка: если файла вообще нет, сразу выходим
|
||||
if (!fs::exists(filePath)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::ifstream f(filePath, std::ios::in | std::ios::binary);
|
||||
if (!f.is_open()) {
|
||||
std::cerr << "[settings] Could not open " << filePath << " for reading" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Эффективное чтение всего файла в строку
|
||||
return std::string((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
catch (const fs::filesystem_error& e) {
|
||||
std::cerr << "[settings] Filesystem error during read: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void emscriptenSyncFs()
|
||||
{
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
EM_ASM({
|
||||
FS.syncfs(false, function(err) {
|
||||
if (err) {
|
||||
console.error("Failed to syncfs to IndexedDB:", err);
|
||||
}
|
||||
});
|
||||
});
|
||||
#endif
|
||||
//For other OS - do nothing
|
||||
}
|
||||
|
||||
void emscriptenInitFileSystem()
|
||||
{
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// 1. Создаем точку монтирования в памяти
|
||||
fs::create_directories("/offline");
|
||||
|
||||
// 2. Монтируем IDBFS в эту точку
|
||||
EM_ASM({
|
||||
FS.mount(IDBFS, {}, '/offline');
|
||||
|
||||
// 3. Синхронизируем из IndexedDB в VFS (true = из IDB в память)
|
||||
// Этот вызов асинхронный. Настройки станут доступны только после его завершения.
|
||||
FS.syncfs(true, function(err) {
|
||||
if (err) {
|
||||
console.error("Error loading filesystem from IndexedDB:", err);
|
||||
}
|
||||
else {
|
||||
console.log("IndexedDB successfully synced to VFS.");
|
||||
// Здесь при необходимости можно вызвать коллбэк в C++
|
||||
// для отложенной загрузки файла настроек, если это критично.
|
||||
}
|
||||
});
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
@@ -9,6 +9,12 @@
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "external/nlohmann/json.hpp"
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
std::string readTextFile(const std::string& filename);
|
||||
@@ -19,4 +25,14 @@ namespace ZL
|
||||
|
||||
bool findString(const char* in, char* list);
|
||||
|
||||
std::filesystem::path getSaveDirectory();
|
||||
|
||||
std::string readSavedTextFile(const std::string& filename);
|
||||
|
||||
void emscriptenSyncFs();
|
||||
|
||||
void emscriptenInitFileSystem();
|
||||
|
||||
bool saveJsonToFile(const nlohmann::json& root, const std::string& filename);
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user