diff --git a/source/main/GameContext.cpp b/source/main/GameContext.cpp index 6ebc29c194..c1faab371b 100644 --- a/source/main/GameContext.cpp +++ b/source/main/GameContext.cpp @@ -1684,5 +1684,11 @@ void GameContext::UpdateTruckInputEvents(float dt) { m_player_actor->getTyrePressure().UpdateInputEvents(dt); } + + m_player_actor->UpdatePropAnimInputEvents(); + for (Actor* linked_actor : m_player_actor->getAllLinkedActors()) + { + linked_actor->UpdatePropAnimInputEvents(); + } } diff --git a/source/main/gfx/GfxActor.cpp b/source/main/gfx/GfxActor.cpp index e7e8436b9b..e2d9ec0511 100644 --- a/source/main/gfx/GfxActor.cpp +++ b/source/main/gfx/GfxActor.cpp @@ -1694,6 +1694,13 @@ void RoR::GfxActor::UpdateSimDataBuffer() m_simbuf.simbuf_commandkey[i].simbuf_cmd_value = m_actor->ar_command_key[i].commandValue; } + // Elements: Prop animation keys + m_simbuf.simbuf_prop_anim_keys.resize(m_actor->m_prop_anim_key_states.size()); + for (size_t i = 0; i < m_actor->m_prop_anim_key_states.size(); ++i) + { + m_simbuf.simbuf_prop_anim_keys[i].simbuf_anim_active = m_actor->m_prop_anim_key_states[i].anim_active; + } + // Elements: Aeroengines m_simbuf.simbuf_aeroengines.resize(m_actor->ar_num_aeroengines); for (int i = 0; i < m_actor->ar_num_aeroengines; ++i) @@ -2754,8 +2761,10 @@ void RoR::GfxActor::CalcPropAnimation(const int flag_state, float& cstate, int& } } -void RoR::GfxActor::UpdatePropAnimations(float dt, bool is_player_connected) +void RoR::GfxActor::UpdatePropAnimations(float dt) { + int prop_anim_key_index = 0; + for (Prop& prop: m_props) { int animnum = 0; @@ -2773,50 +2782,12 @@ void RoR::GfxActor::UpdatePropAnimations(float dt, bool is_player_connected) this->CalcPropAnimation(anim.animFlags, cstate, div, dt, lower_limit, upper_limit, animOpt3); - // key triggered animations - if ((anim.animFlags & ANIM_FLAG_EVENT) && anim.animKey != -1 && is_player_connected) + // key triggered animations - state determined in simulation + if (anim.animFlags & ANIM_FLAG_EVENT) { - // TODO: Keys shouldn't be queried from here, but buffered in sim. loop ~ only_a_ptr, 06/2018 - if (RoR::App::GetInputEngine()->getEventValue(anim.animKey)) - { - // keystatelock is disabled then set cstate - if (anim.animKeyState == -1.0f) - { - // TODO: Keys shouldn't be queried from here, but buffered in sim. loop ~ only_a_ptr, 06/2018 - cstate += RoR::App::GetInputEngine()->getEventValue(anim.animKey); - } - else if (!anim.animKeyState) - { - // a key was pressed and a toggle was done already, so bypass - //toggle now - if (!anim.lastanimKS) - { - anim.lastanimKS = 1.0f; - // use animkey as bool to determine keypress / release state of inputengine - anim.animKeyState = 1.0f; - } - else - { - anim.lastanimKS = 0.0f; - // use animkey as bool to determine keypress / release state of inputengine - anim.animKeyState = 1.0f; - } - } - else - { - // bypas mode, get the last set position and set it - cstate += anim.lastanimKS; - } - } - else - { - // keyevent exists and keylock is enabled but the key isnt pressed right now = get lastanimkeystatus for cstate and reset keypressed bool animkey - if (anim.animKeyState != -1.0f) - { - cstate += anim.lastanimKS; - anim.animKeyState = 0.0f; - } - } + ROR_ASSERT(prop_anim_key_index < (int)m_simbuf.simbuf_prop_anim_keys.size()); + const bool anim_active = m_simbuf.simbuf_prop_anim_keys[prop_anim_key_index++].simbuf_anim_active; + cstate += (float)anim_active; } //propanimation placed here to avoid interference with existing hydros(cstate) and permanent prop animation diff --git a/source/main/gfx/GfxActor.h b/source/main/gfx/GfxActor.h index cc2d1dc7b0..9980121a5e 100644 --- a/source/main/gfx/GfxActor.h +++ b/source/main/gfx/GfxActor.h @@ -105,7 +105,7 @@ class GfxActor void UpdateWingMeshes(); void UpdateBeaconFlare(Prop & prop, float dt, bool is_player_actor); void UpdateProps(float dt, bool is_player_actor); - void UpdatePropAnimations(float dt, bool is_player_connected); + void UpdatePropAnimations(float dt); void UpdateAirbrakes(); void UpdateCParticles(); void UpdateAeroEngines(); diff --git a/source/main/gfx/GfxData.h b/source/main/gfx/GfxData.h index 7432b9d920..5657eae629 100644 --- a/source/main/gfx/GfxData.h +++ b/source/main/gfx/GfxData.h @@ -118,9 +118,6 @@ struct PropAnim PropAnimMode animMode = {}; float animOpt3 = 0; //!< Various purposes float animOpt5 = 0; - int animKey = 0; - int animKeyState = 0; - int lastanimKS = 0; float lower_limit = 0; //!< The lower limit for the animation float upper_limit = 0; //!< The upper limit for the animation }; diff --git a/source/main/gfx/GfxScene.cpp b/source/main/gfx/GfxScene.cpp index 8d2c1806bb..d7377dab61 100644 --- a/source/main/gfx/GfxScene.cpp +++ b/source/main/gfx/GfxScene.cpp @@ -98,11 +98,9 @@ void GfxScene::UpdateScene(float dt_sec) // Var GfxActor* player_gfx_actor = nullptr; - std::set player_connected_gfx_actors; if (m_simbuf.simbuf_player_actor != nullptr) { player_gfx_actor = m_simbuf.simbuf_player_actor->GetGfxActor(); - player_connected_gfx_actors = player_gfx_actor->GetLinkedGfxActors(); } // FOV @@ -211,7 +209,6 @@ void GfxScene::UpdateScene(float dt_sec) // Actors - update misc visuals for (GfxActor* gfx_actor: m_all_gfx_actors) { - bool is_player_connected = (player_connected_gfx_actors.find(gfx_actor) != player_connected_gfx_actors.end()); if (gfx_actor->IsActorLive()) { gfx_actor->UpdateRods(); @@ -220,7 +217,7 @@ void GfxScene::UpdateScene(float dt_sec) gfx_actor->UpdateAirbrakes(); gfx_actor->UpdateCParticles(); gfx_actor->UpdateAeroEngines(); - gfx_actor->UpdatePropAnimations(dt_sec, (gfx_actor == player_gfx_actor) || is_player_connected); + gfx_actor->UpdatePropAnimations(dt_sec); gfx_actor->UpdateRenderdashRTT(); } // Beacon flares must always be updated diff --git a/source/main/gfx/SimBuffers.h b/source/main/gfx/SimBuffers.h index 9f746c5bef..9c8c6894ef 100644 --- a/source/main/gfx/SimBuffers.h +++ b/source/main/gfx/SimBuffers.h @@ -82,6 +82,11 @@ struct CommandKeySB float simbuf_cmd_value; }; +struct PropAnimKeySB +{ + bool simbuf_anim_active; +}; + struct AeroEngineSB { AeroEngineType simbuf_ae_type; @@ -129,6 +134,7 @@ struct ActorSB std::vector simbuf_nodes; std::vector simbuf_screwprops; std::vector simbuf_commandkey; + std::vector simbuf_prop_anim_keys; std::vector simbuf_aeroengines; std::vector simbuf_airbrakes; diff --git a/source/main/network/RoRnet.h b/source/main/network/RoRnet.h index f213ef4719..2e1e8cee1d 100644 --- a/source/main/network/RoRnet.h +++ b/source/main/network/RoRnet.h @@ -32,7 +32,7 @@ namespace RoRnet { #define RORNET_LAN_BROADCAST_PORT 13000 //!< port used to send the broadcast announcement in LAN mode #define RORNET_MAX_USERNAME_LEN 40 //!< port used to send the broadcast announcement in LAN mode -#define RORNET_VERSION "RoRnet_2.43" +#define RORNET_VERSION "RoRnet_2.44" enum MessageType { diff --git a/source/main/physics/Actor.cpp b/source/main/physics/Actor.cpp index bfb02a8e3f..b03443e34d 100644 --- a/source/main/physics/Actor.cpp +++ b/source/main/physics/Actor.cpp @@ -347,7 +347,7 @@ void Actor::pushNetwork(char* data, int size) update.wheel_data.resize(ar_num_wheels * sizeof(float)); // check if the size of the data matches to what we expected - if ((unsigned int)size == (m_net_buffer_size + sizeof(RoRnet::VehicleState))) + if ((unsigned int)size == (m_net_total_buffer_size + sizeof(RoRnet::VehicleState))) { // we walk through the incoming data and separate it a bit char* ptr = data; @@ -367,6 +367,15 @@ void Actor::pushNetwork(char* data, int size) update.wheel_data[i] = wspeed; ptr += sizeof(float); } + + // then process the prop animation keys + for (size_t i = 0; i < m_prop_anim_key_states.size(); i++) + { + // Unpack bit array + char byte = *(ptr + (i / 8)); + char mask = char(1) << (7 - (i % 8)); + m_prop_anim_key_states[i].anim_active = (byte & mask); + } } else { @@ -1897,7 +1906,7 @@ void Actor::sendStreamData() ar_net_last_update_time = ar_net_timer.getMilliseconds(); //look if the packet is too big first - if (m_net_buffer_size + sizeof(RoRnet::VehicleState) > 8192) + if (m_net_total_buffer_size + sizeof(RoRnet::VehicleState) > RORNET_MAX_MESSAGE_LENGTH) { ErrorUtils::ShowError(_L("Actor is too big to be sent over the net."), _L("Network error!")); exit(126); @@ -2006,7 +2015,7 @@ void Actor::sendStreamData() { char* ptr = send_buffer + sizeof(RoRnet::VehicleState); float* send_nodes = (float *)ptr; - packet_len += m_net_buffer_size; + packet_len += m_net_total_buffer_size; // copy data into the buffer int i; @@ -2037,6 +2046,19 @@ void Actor::sendStreamData() { wfbuf[i] = ar_wheels[i].wh_net_rp; } + ptr += ar_num_wheels * sizeof(float); + + // Then the anim key states + for (size_t i = 0; i < m_prop_anim_key_states.size(); i++) + { + if (m_prop_anim_key_states[i].anim_active) + { + // Pack as bit array, starting with most signifficant bit + char& dst_byte = *(ptr + (i / 8)); + char mask = ((char)m_prop_anim_key_states[i].anim_active) << (7 - (i % 8)); + dst_byte |= mask; + } + } } App::GetNetwork()->AddPacket(ar_net_stream_id, MSG2_STREAM_DATA_DISCARDABLE, packet_len, send_buffer); @@ -4606,3 +4628,25 @@ void Actor::WriteDiagnosticDump(std::string const& fileName) outStream->write(text.c_str(), text.length()); Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(rgName); } + +void Actor::UpdatePropAnimInputEvents() +{ + for (PropAnimKeyState& state : m_prop_anim_key_states) + { + bool ev_active = App::GetInputEngine()->getEventValue(state.event_id); + if (state.eventlock_present) + { + // Toggle-mode + if (ev_active && (ev_active != state.event_active_prev)) + { + state.anim_active = !state.anim_active; + } + } + else + { + // Direct-mode + state.anim_active = ev_active; + } + state.event_active_prev = ev_active; + } +} diff --git a/source/main/physics/Actor.h b/source/main/physics/Actor.h index 6da46f0154..800699d1c7 100644 --- a/source/main/physics/Actor.h +++ b/source/main/physics/Actor.h @@ -148,7 +148,7 @@ class Actor : public ZeroedMemoryAllocator void toggleBlinkType(BlinkType blink); BlinkType getBlinkType(); void setBlinkType(BlinkType blink); - std::vector getAllLinkedActors() { return m_linked_actors; }; //!< Returns a list of all connected (hooked) actors + std::vector& getAllLinkedActors() { return m_linked_actors; }; //!< Returns a list of all connected (hooked) actors //! @} /// @name Visual state updates @@ -218,6 +218,7 @@ class Actor : public ZeroedMemoryAllocator Ogre::Real getMinimalCameraRadius(); float GetFFbHydroForces() const { return m_force_sensors.out_hydros_forces; } bool isBeingReset() const { return m_ongoing_reset; }; + void UpdatePropAnimInputEvents(); #ifdef USE_ANGELSCRIPT // we have to add this to be able to use the class as reference inside scripts void addRef() {}; @@ -492,8 +493,6 @@ class Actor : public ZeroedMemoryAllocator Ogre::Vector3 m_mouse_grab_pos; float m_mouse_grab_move_force; float m_spawn_rotation; - Ogre::UTFString m_net_username; - int m_net_color_num; Ogre::Timer m_reset_timer; Ogre::Vector3 m_rotation_request_center; float m_rotation_request; //!< Accumulator @@ -510,10 +509,6 @@ class Actor : public ZeroedMemoryAllocator Differential* m_wheel_diffs[MAX_WHEELS/2];//!< Physics int m_num_wheel_diffs; //!< Physics attr TransferCase* m_transfer_case; //!< Physics - float m_net_node_compression; //!< Sim attr; - int m_net_first_wheel_node; //!< Network attr; Determines data buffer layout - int m_net_node_buf_size; //!< Network attr; buffer size - int m_net_buffer_size; //!< Network attr; buffer size int m_wheel_node_count; //!< Static attr; filled at spawn int m_previous_gear; //!< Sim state; land vehicle shifting float m_handbrake_force; //!< Physics attr; defined in truckfile @@ -536,6 +531,20 @@ class Actor : public ZeroedMemoryAllocator bool m_has_axles_section; //!< Temporary (legacy parsing helper) until central diffs are implemented TyrePressure m_tyre_pressure; std::vector m_description; + std::vector m_prop_anim_key_states; + + /// @name Networking + /// @{ + size_t m_net_node_buf_size; //!< For incoming/outgoing traffic; calculated on spawn + size_t m_net_wheel_buf_size; //!< For incoming/outgoing traffic; calculated on spawn + size_t m_net_propanimkey_buf_size; //!< For incoming/outgoing traffic; calculated on spawn + size_t m_net_total_buffer_size; //!< For incoming/outgoing traffic; calculated on spawn + float m_net_node_compression; //!< For incoming/outgoing traffic; calculated on spawn + int m_net_first_wheel_node; //!< Network attr; Determines data buffer layout; calculated on spawn + + Ogre::UTFString m_net_username; + int m_net_color_num; + /// @} /// @name Light states /// @{ diff --git a/source/main/physics/ActorManager.cpp b/source/main/physics/ActorManager.cpp index 479bbb5c49..edf1dc82ae 100644 --- a/source/main/physics/ActorManager.cpp +++ b/source/main/physics/ActorManager.cpp @@ -286,13 +286,20 @@ Actor* ActorManager::CreateNewActor(ActorSpawnRequest rq, RigDef::DocumentPtr de if (App::mp_state->getEnum() == RoR::MpState::CONNECTED) { // network buffer layout (without RoRnet::VehicleState): - // + // ----------------------------------------------------- + // - 3 floats (x,y,z) for the reference node 0 // - ar_num_nodes - 1 times 3 short ints (compressed position info) - // - ar_num_wheels times a float for the wheel rotation - // actor->m_net_node_buf_size = sizeof(float) * 3 + (actor->m_net_first_wheel_node - 1) * sizeof(short int) * 3; - actor->m_net_buffer_size = actor->m_net_node_buf_size + actor->ar_num_wheels * sizeof(float); + actor->m_net_total_buffer_size += actor->m_net_node_buf_size; + // - ar_num_wheels times a float for the wheel rotation + actor->m_net_wheel_buf_size = actor->ar_num_wheels * sizeof(float); + actor->m_net_total_buffer_size += actor->m_net_wheel_buf_size; + // - bit array (made of ints) for the prop animation key states + actor->m_net_propanimkey_buf_size = + (actor->m_prop_anim_key_states.size() / 8) + // whole chars + (size_t)(actor->m_prop_anim_key_states.size() % 8 != 0); // remainder: 0 or 1 chars + actor->m_net_total_buffer_size += actor->m_net_propanimkey_buf_size; if (rq.asr_origin == ActorSpawnRequest::Origin::NETWORK) { diff --git a/source/main/physics/ActorSpawner.cpp b/source/main/physics/ActorSpawner.cpp index 6c265b4080..79b423a592 100644 --- a/source/main/physics/ActorSpawner.cpp +++ b/source/main/physics/ActorSpawner.cpp @@ -1750,7 +1750,6 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def) for (RigDef::Animation& anim_def: def.animations) { PropAnim anim; - anim.animKeyState = -1.0f; // Orig: hardcoded in {add_animation} /* Arg #1: ratio */ anim.animratio = anim_def.ratio; @@ -1868,9 +1867,7 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def) if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_PERMANENT)) { BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_PERMANENT); } - if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_EVENT)) { - BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_EVENT); - } + /* Motor-indexed sources */ std::list::iterator source_itor = anim_def.motor_sources.begin(); for ( ; source_itor != anim_def.motor_sources.end(); source_itor++) @@ -1967,29 +1964,26 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def) BITMASK_SET_1(anim.animMode, PROP_ANIM_MODE_BOUNCE); anim.animOpt5 = 1.f; } - if (BITMASK_IS_1(anim_def.mode, RigDef::Animation::MODE_EVENT_LOCK)) - { - anim.animKeyState = 0.0f; - anim.lastanimKS = 0.0f; - } - - /* Parameter 'event:' */ - if (! anim_def.event.empty()) + // Parameter 'event:' + if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_EVENT) && + anim_def.event_name != "") { - // we are using keys as source - anim.animFlags |= PROP_ANIM_FLAG_EVENT; - - int event_id = RoR::App::GetInputEngine()->resolveEventName(anim_def.event); + int event_id = RoR::App::GetInputEngine()->resolveEventName(anim_def.event_name); if (event_id == -1) { - AddMessage(Message::TYPE_ERROR, "Unknown animation event: " + anim_def.event); + AddMessage(Message::TYPE_ERROR, "Unknown animation event: " + anim_def.event_name); } else { - anim.animKey = event_id; + PropAnimKeyState state; + state.eventlock_present = BITMASK_IS_1(anim_def.mode, RigDef::Animation::MODE_EVENT_LOCK); + state.event_id = static_cast(event_id); + m_actor->m_prop_anim_key_states.push_back(state); + BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_EVENT); } } + prop.pp_animations.push_back(anim); } m_actor->m_gfx_actor->m_props.push_back(prop); diff --git a/source/main/physics/SimData.h b/source/main/physics/SimData.h index 73783286bd..605a761047 100644 --- a/source/main/physics/SimData.h +++ b/source/main/physics/SimData.h @@ -22,7 +22,10 @@ /// @file /// @author Thomas Fischer /// @date 30th of April 2010 -/// @brief Core data structures for simulation. +/// @brief Core data structures for simulation; Everything affected by by either physics, network or user interaction is here. +/// +/// Note that simulation state and gfx state is separated; For example, +/// light states (on/off) are here while the actual lights (renderer objects) are in 'GfxData.h' :) #pragma once @@ -30,6 +33,7 @@ #include "SimConstants.h" #include "BitFlags.h" #include "CmdKeyInertia.h" +#include "InputEngine.h" #include #include @@ -641,6 +645,15 @@ struct cparticle_t Ogre::ParticleSystem* psys; }; +/// User input state for animated props with 'source:event'. +struct PropAnimKeyState +{ + bool eventlock_present = false; + bool event_active_prev = false; + bool anim_active = false; + events event_id = EV_MODE_LAST; // invalid +}; + /// @} // -------------------------------- diff --git a/source/main/resources/rig_def_fileformat/RigDef_File.h b/source/main/resources/rig_def_fileformat/RigDef_File.h index d6cb6ed56c..eedecfbf3c 100644 --- a/source/main/resources/rig_def_fileformat/RigDef_File.h +++ b/source/main/resources/rig_def_fileformat/RigDef_File.h @@ -535,10 +535,7 @@ struct Animation BitMask_t source = 0; std::list motor_sources; BitMask_t mode = 0; - - // NOTE: MSVC highlights 'event' as keyword: http://msdn.microsoft.com/en-us/library/4b612y2s%28v=vs.100%29.aspx - // But it's ok to use as identifier in this context: http://msdn.microsoft.com/en-us/library/8d7y7wz6%28v=vs.100%29.aspx - Ogre::String event; + Ogre::String event_name; void AddMotorSource(BitMask_t source, unsigned int motor); }; diff --git a/source/main/resources/rig_def_fileformat/RigDef_Parser.cpp b/source/main/resources/rig_def_fileformat/RigDef_Parser.cpp index 1daea747d8..37b05a0580 100644 --- a/source/main/resources/rig_def_fileformat/RigDef_Parser.cpp +++ b/source/main/resources/rig_def_fileformat/RigDef_Parser.cpp @@ -1091,9 +1091,9 @@ void Parser::ParseDirectiveAddAnimation() } else if (entry[0] == "event") { - animation.event = entry[1]; - Ogre::StringUtil::trim(animation.event); - Ogre::StringUtil::toUpperCase(animation.event); + animation.event_name = entry[1]; + Ogre::StringUtil::trim(animation.event_name); + Ogre::StringUtil::toUpperCase(animation.event_name); } else if (entry[0] == "source") { diff --git a/source/main/resources/rig_def_fileformat/RigDef_Serializer.cpp b/source/main/resources/rig_def_fileformat/RigDef_Serializer.cpp index c7f5567dcd..0ff2bab3bd 100644 --- a/source/main/resources/rig_def_fileformat/RigDef_Serializer.cpp +++ b/source/main/resources/rig_def_fileformat/RigDef_Serializer.cpp @@ -591,7 +591,7 @@ void Serializer::ProcessDirectiveAddAnimation(RigDef::Animation & anim) if (BITMASK_IS_1(src_flags, RigDef::Animation::SOURCE_EVENT)) { - m_stream << ", event: " << anim.event; + m_stream << ", event: " << anim.event_name; } }