mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
work
This commit is contained in:
24
Timer.cpp
24
Timer.cpp
@@ -23,6 +23,7 @@ DWORD dwFrames{ 0 };
|
||||
double fSimulationTime{ 0.0 };
|
||||
double fSoundTimer{ 0.0 };
|
||||
double fSinceStart{ 0.0 };
|
||||
double override_delta = -1.0f;
|
||||
|
||||
double GetTime()
|
||||
{
|
||||
@@ -39,19 +40,9 @@ double GetDeltaRenderTime()
|
||||
return DeltaRenderTime;
|
||||
}
|
||||
|
||||
void SetDeltaTime(double t)
|
||||
void set_delta_override(double t)
|
||||
{
|
||||
DeltaTime = t;
|
||||
}
|
||||
|
||||
bool GetSoundTimer()
|
||||
{ // Ra: być może, by dźwięki nie modyfikowały się zbyt często, po 0.1s zeruje się ten licznik
|
||||
return (fSoundTimer == 0.0f);
|
||||
}
|
||||
|
||||
double GetFPS()
|
||||
{
|
||||
return fFPS;
|
||||
override_delta = t;
|
||||
}
|
||||
|
||||
void ResetTimers()
|
||||
@@ -59,8 +50,7 @@ void ResetTimers()
|
||||
UpdateTimers( Global.iPause != 0 );
|
||||
DeltaTime = 0.1;
|
||||
DeltaRenderTime = 0.0;
|
||||
fSoundTimer = 0.0;
|
||||
};
|
||||
}
|
||||
|
||||
uint64_t fr, count, oldCount;
|
||||
|
||||
@@ -89,6 +79,11 @@ void UpdateTimers(bool pause)
|
||||
else
|
||||
DeltaTime = 0.0; // wszystko stoi, bo czas nie płynie
|
||||
|
||||
if (override_delta != -1.0f)
|
||||
DeltaTime = override_delta;
|
||||
|
||||
fSimulationTime += DeltaTime;
|
||||
|
||||
oldCount = count;
|
||||
// Keep track of the time lapse and frame count
|
||||
#if __linux__
|
||||
@@ -106,7 +101,6 @@ void UpdateTimers(bool pause)
|
||||
fLastTime = fTime;
|
||||
dwFrames = 0L;
|
||||
}
|
||||
fSimulationTime += DeltaTime;
|
||||
};
|
||||
|
||||
}; // namespace timer
|
||||
|
||||
6
Timer.h
6
Timer.h
@@ -16,11 +16,7 @@ double GetTime();
|
||||
double GetDeltaTime();
|
||||
double GetDeltaRenderTime();
|
||||
|
||||
void SetDeltaTime(double v);
|
||||
|
||||
bool GetSoundTimer();
|
||||
|
||||
double GetFPS();
|
||||
void set_delta_override(double v);
|
||||
|
||||
void ResetTimers();
|
||||
|
||||
|
||||
73
Train.cpp
73
Train.cpp
@@ -348,7 +348,12 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
|
||||
{ user_command::generictoggle6, &TTrain::OnCommand_generictoggle },
|
||||
{ user_command::generictoggle7, &TTrain::OnCommand_generictoggle },
|
||||
{ user_command::generictoggle8, &TTrain::OnCommand_generictoggle },
|
||||
{ user_command::generictoggle9, &TTrain::OnCommand_generictoggle }
|
||||
{ user_command::generictoggle9, &TTrain::OnCommand_generictoggle },
|
||||
|
||||
{ user_command::vehiclemove, &TTrain::OnCommand_vehiclemove },
|
||||
{ user_command::vehiclemoveforwards, &TTrain::OnCommand_vehiclemoveforwards },
|
||||
{ user_command::vehiclemovebackwards, &TTrain::OnCommand_vehiclemovebackwards },
|
||||
{ user_command::vehicleboost, &TTrain::OnCommand_vehicleboost },
|
||||
};
|
||||
|
||||
std::vector<std::string> const TTrain::fPress_labels = {
|
||||
@@ -4706,6 +4711,52 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_vehiclemove(TTrain *Train, const command_data &Command) {
|
||||
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
|
||||
return;
|
||||
|
||||
TDynamicObject *d = Train->DynamicObject;
|
||||
while( d ) {
|
||||
d->Move( Command.param1 * d->DirectionGet() );
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = Train->DynamicObject->Prev();
|
||||
while( d ) {
|
||||
d->Move( Command.param1 * d->DirectionGet() );
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_vehiclemoveforwards(TTrain *Train, const command_data &Command) {
|
||||
command_data modified = Command;
|
||||
modified.param1 = 100.0;
|
||||
OnCommand_vehiclemove(Train, modified);
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_vehiclemovebackwards(TTrain *Train, const command_data &Command) {
|
||||
command_data modified = Command;
|
||||
modified.param1 = -100.0;
|
||||
OnCommand_vehiclemove(Train, modified);
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command) {
|
||||
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
|
||||
return;
|
||||
|
||||
double boost = Command.param1 != 0.0 ? Command.param1 : 2.78;
|
||||
|
||||
TDynamicObject *d = Train->DynamicObject;
|
||||
while( d ) {
|
||||
d->MoverParameters->V += d->DirectionGet() * boost;
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = Train->DynamicObject->Prev();
|
||||
while( d ) {
|
||||
d->MoverParameters->V += d->DirectionGet() * boost;
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
|
||||
// cab movement update, fixed step part
|
||||
void TTrain::UpdateCab() {
|
||||
|
||||
@@ -4791,9 +4842,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
// eventually commands are going to be retrieved directly by the vehicle, filtered through active control stand
|
||||
// and ultimately executed, provided the stand allows it.
|
||||
command_data commanddata;
|
||||
// NOTE: currently we're only storing commands for local vehicle and there's no id system in place,
|
||||
// so we're supplying 'default' vehicle id of 0
|
||||
while( simulation::Commands.pop( commanddata, static_cast<std::size_t>( command_target::vehicle ) | 0 ) ) {
|
||||
while( simulation::Commands.pop( commanddata, (uint32_t)command_target::vehicle | id() )) {
|
||||
|
||||
auto lookup = m_commandhandlers.find( commanddata.command );
|
||||
if( lookup != m_commandhandlers.end() ) {
|
||||
@@ -7906,3 +7955,19 @@ int TTrain::get_drive_direction()
|
||||
{
|
||||
return mvOccupied->ActiveDir * mvOccupied->CabNo;
|
||||
}
|
||||
|
||||
uint16_t TTrain::id() {
|
||||
static uint16_t i = 0; // todo: do something better
|
||||
if (vid == 0) {
|
||||
vid = ++i;
|
||||
WriteLog("assigning id " + std::to_string(vid) + " to vehicle " + Dynamic()->name());
|
||||
}
|
||||
return vid;
|
||||
}
|
||||
|
||||
void train_table::update(double dt)
|
||||
{
|
||||
for (TTrain *train : m_items) {
|
||||
train->Update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
13
Train.h
13
Train.h
@@ -327,6 +327,10 @@ class TTrain
|
||||
static void OnCommand_cabchangeforward( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_generictoggle( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_vehiclemove( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_vehiclemoveforwards( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_vehiclemovebackwards( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_vehicleboost( TTrain *Train, command_data const &Command );
|
||||
|
||||
|
||||
// members
|
||||
@@ -642,6 +646,7 @@ private:
|
||||
float fPPress, fNPress;
|
||||
int iRadioChannel { 1 }; // numer aktualnego kana?u radiowego
|
||||
std::vector<std::tuple<std::string, texture_handle, std::optional<texture_window>>> m_screens;
|
||||
uint16_t vid = 0;
|
||||
|
||||
public:
|
||||
float fPress[20][3]; // cisnienia dla wszystkich czlonow
|
||||
@@ -674,5 +679,11 @@ private:
|
||||
void set_scndctrl(int);
|
||||
void set_trainbrake(float);
|
||||
void set_localbrake(float);
|
||||
|
||||
uint16_t id();
|
||||
};
|
||||
|
||||
class train_table : public basic_table<TTrain> {
|
||||
public:
|
||||
void update(double dt);
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -153,8 +153,35 @@ eu07_application::run() {
|
||||
Timer::subsystem.mainloop_total.start();
|
||||
glfwPollEvents();
|
||||
|
||||
if (!m_modes[ m_modestack.top() ]->update())
|
||||
break;
|
||||
if (!m_network)
|
||||
{
|
||||
if (!m_modes[ m_modestack.top() ]->update())
|
||||
break;
|
||||
}
|
||||
else if (!Global.network_conf.is_server) {
|
||||
double delta;
|
||||
do {
|
||||
auto tup = m_network->get_next_delta();
|
||||
delta = std::get<0>(tup);
|
||||
simulation::Commands.merge_command_sequences(std::get<1>(tup));
|
||||
Timer::set_delta_override(delta);
|
||||
|
||||
simulation::Commands.update();
|
||||
if (!m_modes[ m_modestack.top() ]->update())
|
||||
break;
|
||||
}
|
||||
while (delta != 0.0);
|
||||
}
|
||||
else {
|
||||
auto commands = simulation::Commands.peek_command_sequences();
|
||||
|
||||
simulation::Commands.update();
|
||||
if (!m_modes[ m_modestack.top() ]->update())
|
||||
break;
|
||||
|
||||
double delta = Timer::GetDeltaTime();
|
||||
m_network->push_delta(delta, commands);
|
||||
}
|
||||
|
||||
m_taskqueue.update();
|
||||
opengl_texture::reset_unit_cache();
|
||||
@@ -169,7 +196,6 @@ eu07_application::run() {
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_event_poll();
|
||||
|
||||
simulation::Commands.update();
|
||||
if (m_screenshot_queued) {
|
||||
m_screenshot_queued = false;
|
||||
screenshot_man.make_screenshot();
|
||||
@@ -177,7 +203,7 @@ eu07_application::run() {
|
||||
|
||||
Timer::subsystem.mainloop_total.stop();
|
||||
|
||||
if (Global.network_conf.enabled)
|
||||
if (m_network)
|
||||
m_network->poll();
|
||||
}
|
||||
|
||||
|
||||
38
command.cpp
38
command.cpp
@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Logs.h"
|
||||
#include "Timer.h"
|
||||
#include "utilities.h"
|
||||
#include "simulation.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
@@ -217,7 +218,14 @@ commanddescription_sequence Commands_descriptions = {
|
||||
{ "batterydisable", command_target::vehicle, command_mode::oneoff },
|
||||
{ "motorblowerstogglefront", command_target::vehicle, command_mode::oneoff },
|
||||
{ "motorblowerstogglerear", command_target::vehicle, command_mode::oneoff },
|
||||
{ "motorblowersdisableall", command_target::vehicle, command_mode::oneoff }
|
||||
{ "motorblowersdisableall", command_target::vehicle, command_mode::oneoff },
|
||||
{ "timejump", command_target::simulation, command_mode::oneoff },
|
||||
{ "timejumplarge", command_target::simulation, command_mode::oneoff },
|
||||
{ "timejumpsmall", command_target::simulation, command_mode::oneoff },
|
||||
{ "vehiclemove", command_target::vehicle, command_mode::oneoff },
|
||||
{ "vehiclemoveforwards", command_target::vehicle, command_mode::oneoff },
|
||||
{ "vehiclemovebackwards", command_target::vehicle, command_mode::oneoff },
|
||||
{ "vehicleboost", command_target::vehicle, command_mode::oneoff },
|
||||
};
|
||||
|
||||
} // simulation
|
||||
@@ -225,12 +233,12 @@ commanddescription_sequence Commands_descriptions = {
|
||||
void command_queue::update()
|
||||
{
|
||||
double delta = Timer::GetDeltaTime();
|
||||
for (user_command c : m_active_continuous)
|
||||
for (auto c : m_active_continuous)
|
||||
{
|
||||
auto const &desc = simulation::Commands_descriptions[ static_cast<std::size_t>( c ) ];
|
||||
command_data data { c, GLFW_REPEAT, 0, 0, delta };
|
||||
auto lookup = m_commands.emplace((size_t)desc.target, commanddata_sequence() );
|
||||
lookup.first->second.emplace( data );
|
||||
auto lookup = m_commands.emplace(c.second, commanddata_sequence() );
|
||||
|
||||
command_data data({c.first, GLFW_REPEAT, 0.0, 0.0, delta});
|
||||
lookup.first->second.emplace_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,16 +249,16 @@ command_queue::push( command_data const &Command, std::size_t const Recipient )
|
||||
if (desc.mode == command_mode::continuous)
|
||||
{
|
||||
if (Command.action == GLFW_PRESS)
|
||||
m_active_continuous.emplace(Command.command);
|
||||
m_active_continuous.emplace(std::make_pair(Command.command, Recipient));
|
||||
else if (Command.action == GLFW_RELEASE)
|
||||
m_active_continuous.erase(Command.command);
|
||||
m_active_continuous.erase(std::make_pair(Command.command, Recipient));
|
||||
else if (Command.action == GLFW_REPEAT)
|
||||
return;
|
||||
}
|
||||
|
||||
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
|
||||
// recipient stack was either located or created, so we can add to it quite safely
|
||||
lookup.first->second.emplace( Command );
|
||||
lookup.first->second.emplace_back( Command );
|
||||
}
|
||||
|
||||
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
||||
@@ -269,16 +277,24 @@ command_queue::pop( command_data &Command, std::size_t const Recipient ) {
|
||||
}
|
||||
// we have command stack with command(s) on it, retrieve and pop the first one
|
||||
Command = commands.front();
|
||||
commands.pop();
|
||||
commands.pop_front();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
command_relay::post( user_command const Command, double const Param1, double const Param2,
|
||||
int const Action, std::uint16_t const Recipient) const {
|
||||
int const Action, uint16_t Recipient) const {
|
||||
|
||||
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
|
||||
|
||||
if (command.target == command_target::vehicle && Recipient == 0) {
|
||||
// default 0 recipient is currently controlled train
|
||||
if (simulation::Train == nullptr)
|
||||
return;
|
||||
Recipient = simulation::Train->id();
|
||||
}
|
||||
|
||||
if( ( command.target == command_target::vehicle )
|
||||
&& ( true == FreeFlyModeFlag )
|
||||
&& ( ( false == DebugModeFlag )
|
||||
|
||||
55
command.h
55
command.h
@@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
enum class user_command {
|
||||
|
||||
aidriverenable,
|
||||
aidriverenable = 0,
|
||||
aidriverdisable,
|
||||
mastercontrollerincrease,
|
||||
mastercontrollerincreasefast,
|
||||
@@ -213,13 +213,18 @@ enum class user_command {
|
||||
motorblowerstogglerear,
|
||||
motorblowersdisableall,
|
||||
|
||||
timejump,
|
||||
timejumplarge,
|
||||
timejumpsmall,
|
||||
vehiclemove,
|
||||
vehiclemoveforwards,
|
||||
vehiclemovebackwards,
|
||||
vehicleboost,
|
||||
|
||||
none = -1
|
||||
};
|
||||
|
||||
enum class command_target {
|
||||
|
||||
userinterface,
|
||||
simulation,
|
||||
/*
|
||||
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
|
||||
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
|
||||
@@ -229,7 +234,9 @@ enum class command_target {
|
||||
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
|
||||
vehicle = 0x10000,
|
||||
signal = 0x20000,
|
||||
entity = 0x40000
|
||||
entity = 0x40000,
|
||||
|
||||
simulation = 0x8000,
|
||||
};
|
||||
|
||||
enum class command_mode {
|
||||
@@ -259,6 +266,10 @@ struct command_data {
|
||||
class command_queue {
|
||||
|
||||
public:
|
||||
// types
|
||||
typedef std::deque<command_data> commanddata_sequence;
|
||||
typedef std::unordered_map<std::size_t, commanddata_sequence> commanddatasequence_map;
|
||||
|
||||
// methods
|
||||
// posts specified command for specified recipient
|
||||
void
|
||||
@@ -268,16 +279,33 @@ public:
|
||||
pop( command_data &Command, std::size_t const Recipient );
|
||||
void update();
|
||||
|
||||
commanddatasequence_map peek_command_sequences() const {
|
||||
commanddatasequence_map map(m_commands);
|
||||
for (auto &kv : map) {
|
||||
if (kv.first & 0)
|
||||
kv.second.clear();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
void merge_command_sequences(commanddatasequence_map map) {
|
||||
for (auto const &kv : map)
|
||||
for (command_data const &data : kv.second)
|
||||
push(data, kv.first);
|
||||
}
|
||||
|
||||
private:
|
||||
// types
|
||||
typedef std::queue<command_data> commanddata_sequence;
|
||||
typedef std::unordered_map<std::size_t, commanddata_sequence> commanddatasequence_map;
|
||||
// members
|
||||
commanddatasequence_map m_commands;
|
||||
|
||||
// TODO: this set should contain more than just user_command
|
||||
// also, maybe that and all continuous input logic should be in command_relay?
|
||||
std::unordered_set<user_command> m_active_continuous;
|
||||
struct command_set_hash {
|
||||
uint64_t operator() (const std::pair<user_command, uint32_t> &pair) const {
|
||||
return ((uint64_t)pair.first << 32) | ((uint64_t) pair.second);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_set<std::pair<user_command, uint32_t>, command_set_hash> m_active_continuous;
|
||||
};
|
||||
|
||||
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
|
||||
@@ -299,11 +327,10 @@ class command_relay {
|
||||
public:
|
||||
// constructors
|
||||
// methods
|
||||
// posts specified command for the specified recipient
|
||||
// TODO: replace uint16_t with recipient handle, based on item id
|
||||
// posts specified command for the specified recipient
|
||||
void
|
||||
post( user_command const Command, double const Param1, double const Param2,
|
||||
int const Action, std::uint16_t const Recipient ) const;
|
||||
post(user_command const Command, double const Param1, double const Param2,
|
||||
int const Action, uint16_t Recipient ) const;
|
||||
private:
|
||||
// types
|
||||
// members
|
||||
|
||||
@@ -219,8 +219,14 @@ driverkeyboard_input::default_bindings() {
|
||||
// batterydisable,
|
||||
{ user_command::motorblowerstogglefront, GLFW_KEY_N | keymodifier::shift },
|
||||
{ user_command::motorblowerstogglerear, GLFW_KEY_M | keymodifier::shift },
|
||||
{ user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control }
|
||||
|
||||
{ user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control },
|
||||
// admin_timejump,
|
||||
{ user_command::timejumplarge, GLFW_KEY_F1 | keymodifier::control },
|
||||
{ user_command::timejumpsmall, GLFW_KEY_F1 | keymodifier::shift },
|
||||
// admin_vehiclemove,
|
||||
{ user_command::vehiclemoveforwards, GLFW_KEY_LEFT_BRACKET | keymodifier::control },
|
||||
{ user_command::vehiclemovebackwards, GLFW_KEY_RIGHT_BRACKET | keymodifier::control },
|
||||
{ user_command::vehicleboost, GLFW_KEY_TAB | keymodifier::control },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
301
drivermode.cpp
301
drivermode.cpp
@@ -100,106 +100,106 @@ driver_mode::update() {
|
||||
|
||||
double const deltatime = Timer::GetDeltaTime(); // 0.0 gdy pauza
|
||||
|
||||
if( Global.iPause == 0 ) {
|
||||
simulation::State.update_clocks();
|
||||
simulation::Environment.update();
|
||||
|
||||
if (deltatime != 0.0)
|
||||
{
|
||||
// jak pauza, to nie ma po co tego przeliczać
|
||||
simulation::Time.update( deltatime );
|
||||
}
|
||||
simulation::State.update_clocks();
|
||||
simulation::Environment.update();
|
||||
|
||||
// fixed step, simulation time based updates
|
||||
// m_primaryupdateaccumulator += dt; // unused for the time being
|
||||
m_secondaryupdateaccumulator += deltatime;
|
||||
/*
|
||||
// NOTE: until we have no physics state interpolation during render, we need to rely on the old code,
|
||||
// as doing fixed step calculations but flexible step render results in ugly mini jitter
|
||||
// core routines (physics)
|
||||
int updatecount = 0;
|
||||
while( ( m_primaryupdateaccumulator >= m_primaryupdaterate )
|
||||
&&( updatecount < 20 ) ) {
|
||||
// no more than 20 updates per single pass, to keep physics from hogging up all run time
|
||||
Ground.Update( m_primaryupdaterate, 1 );
|
||||
++updatecount;
|
||||
m_primaryupdateaccumulator -= m_primaryupdaterate;
|
||||
}
|
||||
*/
|
||||
int updatecount = 1;
|
||||
if( deltatime > m_primaryupdaterate ) // normalnie 0.01s
|
||||
{
|
||||
/*
|
||||
// NOTE: experimentally disabled physics update cap
|
||||
auto const iterations = std::ceil(dt / m_primaryupdaterate);
|
||||
updatecount = std::min( 20, static_cast<int>( iterations ) );
|
||||
*/
|
||||
updatecount = std::ceil( deltatime / m_primaryupdaterate );
|
||||
/*
|
||||
// NOTE: changing dt wrecks things further down the code. re-acquire proper value later or cleanup here
|
||||
dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem
|
||||
*/
|
||||
}
|
||||
auto const stepdeltatime { deltatime / updatecount };
|
||||
// NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations
|
||||
// this means at count > 20 simulation and render are going to desync. is that right?
|
||||
// NOTE: experimentally changing this to prevent the desync.
|
||||
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
|
||||
Timer::subsystem.sim_dynamics.start();
|
||||
if( true == Global.FullPhysics ) {
|
||||
// mixed calculation mode, steps calculated in ~0.05s chunks
|
||||
while( updatecount >= 5 ) {
|
||||
simulation::State.update( stepdeltatime, 5 );
|
||||
updatecount -= 5;
|
||||
}
|
||||
if( updatecount ) {
|
||||
simulation::State.update( stepdeltatime, updatecount );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// simplified calculation mode; faster but can lead to errors
|
||||
simulation::State.update( stepdeltatime, updatecount );
|
||||
}
|
||||
Timer::subsystem.sim_dynamics.stop();
|
||||
// m_primaryupdateaccumulator += dt; // unused for the time being
|
||||
m_secondaryupdateaccumulator += deltatime;
|
||||
/*
|
||||
// NOTE: until we have no physics state interpolation during render, we need to rely on the old code,
|
||||
// as doing fixed step calculations but flexible step render results in ugly mini jitter
|
||||
// core routines (physics)
|
||||
int updatecount = 0;
|
||||
while( ( m_primaryupdateaccumulator >= m_primaryupdaterate )
|
||||
&&( updatecount < 20 ) ) {
|
||||
// no more than 20 updates per single pass, to keep physics from hogging up all run time
|
||||
Ground.Update( m_primaryupdaterate, 1 );
|
||||
++updatecount;
|
||||
m_primaryupdateaccumulator -= m_primaryupdaterate;
|
||||
}
|
||||
*/
|
||||
int updatecount = 1;
|
||||
if( deltatime > m_primaryupdaterate ) // normalnie 0.01s
|
||||
{
|
||||
/*
|
||||
// NOTE: experimentally disabled physics update cap
|
||||
auto const iterations = std::ceil(dt / m_primaryupdaterate);
|
||||
updatecount = std::min( 20, static_cast<int>( iterations ) );
|
||||
*/
|
||||
updatecount = std::ceil( deltatime / m_primaryupdaterate );
|
||||
/*
|
||||
// NOTE: changing dt wrecks things further down the code. re-acquire proper value later or cleanup here
|
||||
dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem
|
||||
*/
|
||||
}
|
||||
auto const stepdeltatime { deltatime / updatecount };
|
||||
// NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations
|
||||
// this means at count > 20 simulation and render are going to desync. is that right?
|
||||
// NOTE: experimentally changing this to prevent the desync.
|
||||
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
|
||||
Timer::subsystem.sim_dynamics.start();
|
||||
if( true == Global.FullPhysics ) {
|
||||
// mixed calculation mode, steps calculated in ~0.05s chunks
|
||||
while( updatecount >= 5 ) {
|
||||
simulation::State.update( stepdeltatime, 5 );
|
||||
updatecount -= 5;
|
||||
}
|
||||
if( updatecount ) {
|
||||
simulation::State.update( stepdeltatime, updatecount );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// simplified calculation mode; faster but can lead to errors
|
||||
simulation::State.update( stepdeltatime, updatecount );
|
||||
}
|
||||
Timer::subsystem.sim_dynamics.stop();
|
||||
|
||||
// secondary fixed step simulation time routines
|
||||
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
|
||||
// secondary fixed step simulation time routines
|
||||
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
|
||||
|
||||
// awaria PoKeys mogła włączyć pauzę - przekazać informację
|
||||
if( Global.iMultiplayer ) // dajemy znać do serwera o wykonaniu
|
||||
if( iPause != Global.iPause ) { // przesłanie informacji o pauzie do programu nadzorującego
|
||||
multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania
|
||||
iPause = Global.iPause;
|
||||
}
|
||||
// awaria PoKeys mogła włączyć pauzę - przekazać informację
|
||||
if( Global.iMultiplayer ) // dajemy znać do serwera o wykonaniu
|
||||
if( iPause != Global.iPause ) { // przesłanie informacji o pauzie do programu nadzorującego
|
||||
multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania
|
||||
iPause = Global.iPause;
|
||||
}
|
||||
|
||||
// TODO: generic shake update pass for vehicles within view range
|
||||
if( Camera.m_owner != nullptr ) {
|
||||
Camera.m_owner->update_shake( m_secondaryupdaterate );
|
||||
}
|
||||
// TODO: generic shake update pass for vehicles within view range
|
||||
if( Camera.m_owner != nullptr ) {
|
||||
Camera.m_owner->update_shake( m_secondaryupdaterate );
|
||||
}
|
||||
|
||||
m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap
|
||||
}
|
||||
m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap
|
||||
}
|
||||
|
||||
// variable step simulation time routines
|
||||
// variable step simulation time routines
|
||||
|
||||
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||
// intercept cases when the driven train got removed after entering portal
|
||||
InOutKey();
|
||||
}
|
||||
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||
// intercept cases when the driven train got removed after entering portal
|
||||
InOutKey();
|
||||
}
|
||||
|
||||
if( Global.changeDynObj ) {
|
||||
// ABu zmiana pojazdu - przejście do innego
|
||||
ChangeDynamic();
|
||||
}
|
||||
if( Global.changeDynObj ) {
|
||||
// ABu zmiana pojazdu - przejście do innego
|
||||
ChangeDynamic();
|
||||
}
|
||||
|
||||
if( simulation::Train != nullptr ) {
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
|
||||
simulation::Train->Update( deltatime );
|
||||
}
|
||||
else {
|
||||
TSubModel::iInstance = 0;
|
||||
}
|
||||
if( simulation::Train != nullptr )
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
|
||||
else
|
||||
TSubModel::iInstance = 0;
|
||||
|
||||
simulation::Events.update();
|
||||
simulation::Region->update_events();
|
||||
simulation::Lights.update();
|
||||
simulation::Trains.update(deltatime);
|
||||
simulation::Events.update();
|
||||
simulation::Region->update_events();
|
||||
simulation::Lights.update();
|
||||
}
|
||||
|
||||
// render time routines follow:
|
||||
|
||||
@@ -263,24 +263,22 @@ driver_mode::enter() {
|
||||
{
|
||||
WriteLog( "Initializing player train, \"" + Global.asHumanCtrlVehicle + "\"" );
|
||||
|
||||
if( simulation::Train == nullptr ) {
|
||||
simulation::Train = new TTrain();
|
||||
}
|
||||
if( simulation::Train->Init( nPlayerTrain ) )
|
||||
{
|
||||
WriteLog("Player train initialization OK");
|
||||
TTrain *train = new TTrain();
|
||||
if (train->Init(nPlayerTrain)) {
|
||||
simulation::Trains.insert(train, nPlayerTrain->name());
|
||||
simulation::Train = train;
|
||||
|
||||
Application.set_title( Global.AppName + " (" + simulation::Train->Controlled()->Name + " @ " + Global.SceneryFile + ")" );
|
||||
WriteLog("Player train initialization OK");
|
||||
Application.set_title( Global.AppName + " (" + simulation::Train->Controlled()->Name + " @ " + Global.SceneryFile + ")" );
|
||||
CabView();
|
||||
}
|
||||
else {
|
||||
delete train;
|
||||
|
||||
CabView();
|
||||
}
|
||||
else
|
||||
{
|
||||
Error("Bad init: player train initialization failed");
|
||||
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
|
||||
SafeDelete( simulation::Train );
|
||||
Camera.m_owner = nullptr;
|
||||
}
|
||||
Error("Bad init: player train initialization failed");
|
||||
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
|
||||
Camera.m_owner = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -672,22 +670,6 @@ driver_mode::OnKeyDown(int cKey) {
|
||||
|
||||
switch (cKey) {
|
||||
|
||||
case GLFW_KEY_F1: {
|
||||
|
||||
if( DebugModeFlag ) {
|
||||
// additional simulation clock jump keys in debug mode
|
||||
if( Global.ctrlState ) {
|
||||
// ctrl-f1
|
||||
simulation::Time.update( 20.0 * 60.0 );
|
||||
}
|
||||
else if( Global.shiftState ) {
|
||||
// shift-f1
|
||||
simulation::Time.update( 5.0 * 60.0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F4: {
|
||||
|
||||
if( Global.shiftState ) { ExternalView(); } // with Shift, cycle through external views
|
||||
@@ -713,19 +695,22 @@ driver_mode::OnKeyDown(int cKey) {
|
||||
|
||||
if( ( true == DebugModeFlag )
|
||||
|| ( tmp->MoverParameters->Vel <= 5.0 ) ) {
|
||||
// works always in debug mode, or for stopped/slow moving vehicles otherwise
|
||||
if( simulation::Train == nullptr ) {
|
||||
simulation::Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy
|
||||
}
|
||||
if( simulation::Train->Init( tmp ) ) { // przejmujemy sterowanie
|
||||
simulation::Train->Dynamic()->Mechanik->TakeControl( false );
|
||||
}
|
||||
else {
|
||||
SafeDelete( simulation::Train ); // i nie ma czym sterować
|
||||
}
|
||||
if( simulation::Train ) {
|
||||
InOutKey(); // do kabiny
|
||||
}
|
||||
TTrain *train = simulation::Trains.find(tmp->name());
|
||||
if (train == nullptr) {
|
||||
train = new TTrain();
|
||||
if (train->Init(tmp)) {
|
||||
simulation::Trains.insert(train, tmp->name());
|
||||
}
|
||||
else {
|
||||
delete train;
|
||||
train = nullptr;
|
||||
}
|
||||
}
|
||||
if (train != nullptr) {
|
||||
train->Dynamic()->Mechanik->TakeControl( false );
|
||||
simulation::Train = train;
|
||||
InOutKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -780,58 +765,6 @@ driver_mode::OnKeyDown(int cKey) {
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_LEFT_BRACKET:
|
||||
case GLFW_KEY_RIGHT_BRACKET:
|
||||
case GLFW_KEY_TAB: {
|
||||
// consist movement in debug mode
|
||||
if( ( true == DebugModeFlag )
|
||||
&& ( false == Global.shiftState )
|
||||
&& ( true == Global.ctrlState )
|
||||
&& ( simulation::Train != nullptr )
|
||||
&& ( simulation::Train->Dynamic()->Controller == Humandriver ) ) {
|
||||
|
||||
if( DebugModeFlag ) {
|
||||
// przesuwanie składu o 100m
|
||||
auto *vehicle { simulation::Train->Dynamic() };
|
||||
TDynamicObject *d = vehicle;
|
||||
if( cKey == GLFW_KEY_LEFT_BRACKET ) {
|
||||
while( d ) {
|
||||
d->Move( 100.0 * d->DirectionGet() );
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = vehicle->Prev();
|
||||
while( d ) {
|
||||
d->Move( 100.0 * d->DirectionGet() );
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
else if( cKey == GLFW_KEY_RIGHT_BRACKET ) {
|
||||
while( d ) {
|
||||
d->Move( -100.0 * d->DirectionGet() );
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = vehicle->Prev();
|
||||
while( d ) {
|
||||
d->Move( -100.0 * d->DirectionGet() );
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
else if( cKey == GLFW_KEY_TAB ) {
|
||||
while( d ) {
|
||||
d->MoverParameters->V += d->DirectionGet()*2.78;
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = vehicle->Prev();
|
||||
while( d ) {
|
||||
d->MoverParameters->V += d->DirectionGet()*2.78;
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -210,9 +210,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
|
||||
Mousex,
|
||||
Mousey,
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
else {
|
||||
// control picking mode
|
||||
@@ -223,8 +221,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
|
||||
m_slider.value(),
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
|
||||
if( false == m_pickmodepanning ) {
|
||||
@@ -240,9 +237,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
|
||||
viewoffset.x,
|
||||
viewoffset.y,
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
m_cursorposition = cursorposition;
|
||||
}
|
||||
}
|
||||
@@ -315,7 +310,7 @@ drivermouse_input::button( int const Button, int const Action ) {
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
mousecommand = user_command::none;
|
||||
}
|
||||
else {
|
||||
@@ -393,9 +388,9 @@ drivermouse_input::button( int const Button, int const Action ) {
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
if (!pickwaiting) // already depressed
|
||||
m_relay.post( mousecommand, 0, 0, GLFW_RELEASE, 0 );
|
||||
m_relay.post( mousecommand, 0, 0, GLFW_RELEASE, 0 );
|
||||
m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one
|
||||
}
|
||||
else {
|
||||
@@ -431,13 +426,13 @@ drivermouse_input::poll() {
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 );
|
||||
m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 );
|
||||
}
|
||||
if( m_mousecommandright != user_command::none ) {
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 );
|
||||
m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 );
|
||||
}
|
||||
m_updateaccumulator -= updaterate;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,8 @@ editormouse_input::position( double Horizontal, double Vertical ) {
|
||||
viewoffset.x,
|
||||
viewoffset.y,
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
m_cursorposition = cursorposition;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,9 +201,7 @@ gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, g
|
||||
turnx,
|
||||
turny,
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
|
||||
// left stick, either movement or controls, depending on currently active mode
|
||||
@@ -216,7 +214,7 @@ gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, g
|
||||
Leftstick.x,
|
||||
Leftstick.y,
|
||||
GLFW_PRESS,
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -59,7 +59,11 @@ keyboard_input::recall_bindings() {
|
||||
{ "num_7", GLFW_KEY_KP_7 }, { "num_8", GLFW_KEY_KP_8 }, { "num_9", GLFW_KEY_KP_9 }, { "num_+", GLFW_KEY_KP_ADD },
|
||||
{ "num_4", GLFW_KEY_KP_4 }, { "num_5", GLFW_KEY_KP_5 }, { "num_6", GLFW_KEY_KP_6 },
|
||||
{ "num_1", GLFW_KEY_KP_1 }, { "num_2", GLFW_KEY_KP_2 }, { "num_3", GLFW_KEY_KP_3 }, { "num_enter", GLFW_KEY_KP_ENTER },
|
||||
{ "num_0", GLFW_KEY_KP_0 }, { "num_.", GLFW_KEY_KP_DECIMAL }
|
||||
{ "num_0", GLFW_KEY_KP_0 }, { "num_.", GLFW_KEY_KP_DECIMAL },
|
||||
// misc
|
||||
{ "f1", GLFW_KEY_F1 }, { "f2", GLFW_KEY_F2 }, { "f3", GLFW_KEY_F3 }, { "f4", GLFW_KEY_F4 }, { "f5", GLFW_KEY_F5 },
|
||||
{ "f6", GLFW_KEY_F6 }, { "f7", GLFW_KEY_F7 }, { "f8", GLFW_KEY_F8 }, { "f9", GLFW_KEY_F9 }, { "f10", GLFW_KEY_F10 },
|
||||
{ "f11", GLFW_KEY_F11 }, { "f12", GLFW_KEY_F12 }, { "tab", GLFW_KEY_TAB }
|
||||
};
|
||||
|
||||
// NOTE: to simplify things we expect one entry per line, and whole entry in one line
|
||||
@@ -167,7 +171,7 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( lookup->second, 0, 0, Action, 0 );
|
||||
m_relay.post( lookup->second, 0, 0, Action, 0 );
|
||||
m_command = (
|
||||
Action == GLFW_RELEASE ?
|
||||
user_command::none :
|
||||
@@ -247,7 +251,7 @@ keyboard_input::poll() {
|
||||
movementhorizontal.x,
|
||||
movementhorizontal.y,
|
||||
GLFW_PRESS,
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
|
||||
m_movementhorizontal = movementhorizontal;
|
||||
@@ -268,7 +272,7 @@ keyboard_input::poll() {
|
||||
movementvertical,
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
|
||||
m_movementvertical = movementvertical;
|
||||
|
||||
@@ -7,7 +7,7 @@ network::manager::manager()
|
||||
|
||||
void network::manager::create_server()
|
||||
{
|
||||
servers.emplace_back(std::make_shared<tcp_server>(io_context));
|
||||
server = std::make_shared<tcp_server>(io_context);
|
||||
}
|
||||
|
||||
void network::manager::poll()
|
||||
@@ -19,3 +19,13 @@ void network::manager::connect()
|
||||
{
|
||||
client = std::make_shared<tcp_client>(io_context);
|
||||
}
|
||||
|
||||
std::tuple<double, command_queue::commanddatasequence_map> network::manager::get_next_delta()
|
||||
{
|
||||
return client->get_next_delta();
|
||||
}
|
||||
|
||||
void network::manager::push_delta(double delta, command_queue::commanddatasequence_map commands)
|
||||
{
|
||||
server->push_delta(delta, commands);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
#include <asio.hpp>
|
||||
#include <memory>
|
||||
#include "network/network.h"
|
||||
#include "command.h"
|
||||
|
||||
namespace network
|
||||
{
|
||||
class manager
|
||||
{
|
||||
asio::io_context io_context;
|
||||
std::vector<std::shared_ptr<server>> servers;
|
||||
std::shared_ptr<network::server> server;
|
||||
std::shared_ptr<network::client> client;
|
||||
|
||||
public:
|
||||
@@ -17,5 +18,8 @@ namespace network
|
||||
void create_server();
|
||||
void connect();
|
||||
void poll();
|
||||
|
||||
std::tuple<double, command_queue::commanddatasequence_map> get_next_delta();
|
||||
void push_delta(double delta, command_queue::commanddatasequence_map commands);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,16 +3,85 @@
|
||||
|
||||
void network::message::serialize(std::ostream &stream)
|
||||
{
|
||||
sn_utils::ls_uint16(stream, (uint16_t)type);
|
||||
|
||||
}
|
||||
|
||||
network::message network::message::deserialize(std::istream &stream)
|
||||
void network::message::deserialize(std::istream &stream)
|
||||
{
|
||||
type_e type = (type_e)sn_utils::ld_uint16(stream);
|
||||
if ((int)type > (int)message::TYPE_MAX)
|
||||
{
|
||||
type = message::TYPE_MAX;
|
||||
|
||||
}
|
||||
|
||||
void::network::delta_message::serialize(std::ostream &stream)
|
||||
{
|
||||
sn_utils::ls_float64(stream, dt);
|
||||
|
||||
sn_utils::ls_uint32(stream, commands.size());
|
||||
for (auto const &kv : commands) {
|
||||
sn_utils::ls_uint32(stream, kv.first);
|
||||
sn_utils::ls_uint32(stream, kv.second.size());
|
||||
for (command_data const &data : kv.second) {
|
||||
sn_utils::ls_uint32(stream, (uint32_t)data.command);
|
||||
sn_utils::ls_int32(stream, data.action);
|
||||
sn_utils::ls_float64(stream, data.param1);
|
||||
sn_utils::ls_float64(stream, data.param2);
|
||||
sn_utils::ls_float64(stream, data.time_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void network::delta_message::deserialize(std::istream &stream)
|
||||
{
|
||||
dt = sn_utils::ld_float64(stream);
|
||||
|
||||
uint32_t commands_size = sn_utils::ld_uint32(stream);
|
||||
for (uint32_t i = 0; i < commands_size; i++) {
|
||||
uint32_t recipient = sn_utils::ld_uint32(stream);
|
||||
uint32_t sequence_size = sn_utils::ld_uint32(stream);
|
||||
|
||||
command_queue::commanddata_sequence sequence;
|
||||
for (uint32_t i = 0; i < sequence_size; i++) {
|
||||
command_data data;
|
||||
data.command = (user_command)sn_utils::ld_uint32(stream);
|
||||
data.action = sn_utils::ld_int32(stream);
|
||||
data.param1 = sn_utils::ld_float64(stream);
|
||||
data.param2 = sn_utils::ld_float64(stream);
|
||||
data.time_delta = sn_utils::ld_float64(stream);
|
||||
|
||||
sequence.emplace_back(data);
|
||||
}
|
||||
|
||||
commands.emplace(recipient, sequence);
|
||||
}
|
||||
}
|
||||
|
||||
size_t network::delta_message::get_size()
|
||||
{
|
||||
size_t cmd_size = 4;
|
||||
|
||||
for (auto const &kv : commands) {
|
||||
cmd_size += 8;
|
||||
for (command_data const &data : kv.second) {
|
||||
cmd_size += 8 + 3 * 8;
|
||||
}
|
||||
}
|
||||
|
||||
return message({type});
|
||||
return message::get_size() + cmd_size + 8;
|
||||
}
|
||||
|
||||
std::shared_ptr<network::message> network::deserialize_message(std::istream &stream)
|
||||
{
|
||||
message::type_e type = (message::type_e)sn_utils::ld_uint16(stream);
|
||||
|
||||
std::shared_ptr<message> msg;
|
||||
if (type == message::STEP_INFO) {
|
||||
auto m = std::make_shared<delta_message>();
|
||||
m->type = type;
|
||||
m->deserialize(stream);
|
||||
msg = m;
|
||||
}
|
||||
else {
|
||||
msg = std::make_shared<message>(type);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include "network/message.h"
|
||||
#include "command.h"
|
||||
#include <queue>
|
||||
|
||||
namespace network
|
||||
{
|
||||
@@ -16,8 +18,23 @@ namespace network
|
||||
|
||||
type_e type;
|
||||
|
||||
void serialize(std::ostream &stream);
|
||||
|
||||
static message deserialize(std::istream &stream);
|
||||
message(type_e t) : type(t) {}
|
||||
virtual void serialize(std::ostream &stream);
|
||||
virtual void deserialize(std::istream &stream);
|
||||
virtual size_t get_size() { return 2; }
|
||||
};
|
||||
|
||||
struct delta_message : public message
|
||||
{
|
||||
delta_message() : message(STEP_INFO) {}
|
||||
|
||||
double dt;
|
||||
command_queue::commanddatasequence_map commands;
|
||||
|
||||
virtual void serialize(std::ostream &stream) override;
|
||||
virtual void deserialize(std::istream &stream) override;
|
||||
virtual size_t get_size() override;
|
||||
};
|
||||
|
||||
std::shared_ptr<message> deserialize_message(std::istream &stream);
|
||||
}
|
||||
|
||||
@@ -2,52 +2,102 @@
|
||||
#include "network/message.h"
|
||||
#include "Logs.h"
|
||||
#include "sn_utils.h"
|
||||
#include "Timer.h"
|
||||
|
||||
void network::connection::connected()
|
||||
{
|
||||
WriteLog("net: socket connected", logtype::net);
|
||||
|
||||
message hello;
|
||||
hello.type = message::CONNECT_REQUEST;
|
||||
std::shared_ptr<message> hello = std::make_shared<message>(message::CONNECT_REQUEST);
|
||||
send_message(hello);
|
||||
}
|
||||
|
||||
void network::connection::message_received(message &msg)
|
||||
void network::connection::message_received(std::shared_ptr<message> &msg)
|
||||
{
|
||||
if (msg.type == message::TYPE_MAX)
|
||||
if (msg->type == message::TYPE_MAX)
|
||||
{
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.type == message::CONNECT_REQUEST)
|
||||
if (msg->type == message::CONNECT_REQUEST)
|
||||
{
|
||||
message reply({message::CONNECT_ACCEPT});
|
||||
std::shared_ptr<message> reply = std::make_shared<message>(message::CONNECT_ACCEPT);
|
||||
|
||||
WriteLog("client accepted", logtype::net);
|
||||
|
||||
std::string reply_buf;
|
||||
std::ostringstream stream(reply_buf);
|
||||
reply.serialize(stream);
|
||||
send_message(reply);
|
||||
}
|
||||
else if (msg->type == message::CONNECT_ACCEPT)
|
||||
{
|
||||
WriteLog("accept received", logtype::net);
|
||||
}
|
||||
else if (msg->type == message::STEP_INFO)
|
||||
{
|
||||
auto delta = std::dynamic_pointer_cast<delta_message>(msg);
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
delta_queue.push(std::make_pair(now, delta));
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<double, command_queue::commanddatasequence_map> network::connection::get_next_delta()
|
||||
{
|
||||
if (delta_queue.empty()) {
|
||||
return std::tuple<double,
|
||||
command_queue::commanddatasequence_map>(0.0, command_queue::commanddatasequence_map());
|
||||
}
|
||||
|
||||
///auto now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
//double last_frame = std::chrono::duration_cast<std::chrono::seconds>(now - last_time).count();
|
||||
//last_time = now;
|
||||
//accum += last_frame;
|
||||
|
||||
auto entry = delta_queue.front();
|
||||
|
||||
//if (accum > remote_dt) {
|
||||
//accum -= remote_dt;
|
||||
|
||||
delta_queue.pop();
|
||||
return std::make_tuple(entry.second->dt, entry.second->commands);
|
||||
//}
|
||||
//else {
|
||||
//return 0.0;
|
||||
//}
|
||||
}
|
||||
|
||||
void network::connection::data_received(std::string &buffer)
|
||||
{
|
||||
std::istringstream body(buffer);
|
||||
message msg = message::deserialize(body);
|
||||
std::shared_ptr<message> msg = deserialize_message(body);
|
||||
|
||||
message_received(msg);
|
||||
}
|
||||
|
||||
void network::connection::send_message(message &msg)
|
||||
void network::connection::send_message(std::shared_ptr<message> msg)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
sn_utils::ls_uint32(stream, 0x37305545);
|
||||
sn_utils::ls_uint32(stream, 2);
|
||||
msg.serialize(stream);
|
||||
sn_utils::ls_uint32(stream, msg->get_size());
|
||||
sn_utils::ls_uint16(stream, (uint16_t)msg->type);
|
||||
msg->serialize(stream);
|
||||
stream.flush();
|
||||
|
||||
std::shared_ptr<std::string> buf = std::make_shared<std::string>(stream.str());
|
||||
send_data(buf);
|
||||
}
|
||||
|
||||
void network::server::push_delta(double dt, command_queue::commanddatasequence_map commands)
|
||||
{
|
||||
std::shared_ptr<delta_message> msg = std::make_shared<delta_message>();
|
||||
msg->dt = dt;
|
||||
msg->commands = commands;
|
||||
|
||||
for (auto c : clients)
|
||||
c->send_message(msg);
|
||||
}
|
||||
|
||||
std::tuple<double, command_queue::commanddatasequence_map> network::client::get_next_delta()
|
||||
{
|
||||
return conn->get_next_delta();
|
||||
}
|
||||
|
||||
@@ -3,15 +3,23 @@
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <chrono>
|
||||
#include "network/message.h"
|
||||
#include "command.h"
|
||||
|
||||
namespace network
|
||||
{
|
||||
class connection : public std::enable_shared_from_this<connection>
|
||||
{
|
||||
private:
|
||||
void message_received(message &msg);
|
||||
void send_message(message &msg);
|
||||
void message_received(std::shared_ptr<message> &msg);
|
||||
std::queue<
|
||||
std::pair<std::chrono::high_resolution_clock::time_point,
|
||||
std::shared_ptr<delta_message>>> delta_queue;
|
||||
|
||||
//std::chrono::high_resolution_clock::time_point last_time;
|
||||
//double accum = -1.0;
|
||||
|
||||
protected:
|
||||
virtual void disconnect() = 0;
|
||||
@@ -20,16 +28,27 @@ namespace network
|
||||
void data_received(std::string &buffer);
|
||||
|
||||
public:
|
||||
void send_message(std::shared_ptr<message> msg);
|
||||
virtual void connected();
|
||||
|
||||
std::tuple<double, command_queue::commanddatasequence_map> get_next_delta();
|
||||
};
|
||||
|
||||
class server
|
||||
{
|
||||
protected:
|
||||
std::vector<std::shared_ptr<connection>> clients;
|
||||
|
||||
public:
|
||||
void push_delta(double dt, command_queue::commanddatasequence_map commands);
|
||||
};
|
||||
|
||||
class client
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<connection> conn;
|
||||
|
||||
public:
|
||||
std::tuple<double, command_queue::commanddatasequence_map> get_next_delta();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -117,10 +117,11 @@ void network::tcp_server::handle_accept(std::shared_ptr<tcp_conn> conn, const as
|
||||
network::tcp_client::tcp_client(asio::io_context &io_ctx)
|
||||
{
|
||||
conn = std::make_shared<tcp_conn>(io_ctx);
|
||||
auto tcpconn = std::static_pointer_cast<tcp_conn>(conn);
|
||||
|
||||
asio::ip::tcp::endpoint endpoint(
|
||||
asio::ip::address::from_string("127.0.0.1"), 7424);
|
||||
conn->socket().async_connect(endpoint,
|
||||
tcpconn->socket().async_connect(endpoint,
|
||||
std::bind(&tcp_client::handle_accept, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace network
|
||||
class tcp_client : public client
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<tcp_conn> conn;
|
||||
void handle_accept(const asio::error_code &err);
|
||||
|
||||
public:
|
||||
|
||||
@@ -34,6 +34,7 @@ traction_table Traction;
|
||||
powergridsource_table Powergrid;
|
||||
instance_table Instances;
|
||||
vehicle_table Vehicles;
|
||||
train_table Trains;
|
||||
light_array Lights;
|
||||
sound_table Sounds;
|
||||
lua Lua;
|
||||
@@ -64,6 +65,8 @@ state_manager::update( double const Deltatime, int Iterationcount ) {
|
||||
return;
|
||||
}
|
||||
|
||||
process_commands();
|
||||
|
||||
auto const totaltime { Deltatime * Iterationcount };
|
||||
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
|
||||
TAnimModel::AnimUpdate( totaltime ); // wykonanie zakolejkowanych animacji
|
||||
@@ -72,6 +75,26 @@ state_manager::update( double const Deltatime, int Iterationcount ) {
|
||||
simulation::Vehicles.update( Deltatime, Iterationcount );
|
||||
}
|
||||
|
||||
void state_manager::process_commands() {
|
||||
command_data commanddata;
|
||||
while( Commands.pop( commanddata, (uint32_t)command_target::simulation )) {
|
||||
if (commanddata.action == GLFW_RELEASE)
|
||||
continue;
|
||||
|
||||
if (DebugModeFlag) {
|
||||
if (commanddata.command == user_command::timejump) {
|
||||
Time.update(commanddata.param1);
|
||||
}
|
||||
else if (commanddata.command == user_command::timejumplarge) {
|
||||
Time.update(20.0 * 60.0);
|
||||
}
|
||||
else if (commanddata.command == user_command::timejumpsmall) {
|
||||
Time.update(5.0 * 60.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::update_clocks() {
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "lua.h"
|
||||
#include "Event.h"
|
||||
#include "Train.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
@@ -35,6 +36,8 @@ public:
|
||||
private:
|
||||
// members
|
||||
state_serializer m_serializer;
|
||||
|
||||
void process_commands();
|
||||
};
|
||||
|
||||
// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel
|
||||
@@ -48,6 +51,7 @@ extern traction_table Traction;
|
||||
extern powergridsource_table Powergrid;
|
||||
extern instance_table Instances;
|
||||
extern vehicle_table Vehicles;
|
||||
extern train_table Trains;
|
||||
extern light_array Lights;
|
||||
extern sound_table Sounds;
|
||||
extern lua Lua;
|
||||
|
||||
10
uart.cpp
10
uart.cpp
@@ -180,7 +180,7 @@ void uart_input::poll()
|
||||
std::get<3>( entry ) ) ) };
|
||||
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
relay.post( command, 0, 0, action, 0 );
|
||||
relay.post( command, 0, 0, action, 0 );
|
||||
}
|
||||
|
||||
if( true == conf.mainenable ) {
|
||||
@@ -191,7 +191,7 @@ void uart_input::poll()
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
if( true == conf.scndenable ) {
|
||||
// second controller
|
||||
@@ -201,7 +201,7 @@ void uart_input::poll()
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
if( true == conf.trainenable ) {
|
||||
// train brake
|
||||
@@ -212,7 +212,7 @@ void uart_input::poll()
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
if( true == conf.localenable ) {
|
||||
// independent brake
|
||||
@@ -223,7 +223,7 @@ void uart_input::poll()
|
||||
0,
|
||||
GLFW_PRESS,
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
0 );
|
||||
}
|
||||
|
||||
old_packet = buffer;
|
||||
|
||||
Reference in New Issue
Block a user