diff --git a/source/network/Server.cpp b/source/network/Server.cpp index c384e9ec68..56a8d497d6 100644 --- a/source/network/Server.cpp +++ b/source/network/Server.cpp @@ -67,8 +67,8 @@ CNetServer::CNetServer(CGame *pGame, CGameAttributes *pGameAttribs): m_pGame->GetSimulation()->SetTurnManager(this); // Set an incredibly long turn length for debugging - less command batch spam that way - for (int i=0;i<3;i++) - CTurnManager::SetTurnLength(i, 1000); + for (int i=0; i<3; i++) + CTurnManager::SetTurnLength(i, 150); g_ScriptingHost.SetGlobal("g_NetServer", OBJECT_TO_JSVAL(GetScript())); } diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index e1e443abf9..514e6323b4 100644 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -224,21 +224,21 @@ public: private: CEntity( CEntityTemplate* base, CVector3D position, float orientation, const std::set& actorSelections, const CStrW* building = 0 ); - uint ProcessGotoHelper( CEntityOrder* current, size_t timestep_milli, HEntity& collide ); + uint ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, HEntity& collide, float& timeLeft ); bool ProcessContactAction( CEntityOrder* current, size_t timestep_millis, CEntityOrder::EOrderType transition, SEntityAction* action ); bool ProcessContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, const CStr& animation, CScriptEvent* contactEvent, SEntityAction* action ); - bool ProcessGeneric( CEntityOrder* current, size_t timestep_milli ); - bool ProcessGenericNoPathing( CEntityOrder* current, size_t timestep_milli ); + bool ProcessGeneric( CEntityOrder* current, size_t timestep_millis ); + bool ProcessGenericNoPathing( CEntityOrder* current, size_t timestep_millis ); bool ProcessProduce( CEntityOrder* order ); - bool ProcessGotoNoPathing( CEntityOrder* current, size_t timestep_milli ); - bool ProcessGoto( CEntityOrder* current, size_t timestep_milli ); - bool ProcessGotoWaypoint( CEntityOrder* current, size_t timestep_milli, bool contact ); + bool ProcessGotoNoPathing( CEntityOrder* current, size_t timestep_millis ); + bool ProcessGoto( CEntityOrder* current, size_t timestep_millis ); + bool ProcessGotoWaypoint( CEntityOrder* current, size_t timestep_millis, bool contact ); - bool ProcessPatrol( CEntityOrder* current, size_t timestep_milli ); + bool ProcessPatrol( CEntityOrder* current, size_t timestep_millis ); float ChooseMovementSpeed( float distance ); diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index 4ae496c197..5cdd9265d5 100644 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -85,7 +85,7 @@ float CEntity::ChooseMovementSpeed( float distance ) // Does all the shared processing for line-of-sight gotos -uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, HEntity& collide ) +uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, HEntity& collide, float& timeLeft ) { float timestep=timestep_millis/1000.0f; @@ -101,7 +101,8 @@ uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, // Curve smoothing. // Here there be trig. - float scale = ChooseMovementSpeed( len ) * timestep; + float speed = ChooseMovementSpeed( len ); + float scale = speed * timestep; // Note: Easy optimization: flag somewhere that this unit // is already pointing the way, and don't do this @@ -116,7 +117,7 @@ uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, { if ( m_turningRadius != 0 ) { - float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep; + float maxTurningSpeed = ( speed / m_turningRadius ) * timestep; deltatheta = clamp( deltatheta, -maxTurningSpeed, maxTurningSpeed ); } m_orientation.Y = m_orientation.Y + deltatheta; @@ -152,13 +153,15 @@ uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, UpdateXZOrientation(); if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB ) - ((CBoundingBox*)m_bounds)->SetOrientation( m_ahead ); + ((CBoundingBox*) m_bounds)->SetOrientation( m_ahead ); EGotoSituation rc = NORMAL; if( scale > len ) { + // Reached destination. Calculate how much time we have left for the next order. scale = len; + timeLeft = timestep - (len / speed); rc = REACHED_DESTINATION; } @@ -218,7 +221,6 @@ uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, // No? return( COLLISION_OTHER ); - } } @@ -258,30 +260,46 @@ uint CEntity::ProcessGotoHelper( CEntityOrder* current, size_t timestep_millis, bool CEntity::ProcessGotoNoPathing( CEntityOrder* current, size_t timestep_millis ) { HEntity collide; - switch( ProcessGotoHelper( current, timestep_millis, collide ) ) + float timeLeft; + switch( ProcessGotoHelper( current, timestep_millis, collide, timeLeft ) ) + { + case ALREADY_AT_DESTINATION: { - case ALREADY_AT_DESTINATION: // If on a collision path; decide where to go next. Otherwise, proceed to the next waypoint. if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION ) - { Repath(); - } else - { m_orderQueue.pop_front(); - //entf_clear(ENTF_IS_RUNNING); - //entf_clear(ENTF_SHOULD_RUN); + return( false ); + } + case REACHED_DESTINATION: + { + // Start along the next segment of the path, if one exists + m_orderQueue.pop_front(); + if( !m_orderQueue.empty() ) + { + CEntityOrder* newOrder = &m_orderQueue.front(); + switch( newOrder->m_type ) + { + case CEntityOrder::ORDER_GOTO_NOPATHING: + case CEntityOrder::ORDER_GOTO_COLLISION: + case CEntityOrder::ORDER_GOTO_SMOOTHED: + size_t newTimestep = cpu_i32FromFloat(timeLeft * 1000.0f); + return( ProcessGotoNoPathing( current, newTimestep ) ); + } } return( false ); + } case COLLISION_OVERLAPPING_OBJECTS: + { return( false ); + } case COLLISION_WITH_DESTINATION: + { // We're as close as we can get... m_orderQueue.pop_front(); - //entf_clear(ENTF_IS_RUNNING); - //entf_clear(ENTF_SHOULD_RUN); - return( false ); + } case COLLISION_NEAR_DESTINATION: { // Here's a weird idea: (I hope it works) @@ -340,16 +358,14 @@ bool CEntity::ProcessGotoNoPathing( CEntityOrder* current, size_t timestep_milli return( false ); } case WOULD_LEAVE_MAP: + { // Just stop here, Repath if necessary. m_orderQueue.pop_front(); - //entf_clear(ENTF_IS_RUNNING); - //entf_clear(ENTF_SHOULD_RUN); return( false ); + } case STANCE_DISALLOWS: return( false ); // The stance will have cleared our order queue already - - default: - + default: return( false ); } } @@ -511,11 +527,12 @@ bool CEntity::ProcessContactActionNoPathing( CEntityOrder* current, size_t times current->m_target_location = (CVector2D)target->m_position - delta; - HEntity collide; - switch( ProcessGotoHelper( current, timestep_millis, collide ) ) + HEntity collide; + float timeLeft; + switch( ProcessGotoHelper( current, timestep_millis, collide, timeLeft ) ) { - case ALREADY_AT_DESTINATION: case REACHED_DESTINATION: + case ALREADY_AT_DESTINATION: case COLLISION_WITH_DESTINATION: case WOULD_LEAVE_MAP: case STANCE_DISALLOWS: @@ -530,8 +547,7 @@ bool CEntity::ProcessContactActionNoPathing( CEntityOrder* current, size_t times // Otherwise, continue chasing return( false ); default: - // Path around it. - + // We have a collision. Path around it. CEntityOrder avoidance; avoidance.m_type = CEntityOrder::ORDER_GOTO_COLLISION; CVector2D right; diff --git a/source/simulation/PathfindEngine.cpp b/source/simulation/PathfindEngine.cpp index 1cd7fa4a2c..be38dbaea5 100644 --- a/source/simulation/PathfindEngine.cpp +++ b/source/simulation/PathfindEngine.cpp @@ -38,7 +38,23 @@ void CPathfindEngine::RequestLowLevelPath( HEntity entity, const CVector2D& dest if ( mLowPathfinder.FindPath(source, destination, entity, radius) ) { - std::vector path = mLowPathfinder.GetLastPath(); + std::vector stepwisePath = mLowPathfinder.GetLastPath(); + + // Make the path take as few steps as possible by collapsing steps in the same direction together. + std::vector path; + CVector2D lastDir(0, 0); + for(size_t i=0; i < stepwisePath.size(); i++) + { + if(i >= 2 && stepwisePath[i]-stepwisePath[i-1] == lastDir) + // We're in a colinear range; just update last point + path[path.size()-1] = stepwisePath[i]; + else + path.push_back(stepwisePath[i]); + + if(i >= 1) + lastDir = stepwisePath[i] - stepwisePath[i-1]; + } + if( path.size() > 0 ) { // Push the path onto the front of our order queue in reverse order,