17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-28 12:17:29 +01:00
Files
maszyna/utilities/Globals.h
Hirek193 0112d81b77 multiplayer: names instead of peer numbers, a chat, and the exe as a dedicated server
Three things that turn out to be one thing: a session with people in it needs
to be able to say who they are, and a machine that only referees one should not
have to open a window to do it.

Names. A peer id is what the protocol addresses; "player 4" is no use to anybody
reading a lobby. CLIENT_HELLO carries a requested nickname now, and the server
decides what it actually is: trimmed of control characters and runs of spaces,
capped at 24, and made unique - two people called Marcin are two people and the
lobby has to say which is which. The result goes out as PEER_ROSTER whenever
somebody joins or leaves, and to a joining peer just before its snapshot, so the
crew section resolves to names rather than numbers. The name comes from
multiplayer.nickname in the ini or --nick on the command line, falling back to
the account name and, failing that, to the old numbering. The host is a peer
like any other here too, and registers its own name at startup.

Chat, on the key left of 1. Going up a line carries only its text: who said it
is decided by the connection it arrived on, never by the field in the packet,
which is what stops anybody putting words in anybody's mouth. The server tidies
and caps it, says it, and passes it on - a client waits to hear itself back, so
that everybody sees the conversation in the same order. While the box has the
keyboard imgui swallows the input before the driver mode sees it, so typing "d"
types "d" instead of opening the doors of whatever you are driving; that also
means the key that opened the panel cannot close it, hence escape.

And --nogui. No glfw, no window, no imgui, the null renderer, sound off, log to
the console it was started from, and nobody in a cab - the scenario is left to
its own drivers and this process is a referee rather than a participant. Every
window-dependent path is guarded on an empty window list rather than on a flag
scattered through the code, and the loop is paced at fifty steps a second
because nothing is waiting on a swapchain to slow it down. Chat lines go to the
log, which is what a machine with no window has instead of a chat panel.

    eu07.exe -s scenario.scn --host 0.0.0.0:7420 --nogui --nick Dispatcher
2026-09-07 13:54:34 +00:00

440 lines
18 KiB
C++

/*
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 "utilities/Classes.h"
#include "vehicle/Camera.h"
#include "utilities/Float3d.h"
#include "rendering/light.h"
#include "utilities/utilities.h"
#include "utilities/motiontelemetry.h"
#include <map>
#ifdef WITH_UART
#include "utilities/uart.h"
#endif
#ifdef WITH_HARDWARE_PROTOCOL_V2
#include "hardware/hardware_config.h"
#endif
#ifdef WITH_ZMQ
#include "input/zmq_input.h"
#endif
struct global_settings {
// members
// data items
// TODO: take these out of the settings
std::chrono::steady_clock::time_point startTimestamp;
/// <summary>
/// Mapa z watkami w formacie <std::string nazwa, std::thread watek>
/// </summary>
std::map<std::string, std::thread> threads = {};
bool shiftState{ false }; //m7todo: brzydko
bool ctrlState{ false };
bool altState{ false };
std::mt19937 random_engine;
std::mt19937 local_random_engine;
bool ready_to_load{ false };
std::time_t starting_timestamp = 0; // starting time, in local timezone
uint32_t random_seed = 0;
TCamera pCamera; // parametry kamery
TCamera pDebugCamera;
std::array<glm::dvec3, 10> FreeCameraInit; // pozycje kamery
std::array<glm::vec3, 10> FreeCameraInitAngle;
int iCameraLast{ -1 };
int iSlowMotion{ 0 }; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km
basic_light DayLight;
float SunAngle{ 0.f }; // angle of the sun relative to horizon
int trainThreads{0};
double fLuminance{ 1.0 }; // jasność światła do automatycznego zapalania // TODO: Why double?
double fTimeAngleDeg{ 0.0 }; // godzina w postaci kąta
float fClockAngleDeg[ 6 ]; // kąty obrotu cylindrów dla zegara cyfrowego
std::string LastGLError;
float ZoomFactor{ 1.f }; // determines current camera zoom level. TODO: move it to the renderer
bool CabWindowOpen{ false }; // controls sound attenuation between cab and outside
bool ControlPicking{ true }; // indicates controls pick mode is active
bool DLFont{ false }; // switch indicating presence of basic font
bool bActive{ true }; // czy jest aktywnym oknem
int iPause{ 0 }; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie
float AirTemperature{ 15.f };
std::string asCurrentSceneryPath{ "scenery/" };
std::string asCurrentTexturePath{ paths::textures };
std::string asCurrentDynamicPath;
int CurrentMaxTextureSize{ 4096 };
bool UpdateMaterials{ true };
// settings
// filesystem
bool bLoadTraction{ true };
bool bSmoothTraction{ true };
bool CreateSwitchTrackbeds{ true };
std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA
std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS
std::string szDefaultExt{ szTexturesDDS };
std::string SceneryFile;
std::string local_start_vehicle{ "EU07-424" };
// set when the starting vehicle was explicitly requested (command line -v),
// so multiplayer clients can tell an intentional choice from the built-in default
bool local_start_vehicle_override{ false };
int iConvertModels{ 0 }; // tworzenie plików binarnych
int iConvertIndexRange{ 1000 }; // range of duplicate vertex scan
bool file_binary_terrain{ true }; // enable binary terrain (de)serialization
bool file_binary_terrain_state{true};
// logs
bool priorityLoadText3D{false}; // ladowanie T3D priorytetowo
int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool MultipleLogs{ false };
bool ShowSystemConsole{ false }; // toggle visibility of the OS console window with log output
unsigned int DisabledLogTypes{ 0 };
bool ParserLogIncludes{ true };
// simulation
bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views
bool bEnableTraction{ true };
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
float FrictionWeatherFactor{ 1.f };
bool bLiveTraction{ true };
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
float fFogEnd{ 7500 };
float fTurbidity{ 128 };
std::string Season{}; // season of the year, based on simulation date
std::string Weather{ "cloudy:" }; // current weather
std::string Period{}; // time of the day, based on sun position
bool FullPhysics{ true }; // full calculations performed for each simulation step
bool bnewAirCouplers{ true };
float fMoveLight{ 0.f }; // numer dnia w roku albo -1
bool FakeLight{ false }; // toggle between fixed and dynamic daylight
double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów
double default_timespeed { 1.0 }; // timescale loaded from config
double fLatitudeDeg{ 52.0 }; // szerokość geograficzna
float ScenarioTimeOverride{ std::numeric_limits<float>::quiet_NaN() }; // requested scenario start time
float ScenarioTimeOffset{ 0.f }; // time shift (in hours) applied to train timetables
bool ScenarioTimeCurrent{ false }; // automatic time shift to match scenario time with local clock
bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne
int iSlowMotionMask{ -1 }; // maska wyłączanych właściwości
bool bHideConsole{ false }; // hunter-271211: ukrywanie konsoli
bool bRollFix{ true }; // czy wykonać przeliczanie przechyłki
bool bJoinEvents{ false }; // czy grupować eventy o tych samych nazwach
int iHiddenEvents{ 1 }; // czy łączyć eventy z torami poprzez nazwę toru
bool AITrainman{ true }; // virtual assistant performing consist coupling/decoupling and other maintenance tasks
// ui
int PythonScreenUpdateRate{ 200 }; // delay between python-based screen updates, in milliseconds
int iTextMode{ 0 }; // tryb pracy wyświetlacza tekstowego
glm::vec4 UITextColor{ glm::vec4( 225.f / 255.f, 225.f / 255.f, 225.f / 255.f, 1.f ) }; // base color of UI text
float UIBgOpacity{ 0.94f }; // opacity of ui windows
std::string asLang{ "pl" }; // domyślny język - http://tools.ietf.org/html/bcp47
// gfx
glm::ivec2 window_size; // main window size in platform-specific virtual pixels
glm::ivec2 cursor_pos; // cursor position in platform-specific virtual pixels
glm::ivec2 fb_size; // main window framebuffer size
float ShakingMultiplierBF {1.f}; // mnożnik bujania kamera przod/tyl
float ShakingMultiplierRL {1.f}; // mnożnik bujania kamera lewo/prawo
float ShakingMultiplierUD {1.f}; // mnożnik bujania kamera gora/dol
float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD
float targetfps{ 60.0f };
bool bFullScreen{ false };
bool VSync{ false };
bool bWireFrame{ false };
bool bAdjustScreenFreq{ true };
float BaseDrawRange{ 2500.f };
int DynamicLightCount{ 7 };
bool ScaleSpecularValues{ true };
std::string GfxRenderer{ "default" };
bool LegacyRenderer{ false };
bool NvRenderer{ false };
bool BasicRenderer{ false };
bool RenderShadows{ true };
bool applicationQuitOrder{false};
int RenderCabShadowsRange{ 0 };
struct shadowtune_t {
unsigned int map_size{ 2048 };
float range{ 250.f };
} shadowtune;
struct reflectiontune_t {
double update_interval{ 300.0 };
int fidelity{ 0 }; // 0: sections, 1: +static models, 2: +vehicles
float range_instances{ 750.f };
float range_vehicles{ 250.f };
} reflectiontune;
bool bUseVBO{ true }; // czy jest VBO w karcie graficznej (czy użyć)
float AnisotropicFiltering{ 8.f }; // requested level of anisotropic filtering. TODO: move it to renderer object
float FieldOfView{ 45.f }; // vertical field of view for the camera. TODO: move it to the renderer
GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury
GLint iMaxCabTextureSize{ 4096 }; // largest allowed texture in vehicle cab
int iMultisampling{ 2 }; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px
float SplineFidelity{ 1.f }; // determines segment size during conversion of splines to geometry
float SleeperDistance{ 250.f }; // max distance (in meters) at which per-track sleeper models are still drawn; 0 disables sleeper rendering entirely
bool Smoke{ true }; // toggles smoke simulation and visualization
float SmokeFidelity{ 1.f }; // determines amount of generated smoke particles
bool ResourceSweep{ true }; // gfx resource garbage collection
bool ResourceMove{ false }; // gfx resources are moved between cpu and gpu side instead of sending a copy
bool compress_tex{ true }; // all textures are compressed on gpu side
std::string asSky{ "1" };
float fFpsAverage{ 0.f }; // oczekiwana wartosć FPS
float fFpsDeviation{ 5.f }; // odchylenie standardowe FPS
double fFpsMin{ 30.0 }; // dolna granica FPS, przy której promień scenerii będzie zmniejszany
double fFpsMax{ 65.0 }; // górna granica FPS, przy której promień scenerii będzie zwiększany
// audio
bool bSoundEnabled{ true };
float AudioVolume{ 1.f };
float DefaultRadioVolume{ 0.75f };
float VehicleVolume{ 1.0f };
float EnvironmentPositionalVolume{ 1.0f };
float EnvironmentAmbientVolume{ 1.0f };
int audio_max_sources = 30;
std::string AudioRenderer;
// input
float fMouseXScale{ 1.5f };
float fMouseYScale{ 0.2f };
int iFeedbackMode{ 1 }; // tryb pracy informacji zwrotnej
int iFeedbackPort{ 0 }; // dodatkowy adres dla informacji zwrotnych
bool InputGamepad{ true }; // whether gamepad support is enabled
bool InputMouse{ true }; // whether control pick mode can be activated
double fBrakeStep { 1.0 }; // krok zmiany hamulca innych niż FV4a dla klawiszy [Num3] i [Num9]
double brake_speed { 3.0 }; // prędkość przesuwu hamulca dla FV4a
// parametry kalibracyjne wejść z pulpitu
double fCalibrateIn[ 6 ][ 6 ] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 } };
// parametry kalibracyjne wyjść dla pulpitu
double fCalibrateOut[ 7 ][ 6 ] = {
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 } };
// wartości maksymalne wyjść dla pulpitu
double fCalibrateOutMax[ 7 ] = {
0, 0, 0, 0, 0, 0, 0 };
int iCalibrateOutDebugInfo{ -1 }; // numer wyjścia kalibrowanego dla którego wyświetlać informacje podczas kalibracji
int iPoKeysPWM[ 7 ] = { 0, 1, 2, 3, 4, 5, 6 }; // numery wejść dla PWM
#ifdef WITH_UART
uart_input::conf_t uart_conf;
std::map<std::string, bool *> uartfeatures_map = {
{"main", &uart_conf.mainenable},
{"scnd", &uart_conf.scndenable},
{"train", &uart_conf.trainenable},
{"local", &uart_conf.localenable},
{"radiovolume", &uart_conf.radiovolumeenable},
{"radiochannel", &uart_conf.radiochannelenable},
{"dynamicbrake", &uart_conf.dynamicenable},
};
#endif
#ifdef WITH_HARDWARE_PROTOCOL_V2
// hardware protocol v2; independent of the legacy uart link above, both may run at the same time
hardware::config hardware_conf;
#endif
#ifdef WITH_ZMQ
std::string zmq_address;
#endif
// multiplayer
int iMultiplayer{ 0 }; // blokada działania niektórych eventów na rzecz kominikacji
bool bIsolatedTrainName{ false }; //wysyłanie zajęcia odcinka izolowanego z nazwą pociągu
// other
std::string AppName{ "MaSzyna" };
std::string asVersion; // z opisem
motiontelemetry::conf_t motiontelemetry_conf;
std::string screenshot_dir;
bool loading_log = false;
bool dds_upper_origin = false;
bool captureonstart = true;
bool render_cab = true;
bool crash_damage = true;
bool gui_defaultwindows = true;
bool gui_showtranscripts = true;
bool gui_trainingdefault = false;
std::string extcam_cmd;
std::string extcam_rec;
glm::ivec2 extcam_res{800, 600};
std::chrono::duration<float> minframetime {0.0f};
std::string fullscreen_monitor;
bool fullscreen_windowed{ false };
bool python_enabled = true;
bool python_mipmaps = true;
bool python_displaywindows = false;
bool python_threadedupload = true;
bool python_vsync = true;
bool python_sharectx = true;
bool python_uploadmain = true;
std::chrono::duration<float> python_minframetime {0.01f};
bool gfx_skiprendering = false;
int gfx_framebuffer_width = -1;
int gfx_framebuffer_height = -1;
bool gfx_shadowmap_enabled = true;
bool gfx_envmap_enabled = true;
bool gfx_postfx_motionblur_enabled = true;
float gfx_postfx_motionblur_shutter = 0.01f;
GLenum gfx_postfx_motionblur_format = GL_RG16F;
GLenum gfx_format_color = GL_RGB16F;
GLenum gfx_format_depth = GL_DEPTH_COMPONENT32F;
bool gfx_postfx_chromaticaberration_enabled = true;
bool gfx_skippipeline = false;
bool gfx_extraeffects = true;
bool gfx_shadergamma = false;
bool gfx_usegles = false;
std::string gfx_angleplatform;
bool gfx_gldebug = false;
bool vr = false;
std::string vr_backend;
float gfx_distance_factor_max { 3.f };
float gfx_shadow_angle_min { -0.2f };
int gfx_shadow_rank_cutoff { 3 };
float ui_fontsize = 13.0f;
float ui_scale = 1.0f;
float map_highlight_distance = 3000.0f;
std::string exec_on_exit;
std::string prepend_scn;
bool gfx_postfx_ssao_enabled {false};
struct extraviewport_config {
std::string monitor;
int width, height;
float draw_range;
viewport_proj_config projection;
};
std::vector<extraviewport_config> extra_viewports;
struct pythonviewport_config {
std::string surface;
std::string monitor;
glm::ivec2 size;
glm::vec2 offset;
glm::vec2 scale;
};
std::vector<pythonviewport_config> python_viewports;
struct headtrack_config {
std::string joy;
bool magic_window = false;
glm::ivec3 move_axes;
glm::vec3 move_mul;
glm::ivec3 rot_axes;
glm::vec3 rot_mul;
};
headtrack_config headtrack_conf;
glm::vec3 viewport_move;
glm::mat3 viewport_rotate;
bool map_manualswitchcontrol = false;;
std::vector<std::pair<std::string, std::string>> network_servers;
std::optional<std::pair<std::string, std::string>> network_client;
float desync = 0.0f;
// human readable state of the network session, presented on the connecting/loading screen
std::string network_status;
// set when the server refused us; keeps the reason for the ui and stops reconnect attempts
std::string network_reject_reason;
// identity of this participant within the session; the host keeps network::PEER_HOST
uint32_t network_peer_id = 0;
// vehicle the local player asked to enter from the multiplayer lobby
std::string network_pending_vehicle;
// set when the local player left the crew and should go back to observing
bool network_leave_pending = false;
// last answer of the server to a lobby request, shown in the lobby
std::string network_lobby_message;
// logical simulation step. the authority counts it up, a client takes it from the
// authoritative frame it is executing; the network timeline hangs off this, not off
// the number of frames the renderer happened to draw
uint64_t simulation_tick = 0;
// set once a joining client has taken over the state of the world from the server
bool network_snapshot_applied = false;
// identity handed out by the server, presented again when reconnecting
uint64_t network_session_token = 0;
// how far the worst vehicle was out of place when the last correction arrived, metres
float network_position_error = 0.0f;
// how far a train may be from where the session says it is before it gets put back,
// in metres. the first applies while it is rolling, where nudging it too eagerly is
// worse than the error itself; the second once it has come to a stand, where it is
// worth getting exactly right and is done once rather than every update.
// the server hands its own values to every client on connect, so a session is
// consistent whatever each player has in their ini
float multiplayer_sync_running = 1.5f;
float multiplayer_sync_stop = 0.2f;
// what this player would like to be called in a session. empty falls back to the
// account name, and failing that to "player <n>"
std::string multiplayer_nickname;
// no window, no renderer and nobody in a cab: the executable as a dedicated server
bool headless = false;
// the scenario has finished loading and the world can be worked with. this is not the
// same as simulation::is_ready, which only goes up once the player has a cab
bool simulation_loaded = false;
// consecutive steps whose state digest disagreed with the server's; diagnostics only
uint64_t network_digest_mismatches = 0;
std::unordered_map<int, std::string> trainset_overrides;
float m_skysaturationcorrection{ 1.65f };
float m_skyhuecorrection{ 0.5f };
// methods
void LoadIniFile( std::string asFileName );
void FinalizeConfig();
void ConfigParse(cParser &parser);
bool ConfigParseGeneral(cParser& Parser, const std::string& token);
bool ConfigParseAudio(cParser& Parser, const std::string& token);
bool ConfigParseGraphics(cParser& Parser, const std::string& token);
bool ConfigParseInput(cParser& Parser, const std::string& token);
bool ConfigParseSimulation(cParser& Parser, const std::string& token);
bool ConfigParseUI(cParser& Parser, const std::string& token);
bool ConfigParsePython(cParser& Parser, const std::string& token);
bool ConfigParseNetwork(cParser& Parser, const std::string& token);
bool ConfigParseHardware(cParser& Parser, const std::string& token);
bool ConfigParseDebug(cParser& Parser, const std::string& token);
bool ConfigParse_gfx( cParser &parser, std::string_view const Token );
// sends basic content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
template <typename Type_>
void
export_as_text( std::ostream &Output, std::string const Key, Type_ const &Value ) const;
};
template <typename Type_>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, Type_ const &Value ) const {
Output << Key << " " << Value << "\n";
}
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, std::string const &Value ) const;
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, bool const &Value ) const;
extern global_settings& GetGlobalSettings();
#define Global (GetGlobalSettings())