diff --git a/proj-windows/CMakeLists.txt b/proj-windows/CMakeLists.txt index 019deba..bb85113 100644 --- a/proj-windows/CMakeLists.txt +++ b/proj-windows/CMakeLists.txt @@ -13,7 +13,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake) # =========================================== # Основной проект ShadowOverBishkekDemo # =========================================== -add_executable(ShadowOverBishkekDemo +add_executable(ShadowOverBishkekDemo WIN32 ../src/main.cpp ../src/Game.cpp ../src/Game.h @@ -124,7 +124,7 @@ set_target_properties(ShadowOverBishkekDemo PROPERTIES target_compile_definitions(ShadowOverBishkekDemo PRIVATE WIN32_LEAN_AND_MEAN PNG_ENABLED - SDL_MAIN_HANDLED +# SDL_MAIN_HANDLED # DEBUG_LIGHT # SHOW_PATH ) @@ -221,7 +221,7 @@ if (WIN32) add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..." - # Копируем SDL2 (целевое имя всегда SDL2.dll) + # Копируем SDL2 COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_SRC}" "${SDL2_DLL_DST}" diff --git a/src/AudioPlayerAsync.cpp b/src/AudioPlayerAsync.cpp index b259e11..5a265e4 100644 --- a/src/AudioPlayerAsync.cpp +++ b/src/AudioPlayerAsync.cpp @@ -1,5 +1,6 @@ #include "AudioPlayerAsync.h" #include +#include "utils/Utils.h" #ifdef __EMSCRIPTEN__ AudioPlayerAsync::AudioPlayerAsync() {} @@ -36,7 +37,7 @@ bool AudioPlayerAsync::init() { Mix_AllocateChannels(16); initialized = true; - std::cout << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl; + ZL::logger() << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl; return true; } @@ -60,7 +61,7 @@ void AudioPlayerAsync::shutdown() { Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); initialized = false; - std::cout << "AudioPlayerAsync shutdown" << std::endl; + ZL::logger() << "AudioPlayerAsync shutdown" << std::endl; } void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, int channel) { diff --git a/src/BoneAnimatedModelNew.cpp b/src/BoneAnimatedModelNew.cpp index 9d40b56..473fff1 100644 --- a/src/BoneAnimatedModelNew.cpp +++ b/src/BoneAnimatedModelNew.cpp @@ -37,7 +37,7 @@ namespace ZL } } - std::cout << "Bone name not found: " << name << std::endl; + logger() << "Bone name not found: " << name << std::endl; throw std::runtime_error("Bone name not found: " + name); return -1; @@ -435,7 +435,7 @@ namespace ZL meshNamesOrdered.push_back(meshName); } - std::cout << "Loaded " << numberMeshes << " meshes from " << fileName << std::endl; + logger() << "Loaded " << numberMeshes << " meshes from " << fileName << std::endl; // ---- Animation Keyframes ---- std::getline(f, tempLine); // === Animation Keyframes === @@ -509,7 +509,7 @@ namespace ZL if (startBones.size() > MAX_GPU_BONES) { - std::cout << "Warning: model has " << startBones.size() + logger() << "Warning: model has " << startBones.size() << " bones, exceeding GPU skinning limit of " << MAX_GPU_BONES << std::endl; } } @@ -706,7 +706,7 @@ namespace ZL if (startBones.size() > MAX_GPU_BONES) { - std::cout << "Warning: model has " << startBones.size() + logger() << "Warning: model has " << startBones.size() << " bones, exceeding GPU skinning limit of " << MAX_GPU_BONES << std::endl; } } @@ -736,7 +736,7 @@ namespace ZL if (startingKeyFrame == -1) { - std::cout << "Exception here: frame number is out of range of keyframes. Frame: " << frame << std::endl; + logger() << "Exception here: frame number is out of range of keyframes. Frame: " << frame << std::endl; throw std::runtime_error("Exception here"); } @@ -794,7 +794,7 @@ namespace ZL { if (md.verticesBoneWeight[i][j].boneIndex == -1) { - std::cout << "Exception here: bone index is -1 but weight is > 0" << std::endl; + logger() << "Exception here: bone index is -1 but weight is > 0" << std::endl; throw std::runtime_error("Bones loaded incorrectly - bone index is -1 but weight is > 0"); } vMoved = true; diff --git a/src/Character.cpp b/src/Character.cpp index cc48362..e870430 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -613,7 +613,7 @@ bool Character::prepareGpuSkinning() { void Character::tryAttackCombo() { - std::cout << "Try Attack Combo" << std::endl; + logger() << "Try Attack Combo" << std::endl; auto it = animations.find(state.currentState); if (it == animations.end()) return; @@ -622,7 +622,7 @@ void Character::tryAttackCombo() if (static_cast(anim.currentFrame) >= 20 && (state.currentState == AnimationState::ACTION_ATTACK || state.currentState == AnimationState::ACTION_ATTACK_2)) { - std::cout << "Try Attack Combo Success" << std::endl; + logger() << "Try Attack Combo Success" << std::endl; anim.currentFrame = anim.model.startingFrame; } } @@ -1234,7 +1234,7 @@ void Character::setupHitSparks(std::shared_ptr sparkTexture) { } void Character::applyDamage(float damageAmount, const Eigen::Vector3f& attackDirection, int attackerIndex) { - std::cout << "Character::applyDamage" << std::endl; + logger() << "Character::applyDamage" << std::endl; state.hp -= damageAmount; if (state.hp < 0) state.hp = 0; diff --git a/src/Character.h b/src/Character.h index f05e1de..711a7e3 100644 --- a/src/Character.h +++ b/src/Character.h @@ -116,7 +116,7 @@ public: std::string weaponAttachBoneName = "RightHand"; SparkEmitter hitSparkEmitter; - AudioPlayerAsync* audioPlayer; + AudioPlayerAsync* audioPlayer = nullptr; static Dialogue::TranslationDatabase nameTranslations; diff --git a/src/Environment.cpp b/src/Environment.cpp index d34b0f3..7363d0a 100644 --- a/src/Environment.cpp +++ b/src/Environment.cpp @@ -22,6 +22,7 @@ int Environment::width = CONST_DEFAULT_WIDTH; int Environment::height = CONST_DEFAULT_HEIGHT; float Environment::zoom = DEFAULT_ZOOM; +bool Environment::enableLogging = false; SDL_Window* Environment::window = nullptr; diff --git a/src/Environment.h b/src/Environment.h index 3e1a382..3594aad 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -31,6 +31,8 @@ public: static int height; static float zoom; + static bool enableLogging; + static Eigen::Matrix3f inverseShipMatrix; static SDL_Window* window; diff --git a/src/Game.cpp b/src/Game.cpp index 0b52bfa..8885e60 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -43,7 +43,7 @@ namespace ZL Game* Game::s_instance = nullptr; void Game::onResourcesZipLoaded(unsigned /*handle*/, void* /*userData*/, const char* /*filename*/) { - std::cout << "Resources.zip loaded successfully--0" << std::endl; + logger() << "Resources.zip loaded successfully--0" << std::endl; if (s_instance) { s_instance->resourcesDownloadProgress = 1.0f; // Builds the loadSteps queue (cheap, no GL work); the actual loading @@ -54,7 +54,7 @@ namespace ZL } void Game::onResourcesZipError(unsigned /*handle*/, void* /*userData*/, int /*httpStatus*/) { - std::cout << "Failed to download resources.zip" << std::endl; + logger() << "Failed to download resources.zip" << std::endl; } void Game::onResourcesZipProgress(unsigned /*handle*/, void* /*userData*/, int percentComplete) { @@ -134,7 +134,7 @@ namespace ZL // Asynchronously download resources.zip; setupPart2() is called on completion. // The loading screen stays visible until the download finishes. s_instance = this; - std::cout << "Load resurces step 1-" << std::endl; + logger() << "Load resurces step 1-" << std::endl; emscripten_async_wget2("resources.zip", "resources.zip", "GET", nullptr, nullptr, onResourcesZipLoaded, onResourcesZipError, onResourcesZipProgress); #else @@ -316,7 +316,7 @@ namespace ZL loadSteps.push([this]() { try { menuManager.setup(gameState.inventory, CONST_ZIP_FILE); - std::cout << "UI loaded successfully" << std::endl; + logger() << "UI loaded successfully" << std::endl; } catch (const std::exception& e) { std::cerr << "Failed to load UI: " << e.what() << std::endl; @@ -366,10 +366,10 @@ namespace ZL if (audioPlayer->init()) { audioPlayer->setMusicVolume(100); audioPlayer->setSoundVolume(80); - std::cout << "Audio initialized successfully" << std::endl; + logger() << "Audio initialized successfully" << std::endl; } else { - std::cout << "Audio initialization failed" << std::endl; + logger() << "Audio initialization failed" << std::endl; } }); @@ -480,12 +480,12 @@ namespace ZL nlohmann::json root; gameState.save(root); const std::string path = "start_state.json"; - std::cout << "[reset] saveInitialState called, to " << path << std::endl; + logger() << "[reset] saveInitialState called, to " << path << std::endl; std::ofstream file(path); if (file.is_open()) { file << root.dump(2); - std::cout << "[reset] Saved initial state snapshot to " << path << std::endl; + logger() << "[reset] Saved initial state snapshot to " << path << std::endl; } else { std::cerr << "[reset] Could not open " << path << " for writing" << std::endl; } @@ -796,7 +796,7 @@ namespace ZL // Teleport callbacks: destination name and position come from the teleport zone data. auto teleportCallback = [this](const std::string& destName, const Eigen::Vector3f& destPos, float destRotY) { - std::cout << "[TELEPORT] " << " -> " << destName << std::endl; + logger() << "[TELEPORT] " << " -> " << destName << std::endl; auto it = gameState.locations.find(destName); if (it == gameState.locations.end()) { std::cerr << "[TELEPORT] Unknown destination location: " << destName << std::endl; @@ -903,12 +903,12 @@ namespace ZL void Game::createShadowMapAndProparateToLocations() { if (shadowMap) { - std::cout << "Shadow map already exists, skipping creation" << std::endl; + logger() << "Shadow map already exists, skipping creation" << std::endl; return; } shadowMap = std::make_shared(2048, 40.0f, 0.1f, 100.0f); shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f)); - std::cout << "Shadow map initialized" << std::endl; + logger() << "Shadow map initialized" << std::endl; for (auto& [name, loc] : gameState.locations) { loc->shadowMap = shadowMap; @@ -1210,7 +1210,7 @@ namespace ZL menuManager.onOrientationChanged(); } - std::cout << "Window resized (Render Size): " << Environment::width << "x" << Environment::height << std::endl; + logger() << "Window resized (Render Size): " << Environment::width << "x" << Environment::height << std::endl; //space.clearTextRendererCache(); } @@ -1300,7 +1300,7 @@ namespace ZL if (Environment::zoom > zoomMax) { Environment::zoom = zoomMax; } - std::cout << "Current zoom: " << Environment::zoom << std::endl; + logger() << "Current zoom: " << Environment::zoom << std::endl; // Tutorial step3 → step4: any mouse-wheel scroll counts as "zoom gesture". if (gameState.tutorialStep == TutorialStep::Step3) { menuManager.advanceTutorialStep(); @@ -1345,7 +1345,7 @@ namespace ZL currentLocation()->editor.selectInteractiveObject(event.key.keysym.sym - SDLK_0); } else { currentLocation()->switchNavigation(event.key.keysym.sym - SDLK_0); - std::cout << "Switched to nav mesh " << (event.key.keysym.sym - SDLK_0) << std::endl; + logger() << "Switched to nav mesh " << (event.key.keysym.sym - SDLK_0) << std::endl; } break; case SDLK_f: @@ -1376,50 +1376,50 @@ namespace ZL const char* modeName = (editorMode == EditorMode::Navigation) ? "Navigation" : (editorMode == EditorMode::InteractiveObjects) ? "InteractiveObjects" : "None"; - std::cout << "[EDITOR] Mode: " << modeName << std::endl; + logger() << "[EDITOR] Mode: " << modeName << std::endl; } break; case SDLK_o: x = x + 0.05; - std::cout << "current x: " << x << std::endl; + logger() << "current x: " << x << std::endl; //y = y + 0.002; //currentLocation->player->hp = 200; //currentLocation->npcs[0]->walkSpeed += 0.01f; - //std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; + //logger() << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; break; case SDLK_k: x = x - 0.05; - std::cout << "current x: " << x << std::endl; - std::cout << "Player pos: " << currentLocation()->player->state.position.transpose() << std::endl; - std::cout << "Player rotation: " << currentLocation()->player->state.facingAngle*180.0/M_PI << std::endl; + logger() << "current x: " << x << std::endl; + logger() << "Player pos: " << currentLocation()->player->state.position.transpose() << std::endl; + logger() << "Player rotation: " << currentLocation()->player->state.facingAngle*180.0/M_PI << std::endl; //currentLocation->npcs[0]->walkSpeed -= 0.01f; - //std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; + //logger() << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; break; case SDLK_p: gameState.currentLocationName = "uni_interior"; currentLocation()->player->state.position = Eigen::Vector3f(-0.0189243, 0, -13.4314); currentLocation()->player->setTarget(currentLocation()->player->state.position); - //std::cout << "Switched to location " << ((currentLocation == locations["location1"]) ? "1" : "2") << std::endl; + //logger() << "Switched to location " << ((currentLocation == locations["location1"]) ? "1" : "2") << std::endl; break; case SDLK_l: //x = x - 1; - //std::cout << "current x: " << x << std::endl; - std::cout << "Azimuth: " << currentLocation()->state.cameraAzimuth << std::endl; - std::cout << "Inclination: " << currentLocation()->state.cameraInclination << std::endl; + //logger() << "current x: " << x << std::endl; + logger() << "Azimuth: " << currentLocation()->state.cameraAzimuth << std::endl; + logger() << "Inclination: " << currentLocation()->state.cameraInclination << std::endl; break; case SDLK_c: - std::cout << "SLOW-MO activated!" << std::endl; + logger() << "SLOW-MO activated!" << std::endl; activateSlowMoEffect(); break; case SDLK_i: y = y - 1; - std::cout << "current y: " << y << std::endl; + logger() << "current y: " << y << std::endl; break; case SDLK_b: @@ -1467,7 +1467,7 @@ namespace ZL if (event.type == SDL_KEYUP) { if (event.key.keysym.sym == SDLK_r) { - std::cout << "Camera position: x=" << x << " y=" << y << " z=" << z << std::endl; + logger() << "Camera position: x=" << x << " y=" << y << " z=" << z << std::endl; } } diff --git a/src/Localization.cpp b/src/Localization.cpp index 8427a18..9c55b04 100644 --- a/src/Localization.cpp +++ b/src/Localization.cpp @@ -67,7 +67,7 @@ void loadLanguageSetting() { // Если файла настроек нет (content пустой), определяем язык системы и выходим if (content.empty()) { g_currentLanguage = detectSystemLanguage(); - std::cout << "[settings] No settings.json found. System language detected: " + logger() << "[settings] No settings.json found. System language detected: " << languageToCode(g_currentLanguage) << std::endl; return; } diff --git a/src/Location.cpp b/src/Location.cpp index 74ddc98..ef6cf31 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -148,7 +148,7 @@ namespace ZL player->setTarget(params.playerPosition); player->setupHitSparks(sparkTexture); player->audioPlayer = audioPlayer; - std::cout << "Load resurces step 9" << std::endl; + logger() << "Load resurces step 9" << std::endl; SDL_PumpEvents(); // Load NPCs from JSON. Aggressive (canAttack) NPCs need a player target @@ -287,7 +287,7 @@ namespace ZL teleportZones.push_back(std::move(tz)); } - std::cout << "[TELEPORT] Loaded " << teleportZones.size() << " teleport(s) from " << jsonPath << std::endl; + logger() << "[TELEPORT] Loaded " << teleportZones.size() << " teleport(s) from " << jsonPath << std::endl; } @@ -338,7 +338,7 @@ namespace ZL } - std::cout << "[TRIGGER] Loaded " << triggerZones.size() << " trigger zone(s) from " << jsonPath << std::endl; + logger() << "[TRIGGER] Loaded " << triggerZones.size() << " trigger zone(s) from " << jsonPath << std::endl; } void Location::loadPointLights(const std::string& jsonPath, const char* zipFile) @@ -400,7 +400,7 @@ namespace ZL pointLights.push_back(std::move(pl)); } - std::cout << "[LIGHTS] Loaded " << pointLights.size() << " light(s) from " << jsonPath << std::endl; + logger() << "[LIGHTS] Loaded " << pointLights.size() << " light(s) from " << jsonPath << std::endl; } void Location::updateTriggerZones(const Eigen::Vector3f& playerPos) @@ -500,28 +500,28 @@ namespace ZL if (editorMode == EditorMode::Navigation) { editor.buildNavMeshes(); } - std::cout << "[NAV] Switched to navigation map " << index << "\n"; + logger() << "[NAV] Switched to navigation map " << index << "\n"; return true; } InteractiveObject* Location::raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir) { if (interactiveObjects.empty()) { - //std::cout << "[RAYCAST] No interactive objects to check" << std::endl; + //logger() << "[RAYCAST] No interactive objects to check" << std::endl; return nullptr; } - //std::cout << "[RAYCAST] Starting raycast with " << interactiveObjects.size() << " objects" << std::endl; - //std::cout << "[RAYCAST] Ray origin: (" << rayOrigin.x() << ", " << rayOrigin.y() << ", " << rayOrigin.z() << ")" << std::endl; - //std::cout << "[RAYCAST] Ray dir: (" << rayDir.x() << ", " << rayDir.y() << ", " << rayDir.z() << ")" << std::endl; + //logger() << "[RAYCAST] Starting raycast with " << interactiveObjects.size() << " objects" << std::endl; + //logger() << "[RAYCAST] Ray origin: (" << rayOrigin.x() << ", " << rayOrigin.y() << ", " << rayOrigin.z() << ")" << std::endl; + //logger() << "[RAYCAST] Ray dir: (" << rayDir.x() << ", " << rayDir.y() << ", " << rayDir.z() << ")" << std::endl; float closestDistance = FLT_MAX; InteractiveObject* closestObject = nullptr; for (auto& intObj : interactiveObjects) { - //std::cout << "[RAYCAST] Checking object: " << intObj.loadedObject.name << " (active: " << intObj.isActive << ")" << std::endl; + //logger() << "[RAYCAST] Checking object: " << intObj.loadedObject.name << " (active: " << intObj.isActive << ")" << std::endl; if (!intObj.state.isActive || intObj.state.isAnimating) { - //std::cout << "[RAYCAST] -> Object inactive or animating, skipping" << std::endl; + //logger() << "[RAYCAST] -> Object inactive or animating, skipping" << std::endl; continue; } @@ -531,7 +531,7 @@ namespace ZL if (!intObj.loadedObject.texture) continue; } - //std::cout << "[RAYCAST] Position: (" << intObj.position.x() << ", " << intObj.position.y() << ", " + //logger() << "[RAYCAST] Position: (" << intObj.position.x() << ", " << intObj.position.y() << ", " // << intObj.position.z() << "), Radius: " << intObj.interactionRadius << std::endl; const bool hasBox = !(intObj.state.boundsMin.isZero() && intObj.state.boundsMax.isZero()); @@ -581,10 +581,10 @@ namespace ZL } /* if (closestObject) { - std::cout << "[RAYCAST] *** RAYCAST SUCCESS: Found object " << closestObject->loadedObject.name << " ***" << std::endl; + logger() << "[RAYCAST] *** RAYCAST SUCCESS: Found object " << closestObject->loadedObject.name << " ***" << std::endl; } else { - std::cout << "[RAYCAST] No objects hit" << std::endl; + logger() << "[RAYCAST] No objects hit" << std::endl; } */ return closestObject; @@ -600,11 +600,11 @@ namespace ZL Character* closestNpc = nullptr; float closestDist = maxDistance; - //std::cout << "[RAYCAST_NPC] Starting raycast with " << npcs.size() << " npcs" << std::endl; + //logger() << "[RAYCAST_NPC] Starting raycast with " << npcs.size() << " npcs" << std::endl; for (auto& npc : npcs) { if (npc->getHp() <= 0.f) { - //std::cout << "[RAYCAST_NPC] " << npc->state.npcId << " is dead, skipping" << std::endl; + //logger() << "[RAYCAST_NPC] " << npc->state.npcId << " is dead, skipping" << std::endl; continue; } if (!npc->state.enabled) continue; @@ -640,7 +640,7 @@ namespace ZL if (entryT > exitT) continue; - //std::cout << "[RAYCAST_NPC] " << npc->npcId << " hit at t=" << entryT << std::endl; + //logger() << "[RAYCAST_NPC] " << npc->npcId << " hit at t=" << entryT << std::endl; if (entryT < closestDist) { closestDist = entryT; @@ -649,10 +649,10 @@ namespace ZL } if (closestNpc) { - //std::cout << "[RAYCAST_NPC] HIT: " << closestNpc->npcId << std::endl; + //logger() << "[RAYCAST_NPC] HIT: " << closestNpc->npcId << std::endl; } else { - //std::cout << "[RAYCAST_NPC] No NPC hit" << std::endl; + //logger() << "[RAYCAST_NPC] No NPC hit" << std::endl; } return closestNpc; @@ -1603,7 +1603,7 @@ namespace ZL if (npc->state.enabled && npc->state.canAttack && (!npc->state.pathWaypoints.empty() || npc->state.battle_state != 0) && npc->getHp() > 0.f) { - //std::cout << "[NPC] NPC '" << npc->state.npcId << "' is attacking target index " << npc->state.attackTargetIndex << std::endl; + //logger() << "[NPC] NPC '" << npc->state.npcId << "' is attacking target index " << npc->state.attackTargetIndex << std::endl; npcAttacking = true; } } @@ -1640,17 +1640,17 @@ namespace ZL // If player is close enough to pick up the item if (distToObject <= obj->state.approachRadius) { - std::cout << "[PICKUP] Player reached object! Distance: " << distToObject << std::endl; - std::cout << "[PICKUP] Calling Lua callback for: " << obj->loadedObject.name << std::endl; + logger() << "[PICKUP] Player reached object! Distance: " << distToObject << std::endl; + logger() << "[PICKUP] Calling Lua callback for: " << obj->loadedObject.name << std::endl; // Call custom activate function if specified, otherwise use fallback try { if (!obj->state.activateFunctionName.empty()) { - std::cout << "[PICKUP] Using custom function: " << obj->state.activateFunctionName << std::endl; + logger() << "[PICKUP] Using custom function: " << obj->state.activateFunctionName << std::endl; scriptEngine.callActivateFunction(obj->state.activateFunctionName); } else { - std::cout << "[PICKUP] Using fallback callback" << std::endl; + logger() << "[PICKUP] Using fallback callback" << std::endl; scriptEngine.callItemPickupCallback(obj->loadedObject.name); } } @@ -1666,7 +1666,7 @@ namespace ZL if (state.targetInteractNpcIndex >= 0 && player) { float distToNpc = (player->state.position - npcs[state.targetInteractNpcIndex]->state.position).norm(); if (distToNpc <= NPC_TALK_DISTANCE) { - std::cout << "[NPC] Player reached NPC index " << state.targetInteractNpcIndex + logger() << "[NPC] Player reached NPC index " << state.targetInteractNpcIndex << " (distance " << distToNpc << "); firing on_npc_interact" << std::endl; // Stop the player at the talk distance and have the NPC turn to face them. player->setTarget(player->state.position); @@ -1686,7 +1686,7 @@ namespace ZL if (auto* tz = getTargetTeleportZone(); tz && player) { float dist = (player->state.position - tz->position).norm(); if (dist <= tz->radius) { - std::cout << "[TELEPORT] Player reached teleport zone '" << tz->id << "'" << std::endl; + logger() << "[TELEPORT] Player reached teleport zone '" << tz->id << "'" << std::endl; if (onTeleport) onTeleport(tz->destinationLocation, tz->destinationPosition, tz->destinationRotationY); state.targetTeleportZoneIndex = -1; return; @@ -1710,7 +1710,7 @@ namespace ZL const bool isInside = (dist <= autoR); if (isInside && !tz.automaticPlayerInside) { tz.automaticPlayerInside = true; - std::cout << "[TELEPORT] Auto-teleport triggered by zone '" << tz.id << "'" << std::endl; + logger() << "[TELEPORT] Auto-teleport triggered by zone '" << tz.id << "'" << std::endl; if (onTeleport) onTeleport(tz.destinationLocation, tz.destinationPosition, tz.destinationRotationY); return; } else if (!isInside) { @@ -1743,10 +1743,10 @@ namespace ZL toTarget.y() = 0.f; if (toTarget.norm() < car.waypointReachRadius) { car.currentWaypoint = car.currentWaypoint + 1; - std::cout << "Waypoint current: " << car.currentWaypoint << std::endl; + logger() << "Waypoint current: " << car.currentWaypoint << std::endl; if (car.currentWaypoint == car.waypoints.size()) { - std::cout << "waypointsOver" << std::endl; + logger() << "waypointsOver" << std::endl; waypointsOver = true; } } @@ -1895,17 +1895,17 @@ namespace ZL return; } - std::cout << "[CLICK] Camera position: (" << camPos.x() << ", " << camPos.y() << ", " << camPos.z() << ")" << std::endl; - std::cout << "[CLICK] Ray direction: (" << rayDir.x() << ", " << rayDir.y() << ", " << rayDir.z() << ")" << std::endl; + //logger() << "[CLICK] Camera position: (" << camPos.x() << ", " << camPos.y() << ", " << camPos.z() << ")" << std::endl; + //logger() << "[CLICK] Ray direction: (" << rayDir.x() << ", " << rayDir.y() << ", " << rayDir.z() << ")" << std::endl; // First check if we clicked on interactive object InteractiveObject* clickedObject = raycastInteractiveObjects(camPos, rayDir); if (clickedObject && player && clickedObject->state.isActive) { - std::cout << "[CLICK] *** SUCCESS: Clicked on interactive object: " << clickedObject->loadedObject.name << " ***" << std::endl; - std::cout << "[CLICK] Object position: (" << clickedObject->state.position.x() << ", " - << clickedObject->state.position.y() << ", " << clickedObject->state.position.z() << ")" << std::endl; - std::cout << "[CLICK] Player position: (" << player->state.position.x() << ", " - << player->state.position.y() << ", " << player->state.position.z() << ")" << std::endl; + //logger() << "[CLICK] *** SUCCESS: Clicked on interactive object: " << clickedObject->loadedObject.name << " ***" << std::endl; + //logger() << "[CLICK] Object position: (" << clickedObject->state.position.x() << ", " + // << clickedObject->state.position.y() << ", " << clickedObject->state.position.z() << ")" << std::endl; + //logger() << "[CLICK] Player position: (" << player->state.position.x() << ", " + // << player->state.position.y() << ", " << player->state.position.z() << ")" << std::endl; state.targetInteractiveObjectIndex = findInteractiveObjectIndex(clickedObject); state.targetInteractNpcIndex = -1; @@ -1914,11 +1914,11 @@ namespace ZL ? clickedObject->state.interactionPosition : clickedObject->state.position); player->state.attackTargetIndex = CharacterState::kNoTarget; - std::cout << "[CLICK] Player moving to object..." << std::endl; + //logger() << "[CLICK] Player moving to object..." << std::endl; } else { - //std::cout << "Raycast npc step 1" << std::endl; + //logger() << "Raycast npc step 1" << std::endl; // Check if we clicked on an NPC Character* clickedNpc = raycastNpcs(camPos, rayDir); if (clickedNpc && player) { @@ -1931,25 +1931,25 @@ namespace ZL } } if (npcIndex != -1) { - //std::cout << "Raycast npc step 2" << std::endl; + //logger() << "Raycast npc step 2" << std::endl; state.targetInteractiveObjectIndex = -1; state.targetTeleportZoneIndex = -1; if (clickedNpc->state.canAttack) { - //std::cout << "Raycast npc step 3" << std::endl; - //std::cout << "player->state.attackTargetIndex=" << player->state.attackTargetIndex << std::endl; - //std::cout << "npcIndex=" << npcIndex << std::endl; + //logger() << "Raycast npc step 3" << std::endl; + //logger() << "player->state.attackTargetIndex=" << player->state.attackTargetIndex << std::endl; + //logger() << "npcIndex=" << npcIndex << std::endl; // Hostile NPC: combat logic walks the player in via attackTargetIndex. if (lastPlayerAttackTarget == npcIndex) { - //std::cout << "Raycast npc step 4" << std::endl; + //logger() << "Raycast npc step 4" << std::endl; player->tryAttackCombo(); } player->state.attackTargetIndex = npcIndex; state.targetInteractNpcIndex = -1; if (distance <= clickedNpc->state.interactionRadius) { - std::cout << "[CLICK] Hostile NPC " << npcIndex << " in range; firing on_npc_interact" << std::endl; + //logger() << "[CLICK] Hostile NPC " << npcIndex << " in range; firing on_npc_interact" << std::endl; scriptEngine.callNpcInteractCallback(npcIndex); } } @@ -1959,15 +1959,15 @@ namespace ZL if (distance <= NPC_TALK_DISTANCE) { // Already in talk range — fire immediately, stop, and face the player. - std::cout << "[CLICK] *** SUCCESS: Clicked on NPC index: " << npcIndex << " (in range) ***" << std::endl; + //logger() << "[CLICK] *** SUCCESS: Clicked on NPC index: " << npcIndex << " (in range) ***" << std::endl; player->setTarget(player->state.position); npcs[npcIndex]->state.faceTargetIndex = CharacterState::kPlayerIndex; scriptEngine.callNpcInteractCallback(npcIndex); state.targetInteractNpcIndex = -1; } else { - std::cout << "[CLICK] NPC " << npcIndex << " out of talk range (distance " << distance - << " > " << NPC_TALK_DISTANCE << "); walking to NPC..." << std::endl; + //logger() << "[CLICK] NPC " << npcIndex << " out of talk range (distance " << distance + // << " > " << NPC_TALK_DISTANCE << "); walking to NPC..." << std::endl; player->setTarget(clickedNpc->state.position); state.targetInteractNpcIndex = npcIndex; } @@ -1979,7 +1979,7 @@ namespace ZL // Unproject click to ground plane for walk target / teleport detection float t = -camPos.y() / rayDir.y(); Eigen::Vector3f hit = camPos + rayDir * t; - std::cout << "[CLICK] Clicked on ground at: (" << hit.x() << ", " << hit.z() << ")" << std::endl; + //logger() << "[CLICK] Clicked on ground at: (" << hit.x() << ", " << hit.z() << ")" << std::endl; TeleportZone* clickedTeleport = nullptr; for (auto& tz : teleportZones) { @@ -1989,7 +1989,7 @@ namespace ZL } if (clickedTeleport) { - std::cout << "[CLICK] Clicked teleport zone '" << clickedTeleport->id << "'" << std::endl; + //logger() << "[CLICK] Clicked teleport zone '" << clickedTeleport->id << "'" << std::endl; state.targetTeleportZoneIndex = findTeleportZoneIndex(clickedTeleport); state.targetInteractiveObjectIndex = -1; state.targetInteractNpcIndex = -1; @@ -2004,10 +2004,10 @@ namespace ZL } } else { - std::cout << "[CLICK] No valid target found" << std::endl; + //logger() << "[CLICK] No valid target found" << std::endl; } } - std::cout << "========================================\n" << std::endl; + //logger() << "========================================\n" << std::endl; } void Location::handleUp(int64_t fingerId, int mx, int my) { diff --git a/src/LocationEditor.cpp b/src/LocationEditor.cpp index 859a920..22db74a 100644 --- a/src/LocationEditor.cpp +++ b/src/LocationEditor.cpp @@ -91,15 +91,15 @@ namespace ZL if (dx * dx + dz * dz <= removeRadius * removeRadius) { navigationEditorPoints.erase(it); rebuildPointsMesh(); - std::cout << "[NAV_EDITOR] Removed point, " << navigationEditorPoints.size() << " remaining\n"; + logger() << "[NAV_EDITOR] Removed point, " << navigationEditorPoints.size() << " remaining\n"; return; } } - std::cout << "[NAV_EDITOR] No point found within " << removeRadius << " units of click\n"; + logger() << "[NAV_EDITOR] No point found within " << removeRadius << " units of click\n"; } else { navigationEditorPoints.push_back(hit); rebuildPointsMesh(); - std::cout << "[NAV_EDITOR] Added point (" << hit.x() << ", " << hit.z() + logger() << "[NAV_EDITOR] Added point (" << hit.x() << ", " << hit.z() << "), total: " << navigationEditorPoints.size() << "\n"; } } @@ -107,7 +107,7 @@ namespace ZL void LocationEditor::handleRightClick() { if (navigationEditorPoints.size() < 3) { - std::cout << "[NAV_EDITOR] Need at least 3 points to form a polygon (have " + logger() << "[NAV_EDITOR] Need at least 3 points to form a polygon (have " << navigationEditorPoints.size() << "); clearing\n"; navigationEditorPoints.clear(); rebuildPointsMesh(); @@ -121,7 +121,7 @@ namespace ZL } if (loc.navigation) loc.navigation->addObstaclePolygon(poly); - std::cout << "[NAV_EDITOR] Added obstacle '" << poly.name << "' with " + logger() << "[NAV_EDITOR] Added obstacle '" << poly.name << "' with " << poly.polygon.size() << " vertices\n"; { @@ -150,12 +150,12 @@ namespace ZL if (!loc.navigation) return; if (loc.navigation->saveConfig(baseName + ".json")) - std::cout << "[NAV_EDITOR] Saved config to: " << baseName << ".json\n"; + logger() << "[NAV_EDITOR] Saved config to: " << baseName << ".json\n"; else std::cerr << "[NAV_EDITOR] Failed to save config to: " << baseName << ".json\n"; if (loc.navigation->saveGrid(baseName + ".txt")) - std::cout << "[NAV_EDITOR] Saved grid to: " << baseName << ".txt\n"; + logger() << "[NAV_EDITOR] Saved grid to: " << baseName << ".txt\n"; else std::cerr << "[NAV_EDITOR] Failed to save grid to: " << baseName << ".txt\n"; } @@ -163,7 +163,7 @@ namespace ZL void LocationEditor::reload() { loc.setupNavigation(loc.navigationMapPaths); - std::cout << "[NAV_EDITOR] Reloaded navigation maps (" << loc.navigationMapPaths.size() << " maps)\n"; + logger() << "[NAV_EDITOR] Reloaded navigation maps (" << loc.navigationMapPaths.size() << " maps)\n"; } static VertexDataStruct CreateBoundsBoxMesh(const Eigen::Vector3f corners[8], const Eigen::Vector3f& color) @@ -290,14 +290,14 @@ namespace ZL void LocationEditor::selectInteractiveObject(int index) { if (index < 0 || index >= static_cast(loc.interactiveObjects.size())) { - std::cout << "[IO_EDITOR] Index " << index << " out of range (" + logger() << "[IO_EDITOR] Index " << index << " out of range (" << loc.interactiveObjects.size() << " objects)\n"; return; } selectedInteractiveObjectIndex = index; boundsClickCount = 0; buildInteractiveObjectBoundsMeshes(); - std::cout << "[IO_EDITOR] Selected object " << index + logger() << "[IO_EDITOR] Selected object " << index << " (" << loc.interactiveObjects[index].loadedObject.name << ")\n"; } @@ -305,7 +305,7 @@ namespace ZL { if (selectedInteractiveObjectIndex < 0 || selectedInteractiveObjectIndex >= static_cast(loc.interactiveObjects.size())) { - std::cout << "[IO_EDITOR] No valid object selected\n"; + logger() << "[IO_EDITOR] No valid object selected\n"; return; } @@ -316,7 +316,7 @@ namespace ZL target.state.hasInteractionPosition = true; boundsClickCount = 0; // cancel any in-progress bounds placement buildInteractiveObjectBoundsMeshes(); - std::cout << "[IO_EDITOR] Interaction position set on object " << selectedInteractiveObjectIndex + logger() << "[IO_EDITOR] Interaction position set on object " << selectedInteractiveObjectIndex << " (" << target.loadedObject.name << ")" << " at (" << worldHit.x() << ", " << worldHit.z() << ")\n"; return; @@ -343,7 +343,7 @@ namespace ZL if (boundsClickCount == 0) { boundsClickA = worldHit; boundsClickCount = 1; - std::cout << "[IO_EDITOR] First corner placed at world (" + logger() << "[IO_EDITOR] First corner placed at world (" << worldHit.x() << ", " << worldHit.z() << ") — click again for second corner\n"; } else { const Eigen::Vector3f localA = worldToLocal(boundsClickA); @@ -358,7 +358,7 @@ namespace ZL boundsClickCount = 0; buildInteractiveObjectBoundsMeshes(); - std::cout << "[IO_EDITOR] Bounds set on object " << selectedInteractiveObjectIndex + logger() << "[IO_EDITOR] Bounds set on object " << selectedInteractiveObjectIndex << " (" << target.loadedObject.name << ")" << " min=(" << target.state.boundsMin.x() << ", " << target.state.boundsMin.z() << ")" << " max=(" << target.state.boundsMax.x() << ", " << target.state.boundsMax.z() << ")\n"; @@ -419,7 +419,7 @@ namespace ZL std::ofstream out(filename); if (out.is_open()) { out << j.dump(4); - std::cout << "[IO_EDITOR] Saved " << loc.interactiveObjects.size() + logger() << "[IO_EDITOR] Saved " << loc.interactiveObjects.size() << " interactive object(s) to " << filename << "\n"; } else { std::cerr << "[IO_EDITOR] Failed to open " << filename << " for writing\n"; @@ -485,7 +485,7 @@ namespace ZL loc.gameObjects[data2.name] = std::move(obj2); editorPlacedObjects.push_back(data2); - std::cout << "[GAME_EDITOR] Placed '" << data.name << "' at (" + logger() << "[GAME_EDITOR] Placed '" << data.name << "' at (" << data.positionX << ", " << data.positionZ << ") scale=" << data.scale << " rotY=" << data.rotationY << "\n"; } @@ -493,7 +493,7 @@ namespace ZL void LocationEditor::saveObjects() { if (editorPlacedObjects.empty()) { - std::cout << "[GAME_EDITOR] No editor-placed objects to save\n"; + logger() << "[GAME_EDITOR] No editor-placed objects to save\n"; return; } @@ -527,7 +527,7 @@ namespace ZL /*std::ofstream out(filename); if (out.is_open()) { out << j.dump(4); - std::cout << "[GAME_EDITOR] Saved " << editorPlacedObjects.size() + logger() << "[GAME_EDITOR] Saved " << editorPlacedObjects.size() << " object(s) to " << filename << "\n"; } else { std::cerr << "[GAME_EDITOR] Failed to open " << filename << " for writing\n"; diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 2e38e47..095fd2c 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -756,7 +756,7 @@ namespace ZL { } void MenuManager::selectInventoryItem(int index) { - std::cout << "MenuManager::selectInventoryItem: " << index << std::endl; + logger() << "MenuManager::selectInventoryItem: " << index << std::endl; const auto& items = inventory->getItems(); if (index < 0 || index >= static_cast(items.size())) return; @@ -862,7 +862,7 @@ namespace ZL { } void MenuManager::toggleQuestJournal() { - std::cout << "[quest] toggleQuestJournal: " << (isQuestJournalOpen() ? "closing" : "opening") << std::endl; + logger() << "[quest] toggleQuestJournal: " << (isQuestJournalOpen() ? "closing" : "opening") << std::endl; if (uiState_ == GameUiState::QuestJournal) { closeQuestJournal(); } @@ -1274,7 +1274,7 @@ namespace ZL { void MenuManager::tutorialShowTaxiHint() { - std::cout << "tutorialShowTaxiHint" << std::endl; + logger() << "tutorialShowTaxiHint" << std::endl; gameState_.tutorialNeedOpenTaxiScreen = true; if (uiState_ == GameUiState::Gameplay) { @@ -1889,7 +1889,7 @@ namespace ZL { void MenuManager::setDarklandsMode(bool enabled) { - std::cout << "MenuManager::setDarklandsMode called" << std::endl; + logger() << "MenuManager::setDarklandsMode called" << std::endl; if (gameState_.currentLocationName == "uni_interior") { if (enabled && gameState_.uniIntTutorialState == UniIntTutorialState::Step11) { @@ -1979,11 +1979,11 @@ namespace ZL { } void MenuManager::applyCurrentHealthBar() { - std::cout << "MenuManager::applyCurrentHealthBar called step 1" << std::endl; - std::cout << "currentPlayerMaxHp_ is " << gameState_.playerMaxHp << std::endl; + logger() << "MenuManager::applyCurrentHealthBar called step 1" << std::endl; + logger() << "currentPlayerMaxHp_ is " << gameState_.playerMaxHp << std::endl; if (gameState_.playerMaxHp <= 0.f) return; - std::cout << "MenuManager::applyCurrentHealthBar called step 2" << std::endl; - std::cout << "currentPlayerHp_ is " << gameState_.playerHp << std::endl; + logger() << "MenuManager::applyCurrentHealthBar called step 2" << std::endl; + logger() << "currentPlayerHp_ is " << gameState_.playerHp << std::endl; const float fraction = std::clamp(gameState_.playerHp / gameState_.playerMaxHp, 0.f, 1.f); diff --git a/src/ScriptEngine.cpp b/src/ScriptEngine.cpp index 87fc1e3..22ca1af 100644 --- a/src/ScriptEngine.cpp +++ b/src/ScriptEngine.cpp @@ -124,14 +124,14 @@ namespace ZL { } const float rad = angle * static_cast(M_PI) / 180.f; - std::cout << "[script] npc_rotate_to: index " << index << " angle " << angle << " degrees (" << rad << " radians)" << std::endl; + logger() << "[script] npc_rotate_to: index " << index << " angle " << angle << " degrees (" << rad << " radians)" << std::endl; npcs[index]->state.targetFacingAngle = rad; }); api.set_function("player_rotate_to", [loc](float angle) { const float rad = angle * static_cast(M_PI) / 180.f; - std::cout << "[script] player_rotate_to: angle " << angle << " degrees (" << rad << " radians)" << std::endl; + logger() << "[script] player_rotate_to: angle " << angle << " degrees (" << rad << " radians)" << std::endl; loc->player->state.targetFacingAngle = rad; }); @@ -172,12 +172,12 @@ namespace ZL { const Item* item = ItemRegistry::instance().findById(itemId); if (item) { if (inventory->hasItem(itemId)) { - std::cout << "[script] has_item: " << item->name << " returns true" << std::endl; + logger() << "[script] has_item: " << item->name << " returns true" << std::endl; return true; } else { - std::cout << "[script] has_item: " << item->name << " returns false" << std::endl; + logger() << "[script] has_item: " << item->name << " returns false" << std::endl; return false; } } @@ -192,7 +192,7 @@ namespace ZL { const Item* item = ItemRegistry::instance().findById(itemId); if (item) { inventory->addItem(item->id); - std::cout << "[script] pickup_item: " << item->name << std::endl; + logger() << "[script] pickup_item: " << item->name << std::endl; } else { std::cerr << "[script] pickup_item: item '" << itemId << "' not found in ItemRegistry\n"; } @@ -200,7 +200,7 @@ namespace ZL { // remove_item(item_id) api.set_function("remove_item", [loc, inventory](const std::string& id) { - std::cout << "[script] remove_item: " << id << std::endl; + logger() << "[script] remove_item: " << id << std::endl; inventory->removeItem(id); }); @@ -209,7 +209,7 @@ namespace ZL { for (auto& intObj : loc->interactiveObjects) { if (intObj.loadedObject.name == objectName) { intObj.state.isActive = false; - std::cout << "[script] deactivate_interactive_object: " << objectName << std::endl; + logger() << "[script] deactivate_interactive_object: " << objectName << std::endl; return; } } @@ -221,7 +221,7 @@ namespace ZL { for (auto& intObj : loc->interactiveObjects) { if (intObj.loadedObject.name == objectName) { intObj.state.isActive = true; - std::cout << "[script] activate_interactive_object: " << objectName << std::endl; + logger() << "[script] activate_interactive_object: " << objectName << std::endl; return; } } @@ -232,7 +232,7 @@ namespace ZL { for (auto& intObj : loc->interactiveObjects) { if (intObj.loadedObject.name == objectName) { intObj.state.rotationY = value * static_cast(M_PI) / 180.f; - std::cout << "[script] set_object_rotation: " << objectName << " " << value << std::endl; + logger() << "[script] set_object_rotation: " << objectName << " " << value << std::endl; return; } } @@ -243,7 +243,7 @@ namespace ZL { for (auto& intObj : loc->interactiveObjects) { if (intObj.loadedObject.name == objectName) { intObj.state.alpha = value; - std::cout << "[script] set_object_alpha: " <requestNightDayTransition(true, false); - std::cout << "Set night called" << std::endl; + logger() << "Set night called" << std::endl; }); api.set_function("set_dawn", [loc]() { loc->requestNightDayTransition(true, true); - std::cout << "Set dawn called" << std::endl; + logger() << "Set dawn called" << std::endl; }); @@ -857,7 +857,7 @@ namespace ZL { std::cerr << "[SCRIPT] on_npc_interact error: " << err.what() << "\n"; } else { - std::cout << "[SCRIPT] on_npc_interact called with index " << npcIndex << std::endl; + logger() << "[SCRIPT] on_npc_interact called with index " << npcIndex << std::endl; } } else { @@ -883,7 +883,7 @@ namespace ZL { } sol::state& lua = impl->lua; - std::cout << "[SCRIPT] Looking for activate function: " << functionName << std::endl; + logger() << "[SCRIPT] Looking for activate function: " << functionName << std::endl; sol::function activateFunc = lua[functionName]; @@ -891,7 +891,7 @@ namespace ZL { throw std::runtime_error("[SCRIPT] Lua function not found: " + functionName); } - std::cout << "[SCRIPT] Found function! Calling: " << functionName << std::endl; + logger() << "[SCRIPT] Found function! Calling: " << functionName << std::endl; auto result = activateFunc(); if (!result.valid()) { @@ -899,7 +899,7 @@ namespace ZL { throw std::runtime_error("[SCRIPT] Error executing " + functionName + ": " + std::string(err.what())); } - std::cout << "[SCRIPT] Function executed successfully!" << std::endl; + logger() << "[SCRIPT] Function executed successfully!" << std::endl; } void ScriptEngine::callItemPickupCallback(const std::string& objectName) { @@ -914,18 +914,18 @@ namespace ZL { sol::function activateFunc = lua["on_item_pickup"]; if (activateFunc.valid()) { - std::cout << "[SCRIPT] Callback found! Calling with argument: " << objectName << std::endl; + logger() << "[SCRIPT] Callback found! Calling with argument: " << objectName << std::endl; auto result = activateFunc(objectName); if (!result.valid()) { sol::error err = result; std::cerr << "[SCRIPT] on_item_pickup callback error: " << err.what() << "\n"; } else { - std::cout << "[SCRIPT] Callback executed successfully!" << std::endl; + logger() << "[SCRIPT] Callback executed successfully!" << std::endl; } } else { - std::cout << "[SCRIPT] Fallback: on_item_pickup not found" << std::endl; + logger() << "[SCRIPT] Fallback: on_item_pickup not found" << std::endl; } } diff --git a/src/SparkEmitter.cpp b/src/SparkEmitter.cpp index 4fde628..929523e 100644 --- a/src/SparkEmitter.cpp +++ b/src/SparkEmitter.cpp @@ -474,7 +474,7 @@ namespace ZL { } bool SparkEmitter::loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile) { - std::cout << "Loading spark config from: " << path << std::endl; + logger() << "Loading spark config from: " << path << std::endl; std::string content; try { @@ -498,13 +498,13 @@ namespace ZL { json j; try { j = json::parse(content); - std::cout << "JSON parsed successfully" << std::endl; + logger() << "JSON parsed successfully" << std::endl; } catch (const std::exception& e) { std::cerr << "JSON parse error: " << e.what() << std::endl; throw std::runtime_error("Failed to load spark emitter config file 9!"); } - std::cout << "JSON content: " << j.dump(2) << std::endl; + logger() << "JSON content: " << j.dump(2) << std::endl; auto requireKey = [&](const std::string& key) { if (!j.contains(key)) { @@ -531,13 +531,13 @@ namespace ZL { particles.resize(maxParticles); drawPositions.reserve(maxParticles * 6); drawTexCoords.reserve(maxParticles * 6); - std::cout << "Max particles: " << maxParticles << std::endl; + logger() << "Max particles: " << maxParticles << std::endl; particleSize = j["particleSize"].get(); - std::cout << "Particle size: " << particleSize << std::endl; + logger() << "Particle size: " << particleSize << std::endl; biasX = j["biasX"].get(); - std::cout << "Bias X: " << biasX << std::endl; + logger() << "Bias X: " << biasX << std::endl; // emissionPoints std::vector points; @@ -546,7 +546,7 @@ namespace ZL { if (el.contains("position") && el["position"].is_array()) { auto arr = el["position"]; points.push_back(Vector3f{ arr[0].get(), arr[1].get(), arr[2].get() }); - std::cout << "Fixed point: [" << arr[0] << ", " << arr[1] << ", " << arr[2] << "]" << std::endl; + logger() << "Fixed point: [" << arr[0] << ", " << arr[1] << ", " << arr[2] << "]" << std::endl; } else if (el.contains("positionRange") && el["positionRange"].is_object()) { auto pr = el["positionRange"]; @@ -564,18 +564,18 @@ namespace ZL { for (int k = 0; k < count; ++k) { Vector3f randomPoint{ dx(gen), dy(gen), dz(gen) }; points.push_back(randomPoint); - std::cout << "Random point " << k + 1 << ": [" << randomPoint(0) + logger() << "Random point " << k + 1 << ": [" << randomPoint(0) << ", " << randomPoint(1) << ", " << randomPoint(2) << "]" << std::endl; } } } if (!points.empty()) { setEmissionPoints(points); - std::cout << "Total emission points: " << emissionPoints.size() << std::endl; + logger() << "Total emission points: " << emissionPoints.size() << std::endl; } else { setEmissionPoints({}); - std::cout << "Emission points parsed but empty" << std::endl; + logger() << "Emission points parsed but empty" << std::endl; //throw std::runtime_error("Failed to load spark emitter config file 10!"); } } @@ -589,7 +589,7 @@ namespace ZL { auto a = j["speedRange"]; speedRange.min = a[0].get(); speedRange.max = a[1].get(); - std::cout << "Speed range: [" << speedRange.min << ", " << speedRange.max << "]" << std::endl; + logger() << "Speed range: [" << speedRange.min << ", " << speedRange.max << "]" << std::endl; } else { std::cerr << "speedRange missing or invalid" << std::endl; @@ -600,7 +600,7 @@ namespace ZL { auto a = j["zSpeedRange"]; zSpeedRange.min = a[0].get(); zSpeedRange.max = a[1].get(); - std::cout << "Z speed range: [" << zSpeedRange.min << ", " << zSpeedRange.max << "]" << std::endl; + logger() << "Z speed range: [" << zSpeedRange.min << ", " << zSpeedRange.max << "]" << std::endl; } else { std::cerr << "zSpeedRange missing or invalid" << std::endl; @@ -611,7 +611,7 @@ namespace ZL { auto a = j["scaleRange"]; scaleRange.min = a[0].get(); scaleRange.max = a[1].get(); - std::cout << "Scale range: [" << scaleRange.min << ", " << scaleRange.max << "]" << std::endl; + logger() << "Scale range: [" << scaleRange.min << ", " << scaleRange.max << "]" << std::endl; } else { std::cerr << "scaleRange missing or invalid" << std::endl; @@ -622,7 +622,7 @@ namespace ZL { auto a = j["lifeTimeRange"]; lifeTimeRange.min = a[0].get(); lifeTimeRange.max = a[1].get(); - std::cout << "Life time range: [" << lifeTimeRange.min << ", " << lifeTimeRange.max << "]" << std::endl; + logger() << "Life time range: [" << lifeTimeRange.min << ", " << lifeTimeRange.max << "]" << std::endl; } else { std::cerr << "lifeTimeRange missing or invalid" << std::endl; @@ -632,17 +632,17 @@ namespace ZL { // texture if (j.contains("texture") && j["texture"].is_string()) { std::string texPath = j["texture"].get(); - std::cout << "Loading texture: " << texPath << " From zip file: " << zipFile << std::endl; + logger() << "Loading texture: " << texPath << " From zip file: " << zipFile << std::endl; try { - std::cout << "Loading texture step 1" << std::endl; + logger() << "Loading texture step 1" << std::endl; auto texData = CreateTextureDataFromPng(texPath.c_str(), zipFile.c_str()); - std::cout << "Loading texture step 2" << std::endl; + logger() << "Loading texture step 2" << std::endl; texture = std::make_shared(texData); - std::cout << "Texture loaded successfully, ID: " << texture->getTexID() << std::endl; + logger() << "Texture loaded successfully, ID: " << texture->getTexID() << std::endl; } catch (const std::exception& e) { - std::cout << "Texture load error: " << e.what() << std::endl; + logger() << "Texture load error: " << e.what() << std::endl; std::cerr << "Texture load error: " << e.what() << std::endl; throw std::runtime_error("Failed to load spark emitter config file 16!"); } @@ -652,11 +652,11 @@ namespace ZL { throw std::runtime_error("Failed to load spark emitter config file 17!"); } - std::cout << "Working with shaders 1" << std::endl; + logger() << "Working with shaders 1" << std::endl; // shaders if (j.contains("shaderProgramName") && j["shaderProgramName"].is_string()) { shaderProgramName = j["shaderProgramName"].get(); - std::cout << "Shader program name: " << shaderProgramName << std::endl; + logger() << "Shader program name: " << shaderProgramName << std::endl; } else { std::cerr << "shaderProgramName missing or invalid" << std::endl; @@ -665,7 +665,7 @@ namespace ZL { drawDataDirty = true; configured = true; - std::cout << "SparkEmitter configuration loaded successfully!" << std::endl; + logger() << "SparkEmitter configuration loaded successfully!" << std::endl; return true; } diff --git a/src/TextModel.cpp b/src/TextModel.cpp index 90e847b..7f5a70c 100644 --- a/src/TextModel.cpp +++ b/src/TextModel.cpp @@ -81,7 +81,7 @@ namespace ZL numberVertices = std::stoi(match.str()); } else { - std::cout << "Vertices header not found or invalid: " << tempLine << std::endl; + logger() << "Vertices header not found or invalid: " << tempLine << std::endl; throw std::runtime_error("Vertices header not found or invalid."); } @@ -116,7 +116,7 @@ namespace ZL // UV - [7], [8] if (floatValues.size() < 9) { - std::cout << "Malformed vertex line at index " << i << ": " << tempLine << std::endl; + logger() << "Malformed vertex line at index " << i << ": " << tempLine << std::endl; throw std::runtime_error("Malformed vertex line at index " + std::to_string(i)); } @@ -137,7 +137,7 @@ namespace ZL numberTriangles = std::stoi(match.str()); } else { - std::cout << "Triangles header not found or invalid: " << tempLine << std::endl; + logger() << "Triangles header not found or invalid: " << tempLine << std::endl; throw std::runtime_error("Triangles header not found."); } @@ -162,7 +162,7 @@ namespace ZL } if (indices.size() != 3) { - std::cout << "Malformed triangle line at index " << i << ": " << tempLine << std::endl; + logger() << "Malformed triangle line at index " << i << ": " << tempLine << std::endl; throw std::runtime_error("Malformed triangle line at index " + std::to_string(i)); } @@ -193,7 +193,7 @@ namespace ZL result.NormalData[i](2) = originalNorm(0); } - std::cout << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." << std::endl; + logger() << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." << std::endl; s_meshCache[key] = result; return result; @@ -266,7 +266,7 @@ namespace ZL } } - std::cout << "Binary model loaded: " << numVertices << " verts, " << numTriangles << " tris." << std::endl; + logger() << "Binary model loaded: " << numVertices << " verts, " << numTriangles << " tris." << std::endl; s_meshCache[key] = result; return result; diff --git a/src/UiManager.cpp b/src/UiManager.cpp index 5a1212e..87f96ce 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -537,7 +537,7 @@ namespace ZL { if (!t.contains(key) || !t[key].is_string()) return nullptr; std::string path = t[key].get(); try { - std::cout << "UiManager: loading texture for button '" << btn->name << "' : " << path << " Zip file: " << zipFile << std::endl; + logger() << "UiManager: loading texture for button '" << btn->name << "' : " << path << " Zip file: " << zipFile << std::endl; return renderer.textureManager.LoadFromPng(path, zipFile, true); } catch (const std::exception& e) { @@ -571,7 +571,7 @@ namespace ZL { if (!t.contains(key) || !t[key].is_string()) return nullptr; std::string path = t[key].get(); try { - std::cout << "UiManager: --loading texture for slider '" << s->name << "' : " << path << " Zip file: " << zipFile << std::endl; + logger() << "UiManager: --loading texture for slider '" << s->name << "' : " << path << " Zip file: " << zipFile << std::endl; return renderer.textureManager.LoadFromPng(path, zipFile, true); } catch (const std::exception& e) { diff --git a/src/cutscene/CutsceneRuntime.cpp b/src/cutscene/CutsceneRuntime.cpp index d26f58c..5cdd72c 100644 --- a/src/cutscene/CutsceneRuntime.cpp +++ b/src/cutscene/CutsceneRuntime.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "utils/Utils.h" namespace ZL::Cutscene { @@ -68,7 +69,7 @@ bool CutsceneRuntime::start(const std::string& cutsceneId) { onLineStarted(firstLine.luaCallback); } - std::cout << "[CUTSCENE] start id=" << cutsceneId + logger() << "[CUTSCENE] start id=" << cutsceneId << " lines=" << def->lines.size() << " totalDuration=" << cutsceneTotalDurationMs << std::endl; @@ -176,7 +177,7 @@ void CutsceneRuntime::skip() { } void CutsceneRuntime::finish() { - std::cout << "[CUTSCENE] finish id=" << activeCutsceneId << std::endl; + logger() << "[CUTSCENE] finish id=" << activeCutsceneId << std::endl; const std::string finishedId = activeCutsceneId; stop(); if (onFinished && !finishedId.empty()) { diff --git a/src/items/GameObjectLoader.cpp b/src/items/GameObjectLoader.cpp index 1a7c1ad..bc5fb91 100644 --- a/src/items/GameObjectLoader.cpp +++ b/src/items/GameObjectLoader.cpp @@ -73,7 +73,7 @@ namespace ZL { objects.push_back(std::move(data)); } - std::cout << "Loaded " << objects.size() << " static objects from " << jsonPath << std::endl; + logger() << "Loaded " << objects.size() << " static objects from " << jsonPath << std::endl; return objects; } @@ -115,7 +115,7 @@ namespace ZL { objects.push_back(std::move(data)); } - std::cout << "Loaded " << objects.size() << " interactive objects from " << jsonPath << std::endl; + logger() << "Loaded " << objects.size() << " interactive objects from " << jsonPath << std::endl; return objects; } @@ -199,7 +199,7 @@ namespace ZL { // Service the OS message queue between loads so the window doesn't // get flagged as "not responding" during long location loads. SDL_PumpEvents(); - std::cout << "Loading game object: " << data.name << std::endl; + logger() << "Loading game object: " << data.name << std::endl; try { LoadedGameObject obj = buildLoadedObject(data, renderer, zipPath); @@ -208,13 +208,13 @@ namespace ZL { obj.mesh.RefreshVBO(); gameObjects[data.name] = std::move(obj); - std::cout << "Successfully loaded: " << data.name << std::endl; + logger() << "Successfully loaded: " << data.name << std::endl; } catch (const std::exception& e) { std::cerr << "GameObjectLoader: Failed to load '" << data.name << "': " << e.what() << std::endl; } } - std::cout << "Total game objects loaded: " << gameObjects.size() << std::endl; + logger() << "Total game objects loaded: " << gameObjects.size() << std::endl; return gameObjects; } @@ -230,17 +230,17 @@ namespace ZL { for (const auto& data : loadInteractiveFromJson(jsonPath, zipPath)) { SDL_PumpEvents(); - std::cout << "Loading interactive object: " << data.base.name << std::endl; + logger() << "Loading interactive object: " << data.base.name << std::endl; try { InteractiveObject intObj = InteractiveObject::createFromState( data.toInteractiveObjectState(), renderer, zipPath); intObj.loadedObject.name = data.base.name; if (!data.activateFunctionName.empty()) - std::cout << "Successfully loaded interactive: " << data.base.name + logger() << "Successfully loaded interactive: " << data.base.name << " (function: " << data.activateFunctionName << ")" << std::endl; else - std::cout << "Successfully loaded interactive: " << data.base.name << std::endl; + logger() << "Successfully loaded interactive: " << data.base.name << std::endl; interactiveObjects.push_back(std::move(intObj)); } catch (const std::exception& e) { @@ -248,7 +248,7 @@ namespace ZL { } } - std::cout << "Total interactive objects loaded: " << interactiveObjects.size() << std::endl; + logger() << "Total interactive objects loaded: " << interactiveObjects.size() << std::endl; return interactiveObjects; } @@ -301,7 +301,7 @@ namespace ZL { npcs.push_back(std::move(data)); } - std::cout << "Successfully loaded " << npcs.size() << " NPCs from " << jsonPath << std::endl; + logger() << "Successfully loaded " << npcs.size() << " NPCs from " << jsonPath << std::endl; } catch (const std::exception& e) { std::cerr << "Error loading NPCs from JSON: " << e.what() << std::endl; } @@ -369,11 +369,11 @@ namespace ZL { for (const auto& npcData : loadNpcsFromJson(jsonPath, zipPath)) { SDL_PumpEvents(); - std::cout << "Loading NPC: " << npcData.name << std::endl; + logger() << "Loading NPC: " << npcData.name << std::endl; try { auto npc = Character::createFromState(npcData.toCharacterState(), renderer, zipPath.c_str()); if (npc) { - std::cout << "Successfully loaded NPC: " << npcData.name << " at (" + logger() << "Successfully loaded NPC: " << npcData.name << " at (" << npcData.positionX << ", " << npcData.positionY << ", " << npcData.positionZ << ")" << std::endl; npc->index = index; npcs.push_back(std::move(npc)); @@ -384,7 +384,7 @@ namespace ZL { } } - std::cout << "Total NPCs loaded: " << npcs.size() << std::endl; + logger() << "Total NPCs loaded: " << npcs.size() << std::endl; return npcs; } diff --git a/src/items/Item.cpp b/src/items/Item.cpp index 23a02af..ed4833e 100644 --- a/src/items/Item.cpp +++ b/src/items/Item.cpp @@ -3,19 +3,20 @@ #include "external/nlohmann/json.hpp" #include #include +#include "../utils/Utils.h" namespace ZL { void Inventory::addItem(const std::string& itemId) { itemIds.push_back(itemId); - std::cout << "Item added to inventory: " << itemId << std::endl; + logger() << "Item added to inventory: " << itemId << std::endl; if (onItemAdded) onItemAdded(itemId); } void Inventory::removeItem(const std::string& itemId) { auto it = std::find(itemIds.begin(), itemIds.end(), itemId); if (it != itemIds.end()) { - std::cout << "Item removed from inventory: " << itemId << std::endl; + logger() << "Item removed from inventory: " << itemId << std::endl; if (onItemRemoved) onItemRemoved(itemId); itemIds.erase(it); } diff --git a/src/items/ItemRegistry.cpp b/src/items/ItemRegistry.cpp index 72fed5d..5859b98 100644 --- a/src/items/ItemRegistry.cpp +++ b/src/items/ItemRegistry.cpp @@ -48,7 +48,7 @@ void ItemRegistry::loadFromJson(const std::string& jsonPath, const std::string& items_[id] = std::move(item); } - std::cout << "[ItemRegistry] Loaded " << items_.size() << " items from " << jsonPath << "\n"; + logger() << "[ItemRegistry] Loaded " << items_.size() << " items from " << jsonPath << "\n"; } const Item* ItemRegistry::findById(const std::string& id) const { diff --git a/src/main.cpp b/src/main.cpp index 2bcc9ae..7f663af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,7 +67,7 @@ static void applyResize(int logicalW, int logicalH) { e.window.data2 = physicalH; SDL_PushEvent(&e); - std::cout << "Resized, new size: " << logicalW << "x" << logicalH + logger() << "Resized, new size: " << logicalW << "x" << logicalH << " (physical: " << physicalW << "x" << physicalH << ", DPR: " << dpr << ")" << std::endl; } @@ -226,11 +226,46 @@ extern "C" int SDL_main(int argc, char* argv[]) { #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__linux__) + // Read the persisted fullscreen preference (if any) before creating the + // window, so it opens directly in the right mode instead of flashing + // windowed -> fullscreen once settings are loaded later during setupPart2(). +void readSettings() +{ + + const std::string settingsContent = ZL::readSavedTextFile("settings.json"); + if (!settingsContent.empty()) { + try { + const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent); + if (settingsRoot.contains("fullscreen")) { + ZL::Environment::isFullscreen = settingsRoot["fullscreen"].get(); + } + + if (settingsRoot.contains("isHighDPIEnabled")) { + ZL::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get(); + } + + if (settingsRoot.contains("enableLogging")) { + ZL::Environment::enableLogging = settingsRoot["enableLogging"].get(); + } + + } + catch (const std::exception& e) { + std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl; + } + } +} + + int main(int argc, char* argv[]) { SDL_GLContext ctx = nullptr; try { + readSettings(); + ZL::initLogger(); + + ZL::logger() << "Log started!" << std::endl; + #ifdef STEAMSDK // Передаем явный App ID демо-версии if (SteamAPI_RestartAppIfNecessary(4945840)) { @@ -259,31 +294,6 @@ int main(int argc, char* argv[]) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - // Read the persisted fullscreen preference (if any) before creating the - // 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::readSavedTextFile("settings.json"); - if (!settingsContent.empty()) { - try { - const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent); - if (settingsRoot.contains("fullscreen")) { - ZL::Environment::isFullscreen = settingsRoot["fullscreen"].get(); - } - - if (settingsRoot.contains("isHighDPIEnabled")) { - ZL::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get(); - } - - } - catch (const std::exception& e) { - std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl; - } - } - } - - Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; if (ZL::Environment::isFullscreen) { windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; @@ -291,7 +301,7 @@ int main(int argc, char* argv[]) { SDL_DisplayMode dm; if (SDL_GetCurrentDisplayMode(0, &dm) == 0) { - std::cout << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n"; + ZL::logger() << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n"; } else { SDL_Log("SDL_GetCurrentDisplayMode failed: %s", SDL_GetError()); @@ -320,14 +330,14 @@ int main(int argc, char* argv[]) { SDL_GL_GetDrawableSize(ZL::Environment::window, &drawW, &drawH); ZL::Environment::width = drawW; ZL::Environment::height = drawH; - std::cout << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl; + ZL::logger() << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl; } else { int winW, winH; SDL_GetWindowSize(ZL::Environment::window, &winW, &winH); ZL::Environment::width = winW; ZL::Environment::height = winH; - std::cout << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl; + ZL::logger() << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl; } // Динамическое создание объекта игры diff --git a/src/navigation/PathFinder.cpp b/src/navigation/PathFinder.cpp index 6cb916a..770f3a3 100644 --- a/src/navigation/PathFinder.cpp +++ b/src/navigation/PathFinder.cpp @@ -100,7 +100,7 @@ void PathFinder::build(const std::string& configPath, if (isTxt) { if (loadGrid(configPath, zipPath)) { ready = true; - std::cout << "[nav] Loaded precomputed grid: " << gridWidth << "x" << gridDepth + logger() << "[nav] Loaded precomputed grid: " << gridWidth << "x" << gridDepth << ", cell=" << cellSize << "\n"; } else { std::cerr << "[nav] Failed to load precomputed grid: " << configPath << "\n"; @@ -120,7 +120,7 @@ void PathFinder::build(const std::string& configPath, rebuildWalkableGrid(); ready = true; - std::cout << "[nav] Polygon grid built: " << gridWidth << "x" << gridDepth + logger() << "[nav] Polygon grid built: " << gridWidth << "x" << gridDepth << ", cell=" << cellSize << ", areas=" << areas.size() << "\n"; } diff --git a/src/render/OpenGlExtensions.cpp b/src/render/OpenGlExtensions.cpp index 294d25c..01fef02 100644 --- a/src/render/OpenGlExtensions.cpp +++ b/src/render/OpenGlExtensions.cpp @@ -329,7 +329,7 @@ namespace ZL { size_t error = glGetError(); if (error != GL_NO_ERROR) { - std::cout << "OpenGL error: " << error << std::endl; + logger() << "OpenGL error: " << error << std::endl; throw std::runtime_error("Gl error"); } } @@ -338,7 +338,7 @@ namespace ZL { size_t error = glGetError(); if (error != GL_NO_ERROR) { - std::cout << "OpenGL error: " << error << " happened in file: " << file << " at line: " << line << std::endl; + logger() << "OpenGL error: " << error << " happened in file: " << file << " at line: " << line << std::endl; throw std::runtime_error("Gl error"); } } diff --git a/src/render/ShaderManager.cpp b/src/render/ShaderManager.cpp index b6c972b..3f6b633 100644 --- a/src/render/ShaderManager.cpp +++ b/src/render/ShaderManager.cpp @@ -10,7 +10,7 @@ namespace ZL { ShaderResource::ShaderResource(const std::string &vertexCode, const std::string &fragmentCode) { - std::cout << "Started creating shader resource" << std::endl; + logger() << "Started creating shader resource" << std::endl; const int CONST_INFOLOG_LENGTH = 256; @@ -45,7 +45,7 @@ namespace ZL { glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled); glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength2, infoLog2); - std::cout << "Creating shader resource step 1" << std::endl; + //logger() << "Creating shader resource step 1" << std::endl; if (!vertexShaderCompiled) { @@ -53,11 +53,11 @@ namespace ZL { __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile vertex shader: %s", infoLog); #endif - std::cout << "Vertex shader compilation failed: " << infoLog << std::endl; + logger() << "Vertex shader compilation failed: " << infoLog << std::endl; throw std::runtime_error("Failed to compile vertex shader code!"); } - std::cout << "Creating shader resource step 2" << std::endl; + //logger() << "Creating shader resource step 2" << std::endl; if (!fragmentShaderCompiled) { @@ -65,12 +65,12 @@ namespace ZL { __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile fragment shader: %s", infoLog); #endif - std::cout << "Fragment shader compilation failed: " << infoLog << std::endl; + logger() << "Fragment shader compilation failed: " << infoLog << std::endl; throw std::runtime_error("Failed to compile fragment shader code!"); } - std::cout << "Creating shader resource step 4" << std::endl; + //logger() << "Creating shader resource step 4" << std::endl; shaderProgram = glCreateProgram(); @@ -86,7 +86,7 @@ namespace ZL { glGetProgramiv(shaderProgram, GL_LINK_STATUS, &programLinked); glGetProgramInfoLog(shaderProgram, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); - std::cout << "Creating shader resource step 4" << std::endl; + //logger() << "Creating shader resource step 4" << std::endl; if (!programLinked) { shaderProgram = 0; @@ -94,11 +94,11 @@ namespace ZL { __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to link shader program: %s", infoLog); #endif - std::cout << "Failed to link shader program: " << infoLog << std::endl; + logger() << "Failed to link shader program: " << infoLog << std::endl; throw std::runtime_error("Failed to link shader program!"); } - std::cout << "Creating shader resource step 5" << std::endl; + //logger() << "Creating shader resource step 5" << std::endl; //================= Parsing all uniforms ================ @@ -121,7 +121,7 @@ namespace ZL { uniformList[uniformName] = glGetUniformLocation(shaderProgram, uniformName); } - std::cout << "Creating shader resource step 6" << std::endl; + //logger() << "Creating shader resource step 6" << std::endl; //================= Parsing all attributes ================ @@ -138,7 +138,7 @@ namespace ZL { attribList[attribName] = glGetAttribLocation(shaderProgram, attribName); } - std::cout << "Creating shader resource step 7" << std::endl; + //logger() << "Creating shader resource step 7" << std::endl; #ifdef __ANDROID__ @@ -173,7 +173,7 @@ namespace ZL { "Fragment shader: %s", fragmentShaderFileName.c_str()); #endif - std::cout <<"Loading shader: " << shaderName << " " << vertexShaderFileName << " " << fragmentShaderFileName <first.substr(0, prefix.size()) == prefix) { - std::cout << "Unloading texture with prefix: " << it->first << std::endl; + logger() << "Unloading texture with prefix: " << it->first << std::endl; it = textureMap.erase(it); } else { diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index dbe3305..20ad5d4 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -11,6 +11,7 @@ #include #include #include +#include "../Environment.h" #ifdef __ANDROID__ #include @@ -108,7 +109,7 @@ namespace ZL 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; + logger() << "Failed to open ZIP: " << zipfilename << " (error code " << zipErr << ")" << std::endl; throw std::runtime_error("Failed to open ZIP: " + zipfilename); } @@ -119,14 +120,14 @@ namespace ZL 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; + logger() << "Failed to stat file in ZIP: " << cleanFilename << " in " << zipfilename << std::endl; 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); - std::cout << "Failed to open file in ZIP: " << cleanFilename << std::endl; + logger() << "Failed to open file in ZIP: " << cleanFilename << std::endl; throw std::runtime_error("Can't open file in ZIP: " + cleanFilename); } @@ -138,7 +139,7 @@ namespace ZL zip_close(archive); if (bytesRead < 0 || static_cast(bytesRead) != fileStat.size) { - std::cout << "Failed to read file from ZIP: " << cleanFilename << " (bytes read: " << bytesRead << ", expected: " << fileStat.size << ")" << std::endl; + logger() << "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); } @@ -348,4 +349,90 @@ namespace ZL #endif } + + // --- Инфраструктура для подавления вывода (когда лог выключен) --- + class NullBuffer : public std::streambuf { + protected: + int overflow(int c) override { return c; } + }; + + class NullStream : public std::ostream { + NullBuffer buf; + public: + NullStream() : std::ostream(&buf) {} + }; + + // --- Инфраструктура для дублирования вывода (Tee-поток) --- + class TeeBuffer : public std::streambuf { + std::streambuf* out1; + std::streambuf* out2; + protected: + int overflow(int c) override { + if (c != EOF) { + int r1 = out1->sputc(c); + int r2 = out2->sputc(c); + if (r1 == EOF || r2 == EOF) return EOF; + } + return c; + } + int sync() override { + int r1 = out1->pubsync(); + int r2 = out2->pubsync(); + return (r1 == -1 || r2 == -1) ? -1 : 0; + } + public: + TeeBuffer(std::streambuf* sb1, std::streambuf* sb2) : out1(sb1), out2(sb2) {} + }; + + // --- Глобальные переменные логгера --- + namespace { + std::ofstream g_logFile; + std::unique_ptr g_teeBuffer; + std::unique_ptr g_teeStream; + NullStream g_nullStream; + } + + // --- Инициализация логгера --- + void initLogger() { + namespace fs = std::filesystem; + try { + fs::path dir = getSaveDirectory(); + + // Если директория не существует, ofstream не сможет создать файл, + // поэтому форсируем создание всей иерархии папок. + if (!fs::exists(dir)) { + fs::create_directories(dir); + } + + fs::path logPath = dir / "log.txt"; + + // std::ios::trunc очищает файл при каждом новом запуске + g_logFile.open(logPath, std::ios::out | std::ios::trunc); + + if (g_logFile.is_open()) { + g_teeBuffer = std::make_unique(std::cout.rdbuf(), g_logFile.rdbuf()); + g_teeStream = std::make_unique(g_teeBuffer.get()); + } + else { + std::cerr << "[logger] Could not open " << logPath << " for writing" << std::endl; + } + } + catch (const fs::filesystem_error& e) { + std::cerr << "[logger] Filesystem error during init: " << e.what() << std::endl; + } + } + + // --- Сама функция логгера --- + std::ostream& logger() { + if (Environment::enableLogging) { + if (g_teeStream) { + return *g_teeStream; + } + // Фолбэк на стандартный вывод, если файл по какой-то причине не открылся + return std::cout; + } + + // Если логирование отключено, возвращаем заглушку. + return g_nullStream; + } }; \ No newline at end of file diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 0ab2a46..9a2fbe5 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -35,4 +35,7 @@ namespace ZL bool saveJsonToFile(const nlohmann::json& root, const std::string& filename); + void initLogger(); + + std::ostream& logger(); } \ No newline at end of file