mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-18 01:59:19 +02:00
fix
This commit is contained in:
@@ -12,9 +12,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "application/drivermode.h"
|
||||
#include "application/editormode.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 "utilities/Globals.h"
|
||||
@@ -710,59 +707,9 @@ void eu07_application::exit()
|
||||
#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()
|
||||
{
|
||||
|
||||
if( loading_overlay_active() ) {
|
||||
render_loading_overlay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_modestack.empty())
|
||||
{
|
||||
return;
|
||||
@@ -774,12 +721,6 @@ void eu07_application::render_ui()
|
||||
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())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "application/applicationmode.h"
|
||||
#include "scripting/PyInt.h"
|
||||
#include "network/manager.h"
|
||||
@@ -57,12 +55,6 @@ public:
|
||||
render_ui();
|
||||
void
|
||||
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
|
||||
bool
|
||||
pop_mode();
|
||||
@@ -123,12 +115,9 @@ private:
|
||||
int init_modes();
|
||||
bool init_network();
|
||||
int run_crashgui();
|
||||
void sync_loading_overlay_state();
|
||||
// members
|
||||
|
||||
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
|
||||
mode_stack m_modestack; // current behaviour mode
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
void begin_ui_frame() {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->begin_ui_frame(); } }
|
||||
virtual
|
||||
inline
|
||||
void set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->set_progress( Progress, Subtaskprogress ); } }
|
||||
|
||||
@@ -404,24 +404,14 @@ bool driver_mode::update()
|
||||
|
||||
Timer::subsystem.sim_total.stop();
|
||||
|
||||
auto const world_presentable {
|
||||
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 );
|
||||
simulation::State.drain_deferred_eu7_trainsets( 12.0 );
|
||||
|
||||
if( scene::eu7::section_stream_active() ) {
|
||||
auto const stream_active {
|
||||
simulation::is_ready || Application.loading_overlay_active() };
|
||||
if( stream_active && scene::eu7::section_stream_needs_bootstrap() ) {
|
||||
if( scene::eu7::section_stream_needs_bootstrap() ) {
|
||||
scene::eu7::kick_section_stream_bootstrap();
|
||||
}
|
||||
if( stream_active ) {
|
||||
scene::eu7::update_section_stream( Global.pCamera.Pos );
|
||||
scene::eu7::drain_section_stream();
|
||||
}
|
||||
scene::eu7::update_section_stream( Global.pCamera.Pos );
|
||||
scene::eu7::drain_section_stream();
|
||||
|
||||
if( scene::eu7::pack_bench_stream_phase_active() ) {
|
||||
static double s_last_stream_bench_log { 0.0 };
|
||||
@@ -442,9 +432,7 @@ bool driver_mode::update()
|
||||
|
||||
GfxRenderer->Update(deltarealtime);
|
||||
|
||||
simulation::is_ready = simulation::is_ready
|
||||
|| ( ( simulation::Train != nullptr ) && ( simulation::Train->is_cab_initialized ) )
|
||||
|| ( Global.local_start_vehicle == "ghostview" && world_presentable );
|
||||
simulation::is_ready = simulation::is_ready || ((simulation::Train != nullptr) && (simulation::Train->is_cab_initialized)) || (Global.local_start_vehicle == "ghostview");
|
||||
|
||||
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)};
|
||||
|
||||
if( scene::eu7::section_stream_active() ) {
|
||||
scene::eu7::dismiss_loading_screen();
|
||||
}
|
||||
|
||||
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr);
|
||||
Global.pCamera = Camera;
|
||||
Global.pDebugCamera = DebugCamera;
|
||||
@@ -462,6 +454,26 @@ void driver_mode::enter()
|
||||
FreeFlyModeFlag = true;
|
||||
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)
|
||||
{
|
||||
WriteLog("Trying to enter player train, \"" + Global.local_start_vehicle + "\"");
|
||||
|
||||
@@ -19,16 +19,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "rendering/renderer.h"
|
||||
#include "utilities/Logs.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"
|
||||
|
||||
namespace {
|
||||
constexpr std::chrono::seconds kEu7LoadTimeout { 90 };
|
||||
constexpr float kDeserializeBarShare { 70.f };
|
||||
constexpr float kPackBarShare { 30.f };
|
||||
} // namespace
|
||||
|
||||
scenarioloader_mode::scenarioloader_mode() {
|
||||
m_userinterface = std::make_shared<scenarioloader_ui>();
|
||||
}
|
||||
@@ -39,13 +31,6 @@ bool scenarioloader_mode::init() {
|
||||
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
|
||||
bool scenarioloader_mode::update() {
|
||||
if (!Global.ready_to_load)
|
||||
@@ -64,80 +49,22 @@ bool scenarioloader_mode::update() {
|
||||
}
|
||||
|
||||
try {
|
||||
if( m_phase == load_phase::deserialize ) {
|
||||
if( simulation::State.deserialize_continue( state ) ) {
|
||||
return true;
|
||||
}
|
||||
m_phase = load_phase::eu7_load;
|
||||
m_eu7_load_started = std::chrono::steady_clock::now();
|
||||
m_eu7_stream_primed = false;
|
||||
}
|
||||
if (simulation::State.deserialize_continue(state))
|
||||
return true;
|
||||
}
|
||||
catch (invalid_scenery_exception &e) {
|
||||
ErrorLog( "Bad init: scenario loading failed" );
|
||||
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" );
|
||||
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.push_mode( eu07_application::mode::driver );
|
||||
|
||||
@@ -153,9 +80,6 @@ void scenarioloader_mode::enter() {
|
||||
// TBD: hide cursor in fullscreen mode?
|
||||
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;
|
||||
|
||||
Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
|
||||
@@ -167,15 +91,3 @@ void scenarioloader_mode::exit() {
|
||||
simulation::Time.init( Global.starting_timestamp );
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -13,21 +13,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "simulation/simulation.h"
|
||||
|
||||
class scenarioloader_mode : public application_mode {
|
||||
|
||||
enum class load_phase {
|
||||
deserialize,
|
||||
eu7_load,
|
||||
finished
|
||||
};
|
||||
|
||||
std::shared_ptr<simulation::deserializer_state> state;
|
||||
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:
|
||||
// constructors
|
||||
@@ -41,7 +28,6 @@ public:
|
||||
void enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void exit() override;
|
||||
void set_progress( float Progress = 0.f, float Subtaskprogress = 0.f ) override;
|
||||
// input handlers
|
||||
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 { ; }
|
||||
|
||||
@@ -195,10 +195,6 @@ void scenarioloader_ui::render_()
|
||||
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);
|
||||
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::SetWindowFontScale(1);
|
||||
const float font_scale_mult = 48 / ImGui::GetFontSize();
|
||||
@@ -232,14 +228,7 @@ void scenarioloader_ui::render_()
|
||||
icon_center_y - text_size.y * 0.5f);
|
||||
|
||||
// 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());
|
||||
|
||||
// Trivia
|
||||
|
||||
@@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/Timer.h"
|
||||
#include "vehicle/Train.h"
|
||||
#include "vehicle/Camera.h"
|
||||
#include "scene/eu7/eu7_section_stream.h"
|
||||
#include "simulation/simulation.h"
|
||||
#include "utilities/Logs.h"
|
||||
#include "simulation/simulationtime.h"
|
||||
@@ -734,9 +733,7 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
|
||||
m_current_viewport = &vp;
|
||||
}
|
||||
|
||||
if( ( false == simulation::is_ready )
|
||||
|| scene::eu7::loading_screen_blocks_world( scene::eu7::stream_loading_position() )
|
||||
|| Global.gfx_skiprendering )
|
||||
if ((!simulation::is_ready) || (Global.gfx_skiprendering))
|
||||
{
|
||||
gl::framebuffer::unbind();
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
@@ -13,7 +13,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/color.h"
|
||||
#include "utilities/Globals.h"
|
||||
#include "vehicle/Camera.h"
|
||||
#include "scene/eu7/eu7_section_stream.h"
|
||||
#include "utilities/Timer.h"
|
||||
#include "simulation/simulation.h"
|
||||
#include "simulation/simulationtime.h"
|
||||
@@ -415,12 +414,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
m_colorpass = m_renderpass;
|
||||
|
||||
if( ( false == simulation::is_ready )
|
||||
|| scene::eu7::loading_screen_blocks_world( scene::eu7::stream_loading_position() )
|
||||
|| Global.gfx_skiprendering ) {
|
||||
::glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
if( ( !simulation::is_ready ) || ( Global.gfx_skiprendering ) ) {
|
||||
::glClearColor( 51.0f / 255.f, 102.0f / 255.f, 85.0f / 255.f, 1.f ); // initial background Color
|
||||
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
Application.render_ui();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ scenario_needs_eu7_regen( std::string const &scenario_file ) {
|
||||
|
||||
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
|
||||
|
||||
@@ -204,28 +204,6 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
|
||||
|
||||
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.message = "uzywam .eu7: " + resolved;
|
||||
@@ -242,7 +220,7 @@ ensure_scenario_eu7( std::string const &scenario_file ) {
|
||||
|
||||
if( false == Global.eu7_auto_bake ) {
|
||||
|
||||
if( should_use_binary_module( scenario_file ) ) {
|
||||
if( probe_baked_scenario( scenario_file ) ) {
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
return outcome;
|
||||
|
||||
#else
|
||||
|
||||
if( should_use_binary_module( scenario_file ) ) {
|
||||
if( probe_baked_scenario( scenario_file ) ) {
|
||||
|
||||
outcome.ok = true;
|
||||
|
||||
|
||||
@@ -257,11 +257,7 @@ load_module_recursive(
|
||||
if( child_loaded ) {
|
||||
continue;
|
||||
}
|
||||
if( !child.empty() && probe_file( child ) && false == should_use_binary_module( ref ) ) {
|
||||
WriteLog(
|
||||
"EU7: przestarzaly .eu7, fallback SCM: " + include_text_path( include ) );
|
||||
}
|
||||
else if( !child.empty() ) {
|
||||
if( !child.empty() ) {
|
||||
WriteLog(
|
||||
"EU7 include niedostepny, fallback SCM: " + include_text_path( include ) );
|
||||
}
|
||||
@@ -458,23 +454,9 @@ text_source_path( std::string const &reference ) {
|
||||
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
|
||||
should_use_binary_module( std::string const &reference ) {
|
||||
auto const eu7 { binary_path( reference ) };
|
||||
return probe_file( eu7 ) && false == text_module_is_newer_than_binary( reference );
|
||||
return probe_file( binary_path( reference ) );
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -75,13 +75,9 @@ namespace eu7 {
|
||||
[[nodiscard]] std::string
|
||||
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
|
||||
text_module_is_newer_than_binary( std::string const &Reference );
|
||||
|
||||
// Istniejacy, poprawny .eu7 nie starszy niz odpowiednik tekstowy.
|
||||
[[nodiscard]] bool
|
||||
should_use_binary_module( std::string const &Reference );
|
||||
should_use_binary_module( std::string const &Reference );
|
||||
|
||||
// Czy plik zawiera chunk TERR.
|
||||
[[nodiscard]] bool
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene/eu7/eu7_types.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace scene::eu7 {
|
||||
|
||||
// Tylko warm_instanceable_cache dla juz zcache'owanych meshy (bez cold GetModel na workerze).
|
||||
void
|
||||
preload_pack_models( std::vector<Eu7Model> const &Models );
|
||||
|
||||
// Main thread: Fetch_Material dla unikalnych texture_file z chunka przed apply.
|
||||
// Zwraca liczbe unikalnych Fetch_Material w tym slice.
|
||||
std::size_t
|
||||
warm_pack_textures_main( Eu7Model const *models, std::size_t count );
|
||||
|
||||
void
|
||||
reset_pack_texture_warm_cache();
|
||||
|
||||
} // namespace scene::eu7
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene/eu7/eu7_types.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace scene::eu7 {
|
||||
|
||||
// Tylko warm_instanceable_cache dla juz zcache'owanych meshy (bez cold GetModel na workerze).
|
||||
void
|
||||
preload_pack_models( std::vector<Eu7Model> const &Models );
|
||||
|
||||
// Main thread: Fetch_Material dla unikalnych texture_file z chunka przed apply.
|
||||
// Zwraca liczbe unikalnych Fetch_Material w tym slice.
|
||||
std::size_t
|
||||
warm_pack_textures_main( Eu7Model const *models, std::size_t count );
|
||||
|
||||
void
|
||||
reset_pack_texture_warm_cache();
|
||||
|
||||
} // namespace scene::eu7
|
||||
|
||||
@@ -497,26 +497,39 @@ parse_pack_section_header(
|
||||
Eu7PackIndexEntry const &entry,
|
||||
Eu7PackSectionCursor &cursor ) {
|
||||
cursor = {};
|
||||
input.seekg(
|
||||
static_cast<std::streamoff>( module.pack_payload_offset + entry.pack_offset ) );
|
||||
auto const section_start {
|
||||
static_cast<std::streamoff>( module.pack_payload_offset + entry.pack_offset ) };
|
||||
input.seekg( section_start );
|
||||
|
||||
const auto peek { input.peek() };
|
||||
const std::uint8_t first_byte {
|
||||
peek == EOF ? std::uint8_t { 0 } : static_cast<std::uint8_t>( peek ) };
|
||||
|
||||
if( first_byte == kPackSectionFormatV8 ) {
|
||||
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 ) {
|
||||
if( first_byte == 2 ) {
|
||||
throw std::runtime_error(
|
||||
"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.solo_remaining = entry.model_count;
|
||||
cursor.inst_remaining = 0;
|
||||
@@ -539,8 +552,10 @@ read_pack_models_chunk_impl(
|
||||
|
||||
std::vector<Eu7Model> models;
|
||||
auto const remaining {
|
||||
static_cast<std::size_t>( cursor.solo_remaining ) +
|
||||
static_cast<std::size_t>( cursor.inst_remaining ) };
|
||||
std::min(
|
||||
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 ) );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -11,7 +11,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "scene/eu7/eu7_types.h"
|
||||
|
||||
#include <istream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -32,30 +31,4 @@ find_pack_entry( Eu7Module const &Module, int Row, int Column );
|
||||
[[nodiscard]] std::vector<Eu7Model>
|
||||
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
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace scene::eu7 {
|
||||
namespace {
|
||||
|
||||
constexpr double kDrainBudgetMs { 12.0 };
|
||||
constexpr double kLoaderDrainBudgetMs { 48.0 };
|
||||
constexpr double kLoaderDrainBudgetMs { 96.0 };
|
||||
constexpr std::size_t kLoaderSectionsPerDrain { 8 };
|
||||
|
||||
constexpr double kGameplayApplyBudgetMs { 4.0 };
|
||||
@@ -72,7 +72,6 @@ constexpr float kStationaryCatchupRingThreshold { 0.70f };
|
||||
constexpr double kStationaryCatchupSpeedMps { 5.0 };
|
||||
constexpr std::size_t kCatchupMaxInFlightSections { 20 };
|
||||
constexpr std::size_t kCatchupMaxReadySections { 8 };
|
||||
constexpr std::size_t kPackWorkerSubChunkModels { 512 };
|
||||
constexpr std::size_t kBootstrapDrainMs { 32 };
|
||||
constexpr std::size_t kBootstrapTimeoutMs { 120000 };
|
||||
constexpr std::chrono::milliseconds kPresentableHoldMs { 200 };
|
||||
@@ -90,10 +89,6 @@ struct PackSectionJob {
|
||||
int column { 0 };
|
||||
std::size_t section_idx { 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 {
|
||||
@@ -102,8 +97,7 @@ struct PackSectionReady {
|
||||
std::size_t section_idx { 0 };
|
||||
std::unique_ptr<std::vector<Eu7Model>> models;
|
||||
bool failed { false };
|
||||
bool section_final { true };
|
||||
std::uint32_t subchunk_index { 0 };
|
||||
std::size_t apply_offset { 0 };
|
||||
};
|
||||
|
||||
struct SectionStreamState {
|
||||
@@ -123,6 +117,8 @@ struct SectionStreamState {
|
||||
std::size_t pending_apply_offset { 0 };
|
||||
glm::dvec3 last_enqueue_position {};
|
||||
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, scene::node_data> nodedata_cache;
|
||||
@@ -165,7 +161,10 @@ void
|
||||
finalize_section( PackSectionReady const &batch );
|
||||
|
||||
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
|
||||
release_pending_buffer();
|
||||
@@ -194,6 +193,12 @@ stream_worker_count() {
|
||||
return std::min( requested, kMaxPackStreamWorkers );
|
||||
}
|
||||
|
||||
void
|
||||
reset_stream_fields();
|
||||
|
||||
void
|
||||
note_apply_progress();
|
||||
|
||||
void
|
||||
reset_stream_fields() {
|
||||
g_stream.module = nullptr;
|
||||
@@ -210,9 +215,12 @@ reset_stream_fields() {
|
||||
g_stream.pending_apply.reset();
|
||||
g_stream.pending_apply_offset = 0;
|
||||
g_stream.has_last_enqueue_position = false;
|
||||
g_stream.anchor_position = {};
|
||||
g_stream.has_anchor_position = false;
|
||||
g_stream.mesh_cache.clear();
|
||||
g_stream.nodedata_cache.clear();
|
||||
reset_pack_texture_warm_cache();
|
||||
note_apply_progress();
|
||||
}
|
||||
|
||||
[[nodiscard]] Eu7Module const &
|
||||
@@ -223,14 +231,6 @@ 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
|
||||
release_pending_buffer() {
|
||||
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 );
|
||||
}
|
||||
else if( speed > 600.0 ) {
|
||||
limit = std::min( limit, std::size_t { 96 } );
|
||||
}
|
||||
else if( speed > 300.0 ) {
|
||||
limit = std::min( limit, std::size_t { 80 } );
|
||||
limit = std::min( limit, std::size_t { 128 } );
|
||||
}
|
||||
else {
|
||||
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 ) {
|
||||
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 };
|
||||
if( last_ms >= 24.0 ) {
|
||||
limit = std::min( limit, std::size_t { 32 } );
|
||||
}
|
||||
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 } );
|
||||
@@ -354,12 +345,8 @@ adaptive_slice_instances( std::size_t const section_total ) {
|
||||
|
||||
[[nodiscard]] std::size_t
|
||||
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() };
|
||||
if( stream.last_chunk_ms >= 12.0 ) {
|
||||
if( pack_bench_stream().last_chunk_ms >= 12.0 ) {
|
||||
limit = 1;
|
||||
}
|
||||
return limit;
|
||||
@@ -432,29 +419,82 @@ preload_slice_cold_meshes(
|
||||
return 0;
|
||||
}
|
||||
replace_slashes( model_file );
|
||||
if( g_stream.mesh_cache.contains( model_file ) ) {
|
||||
slice_count = 1;
|
||||
return 0;
|
||||
if( false == g_stream.mesh_cache.contains( model_file ) ) {
|
||||
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 );
|
||||
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;
|
||||
cold_loaded = 1;
|
||||
}
|
||||
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
|
||||
apply_pending_chunk(
|
||||
double const budget_ms,
|
||||
@@ -462,9 +502,16 @@ apply_pending_chunk(
|
||||
std::size_t const max_cold_meshes,
|
||||
double const cold_budget_ms,
|
||||
std::size_t const max_chunks ) {
|
||||
(void)max_instances;
|
||||
(void)max_cold_meshes;
|
||||
(void)cold_budget_ms;
|
||||
if( g_stream.serializer == nullptr ) {
|
||||
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() ) {
|
||||
return false;
|
||||
}
|
||||
@@ -483,7 +530,7 @@ apply_pending_chunk(
|
||||
auto &batch { *g_stream.pending_apply };
|
||||
if( batch.failed || batch.models == nullptr || batch.models->empty() ) {
|
||||
if( batch.failed ) {
|
||||
fail_section( batch.section_idx );
|
||||
fail_section( batch.section_idx, batch.row, batch.column );
|
||||
}
|
||||
else {
|
||||
finalize_section( batch );
|
||||
@@ -497,21 +544,15 @@ apply_pending_chunk(
|
||||
auto const total { batch.models->size() };
|
||||
auto const offset { g_stream.pending_apply_offset };
|
||||
if( offset >= total ) {
|
||||
if( batch.section_final ) {
|
||||
finalize_section( batch );
|
||||
}
|
||||
finalize_section( batch );
|
||||
release_pending_buffer();
|
||||
applied_work = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const effective_instances {
|
||||
std::min( max_instances, adaptive_slice_instances( total ) ) };
|
||||
auto const effective_cold {
|
||||
std::min( max_cold_meshes, adaptive_cold_meshes() ) };
|
||||
// Sekcja 1 km (komorka TCP) — apply w calosci, bez dzielenia na plasterki.
|
||||
auto const remaining { total - offset };
|
||||
auto const chunk_cap { std::min( effective_instances, remaining ) };
|
||||
std::size_t chunk_count { chunk_cap };
|
||||
std::size_t chunk_count { remaining };
|
||||
|
||||
auto const chunk_started { std::chrono::steady_clock::now() };
|
||||
double cold_ms { 0.0 };
|
||||
@@ -524,15 +565,18 @@ apply_pending_chunk(
|
||||
auto const phase_started { std::chrono::steady_clock::now() };
|
||||
cold_loads = preload_slice_cold_meshes(
|
||||
models_ptr + offset,
|
||||
chunk_cap,
|
||||
effective_cold,
|
||||
cold_budget_ms,
|
||||
remaining,
|
||||
remaining,
|
||||
0.0,
|
||||
chunk_count );
|
||||
cold_ms = std::chrono::duration<double, std::milli>(
|
||||
std::chrono::steady_clock::now() - phase_started ).count();
|
||||
}
|
||||
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;
|
||||
g_stream.pending_apply_offset = offset + chunk_count;
|
||||
note_apply_progress();
|
||||
applied_work = true;
|
||||
++chunks_done;
|
||||
|
||||
if( g_stream.pending_apply_offset >= total ) {
|
||||
if( batch.section_final ) {
|
||||
finalize_section( batch );
|
||||
}
|
||||
finalize_section( batch );
|
||||
release_pending_buffer();
|
||||
continue;
|
||||
}
|
||||
@@ -712,134 +755,46 @@ worker_loop( std::stop_token const stop_token ) {
|
||||
auto const &module { stream_module() };
|
||||
auto const entry { find_pack_entry( module, job.row, job.column ) };
|
||||
if( false == entry.has_value() || entry->model_count == 0 ) {
|
||||
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 );
|
||||
enqueue_failed_section( job );
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const &pack_path { pack_stream_file_path() };
|
||||
if( pack_path.empty() ) {
|
||||
throw std::runtime_error( "EU7 PACK: brak sciezki pliku PACK" );
|
||||
}
|
||||
|
||||
std::ifstream input { pack_path, std::ios::binary };
|
||||
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;
|
||||
std::unique_ptr<std::vector<Eu7Model>> models;
|
||||
{
|
||||
PackBenchTimer const read_timer { &Eu7PackBench::worker_read_pack_ms };
|
||||
auto section { read_pack_section( module, job.row, job.column ) };
|
||||
if( false == section.empty() ) {
|
||||
models = std::make_unique<std::vector<Eu7Model>>( std::move( section ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( section_completed ) {
|
||||
pack_bench_inc( &Eu7PackBench::worker_sections_done );
|
||||
PackSectionReady result;
|
||||
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 ) {
|
||||
ErrorLog(
|
||||
std::string{ "EU7 PACK: sekcja " + std::to_string( job.row ) + "," +
|
||||
std::to_string( job.column ) + ": " } + ex.what() );
|
||||
fail_section( job.section_idx );
|
||||
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 );
|
||||
enqueue_failed_section( job );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -894,9 +849,6 @@ start_workers() {
|
||||
|
||||
void
|
||||
finalize_section( PackSectionReady const &batch ) {
|
||||
if( false == batch.section_final ) {
|
||||
return;
|
||||
}
|
||||
g_stream.loaded_sections.insert( batch.section_idx );
|
||||
g_stream.in_flight_sections.erase( batch.section_idx );
|
||||
++load_stats().pack_sections_loaded;
|
||||
@@ -904,11 +856,43 @@ finalize_section( PackSectionReady const &batch ) {
|
||||
}
|
||||
|
||||
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.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
|
||||
section_manhattan_sections(
|
||||
int const row,
|
||||
@@ -1212,35 +1196,66 @@ try_dequeue_ready_batch() {
|
||||
bool has_batch { false };
|
||||
{
|
||||
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() ) {
|
||||
auto const best_it {
|
||||
std::min_element(
|
||||
g_stream.ready.data.begin(),
|
||||
g_stream.ready.data.end(),
|
||||
[]( PackSectionReady const &lhs, PackSectionReady const &rhs ) {
|
||||
auto const lhs_dist {
|
||||
auto const pick_best {
|
||||
[&]( int const max_distance ) -> std::deque<PackSectionReady>::iterator {
|
||||
auto best_it { g_stream.ready.data.end() };
|
||||
auto best_dist { std::numeric_limits<int>::max() };
|
||||
for( auto it { g_stream.ready.data.begin() }; it != g_stream.ready.data.end(); ++it ) {
|
||||
if( it->failed || it->models == nullptr || it->models->empty() ) {
|
||||
continue;
|
||||
}
|
||||
auto const dist {
|
||||
section_manhattan_sections(
|
||||
lhs.row,
|
||||
lhs.column,
|
||||
it->row,
|
||||
it->column,
|
||||
g_stream.center_row,
|
||||
g_stream.center_column ) };
|
||||
auto const rhs_dist {
|
||||
section_manhattan_sections(
|
||||
rhs.row,
|
||||
rhs.column,
|
||||
g_stream.center_row,
|
||||
g_stream.center_column ) };
|
||||
if( lhs_dist != rhs_dist ) {
|
||||
return lhs_dist < rhs_dist;
|
||||
if( max_distance >= 0 && dist > max_distance ) {
|
||||
continue;
|
||||
}
|
||||
if( lhs.section_idx != rhs.section_idx ) {
|
||||
return lhs.section_idx < rhs.section_idx;
|
||||
if( dist < best_dist || ( dist == best_dist && best_it == g_stream.ready.data.end() ) ) {
|
||||
best_dist = dist;
|
||||
best_it = it;
|
||||
}
|
||||
return lhs.subchunk_index < rhs.subchunk_index;
|
||||
} ) };
|
||||
batch = std::move( *best_it );
|
||||
g_stream.ready.data.erase( best_it );
|
||||
has_batch = true;
|
||||
else if(
|
||||
dist == best_dist && best_it != g_stream.ready.data.end() &&
|
||||
it->section_idx < best_it->section_idx ) {
|
||||
best_it = it;
|
||||
}
|
||||
}
|
||||
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 ) {
|
||||
fail_section( batch.section_idx );
|
||||
fail_section( batch.section_idx, batch.row, batch.column );
|
||||
}
|
||||
else {
|
||||
finalize_section( batch );
|
||||
@@ -1259,7 +1274,8 @@ try_dequeue_ready_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;
|
||||
}
|
||||
|
||||
@@ -1371,30 +1387,29 @@ drain_until_budget( double const budget_ms ) {
|
||||
|
||||
void
|
||||
sync_stream_limits( glm::dvec3 const &world_position ) {
|
||||
(void)world_position;
|
||||
g_stream_catchup = false;
|
||||
if( false == g_loading_screen_dismissed ) {
|
||||
g_stream_catchup = false;
|
||||
g_stream_max_in_flight = 6;
|
||||
g_stream_max_ready = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
auto const inner_progress {
|
||||
section_stream_ring_progress( world_position, kSectionStreamGameplayRadiusKm ) };
|
||||
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;
|
||||
g_stream_max_in_flight = kMaxInFlightSections;
|
||||
g_stream_max_ready = kMaxReadySections;
|
||||
}
|
||||
|
||||
} // 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
|
||||
init_section_stream(
|
||||
Eu7Module const &root_module,
|
||||
@@ -1434,6 +1449,8 @@ prime_section_stream( Eu7Module const &root_module ) {
|
||||
return;
|
||||
}
|
||||
|
||||
remember_stream_anchor( initial );
|
||||
|
||||
auto const [row, column] { section_row_column( initial ) };
|
||||
g_stream.center_row = row;
|
||||
g_stream.center_column = column;
|
||||
@@ -1534,12 +1551,14 @@ update_section_stream( glm::dvec3 const &world_position ) {
|
||||
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 {
|
||||
center_row != g_stream.center_row || center_column != g_stream.center_column };
|
||||
auto const moved_since_enqueue {
|
||||
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() };
|
||||
|
||||
if( moved_since_enqueue > kTeleportReenqueueDistanceM ) {
|
||||
@@ -1553,65 +1572,47 @@ update_section_stream( glm::dvec3 const &world_position ) {
|
||||
reprioritize_job_queue();
|
||||
}
|
||||
|
||||
sync_stream_limits( world_position );
|
||||
sync_stream_limits( stream_position );
|
||||
|
||||
auto const ring_radius { g_stream.radius };
|
||||
auto const reenqueue_distance {
|
||||
g_stream_catchup ? kCatchupReenqueueDistanceM : kReenqueueDistanceM };
|
||||
auto max_lookahead { g_stream_catchup ? 15 : 5 };
|
||||
if( g_stream_catchup ) {
|
||||
auto const speed { camera_stream_speed_mps() };
|
||||
if( speed > 1200.0 ) {
|
||||
max_lookahead = 25;
|
||||
}
|
||||
else if( speed > 600.0 ) {
|
||||
max_lookahead = 20;
|
||||
}
|
||||
}
|
||||
auto const inner_ring_ready {
|
||||
section_stream_ready_around( stream_position, kSectionStreamGameplayRadiusKm ) };
|
||||
auto const ring_radius {
|
||||
inner_ring_ready ? g_stream.radius : kSectionStreamGameplayRadiusKm };
|
||||
auto const reenqueue_distance { kReenqueueDistanceM };
|
||||
auto max_lookahead { inner_ring_ready ? 5 : 0 };
|
||||
auto const travel_forward { guess_travel_forward() };
|
||||
|
||||
auto const current_section_unloaded {
|
||||
section_has_pack_models( center_row, center_column )
|
||||
&& false == g_stream.loaded_sections.contains( section_index( center_row, center_column ) ) };
|
||||
auto const inner_ring_incomplete {
|
||||
current_section_unloaded
|
||||
|| false == section_stream_ready_around( world_position, kSectionStreamGameplayRadiusKm ) };
|
||||
auto const inner_ring_incomplete { current_section_unloaded || false == inner_ring_ready };
|
||||
auto const should_reenqueue {
|
||||
center_moved
|
||||
|| false == g_stream.has_last_enqueue_position
|
||||
|| moved_since_enqueue >= reenqueue_distance };
|
||||
|
||||
if( should_reenqueue || inner_ring_incomplete || g_stream_catchup ) {
|
||||
enqueue_sections_around( center_row, center_column, ring_radius, world_position );
|
||||
g_stream.last_enqueue_position = world_position;
|
||||
if( should_reenqueue || inner_ring_incomplete ) {
|
||||
enqueue_sections_around( center_row, center_column, ring_radius, stream_position );
|
||||
g_stream.last_enqueue_position = stream_position;
|
||||
g_stream.has_last_enqueue_position = true;
|
||||
if( should_reenqueue || inner_ring_incomplete ) {
|
||||
pack_bench_inc( &Eu7PackBench::stream_reenqueue );
|
||||
}
|
||||
enqueue_movement_lookahead(
|
||||
center_row,
|
||||
center_column,
|
||||
ring_radius,
|
||||
travel_forward,
|
||||
max_lookahead );
|
||||
if( max_lookahead > 0 ) {
|
||||
enqueue_movement_lookahead(
|
||||
center_row,
|
||||
center_column,
|
||||
ring_radius,
|
||||
travel_forward,
|
||||
max_lookahead );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
section_stream_drain_idle( glm::dvec3 const &world_position ) {
|
||||
if( g_stream.bootstrap_pending || g_stream.bootstrap_active ) {
|
||||
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)world_position;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1624,33 +1625,27 @@ drain_section_stream(
|
||||
if( false == g_stream.active ) {
|
||||
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;
|
||||
}
|
||||
|
||||
if( gameplay_stream_mode() ) {
|
||||
auto apply_budget { gameplay_apply_budget_ms() };
|
||||
std::size_t max_chunks { 1 };
|
||||
if( g_stream_catchup ) {
|
||||
auto const inner_ring {
|
||||
section_stream_ring_progress(
|
||||
Global.pCamera.Pos,
|
||||
kSectionStreamGameplayRadiusKm ) };
|
||||
auto const speed { camera_stream_speed_mps() };
|
||||
if(
|
||||
inner_ring < kStationaryCatchupRingThreshold
|
||||
&& speed < kStationaryCatchupSpeedMps ) {
|
||||
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 );
|
||||
auto const inner_ring_ready {
|
||||
section_stream_ready_around(
|
||||
stream_position,
|
||||
kSectionStreamGameplayRadiusKm ) };
|
||||
|
||||
if( gameplay_stream_mode() && inner_ring_ready ) {
|
||||
drain_until_budget( kDrainBudgetMs );
|
||||
maybe_log_stream_status( stream_position );
|
||||
}
|
||||
else if( gameplay_stream_mode() ) {
|
||||
drain_until_budget( kLoaderDrainBudgetMs );
|
||||
maybe_log_stream_status( stream_position );
|
||||
}
|
||||
else if( false == g_loading_screen_dismissed ) {
|
||||
auto position { stream_loading_position() };
|
||||
@@ -1693,6 +1688,8 @@ kick_section_stream_bootstrap() {
|
||||
return;
|
||||
}
|
||||
|
||||
remember_stream_anchor( position );
|
||||
|
||||
auto const [row, column] { section_row_column( position ) };
|
||||
g_stream.center_row = row;
|
||||
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 ) {
|
||||
position = guess_initial_stream_position( stream_module() );
|
||||
}
|
||||
position = resolve_section_stream_position( position );
|
||||
|
||||
if( section_stream_needs_bootstrap() ) {
|
||||
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();
|
||||
g_loading_screen_dismissed = true;
|
||||
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
|
||||
@@ -1978,15 +1993,24 @@ loading_screen_blocks_world(
|
||||
|
||||
glm::dvec3
|
||||
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;
|
||||
}
|
||||
|
||||
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() };
|
||||
if( position.x != 0.0 || position.y != 0.0 || position.z != 0.0 ) {
|
||||
return position;
|
||||
}
|
||||
|
||||
if( g_stream.has_anchor_position ) {
|
||||
return g_stream.anchor_position;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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
|
||||
reset_section_stream() {
|
||||
flush_pack_stream_bench();
|
||||
|
||||
@@ -19,7 +19,7 @@ class state_serializer;
|
||||
|
||||
namespace scene::eu7 {
|
||||
|
||||
constexpr int kSectionStreamBootstrapRadiusKm { 3 };
|
||||
constexpr int kSectionStreamBootstrapRadiusKm { 4 };
|
||||
constexpr int kSectionStreamGameplayRadiusKm { 4 };
|
||||
|
||||
void
|
||||
@@ -34,6 +34,10 @@ prime_section_stream( Eu7Module const &RootModule );
|
||||
[[nodiscard]] glm::dvec3
|
||||
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).
|
||||
void
|
||||
bootstrap_section_stream( glm::dvec3 const &WorldPosition );
|
||||
|
||||
@@ -360,7 +360,7 @@ struct Eu7PackIndexEntry {
|
||||
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 {
|
||||
std::uint32_t solo_remaining { 0 };
|
||||
std::uint32_t inst_remaining { 0 };
|
||||
|
||||
@@ -617,15 +617,16 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
|
||||
is_pure_eu7_scenario = scene::eu7::probe_file( resolved_scenario );
|
||||
}
|
||||
|
||||
bool const has_baked_eu7_root {
|
||||
false == is_pure_eu7_scenario &&
|
||||
scene::eu7::should_use_binary_module( Scenariofile ) };
|
||||
auto const baked_root_path {
|
||||
scene::eu7::resolve_scenery_path( scene::eu7::binary_path( Scenariofile ) ) };
|
||||
bool const use_eu7_scenario {
|
||||
is_pure_eu7_scenario || scene::eu7::probe_baked_scenario( Scenariofile ) };
|
||||
auto const eu7_load_path {
|
||||
is_pure_eu7_scenario ?
|
||||
resolved_scenario :
|
||||
scene::eu7::resolve_scenery_path( scene::eu7::binary_path( Scenariofile ) ) };
|
||||
|
||||
// Scenariusz EU7B: nie parsujemy binarki jako tekstu SCM.
|
||||
std::shared_ptr<deserializer_state> state;
|
||||
if( is_pure_eu7_scenario ) {
|
||||
if( use_eu7_scenario ) {
|
||||
state = std::make_shared<deserializer_state>(
|
||||
std::string{}, cParser::buffer_TEXT, Global.asCurrentSceneryPath, Global.bLoadTraction );
|
||||
state->scenariofile = Scenariofile;
|
||||
@@ -637,25 +638,12 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
|
||||
|
||||
state->scratchpad.name = Scenariofile;
|
||||
|
||||
if( is_pure_eu7_scenario ) {
|
||||
if( use_eu7_scenario ) {
|
||||
Global.file_binary_terrain_state = true;
|
||||
state->scratchpad.binary.terrain = true;
|
||||
state->scratchpad.binary.terrain_included = true;
|
||||
WriteLog( "EU7 scenario: " + resolved_scenario );
|
||||
if( false == scene::eu7::load_module( resolved_scenario, *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 ) ) {
|
||||
WriteLog( "EU7 scenario: " + eu7_load_path );
|
||||
if( false == scene::eu7::load_module( eu7_load_path, *this ) ) {
|
||||
throw invalid_scenery_exception();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ def read_cstring(f, rva: int) -> str:
|
||||
def parse(path: Path) -> None:
|
||||
with path.open("rb") as f:
|
||||
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"Size: {path.stat().st_size:,} bytes")
|
||||
|
||||
@@ -366,9 +366,7 @@ void cParser::startIncludeFromParser(cParser& srcParser, bool ToLower, std::stri
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( scene::eu7::probe_file( eu7path ) ) {
|
||||
WriteLog( "EU7: przestarzaly .eu7, fallback SCM: " + includefile );
|
||||
}
|
||||
|
||||
if (isTerrain && true == Global.file_binary_terrain_state) {
|
||||
WriteLog("Binary terrain present, ignoring: " + includefile);
|
||||
readParameters(srcParser); // preserve original side-effect: still consume parameters
|
||||
|
||||
@@ -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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
cFrustum frustum;
|
||||
frustum.calculate(transform, glm::mat4());
|
||||
|
||||
m_colored_paths.switches.clear();
|
||||
m_colored_paths.occupied.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++)
|
||||
{
|
||||
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();
|
||||
if (handle != null_handle)
|
||||
{
|
||||
m_section_handles.push_back(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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user