diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e4a74ba..c9ce73bd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,13 +23,13 @@ jobs: env: BUILD_WRAPPER_OUT_DIR: bw-output steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: fetch-depth: 0 submodules: recursive - name: Set up Python 3.14 - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.14' @@ -106,7 +106,7 @@ jobs: -C "$GITHUB_WORKSPACE" . - name: Upload analysis input - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: sonar-input path: /tmp/workspace.tar.gz diff --git a/.github/workflows/build_bin.yml b/.github/workflows/build_bin.yml index f0b1fdec..ac1fa562 100644 --- a/.github/workflows/build_bin.yml +++ b/.github/workflows/build_bin.yml @@ -33,14 +33,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 submodules: recursive - name: Setup Python 3.14 id: python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: "3.14" architecture: "x64" @@ -104,7 +104,7 @@ jobs: -Force - name: Upload Windows build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: maszyna-windows-x64-${{ env.CONFIG_WIN }} path: | @@ -113,7 +113,7 @@ jobs: retention-days: 14 - name: Upload Windows debug symbols - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: maszyna-windows-x64-symbols-${{ env.CONFIG_WIN }} path: | @@ -133,14 +133,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 submodules: recursive - name: Setup Python 3.14 id: python - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: "3.14" @@ -244,7 +244,7 @@ jobs: cp -R shaders/. build/bin/shaders/ - name: Upload Linux build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: maszyna-linux-x64-${{ env.CONFIG_LINUX }} path: | diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 66213c23..b2951189 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -64,15 +64,13 @@ jobs: if: github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-24.04 permissions: - contents: read # checkout trusted config + contents: read # fetch trusted config actions: read # download artifact from the Build run statuses: write # post the commit status pull-requests: read # verify PR head sha via the API env: BUILD_WRAPPER_OUT_DIR: bw-output - # .trusted/ holds the checkout of master used to restore the scanner config; - # it is not part of the analysed change. - SONAR_EXCLUSIONS: betterRenderer/**,ref/**,imgui/**,stb/**,build/**,bw-output/**,.trusted/** + SONAR_EXCLUSIONS: betterRenderer/**,ref/**,imgui/**,stb/**,build/**,bw-output/** SONAR_SCANNER_JAVA_OPTS: -Xmx5g steps: - name: Post pending status @@ -85,16 +83,23 @@ jobs: -f description="Analysis in progress" \ -f target_url="$RUN_URL" - # Trusted copy of the repo config, used to overwrite anything the PR - # might have tampered with (sonar-project.properties etc). - - name: Checkout trusted config from master - uses: actions/checkout@v5 - with: - ref: master - path: .trusted + # Trusted copy of the scanner config, used to overwrite anything the PR + # might have tampered with. Fetched as a single file through the API rather + # than with actions/checkout: nothing gets checked out in this privileged + # context. Kept outside the workspace, so the archive can't overwrite it. + - name: Fetch trusted config from master + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + url="repos/${{ github.repository }}/contents/sonar-project.properties?ref=master" + if ! gh api -H "Accept: application/vnd.github.raw" "$url" > /tmp/trusted-sonar-project.properties; then + echo "::warning::no sonar-project.properties on master" + rm -f /tmp/trusted-sonar-project.properties + fi - name: Download analysis input - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: sonar-input path: /tmp/sonar-input @@ -104,13 +109,7 @@ jobs: - name: Unpack analysis input run: | set -euo pipefail - # The archive holds the whole PR workspace and is unpacked over this one, - # .trusted/ included. Move the trusted config out of reach first, or a PR - # carrying its own .trusted/sonar-project.properties would have it planted - # here and restored below as if it came from master. - if [ -f "$GITHUB_WORKSPACE/.trusted/sonar-project.properties" ]; then - cp "$GITHUB_WORKSPACE/.trusted/sonar-project.properties" /tmp/trusted-sonar-project.properties - fi + # The archive holds the whole PR workspace and is unpacked over this one. # Nothing may be written outside the workspace: reject absolute members and # any member reaching through a parent directory before unpacking anything. tar -tzf /tmp/sonar-input/workspace.tar.gz > /tmp/archive-members.txt diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index e7bd1d23..accbbbaa 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1732,7 +1732,11 @@ class TMoverParameters // bounds-safe read access to MotorParam TMotorParameters const &motor_param(int const Position) const { - return MotorParam[std::clamp(Position, 0, MotorParametersArraySize)]; + if (Position < 0) + return MotorParam[0]; + if (Position > MotorParametersArraySize) + return MotorParam[MotorParametersArraySize]; + return MotorParam[Position]; } TTransmision Transmision; // record {liczba zebow przekladni} diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 82dd245f..ff60c27c 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1752,6 +1752,11 @@ void TMoverParameters::LowVoltagePowerCheck(double const Deltatime) void TMoverParameters::PowerCouplersCheck(double const Deltatime, coupling const Coupling) { + if (Coupling != coupling::highvoltage && Coupling != coupling::power110v && Coupling != coupling::power24v) + { + // only power couplings carry voltage + return; + } auto localvoltage{0.0}; @@ -2403,16 +2408,14 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed) if (CtrlSpeed > 1) { OK = IncMainCtrl(1) && IncMainCtrl(CtrlSpeed - 1); // a fail will propagate up the recursion chain. should this be || instead? + break; } - else + ++MainCtrlPos; + OK = true; + if (EIMCtrlType == 0 && ( SpeedCtrlAutoTurnOffFlag & 1 ) == 1 && MainCtrlActualPos != MainCtrlPos) { - ++MainCtrlPos; - OK = true; - if (EIMCtrlType == 0 && ( SpeedCtrlAutoTurnOffFlag & 1 ) == 1 && MainCtrlActualPos != MainCtrlPos) - { - DecScndCtrl(2); - SpeedCtrlUnit.IsActive = false; - } + DecScndCtrl(2); + SpeedCtrlUnit.IsActive = false; } break; } @@ -6392,10 +6395,7 @@ double TMoverParameters::TractionForce(double dt) // PosRatio = 1.0 * (PosRatio * 0 + 1) * PosRatio; // 1 * 1 * PosRatio = PosRatio Hamulec->SetED(0); // (Hamulec as TLSt).SetLBP(LocBrakePress); - if (PosRatio > eimv_pr) - tmp = 4; - else - tmp = 4; // szybkie malenie, powolne wzrastanie + tmp = 4; // szybkie malenie, powolne wzrastanie } dmoment = eimv[eimv_Fful]; // NOTE: the commands to operate the sandbox are likely to conflict with other similar ai decisions @@ -8022,8 +8022,6 @@ double TMoverParameters::dizel_fillcheck(int mcp, double dt) } if (enrot > nreg) // nad predkoscia regulatora zeruj dawke realfill = 0; - if (enrot < nreg) // pod predkoscia regulatora dawka zadana - realfill = realfill; if (enrot < dizel_nreg_min && RList[mcp].R > 0.001) // jesli ponizej biegu jalowego i niezerowa dawka, to dawaj pelna realfill = 1; } @@ -9118,7 +9116,7 @@ bool TMoverParameters::readMPT0(std::string const &line) } if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -9174,7 +9172,7 @@ bool TMoverParameters::readMPTElectricSeries(std::string const &line) parser >> MotorParam[idx].mfi >> MotorParam[idx].mIsat >> MotorParam[idx].fi >> MotorParam[idx].Isat; if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -9223,7 +9221,7 @@ bool TMoverParameters::readMPTDieselEngine(std::string const &line) parser >> MotorParam[idx].mIsat >> MotorParam[idx].fi >> MotorParam[idx].mfi; if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -11048,7 +11046,7 @@ void TMoverParameters::LoadFIZ_DCEMUED(std::string const &line) void TMoverParameters::LoadFIZ_SpringBrake(std::string const &line) { - double vol; + double vol{1.0}; extract_value(vol, "Volume", line, "1"); if (!SpringBrake.Cylinder) SpringBrake.Cylinder = std::make_shared(); diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index 44e8be4b..64a7fb85 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -3516,10 +3516,7 @@ double TMHZ_K5P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) LimCP = std::min(LimCP, HP); // pozycja + czasowy lub zasilanie ActFlowSpeed = 4; - if (LimCP > CP) // podwyzszanie szybkie - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy; - else - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy + CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy double uop = UnbrakeOverPressure; // unbrake over pressure in actual state ManualOvrldActive = UniversalFlag & TUniversalBrake::ub_HighPressure; // button is pressed @@ -3546,10 +3543,9 @@ double TMHZ_K5P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) else dpMainValve = PFVd(PP, 0, ActFlowSpeed / LBDelay, dpPipe, 0.4); - if ((EQ(i_bcp, -1) && AutoOvrld) || (i_bcp < 0.5 && UniversalFlag & TUniversalBrake::ub_Overload)) + if (((EQ(i_bcp, -1) && AutoOvrld) || (i_bcp < 0.5 && UniversalFlag & TUniversalBrake::ub_Overload)) && TP < OverloadMaxPressure) { - if (TP < OverloadMaxPressure) - TP = TP + 0.03 * dt; + TP = TP + 0.03 * dt; } if (EQ(i_bcp, 3)) @@ -3699,10 +3695,7 @@ double TMHZ_6P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) LimCP = std::min(LimCP, HP); // pozycja + czasowy lub zasilanie ActFlowSpeed = 4; - if (LimCP > CP) // podwyzszanie szybkie - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy; - else - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy + CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy dpPipe = std::min(HP, CP + TP + RedAdj); @@ -3729,10 +3722,9 @@ double TMHZ_6P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) else dpMainValve = PFVd(PP, 0, ActFlowSpeed / LBDelay, dpPipe, 0.4); - if ((EQ(i_bcp, -1) && AutoOvrld) || (i_bcp < 0.5 && UniversalFlag & TUniversalBrake::ub_Overload)) + if (((EQ(i_bcp, -1) && AutoOvrld) || (i_bcp < 0.5 && UniversalFlag & TUniversalBrake::ub_Overload)) && TP < OverloadMaxPressure) { - if (TP < OverloadMaxPressure) - TP = TP + 0.03 * dt; + TP = TP + 0.03 * dt; } if (EQ(i_bcp, 4)) diff --git a/application/application.cpp b/application/application.cpp index ceb5ec6c..81e96c3d 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -498,7 +498,7 @@ int eu07_application::run() { command_queue::commands_map commands_to_exec; command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue(); - double slave_sync; + double slave_sync{0.0}; // if we're the server if (m_network && m_network->servers) diff --git a/application/drivermode.cpp b/application/drivermode.cpp index 80fd3b17..b5b78634 100644 --- a/application/drivermode.cpp +++ b/application/drivermode.cpp @@ -667,7 +667,7 @@ void driver_mode::update_camera(double const Deltatime) // reset window state, it'll be set again if applicable in a check below Global.CabWindowOpen = false; - if (simulation::Train != nullptr && Camera.m_owner != nullptr && false == DebugCameraFlag) + if (simulation::Train != nullptr && controlled != nullptr && Camera.m_owner != nullptr && false == DebugCameraFlag) { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery /* diff --git a/application/scenarioloaderuilayer.cpp b/application/scenarioloaderuilayer.cpp index c4e7df3d..de0d4e64 100644 --- a/application/scenarioloaderuilayer.cpp +++ b/application/scenarioloaderuilayer.cpp @@ -213,7 +213,7 @@ void scenarioloader_ui::render_() const float spacing = 10.0f * scale; // odstęp między ikoną a tekstem // Loading icon - const deferred_image *img = &m_loading_wheel_frames[38]; + deferred_image *img = &m_loading_wheel_frames[38]; const auto loading_tex = img->get(); const auto loading_size = glm::vec2(img->size()) * glm::vec2(scale); diff --git a/application/uitranscripts.cpp b/application/uitranscripts.cpp index 96c9f735..c9780e10 100644 --- a/application/uitranscripts.cpp +++ b/application/uitranscripts.cpp @@ -42,7 +42,7 @@ TTranscripts::Add( std::string const &txt, bool backgorund ) { cParser parser( asciitext ); while( true == parser.getTokens( 3, false, "[]\n" ) ) { - float begin, end; + float begin{ 0.f }, end{ 0.f }; std::string transcript; parser >> begin diff --git a/audio/audiorenderer.cpp b/audio/audiorenderer.cpp index 81f81570..50a6f727 100644 --- a/audio/audiorenderer.cpp +++ b/audio/audiorenderer.cpp @@ -563,15 +563,12 @@ openal_renderer::init_caps() { if( ::alcIsExtensionPresent( nullptr, "ALC_ENUMERATION_EXT" ) == AL_TRUE ) { // enumeration supported WriteLog( "available audio devices:" ); - auto const *devices { ::alcGetString( nullptr, ALC_DEVICE_SPECIFIER ) }; - auto const - *device { devices }, - *next { devices + 1 }; - while( device && *device != '\0' && next && *next != '\0' ) { - WriteLog( { device } ); - auto const len { std::strlen( device ) }; - device += len + 1; - next += len + 2; + // device list is a sequence of null-terminated names, ending with an empty name + auto const *device { ::alcGetString( nullptr, ALC_DEVICE_SPECIFIER ) }; + while( device != nullptr && *device != '\0' ) { + std::string const devicename { device }; + WriteLog( devicename ); + device += devicename.size() + 1; } } diff --git a/launcher/deferred_image.h b/launcher/deferred_image.h index fcd25fd6..85582264 100644 --- a/launcher/deferred_image.h +++ b/launcher/deferred_image.h @@ -1,10 +1,15 @@ #pragma once +#include + #include "model/Texture.h" #include "rendering/renderer.h" class deferred_image { public: + // value returned by get() when the image isn't (yet) available + static constexpr GLuint invalid_id { std::numeric_limits::max() }; + deferred_image() = default; deferred_image(const std::string &p) : path(p) { } deferred_image(const deferred_image&) = delete; @@ -15,7 +20,8 @@ public: return image != null_handle || !path.empty(); } - GLuint get() const + // loads the texture on first use + GLuint get() { if (!path.empty()) { image = GfxRenderer->Fetch_Texture(path, true); @@ -30,7 +36,7 @@ public: return tex.get_id(); } - return -1; + return invalid_id; } glm::ivec2 size() const @@ -43,6 +49,6 @@ public: } private: - mutable std::string path; - mutable texture_handle image = 0; + std::string path; + texture_handle image = 0; }; diff --git a/launcher/scenery_list.cpp b/launcher/scenery_list.cpp index 77f69a35..518669e5 100644 --- a/launcher/scenery_list.cpp +++ b/launcher/scenery_list.cpp @@ -281,7 +281,7 @@ void ui::scenerylist_panel::draw_trainset(trainset_desc &trainset) for (auto &dyn_desc : trainset.vehicles) { deferred_image *mini = nullptr; - if (dyn_desc.skin && dyn_desc.skin->mini.get() != (GLuint)-1) + if (dyn_desc.skin && dyn_desc.skin->mini.get() != deferred_image::invalid_id) mini = &dyn_desc.skin->mini; else mini = &placeholder_mini; diff --git a/launcher/vehicle_picker.cpp b/launcher/vehicle_picker.cpp index f7d3503f..9fe0a29a 100644 --- a/launcher/vehicle_picker.cpp +++ b/launcher/vehicle_picker.cpp @@ -37,7 +37,7 @@ void ui::vehiclepicker_panel::render_contents() if (ImGui::RadioButton(STR_C("texture group"), display_by_groups)) display_by_groups = true; - std::vector skinset_list; + std::vector skinset_list; if (display_by_groups) { std::vector model_list; @@ -114,7 +114,7 @@ void ui::vehiclepicker_panel::render_contents() for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { auto &desc = model_list[i]; - const deferred_image *image = nullptr; + deferred_image *image = nullptr; for (auto const &skinset : desc->matching_skinsets) { if (skinset->mini) { image = &skinset->mini; @@ -256,7 +256,7 @@ bool ui::vehiclepicker_panel::skin_filter(const skin_set *skin, std::vectorget(); - if (tex != (GLuint)-1) { + if (tex != deferred_image::invalid_id) { glm::ivec2 size = image->size(); float width = 30.0f / size.y * size.x; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); diff --git a/launcher/vehicle_picker.h b/launcher/vehicle_picker.h index ad6e6dc2..ffdfb2a4 100644 --- a/launcher/vehicle_picker.h +++ b/launcher/vehicle_picker.h @@ -14,7 +14,7 @@ class vehiclepicker_panel : public ui_panel void render_contents() override; private: - bool selectable_image(const char *desc, bool selected, const deferred_image *image, const skin_set *pickable = nullptr); + bool selectable_image(const char *desc, bool selected, deferred_image *image, const skin_set *pickable = nullptr); vehicle_type selected_type = vehicle_type::none; std::shared_ptr selected_vehicle; diff --git a/model/AnimModel.cpp b/model/AnimModel.cpp index cc54a2a2..1d808676 100644 --- a/model/AnimModel.cpp +++ b/model/AnimModel.cpp @@ -598,11 +598,11 @@ void TAnimModel::on_season_update() { void TAnimModel::RaPrepare() { // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza - bool state; // stan światła if (Global.UpdateMaterials) on_season_update(); for (int i = 0; i < iNumLights; ++i) { + bool state{ false }; // stan światła auto const lightmode { static_cast( std::abs( lsLights[ i ] ) ) }; switch( lightmode ) { case ls_On: diff --git a/model/Model3d.cpp b/model/Model3d.cpp index e1a3a79e..b67663f9 100644 --- a/model/Model3d.cpp +++ b/model/Model3d.cpp @@ -1529,7 +1529,9 @@ void TSubModel::ParentMatrix(float4x4 *m) const void TSubModel::ReplaceMatrix(const glm::mat4 &mat) { - *fMatrix = float4x4(glm::value_ptr(mat)); + for (int column = 0; column < 4; ++column) + for (int row = 0; row < 4; ++row) + fMatrix->e[column * 4 + row] = mat[column][row]; } void TSubModel::ReplaceMaterial(const std::string &name) @@ -1618,13 +1620,8 @@ TSubModel *TModel3d::GetFromName(std::string const &Name) const { // wyszukanie submodelu po nazwie if (Name.empty()) return Root; // potrzebne do terenu z E3D - if (iFlags & 0x0200) // wczytany z pliku tekstowego, wyszukiwanie rekurencyjne - return Root ? Root->GetFromName(Name) : nullptr; - else // wczytano z pliku binarnego, można wyszukać iteracyjnie - { - // for (int i=0;iGetFromName(Name) : nullptr; - } + // both text and binary models are searched recursively + return Root ? Root->GetFromName(Name) : nullptr; }; // locates particle source submodels and stores them on internal list diff --git a/model/Texture.cpp b/model/Texture.cpp index 5c1d852f..a4b9def4 100644 --- a/model/Texture.cpp +++ b/model/Texture.cpp @@ -394,12 +394,12 @@ opengl_texture::make_from_memory(size_t width, size_t height, const uint8_t *raw void opengl_texture::update_from_memory(size_t width, size_t height, const uint8_t *raw) { - if (id != (GLuint)-1 && (width != data_width || height != data_height || GL_SRGB8_ALPHA8 != data_format || GL_RGBA != data_components)) + if (id != invalid_id && (width != data_width || height != data_height || GL_SRGB8_ALPHA8 != data_format || GL_RGBA != data_components)) { glDeleteTextures(1, &id); - id = (GLuint)-1; + id = invalid_id; } - if (id == (GLuint)-1) + if (id == invalid_id) { data_width = width; data_height = height; diff --git a/model/Texture.h b/model/Texture.h index 1f582640..7b285ee3 100644 --- a/model/Texture.h +++ b/model/Texture.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include +#include #include "winheaders.h" #include #include "model/ResourceManager.h" @@ -84,7 +85,8 @@ struct opengl_texture : public ITexture { virtual void update_from_memory(size_t width, size_t height, const uint8_t *data) override; // members - GLuint id{ (GLuint)-1 }; // associated GL resource + static constexpr GLuint invalid_id { std::numeric_limits::max() }; // id value of texture without GL resource + GLuint id{ invalid_id }; // associated GL resource bool has_alpha{ false }; // indicates the texture has alpha channel bool is_ready{ false }; // indicates the texture was processed and is ready for use std::string traits; // requested texture attributes: wrapping modes etc diff --git a/network/message.h b/network/message.h index 871e833f..5aa07d78 100644 --- a/network/message.h +++ b/network/message.h @@ -30,17 +30,17 @@ struct client_hello : public message virtual void serialize(std::ostream &stream) const override; virtual void deserialize(std::istream &stream) override; - int32_t version{}; - uint32_t start_packet{}; + int32_t version{0}; + uint32_t start_packet{0}; }; struct server_hello : public message { server_hello() : message(SERVER_HELLO) {} - uint32_t seed{}; - int64_t timestamp{}; - int64_t config{}; + uint32_t seed{0}; + int64_t timestamp{0}; + int64_t config{0}; std::string scenario; virtual void serialize(std::ostream &stream) const override; @@ -62,9 +62,9 @@ struct frame_info : public request_command { frame_info() : request_command(FRAME_INFO) {} - double render_dt{}; - double dt{}; - double sync{}; + double render_dt{0.0}; + double dt{0.0}; + double sync{0.0}; virtual void serialize(std::ostream &stream) const override; virtual void deserialize(std::istream &stream) override; diff --git a/rendering/frustum.cpp b/rendering/frustum.cpp index afe16441..f4677065 100644 --- a/rendering/frustum.cpp +++ b/rendering/frustum.cpp @@ -22,30 +22,14 @@ cFrustum::calculate() { void cFrustum::calculate( glm::mat4 const &Projection, glm::mat4 const &Modelview ) { - float const *proj = glm::value_ptr( Projection ); - float const *modl = glm::value_ptr( Modelview ); + // multiply the matrices to retrieve clipping planes (column-major, same layout as the old float[16] form) + auto const clipmatrix { Projection * Modelview }; float clip[ 16 ]; - - // multiply the matrices to retrieve clipping planes - clip[ 0 ] = modl[ 0 ] * proj[ 0 ] + modl[ 1 ] * proj[ 4 ] + modl[ 2 ] * proj[ 8 ] + modl[ 3 ] * proj[ 12 ]; - clip[ 1 ] = modl[ 0 ] * proj[ 1 ] + modl[ 1 ] * proj[ 5 ] + modl[ 2 ] * proj[ 9 ] + modl[ 3 ] * proj[ 13 ]; - clip[ 2 ] = modl[ 0 ] * proj[ 2 ] + modl[ 1 ] * proj[ 6 ] + modl[ 2 ] * proj[ 10 ] + modl[ 3 ] * proj[ 14 ]; - clip[ 3 ] = modl[ 0 ] * proj[ 3 ] + modl[ 1 ] * proj[ 7 ] + modl[ 2 ] * proj[ 11 ] + modl[ 3 ] * proj[ 15 ]; - - clip[ 4 ] = modl[ 4 ] * proj[ 0 ] + modl[ 5 ] * proj[ 4 ] + modl[ 6 ] * proj[ 8 ] + modl[ 7 ] * proj[ 12 ]; - clip[ 5 ] = modl[ 4 ] * proj[ 1 ] + modl[ 5 ] * proj[ 5 ] + modl[ 6 ] * proj[ 9 ] + modl[ 7 ] * proj[ 13 ]; - clip[ 6 ] = modl[ 4 ] * proj[ 2 ] + modl[ 5 ] * proj[ 6 ] + modl[ 6 ] * proj[ 10 ] + modl[ 7 ] * proj[ 14 ]; - clip[ 7 ] = modl[ 4 ] * proj[ 3 ] + modl[ 5 ] * proj[ 7 ] + modl[ 6 ] * proj[ 11 ] + modl[ 7 ] * proj[ 15 ]; - - clip[ 8 ] = modl[ 8 ] * proj[ 0 ] + modl[ 9 ] * proj[ 4 ] + modl[ 10 ] * proj[ 8 ] + modl[ 11 ] * proj[ 12 ]; - clip[ 9 ] = modl[ 8 ] * proj[ 1 ] + modl[ 9 ] * proj[ 5 ] + modl[ 10 ] * proj[ 9 ] + modl[ 11 ] * proj[ 13 ]; - clip[ 10 ] = modl[ 8 ] * proj[ 2 ] + modl[ 9 ] * proj[ 6 ] + modl[ 10 ] * proj[ 10 ] + modl[ 11 ] * proj[ 14 ]; - clip[ 11 ] = modl[ 8 ] * proj[ 3 ] + modl[ 9 ] * proj[ 7 ] + modl[ 10 ] * proj[ 11 ] + modl[ 11 ] * proj[ 15 ]; - - clip[ 12 ] = modl[ 12 ] * proj[ 0 ] + modl[ 13 ] * proj[ 4 ] + modl[ 14 ] * proj[ 8 ] + modl[ 15 ] * proj[ 12 ]; - clip[ 13 ] = modl[ 12 ] * proj[ 1 ] + modl[ 13 ] * proj[ 5 ] + modl[ 14 ] * proj[ 9 ] + modl[ 15 ] * proj[ 13 ]; - clip[ 14 ] = modl[ 12 ] * proj[ 2 ] + modl[ 13 ] * proj[ 6 ] + modl[ 14 ] * proj[ 10 ] + modl[ 15 ] * proj[ 14 ]; - clip[ 15 ] = modl[ 12 ] * proj[ 3 ] + modl[ 13 ] * proj[ 7 ] + modl[ 14 ] * proj[ 11 ] + modl[ 15 ] * proj[ 15 ]; + for( int column = 0; column < 4; ++column ) { + for( int row = 0; row < 4; ++row ) { + clip[ column * 4 + row ] = clipmatrix[ column ][ row ]; + } + } // get the sides of the frustum. m_frustum[ side_RIGHT ][ plane_A ] = clip[ 3 ] - clip[ 0 ]; diff --git a/rendering/lightarray.h b/rendering/lightarray.h index 670cbea8..d7459fe9 100644 --- a/rendering/lightarray.h +++ b/rendering/lightarray.h @@ -18,7 +18,7 @@ public: int index{ -1 }; // 0: front lights, 1: rear lights glm::dvec3 position; // position of the light in 3d scene glm::vec3 direction; // direction of the light in 3d scene - glm::vec3 color{ 255.0f / 255.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light + glm::vec3 color{ 1.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light float intensity{ 0.0f }; // (combined) intensity of the light(s) int count{ 0 }; // number (or pattern) of active light(s) glm::vec3 state{ 0.f }; // state of individual lights diff --git a/rendering/opengl33renderer.cpp b/rendering/opengl33renderer.cpp index 2f587033..fcd90aba 100644 --- a/rendering/opengl33renderer.cpp +++ b/rendering/opengl33renderer.cpp @@ -28,6 +28,23 @@ http://mozilla.org/MPL/2.0/. int constexpr EU07_PICKBUFFERSIZE{ 1024 }; // size of (square) textures bound with the pick framebuffer int constexpr EU07_REFLECTIONFIDELITYOFFSET { 250 }; // artificial increase of range for reflection pass detail reduction +namespace { + +// returns material assigned to the submodel, resolving replacable skins. null_handle if no skin set is bound +material_handle +submodel_material( TSubModel const *Submodel ) { + + if( Submodel->m_material >= 0 ) { + return Submodel->m_material; + } + return ( + TSubModel::ReplacableSkinId != nullptr ? + TSubModel::ReplacableSkinId[ -Submodel->m_material ] : + null_handle ); +} + +} // namespace + void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam ) { /* @@ -1935,7 +1952,7 @@ bool opengl33_renderer::Render(world_environment *Environment) auto const fogfactor{std::clamp(Global.fFogEnd / 2000.f, 0.f, 1.f)}; // stronger fog reduces opacity of the celestial bodies float const duskfactor = 1.0f - std::clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f; - glm::vec3 suncolor = glm::mix(glm::vec3(255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor); + glm::vec3 suncolor = glm::mix(glm::vec3(1.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor); // sun { @@ -2341,8 +2358,7 @@ opengl_material &opengl33_renderer::Material(material_handle const Material) opengl_material const & opengl33_renderer::Material( TSubModel const * Submodel ) const { - auto const material { Submodel->m_material >= 0 ? Submodel->m_material : Submodel->ReplacableSkinId[ -Submodel->m_material ] }; - return m_materials.material( material ); + return m_materials.material( submodel_material( Submodel ) ); } texture_handle opengl33_renderer::Fetch_Texture(std::string const &Filename, bool const Loadnow, GLint format_hint) @@ -3767,7 +3783,7 @@ void opengl33_renderer::Render(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); + Bind_Material(submodel_material(Submodel), Submodel); } else { @@ -3804,7 +3820,7 @@ void opengl33_renderer::Render(TSubModel *Submodel) if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material_Shadow(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material_Shadow(submodel_material(Submodel)); } else { @@ -4689,7 +4705,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); + Bind_Material(submodel_material(Submodel), Submodel); } else { @@ -4721,7 +4737,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel) if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material_Shadow(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material_Shadow(submodel_material(Submodel)); } else { diff --git a/rendering/openglrenderer.cpp b/rendering/openglrenderer.cpp index b675c38f..27c94da8 100644 --- a/rendering/openglrenderer.cpp +++ b/rendering/openglrenderer.cpp @@ -1588,7 +1588,7 @@ opengl_renderer::Render( world_environment *Environment ) { auto const fogfactor { std::clamp( Global.fFogEnd / 2000.f, 0.f, 1.f ) }; // closer/denser fog reduces opacity of the celestial bodies float const duskfactor = 1.0f - std::clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; glm::vec3 suncolor = glm::mix( - glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), + glm::vec3( 1.0f, 242.0f / 255.0f, 231.0f / 255.0f ), glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), duskfactor ); // sun diff --git a/rendering/precipitation.cpp b/rendering/precipitation.cpp index 3f9ecaec..02baaada 100644 --- a/rendering/precipitation.cpp +++ b/rendering/precipitation.cpp @@ -31,7 +31,7 @@ basic_precipitation::init() { void basic_precipitation::update() { - auto const timedelta { static_cast( ( DebugModeFlag ? Timer::GetDeltaTime() : Timer::GetDeltaTime() ) ) }; + auto const timedelta { static_cast( Timer::GetDeltaTime() ) }; if( timedelta == 0.0 ) { return; } diff --git a/simulation/simulation.cpp b/simulation/simulation.cpp index a1493f63..36edc4c7 100644 --- a/simulation/simulation.cpp +++ b/simulation/simulation.cpp @@ -137,6 +137,11 @@ state_manager::update_scripting_interface() { auto *time{ Memory.find( "__simulation.time" ) }; auto *date{ Memory.find( "__simulation.date" ) }; + if( weather == nullptr || time == nullptr || date == nullptr ) { + // scripting interface cells weren't created, nothing to synchronize + return; + } + if( simulation::is_ready ) { // potentially adjust weather if( weather->Value1() != m_scriptinginterface.weather->Value1() ) { @@ -396,7 +401,6 @@ void state_manager::process_commands() { pantograph.fLenL1 * std::sin( pantograph.fAngleL ) + pantograph.fLenU1 * std::sin( pantograph.fAngleU ) + pantograph.fHeight; - vehicle->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo; } vehicle = vehicle->Prev(); diff --git a/simulation/simulationenvironment.cpp b/simulation/simulationenvironment.cpp index b96cea20..6c4061c4 100644 --- a/simulation/simulationenvironment.cpp +++ b/simulation/simulationenvironment.cpp @@ -78,7 +78,6 @@ world_environment::compute_weather() { Global.Overcast <= 0.70 ? 6 : Global.Overcast <= 0.80 ? 7 : Global.Overcast <= 0.90 ? 8 : - Global.Overcast > 0.90 ? 9 : 9; } diff --git a/utilities/Logs.cpp b/utilities/Logs.cpp index 737d25d7..5b4d1d9a 100644 --- a/utilities/Logs.cpp +++ b/utilities/Logs.cpp @@ -80,29 +80,20 @@ std::mutex logMutex; void LogService() { - // prevent crash if mutex is not initialized - while (true) - { - try - { - logMutex.lock(); - break; - } - catch (...) {} - } - logMutex.unlock(); - while (!Global.applicationQuitOrder) { { // --- Obsługa InfoStack --- while (!InfoStack.empty()) { - logMutex.lock(); - std::string msg = InfoStack.front().first; - bool isError = InfoStack.front().second; - InfoStack.pop_front(); - logMutex.unlock(); + std::string msg; + bool isError; + { + std::scoped_lock lock(logMutex); + msg = InfoStack.front().first; + isError = InfoStack.front().second; + InfoStack.pop_front(); + } // log to file if (Global.iWriteLogEnabled & 1) @@ -134,10 +125,12 @@ void LogService() // --- Obsługa ErrorStack --- while (!ErrorStack.empty()) { - logMutex.lock(); - std::string msg = ErrorStack.front(); - ErrorStack.pop_front(); - logMutex.unlock(); + std::string msg; + { + std::scoped_lock lock(logMutex); + msg = ErrorStack.front(); + ErrorStack.pop_front(); + } if (!(Global.iWriteLogEnabled & 1)) continue; diff --git a/utilities/parser.cpp b/utilities/parser.cpp index 7209df01..77f91ee3 100644 --- a/utilities/parser.cpp +++ b/utilities/parser.cpp @@ -272,10 +272,9 @@ void cParser::stripFirstTokenBOM(std::string& token, bool ToLower, const char* B } // if first "token" was standalone BOM, read the next real token (avoid recursion) - while (token.empty() && mStream->peek() != EOF) { - readToken(token, ToLower, Break); + if (token.empty() && mStream->peek() != EOF) { // readToken will not re-enter BOM stripping because mFirstToken is now false - break; + readToken(token, ToLower, Break); } } diff --git a/utilities/parser.h b/utilities/parser.h index 0cf51d8c..131efd8b 100644 --- a/utilities/parser.h +++ b/utilities/parser.h @@ -39,7 +39,7 @@ class cParser //: public std::stringstream Output_ getToken( bool const ToLower = true, char const *Break = "\n\r\t ;" ) { getTokens( 1, ToLower, Break ); - Output_ output; + Output_ output{}; *this >> output; return output; }; inline diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 9f1b2586..4437950b 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -2231,7 +2231,7 @@ void TController::AutoRewident() BrakingInitialLevel = IsHeavyCargoTrain ? 1.25 : IsCargoTrain ? 1.25 : 1.00; - BrakingLevelIncrease = IsHeavyCargoTrain ? 0.25 : IsCargoTrain ? 0.25 : 0.25; + BrakingLevelIncrease = 0.25; if( is_emu() ) { auto ep_factor { ( BrakeSystem == TBrakeSystem::ElectroPneumatic ? 8 : 4 ) }; @@ -2320,7 +2320,8 @@ bool TController::CheckVehicles(TOrders user) p = pVehicle->FirstFind(d); // pojazd na czele składu if (!p) p = pVehicle; - pVehicles[end::front] = p; + auto *const frontvehicle { p }; // stays the consist head for the rest of this check + pVehicles[end::front] = frontvehicle; // liczenie pojazdów w składzie i ustalenie parametrów auto dir = d = 1 - d; // a dalej będziemy zliczać od czoła do tyłu fLength = 0.0; // długość składu do badania wyjechania za ograniczenie @@ -2369,7 +2370,7 @@ bool TController::CheckVehicles(TOrders user) if (iDrivigFlags & movePrimary) { // jeśli jest aktywnie prowadzącym pojazd, może zrobić własny porządek auto pantmask = 1; - p = pVehicles[end::front]; + p = frontvehicle; // establish ownership and vehicle order while (p) { @@ -2384,7 +2385,7 @@ bool TController::CheckVehicles(TOrders user) p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła) } // with the order established the virtual train manager can do their work - p = pVehicles[ end::front ]; + p = frontvehicle; ControlledEnginesCount = p->MoverParameters->Power > 1.0 ? 1 : 0; auto hasheaters { false }; while (p) @@ -2457,7 +2458,7 @@ bool TController::CheckVehicles(TOrders user) } // detect push-pull train configurations and mark them accordingly - if( pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::control ) ) { + if( frontvehicle->is_connected( pVehicles[ end::rear ], coupling::control ) ) { // zmiana czoła przez zmianę kabiny iDrivigFlags |= movePushPull; } @@ -2482,7 +2483,7 @@ bool TController::CheckVehicles(TOrders user) } else { // jak dociska - pVehicles[end::front]->RaLightsSet(0, -1); + frontvehicle->RaLightsSet(0, -1); } } // enable door locks @@ -2493,7 +2494,7 @@ bool TController::CheckVehicles(TOrders user) // TODO: replace connection test with connection check between last engine and first car, specifically auto const isheatingcouplingactive { ( ControlledEnginesCount == 1 ? - pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::heating ) : + frontvehicle->is_connected( pVehicles[ end::rear ], coupling::heating ) : true ) }; auto const isheatingneeded { (is_emu() || is_dmu() ? true : @@ -4042,7 +4043,7 @@ void TController::SetTimeControllers() } } - if( std::abs( DizelPercentage_Speed - DizelActualPercentage ) > ( DizelPercentage > 1 ? 0 : 0 ) ) { + if( std::abs( DizelPercentage_Speed - DizelActualPercentage ) > 0 ) { if( PosDec > 0 && ( DizelActualPercentage - DizelPercentage_Speed > 50 @@ -4544,7 +4545,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N if (NewValue1 > 0.0 ? NewValue1 > fStopTime : false) fStopTime = NewValue1; // Ra: włączenie czekania bez zmiany komendy else - OrderList[OrderPos] = Wait_for_orders; // czekanie na komendę (albo dać OrderPos=0) + OrderCurrentSet( Wait_for_orders ); // czekanie na komendę (albo dać OrderPos=0) return true; } @@ -4986,13 +4987,13 @@ TController::PrepareDirection() { void TController::JumpToNextOrder( bool const Ignoremergedchangedirection ) { // wykonanie kolejnej komendy z tablicy rozkazów - if (OrderList[OrderPos] != Wait_for_orders) + if (auto const currentorder { OrderCurrentGet() }; currentorder != Wait_for_orders) { - if( (OrderList[OrderPos] & Change_direction) != 0 // jeśli zmiana kierunku - && OrderList[OrderPos] != Change_direction && false == Ignoremergedchangedirection ) { // ale nałożona na coś + if( (currentorder & Change_direction) != 0 // jeśli zmiana kierunku + && currentorder != Change_direction && false == Ignoremergedchangedirection ) { // ale nałożona na coś // usunięcie zmiany kierunku z innej komendy - OrderList[OrderPos] = TOrders(OrderList[OrderPos] & ~Change_direction); + OrderCurrentSet( TOrders(currentorder & ~Change_direction) ); OrderCheck(); return; } @@ -5032,37 +5033,43 @@ void TController::OrderCheck() // HACK: ensure consist doors will be closed on departure iDrivigFlags |= moveDoorOpened; } - if (OrderList[OrderPos] & Change_direction) // może być nałożona na inną i wtedy ma priorytet + auto const currentorder { OrderCurrentGet() }; + if (currentorder & Change_direction) // może być nałożona na inną i wtedy ma priorytet iDirectionOrder = -iDirection; // trzeba zmienić jawnie, bo się nie domyśli - else if (OrderList[OrderPos] == Obey_train) + else if (currentorder == Obey_train) iDrivigFlags |= moveStopPoint; // W4 są widziane - else if (OrderList[OrderPos] == Disconnect) + else if (currentorder == Disconnect) iVehicleCount = iVehicleCount < 0 ? 0 : iVehicleCount; // odczepianie lokomotywy - else if (OrderList[OrderPos] == Connect) + else if (currentorder == Connect) iDrivigFlags &= ~moveStopPoint; // podczas jazdy na połączenie nie zwracać uwagi na W4 - else if (OrderList[OrderPos] == Wait_for_orders) + else if (currentorder == Wait_for_orders) OrdersClear(); // czyszczenie rozkazów i przeskok do zerowej pozycji } void TController::OrderNext(TOrders NewOrder) { // ustawienie rozkazu do wykonania jako następny - if (OrderList[OrderPos] == NewOrder) + if (OrderCurrentGet() == NewOrder) return; // jeśli robi to, co trzeba, to koniec if (!OrderPos) OrderPos = 1; // na pozycji zerowej pozostaje czekanie OrderTop = OrderPos; // ale może jest czymś zajęty na razie if (NewOrder >= Shunt) // jeśli ma jechać { // ale może być zajęty chwilowymi operacjami - while (OrderList[OrderTop] != Wait_for_orders && OrderList[OrderTop] < Shunt) // jeśli coś robi + while (OrderTop >= 0 && OrderTop < maxorders - 1 + && OrderList[OrderTop] != Wait_for_orders && OrderList[OrderTop] < Shunt) // jeśli coś robi ++OrderTop; // pomijamy wszystkie tymczasowe prace } else { // jeśli ma ustawioną jazdę, to wyłączamy na rzecz operacji - while (OrderList[OrderTop] ? - OrderList[OrderTop] < Shunt && OrderList[OrderTop] != NewOrder : - false) // jeśli coś robi + while (OrderTop >= 0 && OrderTop < maxorders - 1 + && OrderList[OrderTop] != Wait_for_orders && OrderList[OrderTop] < Shunt && OrderList[OrderTop] != NewOrder) // jeśli coś robi ++OrderTop; // pomijamy wszystkie tymczasowe prace } + if (OrderTop < 0 || OrderTop >= maxorders) + { + ErrorLog("Commands overflow: order \"" + Order2Str(NewOrder) + "\" dropped"); + return; + } OrderList[OrderTop++] = NewOrder; // dodanie rozkazu jako następnego #if LOGORDERS OrdersDump( "OrderNext" ); // normalnie nie ma po co tego wypisywać @@ -5071,15 +5078,17 @@ void TController::OrderNext(TOrders NewOrder) void TController::OrderPush(TOrders NewOrder) { // zapisanie na stosie kolejnego rozkazu do wykonania - if (OrderPos == OrderTop && OrderList[OrderPos] < Shunt) // jeśli miałby być zapis na aktalnej pozycji + if (OrderPos == OrderTop && OrderCurrentGet() < Shunt) // jeśli miałby być zapis na aktalnej pozycji // ale nie jedzie ++OrderTop; // niektóre operacje muszą zostać najpierw dokończone => zapis na kolejnej + if (OrderTop < 0 || OrderTop >= maxorders) + { + ErrorLog("Commands overflow: order \"" + Order2Str(NewOrder) + "\" dropped"); + return; + } if (OrderList[OrderTop] != NewOrder) // jeśli jest to samo, to nie dodajemy OrderList[OrderTop++] = NewOrder; // dodanie rozkazu na stos - // if (OrderTop= maxorders) - ErrorLog("Commands overflow: The program will now crash"); #if LOGORDERS OrdersDump( "OrderPush: [" + Order2Str( NewOrder ) + "]" ); // normalnie nie ma po co tego wypisywać #endif @@ -5395,8 +5404,7 @@ TCommandType TController::BackwardScan( double const Range ) // najpierw sprawdzamy, czy semafor czy inny znak został przejechany auto const sl{e->input_location()}; // położenie komórki pamięci auto const pos{pVehicles[end::rear]->RearPosition()}; // pozycja tyłu - auto const sem{sl - pos}; // wektor do komórki pamięci od końca składu - if (dir.x * sem.x + dir.z * sem.z < 0) + if (auto const sem{sl - pos}; dir.x * sem.x + dir.z * sem.z < 0) // wektor do komórki pamięci od końca składu { // jeśli został minięty // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu @@ -5406,13 +5414,10 @@ TCommandType TController::BackwardScan( double const Range ) return TCommandType::cm_Unknown; // nic } scanvel = e->input_value(1); // prędkość przy tym semaforze +#if LOGBACKSCAN // przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu - scandist = glm::length(sem) - 2; // 2m luzu przy manewrach wystarczy - if (scandist < 0) - { - // ujemnych nie ma po co wysyłać - scandist = 0; - } + scandist = std::max(glm::length(sl - pos) - 2.0, 0.0); // 2m luzu przy manewrach wystarczy, ujemnych nie ma po co wysyłać +#endif } auto move{false}; // czy AI w trybie manewerowym ma dociągnąć pod S1 @@ -5425,32 +5430,23 @@ TCommandType TController::BackwardScan( double const Range ) } else { + // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości + // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył + // w przeciwnym razie ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać + // ruszać stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam +#if LOGBACKSCAN if (scandist > fMinProximityDist && mvOccupied->Vel > EU07_AI_NOMOVEMENT && (OrderCurrentGet() & (Shunt | Loose_shunt)) == 0) { - // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości - // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył -#if LOGBACKSCAN - // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist) + - // AnsiString(scanvel)); WriteLog(edir); -#endif - // SetProximityVelocity(scandist,scanvel,&sl); - return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } else { - // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać - // if ((MoverParameters->Vel==0.0)||(scanvel==0.0)) //jeśli stoi lub ma stanąć/stać - // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie - // ruszać stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - // PutCommand("SetVelocity",scanvel,e->Params[9].asMemCell->Value2(),&sl,stopSem); -#if LOGBACKSCAN WriteLog(edir + " - [SetVelocity] [" + to_string(scanvel, 2) + "] [" + to_string(e->input_value(2), 2) + "]"); -#endif - return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } +#endif + return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } } // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe @@ -8118,7 +8114,7 @@ TController::check_route_behind( double const Range ) { } iDirectionOrder = -iDirection; // zmiana kierunku jazdy // zmiana kierunku bez psucia kolejnych komend - OrderList[ OrderPos ] = TOrders( OrderCurrentGet() | Change_direction ); + OrderCurrentSet( TOrders( OrderCurrentGet() | Change_direction ) ); } } } diff --git a/vehicle/Driver.h b/vehicle/Driver.h index b76dbf08..644b8122 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -482,6 +482,7 @@ private: void OrderPush( TOrders NewOrder ); void OrderNext( TOrders NewOrder ); inline TOrders OrderCurrentGet() const; + inline void OrderCurrentSet( TOrders const Order ); inline TOrders OrderNextGet() const; void OrderCheck(); void OrdersInit( double fVel ); @@ -542,7 +543,7 @@ private: double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze TTrack *tLast = nullptr; // ostatni analizowany tor basic_event *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu - static constexpr std::size_t npos{ std::size_t( -1 ) }; + static constexpr std::size_t npos{ std::numeric_limits::max() }; std::size_t SemNextIndex{ npos }; std::size_t SemNextStopIndex{ npos }; double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki @@ -645,9 +646,23 @@ private: }; inline TOrders TController::OrderCurrentGet() const { + if( OrderPos < 0 || OrderPos >= maxorders ) { + return Wait_for_orders; + } return OrderList[ OrderPos ]; } -inline TOrders TController::OrderNextGet() const { - return OrderList[ OrderPos + 1 ]; +inline void TController::OrderCurrentSet( TOrders const Order ) { + if( OrderPos < 0 || OrderPos >= maxorders ) { + return; + } + OrderList[ OrderPos ] = Order; +} + +inline TOrders TController::OrderNextGet() const { + if( OrderPos < 0 || OrderPos >= maxorders ) { + return Wait_for_orders; + } + // the order list wraps around, same as in JumpToNextOrder() + return OrderList[ ( OrderPos + 1 ) % maxorders ]; } diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index 873cc4d3..6af23f07 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -1408,7 +1408,7 @@ TDynamicObject * TDynamicObject::ABuScanNearestObject(glm::vec3 pos, TTrack *Tra TDynamicObject *FoundedObj; FoundedObj = ABuFindNearestObject(pos, Track, this, CouplNr); // zwraca numer sprzęgu znalezionego pojazdu - if (FoundedObj == nullptr) + if (FoundedObj == nullptr && Track != nullptr) { double ActDist; // Przeskanowana odleglosc. double CurrDist = 0; // Aktualna dlugosc toru. @@ -1448,7 +1448,7 @@ TDynamicObject * TDynamicObject::ABuScanNearestObject(glm::vec3 pos, TTrack *Tra ActDist = ScanDist; } else // Jesli nie ma, to wychodzimy. - ActDist = ScanDist; + break; } } // Koniec szukania najblizszego toru z jakims obiektem. return FoundedObj; diff --git a/vehicle/Gauge.cpp b/vehicle/Gauge.cpp index a510b05f..63c042d3 100644 --- a/vehicle/Gauge.cpp +++ b/vehicle/Gauge.cpp @@ -241,8 +241,7 @@ TGauge::Load_mapping( cParser &Input, TGauge::scratch_data &Scratchpad ) { gaugetype == "return" ? TGaugeType::push : gaugetype == "delayed" ? TGaugeType::push_delayed : gaugetype == "pushtoggle" ? TGaugeType::pushtoggle : - gaugetype == "toggle" ? TGaugeType::toggle : - TGaugeType::toggle; // default + TGaugeType::toggle; // "toggle" and default } else if( key == "soundinc:" ) { m_soundfxincrease.deserialize( Input, sound_type::single ); diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 8d2117c4..a77c5749 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/. #include "application/application.h" #include "rendering/renderer.h" #include +#include #include #include /* @@ -646,9 +647,8 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) } DynamicSet(NewDynamicObject); - if (!e3d) - if (DynamicObject->Mechanik == nullptr) - return false; + if (!e3d && DynamicObject->Mechanik == nullptr) + return false; DynamicObject->MechInside = true; @@ -1435,7 +1435,7 @@ void TTrain::OnCommand_secondcontrollerincrease(TTrain *Train, command_data cons // HACK: potentially animate push or pushtoggle control if (Train->ggScndCtrl.is_push()) { - auto const activeposition{Train->ggScndCtrl.is_toggle() ? 1.f : 1.f}; + auto const activeposition{1.f}; auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); } @@ -12398,8 +12398,18 @@ uint16_t TTrain::id() return vid; } -#include -#include +namespace +{ +// updates trains in range [Start, End) +void update_trains(std::deque const &Trains, std::size_t const Start, std::size_t const End, double const Dt) +{ + for (std::size_t j = Start; j < End; ++j) + { + if (Trains[j]) + Trains[j]->Update(Dt); + } +} +} // namespace void train_table::updateAsync(double dt) { @@ -12407,8 +12417,10 @@ void train_table::updateAsync(double dt) const size_t total = m_items.size(); const size_t chunkSize = (total + threads - 1) / threads; - std::vector> futures; - futures.reserve(threads); + std::vector workers; + std::vector> results; // przekazują wyjątki z wątków do głównego wątku + workers.reserve(threads); + results.reserve(threads); for (int i = 0; i < threads; ++i) { @@ -12418,21 +12430,17 @@ void train_table::updateAsync(double dt) if (start >= end) break; // brak więcej danych - futures.emplace_back(std::async(std::launch::async, - [this, start, end, dt]() - { - for (size_t j = start; j < end; ++j) - { - TTrain *train = m_items[j]; - if (train) - train->Update(dt); - } - })); + std::packaged_task task([this, start, end, dt]() { update_trains(m_items, start, end, dt); }); + results.emplace_back(task.get_future()); + workers.emplace_back(std::move(task)); } // Poczekaj aż wszystkie wątki skończą - for (auto &f : futures) - f.get(); + for (auto &worker : workers) + worker.join(); + + for (auto &result : results) + result.get(); // Teraz kasowanie (tylko w głównym wątku) for (TTrain *train : m_items) diff --git a/world/Segment.cpp b/world/Segment.cpp index 2afa264e..c963922a 100644 --- a/world/Segment.cpp +++ b/world/Segment.cpp @@ -294,7 +294,7 @@ TSegment::find_nearest_point( glm::dvec3 const &Point ) const { else { // for curves iterate through segment chunks, and find the one which gives us the least distance to the specified point double distance = std::numeric_limits::max(); - double nearest; + double nearest { 0.0 }; // NOTE: we're reusing already created segment chunks, which are created based on splinefidelity setting // this means depending on splinefidelity the results can be potentially slightly different for( int segmentidx = 0; segmentidx < iSegCount; ++segmentidx ) {