16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 17:29:18 +02:00
This commit is contained in:
maj00r
2026-06-14 04:18:23 +02:00
parent 876a4c7c18
commit ada6553917
22 changed files with 518 additions and 729 deletions

View File

@@ -12,9 +12,6 @@ http://mozilla.org/MPL/2.0/.
#include "application/drivermode.h" #include "application/drivermode.h"
#include "application/editormode.h" #include "application/editormode.h"
#include "application/scenarioloadermode.h" #include "application/scenarioloadermode.h"
#include "application/scenarioloaderuilayer.h"
#include "scene/eu7/eu7_load_stats.h"
#include "scene/eu7/eu7_section_stream.h"
#include "launcher/launchermode.h" #include "launcher/launchermode.h"
#include "utilities/Globals.h" #include "utilities/Globals.h"
@@ -710,59 +707,9 @@ void eu07_application::exit()
#endif #endif
} }
void
eu07_application::extend_loading_overlay( std::chrono::milliseconds const duration ) {
if( duration.count() <= 0 ) {
return;
}
auto const until { std::chrono::steady_clock::now() + duration };
if( until > m_loading_overlay_until ) {
m_loading_overlay_until = until;
}
if( m_loading_overlay == nullptr ) {
m_loading_overlay = std::make_shared<scenarioloader_ui>();
}
}
bool
eu07_application::loading_overlay_active() const {
if( m_modestack.empty() || m_modestack.top() != mode::driver ) {
return false;
}
if( false == simulation::is_ready ) {
return true;
}
return false;
}
void
eu07_application::sync_loading_overlay_state() {
if( m_loading_overlay == nullptr ) {
m_loading_overlay = std::make_shared<scenarioloader_ui>();
}
m_loading_overlay->set_progress( 100.f, 0.f );
}
void
eu07_application::render_loading_overlay() {
sync_loading_overlay_state();
if( m_loading_overlay == nullptr ) {
m_loading_overlay = std::make_shared<scenarioloader_ui>();
}
m_loading_overlay->render();
}
void eu07_application::render_ui() void eu07_application::render_ui()
{ {
if( loading_overlay_active() ) {
render_loading_overlay();
return;
}
if (m_modestack.empty()) if (m_modestack.empty())
{ {
return; return;
@@ -774,12 +721,6 @@ void eu07_application::render_ui()
void eu07_application::begin_ui_frame() void eu07_application::begin_ui_frame()
{ {
if( loading_overlay_active() ) {
sync_loading_overlay_state();
m_loading_overlay->begin_ui_frame();
return;
}
if (m_modestack.empty()) if (m_modestack.empty())
{ {
return; return;

View File

@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
#include <chrono>
#include "application/applicationmode.h" #include "application/applicationmode.h"
#include "scripting/PyInt.h" #include "scripting/PyInt.h"
#include "network/manager.h" #include "network/manager.h"
@@ -57,12 +55,6 @@ public:
render_ui(); render_ui();
void void
begin_ui_frame(); begin_ui_frame();
void
extend_loading_overlay( std::chrono::milliseconds const Duration );
[[nodiscard]] bool
loading_overlay_active() const;
void
render_loading_overlay();
// switches application to specified mode // switches application to specified mode
bool bool
pop_mode(); pop_mode();
@@ -123,12 +115,9 @@ private:
int init_modes(); int init_modes();
bool init_network(); bool init_network();
int run_crashgui(); int run_crashgui();
void sync_loading_overlay_state();
// members // members
bool m_screenshot_queued = false; bool m_screenshot_queued = false;
std::chrono::steady_clock::time_point m_loading_overlay_until {};
std::shared_ptr<class scenarioloader_ui> m_loading_overlay;
modeptr_array m_modes { nullptr }; // collection of available application behaviour modes modeptr_array m_modes { nullptr }; // collection of available application behaviour modes
mode_stack m_modestack; // current behaviour mode mode_stack m_modestack; // current behaviour mode

View File

@@ -32,7 +32,7 @@ public:
void begin_ui_frame() { void begin_ui_frame() {
if( m_userinterface != nullptr ) { if( m_userinterface != nullptr ) {
m_userinterface->begin_ui_frame(); } } m_userinterface->begin_ui_frame(); } }
virtual inline
void set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) { void set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) {
if( m_userinterface != nullptr ) { if( m_userinterface != nullptr ) {
m_userinterface->set_progress( Progress, Subtaskprogress ); } } m_userinterface->set_progress( Progress, Subtaskprogress ); } }

View File

@@ -404,24 +404,14 @@ bool driver_mode::update()
Timer::subsystem.sim_total.stop(); Timer::subsystem.sim_total.stop();
auto const world_presentable { simulation::State.drain_deferred_eu7_trainsets( 12.0 );
false == scene::eu7::section_stream_active()
|| scene::eu7::loading_screen_dismissed() };
auto const gameplay_stream {
scene::eu7::section_stream_active() && scene::eu7::loading_screen_dismissed() };
simulation::State.drain_deferred_eu7_trainsets( gameplay_stream ? 3.0 : 12.0 );
if( scene::eu7::section_stream_active() ) { if( scene::eu7::section_stream_active() ) {
auto const stream_active { if( scene::eu7::section_stream_needs_bootstrap() ) {
simulation::is_ready || Application.loading_overlay_active() };
if( stream_active && scene::eu7::section_stream_needs_bootstrap() ) {
scene::eu7::kick_section_stream_bootstrap(); scene::eu7::kick_section_stream_bootstrap();
} }
if( stream_active ) { scene::eu7::update_section_stream( Global.pCamera.Pos );
scene::eu7::update_section_stream( Global.pCamera.Pos ); scene::eu7::drain_section_stream();
scene::eu7::drain_section_stream();
}
if( scene::eu7::pack_bench_stream_phase_active() ) { if( scene::eu7::pack_bench_stream_phase_active() ) {
static double s_last_stream_bench_log { 0.0 }; static double s_last_stream_bench_log { 0.0 };
@@ -442,9 +432,7 @@ bool driver_mode::update()
GfxRenderer->Update(deltarealtime); GfxRenderer->Update(deltarealtime);
simulation::is_ready = simulation::is_ready simulation::is_ready = simulation::is_ready || ((simulation::Train != nullptr) && (simulation::Train->is_cab_initialized)) || (Global.local_start_vehicle == "ghostview");
|| ( ( simulation::Train != nullptr ) && ( simulation::Train->is_cab_initialized ) )
|| ( Global.local_start_vehicle == "ghostview" && world_presentable );
return true; return true;
} }
@@ -455,6 +443,10 @@ void driver_mode::enter()
TDynamicObject *nPlayerTrain{((Global.local_start_vehicle != "ghostview") ? simulation::Vehicles.find(Global.local_start_vehicle) : nullptr)}; TDynamicObject *nPlayerTrain{((Global.local_start_vehicle != "ghostview") ? simulation::Vehicles.find(Global.local_start_vehicle) : nullptr)};
if( scene::eu7::section_stream_active() ) {
scene::eu7::dismiss_loading_screen();
}
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr); Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr);
Global.pCamera = Camera; Global.pCamera = Camera;
Global.pDebugCamera = DebugCamera; Global.pDebugCamera = DebugCamera;
@@ -462,6 +454,26 @@ void driver_mode::enter()
FreeFlyModeFlag = true; FreeFlyModeFlag = true;
DebugCamera = Camera; DebugCamera = Camera;
if( scene::eu7::section_stream_active() ) {
if( scene::eu7::section_stream_needs_bootstrap() ) {
scene::eu7::kick_section_stream_bootstrap();
}
auto stream_pos { scene::eu7::resolve_section_stream_position( Global.pCamera.Pos ) };
if( stream_pos.x != 0.0 || stream_pos.y != 0.0 || stream_pos.z != 0.0 ) {
Global.pCamera.Pos = stream_pos;
Camera = Global.pCamera;
}
scene::eu7::update_section_stream( Global.pCamera.Pos );
for( int i { 0 }; i < 64; ++i ) {
scene::eu7::drain_section_stream();
if( scene::eu7::section_stream_ready_around(
stream_pos,
scene::eu7::kSectionStreamBootstrapRadiusKm ) ) {
break;
}
}
}
if (nPlayerTrain) if (nPlayerTrain)
{ {
WriteLog("Trying to enter player train, \"" + Global.local_start_vehicle + "\""); WriteLog("Trying to enter player train, \"" + Global.local_start_vehicle + "\"");

View File

@@ -19,16 +19,8 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/renderer.h" #include "rendering/renderer.h"
#include "utilities/Logs.h" #include "utilities/Logs.h"
#include "utilities/translation.h" #include "utilities/translation.h"
#include "scene/eu7/eu7_load_stats.h"
#include "scene/eu7/eu7_pack_bench.h"
#include "scene/eu7/eu7_section_stream.h" #include "scene/eu7/eu7_section_stream.h"
namespace {
constexpr std::chrono::seconds kEu7LoadTimeout { 90 };
constexpr float kDeserializeBarShare { 70.f };
constexpr float kPackBarShare { 30.f };
} // namespace
scenarioloader_mode::scenarioloader_mode() { scenarioloader_mode::scenarioloader_mode() {
m_userinterface = std::make_shared<scenarioloader_ui>(); m_userinterface = std::make_shared<scenarioloader_ui>();
} }
@@ -39,13 +31,6 @@ bool scenarioloader_mode::init() {
return true; return true;
} }
void scenarioloader_mode::update_bar_progress( float const progress ) {
m_bar_progress = std::max( m_bar_progress, std::clamp( progress, 0.f, 100.f ) );
if( m_userinterface != nullptr ) {
m_userinterface->set_progress( m_bar_progress, 0.f );
}
}
// mode-specific update of simulation data. returns: false on error, true otherwise // mode-specific update of simulation data. returns: false on error, true otherwise
bool scenarioloader_mode::update() { bool scenarioloader_mode::update() {
if (!Global.ready_to_load) if (!Global.ready_to_load)
@@ -64,80 +49,22 @@ bool scenarioloader_mode::update() {
} }
try { try {
if( m_phase == load_phase::deserialize ) { if (simulation::State.deserialize_continue(state))
if( simulation::State.deserialize_continue( state ) ) { return true;
return true;
}
m_phase = load_phase::eu7_load;
m_eu7_load_started = std::chrono::steady_clock::now();
m_eu7_stream_primed = false;
}
} }
catch (invalid_scenery_exception &e) { catch (invalid_scenery_exception &e) {
ErrorLog( "Bad init: scenario loading failed" ); ErrorLog( "Bad init: scenario loading failed" );
Application.pop_mode(); Application.pop_mode();
return true;
}
if( m_phase == load_phase::eu7_load ) {
if( scene::eu7::section_stream_active() ) {
simulation::State.drain_deferred_eu7_trainsets( 16.0 );
auto const position { scene::eu7::stream_loading_position() };
if( false == m_eu7_stream_primed ) {
if( scene::eu7::section_stream_needs_bootstrap() ) {
scene::eu7::kick_section_stream_bootstrap();
}
m_eu7_stream_primed = true;
}
scene::eu7::drain_section_stream();
auto const ring_progress {
scene::eu7::section_stream_ring_progress(
position,
scene::eu7::kSectionStreamBootstrapRadiusKm ) };
update_bar_progress(
kDeserializeBarShare + ring_progress * kPackBarShare );
auto const timed_out {
std::chrono::steady_clock::now() - m_eu7_load_started >= kEu7LoadTimeout };
auto const bootstrap_ready {
scene::eu7::section_stream_ready_around(
position,
scene::eu7::kSectionStreamBootstrapRadiusKm ) };
if(
bootstrap_ready
|| scene::eu7::section_stream_presentable_around(
position,
scene::eu7::kSectionStreamBootstrapRadiusKm ) ) {
WriteLog( "EU7 PACK: pierścień wokół pozycji startowej gotowy do pokazania" );
scene::eu7::dismiss_loading_screen();
m_phase = load_phase::finished;
}
else if( timed_out ) {
ErrorLog(
"EU7 PACK: timeout ładowania pierścienia wokół kamery — wchodzę w jazdę (ring=" +
std::to_string( static_cast<int>( ring_progress * 100.f ) ) + "%)" );
scene::eu7::dismiss_loading_screen();
m_phase = load_phase::finished;
}
else {
return true;
}
}
else {
scene::eu7::dismiss_loading_screen();
m_phase = load_phase::finished;
}
} }
WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" ); WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" );
scene::eu7::log_load_stats();
scene::eu7::log_pack_bench();
update_bar_progress( 100.f ); if( scene::eu7::section_stream_active() ) {
scene::eu7::preload_section_stream( 3000.0 );
}
// TODO: implement and use next mode cue
Application.pop_mode(); Application.pop_mode();
Application.push_mode( eu07_application::mode::driver ); Application.push_mode( eu07_application::mode::driver );
@@ -153,9 +80,6 @@ void scenarioloader_mode::enter() {
// TBD: hide cursor in fullscreen mode? // TBD: hide cursor in fullscreen mode?
Application.set_cursor( GLFW_CURSOR_NORMAL ); Application.set_cursor( GLFW_CURSOR_NORMAL );
m_phase = load_phase::deserialize;
m_eu7_stream_primed = false;
m_bar_progress = 0.f;
simulation::is_ready = false; simulation::is_ready = false;
Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" ); Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
@@ -167,15 +91,3 @@ void scenarioloader_mode::exit() {
simulation::Time.init( Global.starting_timestamp ); simulation::Time.init( Global.starting_timestamp );
simulation::Environment.init(); simulation::Environment.init();
} }
void scenarioloader_mode::set_progress(
float const Progress,
float const Subtaskprogress ) {
if( m_phase != load_phase::deserialize ) {
return;
}
auto const parser_progress {
std::max( Progress, Subtaskprogress ) };
update_bar_progress( parser_progress * kDeserializeBarShare / 100.f );
}

View File

@@ -13,21 +13,8 @@ http://mozilla.org/MPL/2.0/.
#include "simulation/simulation.h" #include "simulation/simulation.h"
class scenarioloader_mode : public application_mode { class scenarioloader_mode : public application_mode {
enum class load_phase {
deserialize,
eu7_load,
finished
};
std::shared_ptr<simulation::deserializer_state> state; std::shared_ptr<simulation::deserializer_state> state;
std::chrono::system_clock::time_point timestart; std::chrono::system_clock::time_point timestart;
load_phase m_phase { load_phase::deserialize };
std::chrono::steady_clock::time_point m_eu7_load_started {};
bool m_eu7_stream_primed { false };
float m_bar_progress { 0.f };
void update_bar_progress( float progress );
public: public:
// constructors // constructors
@@ -41,7 +28,6 @@ public:
void enter() override; void enter() override;
// maintenance method, called when the mode is deactivated // maintenance method, called when the mode is deactivated
void exit() override; void exit() override;
void set_progress( float Progress = 0.f, float Subtaskprogress = 0.f ) override;
// input handlers // input handlers
void on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; } void on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; }
void on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } void on_cursor_pos( double const Horizontal, double const Vertical ) override { ; }

View File

@@ -195,10 +195,6 @@ void scenarioloader_ui::render_()
ImGui::SetNextWindowSize(ImVec2(Global.window_size.x + padding * 2, Global.window_size.y + padding * 2)); ImGui::SetNextWindowSize(ImVec2(Global.window_size.x + padding * 2, Global.window_size.y + padding * 2));
ImGui::Begin("Neo Loading Screen", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground); ImGui::Begin("Neo Loading Screen", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddRectFilled(
ImVec2( 0.f, 0.f ),
ImVec2( screen_size.x, screen_size.y ),
IM_COL32( 0, 0, 0, 255 ) );
ImGui::PushFont(font_loading); ImGui::PushFont(font_loading);
ImGui::SetWindowFontScale(1); ImGui::SetWindowFontScale(1);
const float font_scale_mult = 48 / ImGui::GetFontSize(); const float font_scale_mult = 48 / ImGui::GetFontSize();
@@ -232,14 +228,7 @@ void scenarioloader_ui::render_()
icon_center_y - text_size.y * 0.5f); icon_center_y - text_size.y * 0.5f);
// Draw // Draw
if( loading_tex != static_cast<GLuint>( -1 ) ) { //draw_list->AddImage(reinterpret_cast<ImTextureID>(loading_tex), icon_pos, ImVec2(icon_pos.x + loading_size.x, icon_pos.y + loading_size.y), ImVec2(0, 0), ImVec2(1, 1));
draw_list->AddImage(
reinterpret_cast<ImTextureID>( loading_tex ),
icon_pos,
ImVec2( icon_pos.x + loading_size.x, icon_pos.y + loading_size.y ),
ImVec2( 0, 0 ),
ImVec2( 1, 1 ) );
}
draw_list->AddText(text_pos, IM_COL32_WHITE, m_progresstext.c_str()); draw_list->AddText(text_pos, IM_COL32_WHITE, m_progresstext.c_str());
// Trivia // Trivia

View File

@@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/.
#include "utilities/Timer.h" #include "utilities/Timer.h"
#include "vehicle/Train.h" #include "vehicle/Train.h"
#include "vehicle/Camera.h" #include "vehicle/Camera.h"
#include "scene/eu7/eu7_section_stream.h"
#include "simulation/simulation.h" #include "simulation/simulation.h"
#include "utilities/Logs.h" #include "utilities/Logs.h"
#include "simulation/simulationtime.h" #include "simulation/simulationtime.h"
@@ -734,9 +733,7 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
m_current_viewport = &vp; m_current_viewport = &vp;
} }
if( ( false == simulation::is_ready ) if ((!simulation::is_ready) || (Global.gfx_skiprendering))
|| scene::eu7::loading_screen_blocks_world( scene::eu7::stream_loading_position() )
|| Global.gfx_skiprendering )
{ {
gl::framebuffer::unbind(); gl::framebuffer::unbind();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

View File

@@ -13,7 +13,6 @@ http://mozilla.org/MPL/2.0/.
#include "utilities/color.h" #include "utilities/color.h"
#include "utilities/Globals.h" #include "utilities/Globals.h"
#include "vehicle/Camera.h" #include "vehicle/Camera.h"
#include "scene/eu7/eu7_section_stream.h"
#include "utilities/Timer.h" #include "utilities/Timer.h"
#include "simulation/simulation.h" #include "simulation/simulation.h"
#include "simulation/simulationtime.h" #include "simulation/simulationtime.h"
@@ -415,12 +414,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
m_colorpass = m_renderpass; m_colorpass = m_renderpass;
if( ( false == simulation::is_ready ) if( ( !simulation::is_ready ) || ( Global.gfx_skiprendering ) ) {
|| scene::eu7::loading_screen_blocks_world( scene::eu7::stream_loading_position() ) ::glClearColor( 51.0f / 255.f, 102.0f / 255.f, 85.0f / 255.f, 1.f ); // initial background Color
|| Global.gfx_skiprendering ) {
::glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
Application.render_ui();
break; break;
} }

View File

@@ -164,7 +164,7 @@ scenario_needs_eu7_regen( std::string const &scenario_file ) {
if( probe_file( resolved ) ) { if( probe_file( resolved ) ) {
return text_module_is_newer_than_binary( scenario_file ); return false;
} }
@@ -176,7 +176,7 @@ scenario_needs_eu7_regen( std::string const &scenario_file ) {
} }
return false == should_use_binary_module( scenario_file ); return false == probe_baked_scenario( scenario_file );
#else #else
@@ -204,28 +204,6 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
if( probe_file( resolved ) ) { if( probe_file( resolved ) ) {
#ifdef WITH_EU7_PARSER
if( Global.eu7_auto_bake && text_module_is_newer_than_binary( scenario_file ) ) {
auto const text_root { text_source_path( scenario_file ) };
if( false == text_root.empty() ) {
WriteLog(
"EU7: .eu7 nieaktualny wzgledem " + text_root + ", rebake..." );
run_scenario_tree_bake( text_root, eu7_path, outcome );
return outcome;
}
}
#endif
outcome.ok = true; outcome.ok = true;
outcome.message = "uzywam .eu7: " + resolved; outcome.message = "uzywam .eu7: " + resolved;
@@ -242,7 +220,7 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
if( false == Global.eu7_auto_bake ) { if( false == Global.eu7_auto_bake ) {
if( should_use_binary_module( scenario_file ) ) { if( probe_baked_scenario( scenario_file ) ) {
outcome.ok = true; outcome.ok = true;
@@ -282,7 +260,7 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
if( should_use_binary_module( scenario_file ) ) { if( probe_baked_scenario( scenario_file ) ) {
outcome.ok = true; outcome.ok = true;
@@ -296,23 +274,13 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
if( probe_file( eu7_path ) ) {
WriteLog(
"EU7: .eu7 nieaktualny wzgledem " + resolved + ", rebake..." );
}
run_scenario_tree_bake( resolved, eu7_path, outcome ); run_scenario_tree_bake( resolved, eu7_path, outcome );
return outcome; return outcome;
#else #else
if( should_use_binary_module( scenario_file ) ) { if( probe_baked_scenario( scenario_file ) ) {
outcome.ok = true; outcome.ok = true;

View File

@@ -257,11 +257,7 @@ load_module_recursive(
if( child_loaded ) { if( child_loaded ) {
continue; continue;
} }
if( !child.empty() && probe_file( child ) && false == should_use_binary_module( ref ) ) { if( !child.empty() ) {
WriteLog(
"EU7: przestarzaly .eu7, fallback SCM: " + include_text_path( include ) );
}
else if( !child.empty() ) {
WriteLog( WriteLog(
"EU7 include niedostepny, fallback SCM: " + include_text_path( include ) ); "EU7 include niedostepny, fallback SCM: " + include_text_path( include ) );
} }
@@ -458,23 +454,9 @@ text_source_path( std::string const &reference ) {
return {}; return {};
} }
bool
text_module_is_newer_than_binary( std::string const &reference ) {
auto const text { text_source_path( reference ) };
if( text.empty() || false == FileExists( text ) ) {
return false;
}
auto const eu7 { binary_path( reference ) };
if( false == FileExists( eu7 ) ) {
return true;
}
return last_modified( text ) > last_modified( eu7 );
}
bool bool
should_use_binary_module( std::string const &reference ) { should_use_binary_module( std::string const &reference ) {
auto const eu7 { binary_path( reference ) }; return probe_file( binary_path( reference ) );
return probe_file( eu7 ) && false == text_module_is_newer_than_binary( reference );
} }
bool bool

View File

@@ -75,13 +75,9 @@ namespace eu7 {
[[nodiscard]] std::string [[nodiscard]] std::string
text_source_path( std::string const &Reference ); text_source_path( std::string const &Reference );
// Tekst istnieje i jest nowszy niz .eu7 (lub brak .eu7). // Istniejacy, poprawny plik .eu7 obok referencji tekstowej.
[[nodiscard]] bool [[nodiscard]] bool
text_module_is_newer_than_binary( std::string const &Reference ); should_use_binary_module( std::string const &Reference );
// Istniejacy, poprawny .eu7 nie starszy niz odpowiednik tekstowy.
[[nodiscard]] bool
should_use_binary_module( std::string const &Reference );
// Czy plik zawiera chunk TERR. // Czy plik zawiera chunk TERR.
[[nodiscard]] bool [[nodiscard]] bool

View File

@@ -1,33 +1,33 @@
/* /*
This Source Code Form is subject to the This Source Code Form is subject to the
terms of the Mozilla Public License, v. terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not 2.0. If a copy of the MPL was not
distributed with this file, You can distributed with this file, You can
obtain one at obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include "scene/eu7/eu7_types.h" #include "scene/eu7/eu7_types.h"
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
namespace scene::eu7 { namespace scene::eu7 {
// Tylko warm_instanceable_cache dla juz zcache'owanych meshy (bez cold GetModel na workerze). // Tylko warm_instanceable_cache dla juz zcache'owanych meshy (bez cold GetModel na workerze).
void void
preload_pack_models( std::vector<Eu7Model> const &Models ); preload_pack_models( std::vector<Eu7Model> const &Models );
// Main thread: Fetch_Material dla unikalnych texture_file z chunka przed apply. // Main thread: Fetch_Material dla unikalnych texture_file z chunka przed apply.
// Zwraca liczbe unikalnych Fetch_Material w tym slice. // Zwraca liczbe unikalnych Fetch_Material w tym slice.
std::size_t std::size_t
warm_pack_textures_main( Eu7Model const *models, std::size_t count ); warm_pack_textures_main( Eu7Model const *models, std::size_t count );
void void
reset_pack_texture_warm_cache(); reset_pack_texture_warm_cache();
} // namespace scene::eu7 } // namespace scene::eu7

View File

@@ -497,26 +497,39 @@ parse_pack_section_header(
Eu7PackIndexEntry const &entry, Eu7PackIndexEntry const &entry,
Eu7PackSectionCursor &cursor ) { Eu7PackSectionCursor &cursor ) {
cursor = {}; cursor = {};
input.seekg( auto const section_start {
static_cast<std::streamoff>( module.pack_payload_offset + entry.pack_offset ) ); static_cast<std::streamoff>( module.pack_payload_offset + entry.pack_offset ) };
input.seekg( section_start );
const auto peek { input.peek() }; const auto peek { input.peek() };
const std::uint8_t first_byte { const std::uint8_t first_byte {
peek == EOF ? std::uint8_t { 0 } : static_cast<std::uint8_t>( peek ) }; peek == EOF ? std::uint8_t { 0 } : static_cast<std::uint8_t>( peek ) };
if( first_byte == kPackSectionFormatV8 ) { if( first_byte == 2 ) {
cursor.section_format = sn_utils::d_uint8( input );
const std::uint32_t solo_total { sn_utils::ld_uint32( input ) };
const std::uint32_t inst_total { sn_utils::ld_uint32( input ) };
cursor.model_total = solo_total + inst_total;
cursor.solo_remaining = solo_total;
cursor.inst_remaining = inst_total;
}
else if( first_byte == 2 ) {
throw std::runtime_error( throw std::runtime_error(
"EU7 PACK: format v9 nieobslugiwany — przebake plik .eu7" ); "EU7 PACK: format v9 nieobslugiwany — przebake plik .eu7" );
} }
else {
// v8 header starts with byte 1 — same as kNodeFlagHasName on flat v7 models.
// Accept v8 only when PROT exists and solo+inst counts match PIDX model_count.
bool use_v8_header { false };
if(
first_byte == kPackSectionFormatV8 &&
false == module.model_prototypes.empty() ) {
cursor.section_format = sn_utils::d_uint8( input );
const std::uint32_t solo_total { sn_utils::ld_uint32( input ) };
const std::uint32_t inst_total { sn_utils::ld_uint32( input ) };
if( solo_total + inst_total == entry.model_count ) {
use_v8_header = true;
cursor.model_total = solo_total + inst_total;
cursor.solo_remaining = solo_total;
cursor.inst_remaining = inst_total;
}
}
if( false == use_v8_header ) {
input.seekg( section_start );
cursor.section_format = 0;
cursor.model_total = entry.model_count; cursor.model_total = entry.model_count;
cursor.solo_remaining = entry.model_count; cursor.solo_remaining = entry.model_count;
cursor.inst_remaining = 0; cursor.inst_remaining = 0;
@@ -539,8 +552,10 @@ read_pack_models_chunk_impl(
std::vector<Eu7Model> models; std::vector<Eu7Model> models;
auto const remaining { auto const remaining {
static_cast<std::size_t>( cursor.solo_remaining ) + std::min(
static_cast<std::size_t>( cursor.inst_remaining ) }; static_cast<std::size_t>( cursor.solo_remaining ) +
static_cast<std::size_t>( cursor.inst_remaining ),
static_cast<std::size_t>( cursor.model_total ) ) };
models.reserve( std::min( max_count, remaining ) ); models.reserve( std::min( max_count, remaining ) );
while( while(
@@ -1104,46 +1119,4 @@ read_pack_section( Eu7Module const &module, int const row, int const column ) {
return read_pack_section_impl( module, row, column ); return read_pack_section_impl( module, row, column );
} }
void
seek_pack_section(
Eu7Module const &module,
std::istream &input,
Eu7PackIndexEntry const &entry,
Eu7PackSectionCursor &cursor ) {
if( false == module.has_pack_chunk ) {
cursor = {};
return;
}
parse_pack_section_header( module, input, entry, cursor );
}
std::vector<Eu7Model>
read_pack_models_chunk(
Eu7Module const &module,
std::istream &input,
Eu7PackSectionCursor &cursor,
std::size_t const max_count ) {
StringTable const strings { module.strings };
return read_pack_models_chunk_impl( module, input, cursor, max_count, strings );
}
void
resume_pack_section(
Eu7Module const &module,
std::istream &input,
Eu7PackIndexEntry const &entry,
std::uint64_t const resume_byte_offset,
Eu7PackSectionCursor const resume_cursor,
Eu7PackSectionCursor &cursor ) {
if( false == module.has_pack_chunk ) {
cursor = {};
return;
}
input.seekg(
static_cast<std::streamoff>(
module.pack_payload_offset + entry.pack_offset + resume_byte_offset ) );
cursor = resume_cursor;
}
} // namespace scene::eu7 } // namespace scene::eu7

View File

@@ -11,7 +11,6 @@ http://mozilla.org/MPL/2.0/.
#include "scene/eu7/eu7_types.h" #include "scene/eu7/eu7_types.h"
#include <istream>
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -32,30 +31,4 @@ find_pack_entry( Eu7Module const &Module, int Row, int Column );
[[nodiscard]] std::vector<Eu7Model> [[nodiscard]] std::vector<Eu7Model>
read_pack_section( Eu7Module const &Module, int Row, int Column ); read_pack_section( Eu7Module const &Module, int Row, int Column );
// Seek do pack_offset z PIDX i parsuj naglowek sekcji (v7/v8).
void
seek_pack_section(
Eu7Module const &Module,
std::istream &Input,
Eu7PackIndexEntry const &Entry,
Eu7PackSectionCursor &Cursor );
// Odczyt do max_count modeli z biezacej pozycji strumienia (po seek_pack_section).
[[nodiscard]] std::vector<Eu7Model>
read_pack_models_chunk(
Eu7Module const &Module,
std::istream &Input,
Eu7PackSectionCursor &Cursor,
std::size_t MaxCount );
// Wznowienie odczytu sub-chunka (offset wzgledem pack_offset sekcji z PIDX).
void
resume_pack_section(
Eu7Module const &Module,
std::istream &Input,
Eu7PackIndexEntry const &Entry,
std::uint64_t ResumeByteOffset,
Eu7PackSectionCursor ResumeCursor,
Eu7PackSectionCursor &Cursor );
} // namespace scene::eu7 } // namespace scene::eu7

View File

@@ -44,7 +44,7 @@ namespace scene::eu7 {
namespace { namespace {
constexpr double kDrainBudgetMs { 12.0 }; constexpr double kDrainBudgetMs { 12.0 };
constexpr double kLoaderDrainBudgetMs { 48.0 }; constexpr double kLoaderDrainBudgetMs { 96.0 };
constexpr std::size_t kLoaderSectionsPerDrain { 8 }; constexpr std::size_t kLoaderSectionsPerDrain { 8 };
constexpr double kGameplayApplyBudgetMs { 4.0 }; constexpr double kGameplayApplyBudgetMs { 4.0 };
@@ -72,7 +72,6 @@ constexpr float kStationaryCatchupRingThreshold { 0.70f };
constexpr double kStationaryCatchupSpeedMps { 5.0 }; constexpr double kStationaryCatchupSpeedMps { 5.0 };
constexpr std::size_t kCatchupMaxInFlightSections { 20 }; constexpr std::size_t kCatchupMaxInFlightSections { 20 };
constexpr std::size_t kCatchupMaxReadySections { 8 }; constexpr std::size_t kCatchupMaxReadySections { 8 };
constexpr std::size_t kPackWorkerSubChunkModels { 512 };
constexpr std::size_t kBootstrapDrainMs { 32 }; constexpr std::size_t kBootstrapDrainMs { 32 };
constexpr std::size_t kBootstrapTimeoutMs { 120000 }; constexpr std::size_t kBootstrapTimeoutMs { 120000 };
constexpr std::chrono::milliseconds kPresentableHoldMs { 200 }; constexpr std::chrono::milliseconds kPresentableHoldMs { 200 };
@@ -90,10 +89,6 @@ struct PackSectionJob {
int column { 0 }; int column { 0 };
std::size_t section_idx { 0 }; std::size_t section_idx { 0 };
int priority { 0 }; int priority { 0 };
std::uint64_t resume_byte_offset { 0 };
std::uint32_t subchunk_index { 0 };
Eu7PackSectionCursor header_cursor {};
Eu7PackSectionCursor resume_cursor {};
}; };
struct PackSectionReady { struct PackSectionReady {
@@ -102,8 +97,7 @@ struct PackSectionReady {
std::size_t section_idx { 0 }; std::size_t section_idx { 0 };
std::unique_ptr<std::vector<Eu7Model>> models; std::unique_ptr<std::vector<Eu7Model>> models;
bool failed { false }; bool failed { false };
bool section_final { true }; std::size_t apply_offset { 0 };
std::uint32_t subchunk_index { 0 };
}; };
struct SectionStreamState { struct SectionStreamState {
@@ -123,6 +117,8 @@ struct SectionStreamState {
std::size_t pending_apply_offset { 0 }; std::size_t pending_apply_offset { 0 };
glm::dvec3 last_enqueue_position {}; glm::dvec3 last_enqueue_position {};
bool has_last_enqueue_position { false }; bool has_last_enqueue_position { false };
glm::dvec3 anchor_position {};
bool has_anchor_position { false };
std::unordered_map<std::string, TModel3d *> mesh_cache; std::unordered_map<std::string, TModel3d *> mesh_cache;
std::unordered_map<std::string, scene::node_data> nodedata_cache; std::unordered_map<std::string, scene::node_data> nodedata_cache;
@@ -165,7 +161,10 @@ void
finalize_section( PackSectionReady const &batch ); finalize_section( PackSectionReady const &batch );
void void
fail_section( std::size_t const section_idx ); fail_section( std::size_t const section_idx, int const row = -1, int const column = -1 );
void
enqueue_failed_section( PackSectionJob const &job );
void void
release_pending_buffer(); release_pending_buffer();
@@ -194,6 +193,12 @@ stream_worker_count() {
return std::min( requested, kMaxPackStreamWorkers ); return std::min( requested, kMaxPackStreamWorkers );
} }
void
reset_stream_fields();
void
note_apply_progress();
void void
reset_stream_fields() { reset_stream_fields() {
g_stream.module = nullptr; g_stream.module = nullptr;
@@ -210,9 +215,12 @@ reset_stream_fields() {
g_stream.pending_apply.reset(); g_stream.pending_apply.reset();
g_stream.pending_apply_offset = 0; g_stream.pending_apply_offset = 0;
g_stream.has_last_enqueue_position = false; g_stream.has_last_enqueue_position = false;
g_stream.anchor_position = {};
g_stream.has_anchor_position = false;
g_stream.mesh_cache.clear(); g_stream.mesh_cache.clear();
g_stream.nodedata_cache.clear(); g_stream.nodedata_cache.clear();
reset_pack_texture_warm_cache(); reset_pack_texture_warm_cache();
note_apply_progress();
} }
[[nodiscard]] Eu7Module const & [[nodiscard]] Eu7Module const &
@@ -223,14 +231,6 @@ stream_module() {
return *g_stream.module; return *g_stream.module;
} }
[[nodiscard]] std::string const &
pack_stream_file_path() {
if( false == g_stream.path.empty() ) {
return g_stream.path;
}
return stream_module().source_path;
}
void void
release_pending_buffer() { release_pending_buffer() {
if( false == g_stream.pending_apply.has_value() ) { if( false == g_stream.pending_apply.has_value() ) {
@@ -315,10 +315,7 @@ adaptive_slice_instances( std::size_t const section_total ) {
limit = std::min( limit, kCatchupSliceInstances ); limit = std::min( limit, kCatchupSliceInstances );
} }
else if( speed > 600.0 ) { else if( speed > 600.0 ) {
limit = std::min( limit, std::size_t { 96 } ); limit = std::min( limit, std::size_t { 128 } );
}
else if( speed > 300.0 ) {
limit = std::min( limit, std::size_t { 80 } );
} }
else { else {
limit = std::min( limit, std::size_t { 96 } ); limit = std::min( limit, std::size_t { 96 } );
@@ -334,19 +331,13 @@ adaptive_slice_instances( std::size_t const section_total ) {
else if( section_total > 800 ) { else if( section_total > 800 ) {
limit = std::min( limit, std::size_t { 80 } ); limit = std::min( limit, std::size_t { 80 } );
} }
else if( section_total <= kPackWorkerSubChunkModels ) {
limit = std::min( limit, std::size_t { 64 } );
if( g_stream_catchup && camera_stream_speed_mps() > 300.0 ) {
limit = std::min( limit, std::size_t { 48 } );
}
}
auto const last_ms { pack_bench_stream().last_chunk_ms }; auto const last_ms { pack_bench_stream().last_chunk_ms };
if( last_ms >= 24.0 ) { if( last_ms >= 24.0 ) {
limit = std::min( limit, std::size_t { 32 } ); limit = std::min( limit, std::size_t { 32 } );
} }
else if( last_ms >= 12.0 ) { else if( last_ms >= 12.0 ) {
limit = std::min( limit, std::size_t { 48 } ); limit = std::min( limit, std::size_t { 64 } );
} }
return std::max( limit, std::size_t { 16 } ); return std::max( limit, std::size_t { 16 } );
@@ -354,12 +345,8 @@ adaptive_slice_instances( std::size_t const section_total ) {
[[nodiscard]] std::size_t [[nodiscard]] std::size_t
adaptive_cold_meshes() { adaptive_cold_meshes() {
auto const &stream { pack_bench_stream() };
if( stream.last_chunk_ms >= 40.0 || stream.peak_chunk_ms >= 80.0 ) {
return 0;
}
auto limit { gameplay_slice_cold_meshes() }; auto limit { gameplay_slice_cold_meshes() };
if( stream.last_chunk_ms >= 12.0 ) { if( pack_bench_stream().last_chunk_ms >= 12.0 ) {
limit = 1; limit = 1;
} }
return limit; return limit;
@@ -432,29 +419,82 @@ preload_slice_cold_meshes(
return 0; return 0;
} }
replace_slashes( model_file ); replace_slashes( model_file );
if( g_stream.mesh_cache.contains( model_file ) ) { if( false == g_stream.mesh_cache.contains( model_file ) ) {
slice_count = 1; TModel3d *mesh { nullptr };
return 0; {
PackBenchTimer const load_timer { &Eu7PackBench::main_cold_getmodel_ms };
mesh = TModelsManager::GetModel( model_file, false, false );
pack_bench_inc( &Eu7PackBench::main_cold_getmodel_calls );
}
if( mesh != nullptr ) {
TAnimModel::warm_instanceable_cache( mesh );
}
g_stream.mesh_cache.emplace( model_file, mesh );
cold_loaded = 1;
} }
if( max_cold_meshes == 0 ) {
return 0;
}
TModel3d *mesh { nullptr };
{
PackBenchTimer const load_timer { &Eu7PackBench::main_cold_getmodel_ms };
mesh = TModelsManager::GetModel( model_file, false, false );
pack_bench_inc( &Eu7PackBench::main_cold_getmodel_calls );
}
if( mesh != nullptr ) {
TAnimModel::warm_instanceable_cache( mesh );
}
g_stream.mesh_cache.emplace( model_file, mesh );
slice_count = 1; slice_count = 1;
cold_loaded = 1;
} }
return cold_loaded; return cold_loaded;
} }
constexpr int kApplyStuckSkipFrames { 20 };
std::size_t g_apply_stuck_offset { std::numeric_limits<std::size_t>::max() };
int g_apply_stuck_frames { 0 };
void
note_apply_progress() {
g_apply_stuck_offset = std::numeric_limits<std::size_t>::max();
g_apply_stuck_frames = 0;
}
[[nodiscard]] bool
maybe_skip_stuck_apply_offset() {
if( false == g_stream.pending_apply.has_value() ) {
return false;
}
auto const offset { g_stream.pending_apply_offset };
if( offset == g_apply_stuck_offset ) {
++g_apply_stuck_frames;
}
else {
g_apply_stuck_offset = offset;
g_apply_stuck_frames = 0;
}
if( g_apply_stuck_frames < kApplyStuckSkipFrames ) {
return false;
}
auto const total {
g_stream.pending_apply->models != nullptr ?
g_stream.pending_apply->models->size() :
0 };
if( offset >= total ) {
return false;
}
auto model_file { ( *g_stream.pending_apply->models )[ offset ].model_file };
WriteLog(
"EU7 PACK: skip stuck model offset=" + std::to_string( offset ) + "/" +
std::to_string( total ) + " sec=" + std::to_string( g_stream.pending_apply->row ) + "," +
std::to_string( g_stream.pending_apply->column ) +
( model_file.empty() ? "" : " file=\"" + model_file + "\"" ) );
if( false == model_file.empty() && model_file != "notload" ) {
replace_slashes( model_file );
g_stream.mesh_cache.emplace( std::move( model_file ), nullptr );
}
g_stream.pending_apply_offset = offset + 1;
note_apply_progress();
return true;
}
void
maybe_preempt_distant_pending() {
// Wyłączone — najpierw stabilność: dokończ bieżącą sekcję zamiast preemptować.
}
[[nodiscard]] bool [[nodiscard]] bool
apply_pending_chunk( apply_pending_chunk(
double const budget_ms, double const budget_ms,
@@ -462,9 +502,16 @@ apply_pending_chunk(
std::size_t const max_cold_meshes, std::size_t const max_cold_meshes,
double const cold_budget_ms, double const cold_budget_ms,
std::size_t const max_chunks ) { std::size_t const max_chunks ) {
(void)max_instances;
(void)max_cold_meshes;
(void)cold_budget_ms;
if( g_stream.serializer == nullptr ) { if( g_stream.serializer == nullptr ) {
return false; return false;
} }
if( maybe_skip_stuck_apply_offset() ) {
return true;
}
maybe_preempt_distant_pending();
if( false == g_stream.pending_apply.has_value() && false == try_dequeue_ready_batch() ) { if( false == g_stream.pending_apply.has_value() && false == try_dequeue_ready_batch() ) {
return false; return false;
} }
@@ -483,7 +530,7 @@ apply_pending_chunk(
auto &batch { *g_stream.pending_apply }; auto &batch { *g_stream.pending_apply };
if( batch.failed || batch.models == nullptr || batch.models->empty() ) { if( batch.failed || batch.models == nullptr || batch.models->empty() ) {
if( batch.failed ) { if( batch.failed ) {
fail_section( batch.section_idx ); fail_section( batch.section_idx, batch.row, batch.column );
} }
else { else {
finalize_section( batch ); finalize_section( batch );
@@ -497,21 +544,15 @@ apply_pending_chunk(
auto const total { batch.models->size() }; auto const total { batch.models->size() };
auto const offset { g_stream.pending_apply_offset }; auto const offset { g_stream.pending_apply_offset };
if( offset >= total ) { if( offset >= total ) {
if( batch.section_final ) { finalize_section( batch );
finalize_section( batch );
}
release_pending_buffer(); release_pending_buffer();
applied_work = true; applied_work = true;
continue; continue;
} }
auto const effective_instances { // Sekcja 1 km (komorka TCP) — apply w calosci, bez dzielenia na plasterki.
std::min( max_instances, adaptive_slice_instances( total ) ) };
auto const effective_cold {
std::min( max_cold_meshes, adaptive_cold_meshes() ) };
auto const remaining { total - offset }; auto const remaining { total - offset };
auto const chunk_cap { std::min( effective_instances, remaining ) }; std::size_t chunk_count { remaining };
std::size_t chunk_count { chunk_cap };
auto const chunk_started { std::chrono::steady_clock::now() }; auto const chunk_started { std::chrono::steady_clock::now() };
double cold_ms { 0.0 }; double cold_ms { 0.0 };
@@ -524,15 +565,18 @@ apply_pending_chunk(
auto const phase_started { std::chrono::steady_clock::now() }; auto const phase_started { std::chrono::steady_clock::now() };
cold_loads = preload_slice_cold_meshes( cold_loads = preload_slice_cold_meshes(
models_ptr + offset, models_ptr + offset,
chunk_cap, remaining,
effective_cold, remaining,
cold_budget_ms, 0.0,
chunk_count ); chunk_count );
cold_ms = std::chrono::duration<double, std::milli>( cold_ms = std::chrono::duration<double, std::milli>(
std::chrono::steady_clock::now() - phase_started ).count(); std::chrono::steady_clock::now() - phase_started ).count();
} }
if( chunk_count == 0 ) { if( chunk_count == 0 ) {
return applied_work; g_stream.pending_apply_offset = offset + 1;
note_apply_progress();
applied_work = true;
continue;
} }
{ {
@@ -582,13 +626,12 @@ apply_pending_chunk(
} }
load_stats().pack_models += chunk_count; load_stats().pack_models += chunk_count;
g_stream.pending_apply_offset = offset + chunk_count; g_stream.pending_apply_offset = offset + chunk_count;
note_apply_progress();
applied_work = true; applied_work = true;
++chunks_done; ++chunks_done;
if( g_stream.pending_apply_offset >= total ) { if( g_stream.pending_apply_offset >= total ) {
if( batch.section_final ) { finalize_section( batch );
finalize_section( batch );
}
release_pending_buffer(); release_pending_buffer();
continue; continue;
} }
@@ -712,134 +755,46 @@ worker_loop( std::stop_token const stop_token ) {
auto const &module { stream_module() }; auto const &module { stream_module() };
auto const entry { find_pack_entry( module, job.row, job.column ) }; auto const entry { find_pack_entry( module, job.row, job.column ) };
if( false == entry.has_value() || entry->model_count == 0 ) { if( false == entry.has_value() || entry->model_count == 0 ) {
PackSectionReady result; enqueue_failed_section( job );
result.row = job.row;
result.column = job.column;
result.section_idx = job.section_idx;
result.failed = true;
result.section_final = true;
{
std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
g_stream.ready.data.push_back( std::move( result ) );
}
pack_bench_inc( &Eu7PackBench::worker_failures );
continue; continue;
} }
auto const &pack_path { pack_stream_file_path() }; std::unique_ptr<std::vector<Eu7Model>> models;
if( pack_path.empty() ) { {
throw std::runtime_error( "EU7 PACK: brak sciezki pliku PACK" ); PackBenchTimer const read_timer { &Eu7PackBench::worker_read_pack_ms };
} auto section { read_pack_section( module, job.row, job.column ) };
if( false == section.empty() ) {
std::ifstream input { pack_path, std::ios::binary }; models = std::make_unique<std::vector<Eu7Model>>( std::move( section ) );
if( !input ) {
throw std::runtime_error(
"EU7 PACK: nie mozna otworzyc \"" + pack_path + "\"" );
}
Eu7PackSectionCursor header_cursor {};
Eu7PackSectionCursor cursor {};
if( job.resume_byte_offset == 0 ) {
seek_pack_section( module, input, *entry, header_cursor );
cursor = header_cursor;
}
else {
header_cursor = job.header_cursor;
resume_pack_section(
module,
input,
*entry,
job.resume_byte_offset,
job.resume_cursor,
cursor );
}
auto batch_index { job.subchunk_index };
bool section_completed { false };
for( ;; ) {
if( cursor.solo_remaining == 0 && cursor.inst_remaining == 0 ) {
break;
}
if( ready_queue_size() >= g_stream_max_ready ) {
PackSectionJob resume_job { job };
resume_job.header_cursor = header_cursor;
resume_job.resume_byte_offset = static_cast<std::uint64_t>(
input.tellg() - static_cast<std::streamoff>(
module.pack_payload_offset + entry->pack_offset ) );
resume_job.subchunk_index = batch_index;
resume_job.resume_cursor = cursor;
{
std::lock_guard<std::mutex> lock { g_stream.jobs.mutex };
g_stream.jobs.data.push_front( std::move( resume_job ) );
}
g_stream.work_cv.notify_all();
break;
}
std::unique_ptr<std::vector<Eu7Model>> models;
{
PackBenchTimer const read_timer { &Eu7PackBench::worker_read_pack_ms };
auto chunk {
read_pack_models_chunk(
module,
input,
cursor,
kPackWorkerSubChunkModels ) };
if( chunk.empty() ) {
break;
}
models = std::make_unique<std::vector<Eu7Model>>( std::move( chunk ) );
}
section_completed =
cursor.solo_remaining == 0 && cursor.inst_remaining == 0;
PackSectionReady result;
result.row = job.row;
result.column = job.column;
result.section_idx = job.section_idx;
result.models = std::move( models );
result.subchunk_index = batch_index;
result.section_final = section_completed;
if( result.models != nullptr ) {
pack_bench_inc(
&Eu7PackBench::worker_models_decoded, result.models->size() );
}
{
std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
g_stream.ready.data.push_back( std::move( result ) );
}
++batch_index;
if( section_completed ) {
break;
} }
} }
if( section_completed ) { PackSectionReady result;
pack_bench_inc( &Eu7PackBench::worker_sections_done ); result.row = job.row;
result.column = job.column;
result.section_idx = job.section_idx;
result.models = std::move( models );
result.failed = result.models == nullptr;
if( result.failed ) {
enqueue_failed_section( job );
continue;
} }
pack_bench_inc(
&Eu7PackBench::worker_models_decoded, result.models->size() );
{
std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
g_stream.ready.data.push_back( std::move( result ) );
}
pack_bench_inc( &Eu7PackBench::worker_sections_done );
} }
catch( std::exception const &ex ) { catch( std::exception const &ex ) {
ErrorLog( ErrorLog(
std::string{ "EU7 PACK: sekcja " + std::to_string( job.row ) + "," + std::string{ "EU7 PACK: sekcja " + std::to_string( job.row ) + "," +
std::to_string( job.column ) + ": " } + ex.what() ); std::to_string( job.column ) + ": " } + ex.what() );
fail_section( job.section_idx ); enqueue_failed_section( job );
PackSectionReady result;
result.row = job.row;
result.column = job.column;
result.section_idx = job.section_idx;
result.failed = true;
result.section_final = true;
{
std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
g_stream.ready.data.push_back( std::move( result ) );
}
pack_bench_inc( &Eu7PackBench::worker_failures );
} }
} }
} }
@@ -894,9 +849,6 @@ start_workers() {
void void
finalize_section( PackSectionReady const &batch ) { finalize_section( PackSectionReady const &batch ) {
if( false == batch.section_final ) {
return;
}
g_stream.loaded_sections.insert( batch.section_idx ); g_stream.loaded_sections.insert( batch.section_idx );
g_stream.in_flight_sections.erase( batch.section_idx ); g_stream.in_flight_sections.erase( batch.section_idx );
++load_stats().pack_sections_loaded; ++load_stats().pack_sections_loaded;
@@ -904,11 +856,43 @@ finalize_section( PackSectionReady const &batch ) {
} }
void void
fail_section( std::size_t const section_idx ) { fail_section(
std::size_t const section_idx,
int const row,
int const column ) {
if( g_stream.loaded_sections.contains( section_idx ) ) {
return;
}
if( row >= 0 && column >= 0 ) {
WriteLog(
"EU7 PACK: failed section " + std::to_string( row ) + "," +
std::to_string( column ) );
}
else {
WriteLog( "EU7 PACK: failed section idx=" + std::to_string( section_idx ) );
}
g_stream.loaded_sections.insert( section_idx ); g_stream.loaded_sections.insert( section_idx );
g_stream.in_flight_sections.erase( section_idx ); g_stream.in_flight_sections.erase( section_idx );
} }
void
enqueue_failed_section( PackSectionJob const &job ) {
PackSectionReady result;
result.row = job.row;
result.column = job.column;
result.section_idx = job.section_idx;
result.failed = true;
{
std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
g_stream.ready.data.push_back( std::move( result ) );
}
pack_bench_inc( &Eu7PackBench::worker_failures );
}
[[nodiscard]] int [[nodiscard]] int
section_manhattan_sections( section_manhattan_sections(
int const row, int const row,
@@ -1212,35 +1196,66 @@ try_dequeue_ready_batch() {
bool has_batch { false }; bool has_batch { false };
{ {
std::lock_guard<std::mutex> lock { g_stream.ready.mutex }; std::lock_guard<std::mutex> lock { g_stream.ready.mutex };
for( auto it { g_stream.ready.data.begin() }; it != g_stream.ready.data.end(); ) {
if( it->failed || it->models == nullptr || it->models->empty() ) {
if( it->failed ) {
fail_section( it->section_idx, it->row, it->column );
}
else {
finalize_section( *it );
}
it = g_stream.ready.data.erase( it );
continue;
}
++it;
}
if( false == g_stream.ready.data.empty() ) { if( false == g_stream.ready.data.empty() ) {
auto const best_it { auto const pick_best {
std::min_element( [&]( int const max_distance ) -> std::deque<PackSectionReady>::iterator {
g_stream.ready.data.begin(), auto best_it { g_stream.ready.data.end() };
g_stream.ready.data.end(), auto best_dist { std::numeric_limits<int>::max() };
[]( PackSectionReady const &lhs, PackSectionReady const &rhs ) { for( auto it { g_stream.ready.data.begin() }; it != g_stream.ready.data.end(); ++it ) {
auto const lhs_dist { if( it->failed || it->models == nullptr || it->models->empty() ) {
continue;
}
auto const dist {
section_manhattan_sections( section_manhattan_sections(
lhs.row, it->row,
lhs.column, it->column,
g_stream.center_row, g_stream.center_row,
g_stream.center_column ) }; g_stream.center_column ) };
auto const rhs_dist { if( max_distance >= 0 && dist > max_distance ) {
section_manhattan_sections( continue;
rhs.row,
rhs.column,
g_stream.center_row,
g_stream.center_column ) };
if( lhs_dist != rhs_dist ) {
return lhs_dist < rhs_dist;
} }
if( lhs.section_idx != rhs.section_idx ) { if( dist < best_dist || ( dist == best_dist && best_it == g_stream.ready.data.end() ) ) {
return lhs.section_idx < rhs.section_idx; best_dist = dist;
best_it = it;
} }
return lhs.subchunk_index < rhs.subchunk_index; else if(
} ) }; dist == best_dist && best_it != g_stream.ready.data.end() &&
batch = std::move( *best_it ); it->section_idx < best_it->section_idx ) {
g_stream.ready.data.erase( best_it ); best_it = it;
has_batch = true; }
}
return best_it;
} };
auto best_it {
pick_best( kSectionStreamGameplayRadiusKm ) };
if( best_it == g_stream.ready.data.end() ) {
best_it = pick_best( -1 );
}
if(
best_it == g_stream.ready.data.end()
&& false == g_stream.ready.data.empty() ) {
best_it = g_stream.ready.data.begin();
}
if( best_it != g_stream.ready.data.end() ) {
batch = std::move( *best_it );
g_stream.ready.data.erase( best_it );
has_batch = true;
}
} }
} }
@@ -1250,7 +1265,7 @@ try_dequeue_ready_batch() {
if( batch.failed || batch.models == nullptr || batch.models->empty() ) { if( batch.failed || batch.models == nullptr || batch.models->empty() ) {
if( batch.failed ) { if( batch.failed ) {
fail_section( batch.section_idx ); fail_section( batch.section_idx, batch.row, batch.column );
} }
else { else {
finalize_section( batch ); finalize_section( batch );
@@ -1259,7 +1274,8 @@ try_dequeue_ready_batch() {
} }
g_stream.pending_apply = std::move( batch ); g_stream.pending_apply = std::move( batch );
g_stream.pending_apply_offset = 0; g_stream.pending_apply_offset = g_stream.pending_apply->apply_offset;
g_stream.pending_apply->apply_offset = 0;
return true; return true;
} }
@@ -1371,30 +1387,29 @@ drain_until_budget( double const budget_ms ) {
void void
sync_stream_limits( glm::dvec3 const &world_position ) { sync_stream_limits( glm::dvec3 const &world_position ) {
(void)world_position;
g_stream_catchup = false;
if( false == g_loading_screen_dismissed ) { if( false == g_loading_screen_dismissed ) {
g_stream_catchup = false;
g_stream_max_in_flight = 6; g_stream_max_in_flight = 6;
g_stream_max_ready = 2; g_stream_max_ready = 2;
return; return;
} }
auto const inner_progress { g_stream_max_in_flight = kMaxInFlightSections;
section_stream_ring_progress( world_position, kSectionStreamGameplayRadiusKm ) }; g_stream_max_ready = kMaxReadySections;
g_stream_catchup =
inner_progress < 0.99f
|| false == section_stream_ready_around(
world_position,
kSectionStreamGameplayRadiusKm );
g_stream_max_in_flight = g_stream_catchup ?
kCatchupMaxInFlightSections :
kMaxInFlightSections;
g_stream_max_ready = g_stream_catchup ?
kCatchupMaxReadySections :
kMaxReadySections;
} }
} // namespace } // namespace
void
remember_stream_anchor( glm::dvec3 const &position );
[[nodiscard]] bool
camera_far_from_stream_anchor( glm::dvec3 const &camera_position );
[[nodiscard]] glm::dvec3
resolve_section_stream_position( glm::dvec3 const &hint );
void void
init_section_stream( init_section_stream(
Eu7Module const &root_module, Eu7Module const &root_module,
@@ -1434,6 +1449,8 @@ prime_section_stream( Eu7Module const &root_module ) {
return; return;
} }
remember_stream_anchor( initial );
auto const [row, column] { section_row_column( initial ) }; auto const [row, column] { section_row_column( initial ) };
g_stream.center_row = row; g_stream.center_row = row;
g_stream.center_column = column; g_stream.center_column = column;
@@ -1534,12 +1551,14 @@ update_section_stream( glm::dvec3 const &world_position ) {
return; return;
} }
auto const [center_row, center_column] { section_row_column( world_position ) }; auto const stream_position { resolve_section_stream_position( world_position ) };
auto const [center_row, center_column] { section_row_column( stream_position ) };
auto const center_moved { auto const center_moved {
center_row != g_stream.center_row || center_column != g_stream.center_column }; center_row != g_stream.center_row || center_column != g_stream.center_column };
auto const moved_since_enqueue { auto const moved_since_enqueue {
g_stream.has_last_enqueue_position ? g_stream.has_last_enqueue_position ?
glm::length( world_position - g_stream.last_enqueue_position ) : glm::length( stream_position - g_stream.last_enqueue_position ) :
std::numeric_limits<double>::infinity() }; std::numeric_limits<double>::infinity() };
if( moved_since_enqueue > kTeleportReenqueueDistanceM ) { if( moved_since_enqueue > kTeleportReenqueueDistanceM ) {
@@ -1553,65 +1572,47 @@ update_section_stream( glm::dvec3 const &world_position ) {
reprioritize_job_queue(); reprioritize_job_queue();
} }
sync_stream_limits( world_position ); sync_stream_limits( stream_position );
auto const ring_radius { g_stream.radius }; auto const inner_ring_ready {
auto const reenqueue_distance { section_stream_ready_around( stream_position, kSectionStreamGameplayRadiusKm ) };
g_stream_catchup ? kCatchupReenqueueDistanceM : kReenqueueDistanceM }; auto const ring_radius {
auto max_lookahead { g_stream_catchup ? 15 : 5 }; inner_ring_ready ? g_stream.radius : kSectionStreamGameplayRadiusKm };
if( g_stream_catchup ) { auto const reenqueue_distance { kReenqueueDistanceM };
auto const speed { camera_stream_speed_mps() }; auto max_lookahead { inner_ring_ready ? 5 : 0 };
if( speed > 1200.0 ) {
max_lookahead = 25;
}
else if( speed > 600.0 ) {
max_lookahead = 20;
}
}
auto const travel_forward { guess_travel_forward() }; auto const travel_forward { guess_travel_forward() };
auto const current_section_unloaded { auto const current_section_unloaded {
section_has_pack_models( center_row, center_column ) section_has_pack_models( center_row, center_column )
&& false == g_stream.loaded_sections.contains( section_index( center_row, center_column ) ) }; && false == g_stream.loaded_sections.contains( section_index( center_row, center_column ) ) };
auto const inner_ring_incomplete { auto const inner_ring_incomplete { current_section_unloaded || false == inner_ring_ready };
current_section_unloaded
|| false == section_stream_ready_around( world_position, kSectionStreamGameplayRadiusKm ) };
auto const should_reenqueue { auto const should_reenqueue {
center_moved center_moved
|| false == g_stream.has_last_enqueue_position || false == g_stream.has_last_enqueue_position
|| moved_since_enqueue >= reenqueue_distance }; || moved_since_enqueue >= reenqueue_distance };
if( should_reenqueue || inner_ring_incomplete || g_stream_catchup ) { if( should_reenqueue || inner_ring_incomplete ) {
enqueue_sections_around( center_row, center_column, ring_radius, world_position ); enqueue_sections_around( center_row, center_column, ring_radius, stream_position );
g_stream.last_enqueue_position = world_position; g_stream.last_enqueue_position = stream_position;
g_stream.has_last_enqueue_position = true; g_stream.has_last_enqueue_position = true;
if( should_reenqueue || inner_ring_incomplete ) { if( should_reenqueue || inner_ring_incomplete ) {
pack_bench_inc( &Eu7PackBench::stream_reenqueue ); pack_bench_inc( &Eu7PackBench::stream_reenqueue );
} }
enqueue_movement_lookahead( if( max_lookahead > 0 ) {
center_row, enqueue_movement_lookahead(
center_column, center_row,
ring_radius, center_column,
travel_forward, ring_radius,
max_lookahead ); travel_forward,
max_lookahead );
}
} }
} }
[[nodiscard]] bool [[nodiscard]] bool
section_stream_drain_idle( glm::dvec3 const &world_position ) { section_stream_drain_idle( glm::dvec3 const &world_position ) {
if( g_stream.bootstrap_pending || g_stream.bootstrap_active ) { (void)world_position;
return false; return false;
}
if( g_stream.pending_apply.has_value() || ready_queue_size() > 0 ) {
return false;
}
if( false == g_stream.in_flight_sections.empty() || g_stream_catchup ) {
return false;
}
if( false == section_stream_ready_around( world_position, kSectionStreamGameplayRadiusKm ) ) {
return false;
}
return load_stats().pack_models >= 500;
} }
void void
@@ -1624,33 +1625,27 @@ drain_section_stream(
if( false == g_stream.active ) { if( false == g_stream.active ) {
return; return;
} }
if( section_stream_drain_idle( Global.pCamera.Pos ) ) { auto const stream_position {
resolve_section_stream_position(
g_loading_screen_dismissed ?
Global.pCamera.Pos :
stream_loading_position() ) };
if( gameplay_stream_mode() && section_stream_drain_idle( stream_position ) ) {
return; return;
} }
if( gameplay_stream_mode() ) { auto const inner_ring_ready {
auto apply_budget { gameplay_apply_budget_ms() }; section_stream_ready_around(
std::size_t max_chunks { 1 }; stream_position,
if( g_stream_catchup ) { kSectionStreamGameplayRadiusKm ) };
auto const inner_ring {
section_stream_ring_progress( if( gameplay_stream_mode() && inner_ring_ready ) {
Global.pCamera.Pos, drain_until_budget( kDrainBudgetMs );
kSectionStreamGameplayRadiusKm ) }; maybe_log_stream_status( stream_position );
auto const speed { camera_stream_speed_mps() }; }
if( else if( gameplay_stream_mode() ) {
inner_ring < kStationaryCatchupRingThreshold drain_until_budget( kLoaderDrainBudgetMs );
&& speed < kStationaryCatchupSpeedMps ) { maybe_log_stream_status( stream_position );
max_chunks = 2;
apply_budget = std::max( apply_budget, kCatchupApplyBudgetMs * 1.25 );
}
}
drain_apply_budget(
apply_budget,
gameplay_slice_instances(),
gameplay_slice_cold_meshes(),
gameplay_cold_budget_ms(),
max_chunks );
maybe_log_stream_status( Global.pCamera.Pos );
} }
else if( false == g_loading_screen_dismissed ) { else if( false == g_loading_screen_dismissed ) {
auto position { stream_loading_position() }; auto position { stream_loading_position() };
@@ -1693,6 +1688,8 @@ kick_section_stream_bootstrap() {
return; return;
} }
remember_stream_anchor( position );
auto const [row, column] { section_row_column( position ) }; auto const [row, column] { section_row_column( position ) };
g_stream.center_row = row; g_stream.center_row = row;
g_stream.center_column = column; g_stream.center_column = column;
@@ -1734,6 +1731,7 @@ preload_section_stream( double const max_drain_ms ) {
if( position.x == 0.0 && position.y == 0.0 && position.z == 0.0 ) { if( position.x == 0.0 && position.y == 0.0 && position.z == 0.0 ) {
position = guess_initial_stream_position( stream_module() ); position = guess_initial_stream_position( stream_module() );
} }
position = resolve_section_stream_position( position );
if( section_stream_needs_bootstrap() ) { if( section_stream_needs_bootstrap() ) {
if( position.x != 0.0 || position.y != 0.0 || position.z != 0.0 ) { if( position.x != 0.0 || position.y != 0.0 || position.z != 0.0 ) {
@@ -1932,6 +1930,23 @@ dismiss_loading_screen() {
pack_bench_begin_stream_phase(); pack_bench_begin_stream_phase();
g_loading_screen_dismissed = true; g_loading_screen_dismissed = true;
g_ring_ready_since.reset(); g_ring_ready_since.reset();
if( g_stream.has_anchor_position ) {
auto const &saved_camera { Global.FreeCameraInit[ 0 ] };
auto const camera_unset {
saved_camera.x == 0.0 && saved_camera.y == 0.0 && saved_camera.z == 0.0 };
auto const camera_off_scenery {
false == camera_unset && camera_far_from_stream_anchor( saved_camera ) };
if( camera_unset || camera_off_scenery ) {
Global.FreeCameraInit[ 0 ] = g_stream.anchor_position;
Global.pCamera.Pos = g_stream.anchor_position;
WriteLog(
"EU7 PACK: ustawiam kamere startowa na " +
std::to_string( g_stream.anchor_position.x ) + "," +
std::to_string( g_stream.anchor_position.y ) + "," +
std::to_string( g_stream.anchor_position.z ) );
}
}
} }
bool bool
@@ -1978,15 +1993,24 @@ loading_screen_blocks_world(
glm::dvec3 glm::dvec3
stream_loading_position() { stream_loading_position() {
if( Global.pCamera.Pos.x != 0.0 || Global.pCamera.Pos.y != 0.0 || Global.pCamera.Pos.z != 0.0 ) { if( g_loading_screen_dismissed ) {
return Global.pCamera.Pos; return Global.pCamera.Pos;
} }
auto const &camera { Global.pCamera.Pos };
if( camera.x != 0.0 || camera.y != 0.0 || camera.z != 0.0 ) {
return camera;
}
auto position { resolve_stream_position() }; auto position { resolve_stream_position() };
if( position.x != 0.0 || position.y != 0.0 || position.z != 0.0 ) { if( position.x != 0.0 || position.y != 0.0 || position.z != 0.0 ) {
return position; return position;
} }
if( g_stream.has_anchor_position ) {
return g_stream.anchor_position;
}
return Global.FreeCameraInit[ 0 ]; return Global.FreeCameraInit[ 0 ];
} }
@@ -2025,6 +2049,48 @@ section_stream_ring_progress(
return std::clamp( accumulated / static_cast<float>( pack_sections ), 0.f, 1.f ); return std::clamp( accumulated / static_cast<float>( pack_sections ), 0.f, 1.f );
} }
void
remember_stream_anchor( glm::dvec3 const &position ) {
if( position.x == 0.0 && position.y == 0.0 && position.z == 0.0 ) {
return;
}
g_stream.anchor_position = position;
g_stream.has_anchor_position = true;
}
[[nodiscard]] glm::dvec3
resolve_section_stream_position( glm::dvec3 const &hint ) {
if(
hint.x == 0.0 && hint.y == 0.0 && hint.z == 0.0
&& g_stream.has_anchor_position ) {
return g_stream.anchor_position;
}
if( camera_far_from_stream_anchor( hint ) && g_stream.has_anchor_position ) {
return g_stream.anchor_position;
}
return hint;
}
[[nodiscard]] bool
camera_far_from_stream_anchor( glm::dvec3 const &camera_position ) {
if( false == g_stream.has_anchor_position ) {
return false;
}
auto const anchor_dist {
glm::length(
glm::dvec2 {
camera_position.x - g_stream.anchor_position.x,
camera_position.z - g_stream.anchor_position.z } ) };
auto const anchor_magnitude {
glm::length(
glm::dvec2 { g_stream.anchor_position.x, g_stream.anchor_position.z } ) };
auto const camera_magnitude {
glm::length( glm::dvec2 { camera_position.x, camera_position.z } ) };
return anchor_dist > 30000.0
&& camera_magnitude < 30000.0
&& anchor_magnitude > 50000.0;
}
void void
reset_section_stream() { reset_section_stream() {
flush_pack_stream_bench(); flush_pack_stream_bench();

View File

@@ -19,7 +19,7 @@ class state_serializer;
namespace scene::eu7 { namespace scene::eu7 {
constexpr int kSectionStreamBootstrapRadiusKm { 3 }; constexpr int kSectionStreamBootstrapRadiusKm { 4 };
constexpr int kSectionStreamGameplayRadiusKm { 4 }; constexpr int kSectionStreamGameplayRadiusKm { 4 };
void void
@@ -34,6 +34,10 @@ prime_section_stream( Eu7Module const &RootModule );
[[nodiscard]] glm::dvec3 [[nodiscard]] glm::dvec3
resolve_stream_position(); resolve_stream_position();
// Kamera / pojazd moga byc w innej przestrzeni wspolrzednych niz PACK — uzyj kotwicy scenerii.
[[nodiscard]] glm::dvec3
resolve_section_stream_position( glm::dvec3 const &Hint );
// Opcjonalnie blokuje do zaladowania pierścienia bootstrap wokol pozycji (debug/narzedzia). // Opcjonalnie blokuje do zaladowania pierścienia bootstrap wokol pozycji (debug/narzedzia).
void void
bootstrap_section_stream( glm::dvec3 const &WorldPosition ); bootstrap_section_stream( glm::dvec3 const &WorldPosition );

View File

@@ -360,7 +360,7 @@ struct Eu7PackIndexEntry {
std::uint64_t pack_offset = 0; std::uint64_t pack_offset = 0;
}; };
// Stan inkrementalnego odczytu sekcji PACK z istream (po seek_pack_section). // Stan odczytu sekcji PACK z istream (uzywany wewnetrznie przez reader).
struct Eu7PackSectionCursor { struct Eu7PackSectionCursor {
std::uint32_t solo_remaining { 0 }; std::uint32_t solo_remaining { 0 };
std::uint32_t inst_remaining { 0 }; std::uint32_t inst_remaining { 0 };

View File

@@ -617,15 +617,16 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
is_pure_eu7_scenario = scene::eu7::probe_file( resolved_scenario ); is_pure_eu7_scenario = scene::eu7::probe_file( resolved_scenario );
} }
bool const has_baked_eu7_root { bool const use_eu7_scenario {
false == is_pure_eu7_scenario && is_pure_eu7_scenario || scene::eu7::probe_baked_scenario( Scenariofile ) };
scene::eu7::should_use_binary_module( Scenariofile ) }; auto const eu7_load_path {
auto const baked_root_path { is_pure_eu7_scenario ?
scene::eu7::resolve_scenery_path( scene::eu7::binary_path( Scenariofile ) ) }; resolved_scenario :
scene::eu7::resolve_scenery_path( scene::eu7::binary_path( Scenariofile ) ) };
// Scenariusz EU7B: nie parsujemy binarki jako tekstu SCM. // Scenariusz EU7B: nie parsujemy binarki jako tekstu SCM.
std::shared_ptr<deserializer_state> state; std::shared_ptr<deserializer_state> state;
if( is_pure_eu7_scenario ) { if( use_eu7_scenario ) {
state = std::make_shared<deserializer_state>( state = std::make_shared<deserializer_state>(
std::string{}, cParser::buffer_TEXT, Global.asCurrentSceneryPath, Global.bLoadTraction ); std::string{}, cParser::buffer_TEXT, Global.asCurrentSceneryPath, Global.bLoadTraction );
state->scenariofile = Scenariofile; state->scenariofile = Scenariofile;
@@ -637,25 +638,12 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
state->scratchpad.name = Scenariofile; state->scratchpad.name = Scenariofile;
if( is_pure_eu7_scenario ) { if( use_eu7_scenario ) {
Global.file_binary_terrain_state = true; Global.file_binary_terrain_state = true;
state->scratchpad.binary.terrain = true; state->scratchpad.binary.terrain = true;
state->scratchpad.binary.terrain_included = true; state->scratchpad.binary.terrain_included = true;
WriteLog( "EU7 scenario: " + resolved_scenario ); WriteLog( "EU7 scenario: " + eu7_load_path );
if( false == scene::eu7::load_module( resolved_scenario, *this ) ) { if( false == scene::eu7::load_module( eu7_load_path, *this ) ) {
throw invalid_scenery_exception();
}
}
else if( has_baked_eu7_root ) {
Global.file_binary_terrain_state = true;
state->scratchpad.binary.terrain = true;
if( scene::eu7::is_scenario_terrain( Scenariofile ) ) {
state->scratchpad.binary.terrain_included = true;
}
WriteLog(
"EU7 hybrid: metadata z \"" + Scenariofile + "\", sceneria z \"" +
baked_root_path + "\"" );
if( false == scene::eu7::load_module( baked_root_path, *this ) ) {
throw invalid_scenery_exception(); throw invalid_scenery_exception();
} }
} }

View File

@@ -43,7 +43,7 @@ def read_cstring(f, rva: int) -> str:
def parse(path: Path) -> None: def parse(path: Path) -> None:
with path.open("rb") as f: with path.open("rb") as f:
sig, ver, num_streams, dir_rva, checksum, ts, flags = struct.unpack( sig, ver, num_streams, dir_rva, checksum, ts, flags = struct.unpack(
"<IIIIIQ", f.read(32) "<IIIIIIQ", f.read(32)
) )
print(f"File: {path}") print(f"File: {path}")
print(f"Size: {path.stat().st_size:,} bytes") print(f"Size: {path.stat().st_size:,} bytes")

View File

@@ -366,9 +366,7 @@ void cParser::startIncludeFromParser(cParser& srcParser, bool ToLower, std::stri
return; return;
} }
} }
else if ( scene::eu7::probe_file( eu7path ) ) {
WriteLog( "EU7: przestarzaly .eu7, fallback SCM: " + includefile );
}
if (isTerrain && true == Global.file_binary_terrain_state) { if (isTerrain && true == Global.file_binary_terrain_state) {
WriteLog("Binary terrain present, ignoring: " + includefile); WriteLog("Binary terrain present, ignoring: " + includefile);
readParameters(srcParser); // preserve original side-effect: still consume parameters readParameters(srcParser); // preserve original side-effect: still consume parameters

View File

@@ -75,6 +75,17 @@ ui::map_panel::map_panel() : ui_panel(STR_C("Map"), false)
scene_ubo = std::make_unique<gl::ubo>(sizeof(gl::scene_ubs), 0); scene_ubo = std::make_unique<gl::ubo>(sizeof(gl::scene_ubs), 0);
if( simulation::Train != nullptr && simulation::Train->Dynamic() != nullptr ) {
mode = MODE_VEHICLE;
}
else {
auto const &start { Global.FreeCameraInit[ 0 ] };
if( start.x != 0.0 || start.z != 0.0 ) {
mode = MODE_CAMERA;
translate = glm::vec2( static_cast<float>( start.x ), static_cast<float>( start.z ) ) * -zoom;
}
}
init_done = true; init_done = true;
} }
@@ -88,9 +99,6 @@ float ui::map_panel::get_vehicle_rotation()
void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_size) void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_size)
{ {
cFrustum frustum;
frustum.calculate(transform, glm::mat4());
m_colored_paths.switches.clear(); m_colored_paths.switches.clear();
m_colored_paths.occupied.clear(); m_colored_paths.occupied.clear();
m_colored_paths.future.clear(); m_colored_paths.future.clear();
@@ -102,14 +110,14 @@ void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_si
for (int column = 0; column < scene::EU07_REGIONSIDESECTIONCOUNT; column++) for (int column = 0; column < scene::EU07_REGIONSIDESECTIONCOUNT; column++)
{ {
scene::basic_section *section = simulation::Region->get_section(row * scene::EU07_REGIONSIDESECTIONCOUNT + column); scene::basic_section *section = simulation::Region->get_section(row * scene::EU07_REGIONSIDESECTIONCOUNT + column);
if (section && frustum.sphere_inside(section->area().center, section->area().radius) > 0.f) if( section == nullptr ) {
continue;
}
const gfx::geometrybank_handle handle = section->get_map_geometry();
if( handle != null_handle )
{ {
const gfx::geometrybank_handle handle = section->get_map_geometry(); m_section_handles.push_back(handle);
if (handle != null_handle) section->get_map_active_paths(m_colored_paths);
{
m_section_handles.push_back(handle);
section->get_map_active_paths(m_colored_paths);
}
} }
} }
} }
@@ -230,6 +238,17 @@ void ui::map_panel::render_contents()
return; return;
} }
if( simulation::Train != nullptr && simulation::Train->Dynamic() != nullptr ) {
if( mode == MODE_MANUAL ) {
mode = MODE_VEHICLE;
}
}
else if(
mode == MODE_MANUAL
&& ( Global.pCamera.Pos.x != 0.0 || Global.pCamera.Pos.z != 0.0 ) ) {
mode = MODE_CAMERA;
}
{ {
float prev_zoom = zoom; float prev_zoom = zoom;