Finish soccer mode in network

This commit is contained in:
Benau 2018-07-18 16:37:09 +08:00
parent d5168691e1
commit c5cdfcebfe
5 changed files with 243 additions and 40 deletions

View File

@ -328,13 +328,6 @@ void PlayerController::update(int ticks)
{
steer(ticks, m_steer_val);
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{
m_controls->setBrake(false);
m_controls->setAccel(0.0f);
return;
}
if (World::getWorld()->isStartPhase())
{
if (m_controls->getAccel() || m_controls->getBrake()||

View File

@ -32,7 +32,10 @@
#include "karts/controller/local_player_controller.hpp"
#include "karts/controller/network_player_controller.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/rewind_manager.hpp"
#include "network/stk_host.hpp"
#include "physics/physics.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/track.hpp"
@ -146,7 +149,8 @@ void SoccerWorld::reset()
m_blue_kdm.clear();
m_ball_heading = 0.0f;
m_ball_invalid_timer = 0;
m_goal_transforms.clear();
m_goal_transforms.resize(m_karts.size());
if (m_goal_sound != NULL &&
m_goal_sound->getStatus() == SFXBase::SFX_PLAYING)
{
@ -158,9 +162,11 @@ void SoccerWorld::reset()
m_ball_track_sector->reset();
}
m_reset_ball_ticks = -1;
initKartList();
m_ball->reset();
m_bgd.reset();
m_ball->setEnabled(false);
// Make the player kart in profiling mode up
// ie make this kart less likely to affect gaming result
@ -169,6 +175,27 @@ void SoccerWorld::reset()
} // reset
//-----------------------------------------------------------------------------
void SoccerWorld::onGo()
{
m_ball->setEnabled(true);
m_ball->reset();
WorldWithRank::onGo();
} // onGo
//-----------------------------------------------------------------------------
void SoccerWorld::terminateRace()
{
const unsigned int kart_amount = getNumKarts();
for (unsigned int i = 0; i < kart_amount ; i++)
{
// Soccer mode use goal for race result, and each goal time is
// handled by handlePlayerGoalFromServer already
m_karts[i]->finishedRace(0.0f, true/*from_server*/);
} // i<kart_amount
WorldWithRank::terminateRace();
} // terminateRace
//-----------------------------------------------------------------------------
/** Returns the internal identifier for this race.
*/
@ -196,23 +223,29 @@ void SoccerWorld::update(int ticks)
if (getPhase() == World::GOAL_PHASE)
{
if (m_goal_timer == 0)
for (unsigned int i = 0; i < m_karts.size(); i++)
{
// Stop all karts
for (unsigned int i = 0; i < m_karts.size(); i++)
m_karts[i]->setVelocity(btVector3(0, 0, 0));
AbstractKart* kart = m_karts[i];
if (kart->isEliminated())
continue;
kart->getBody()->setLinearVelocity(Vec3(0.0f));
kart->getBody()->setAngularVelocity(Vec3(0.0f));
kart->getBody()->proceedToTransform(m_goal_transforms[i]);
kart->setTrans(m_goal_transforms[i]);
}
m_goal_timer += ticks;
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient())
return;
m_goal_timer += ticks;
if (m_goal_timer > stk_config->time2Ticks(3.0f))
{
setPhase(WorldStatus::RACE_PHASE);
m_goal_timer = 0;
if (!isRaceOver())
{
// Reset all karts
for (unsigned int i = 0; i < m_karts.size(); i++)
moveKartAfterRescue(m_karts[i]);
// Reset all karts and ball
resetKartsToSelfGoals();
if (UserConfigParams::m_arena_ai_stats)
getKart(8)->flyUp();
}
@ -226,11 +259,14 @@ void SoccerWorld::update(int ticks)
//-----------------------------------------------------------------------------
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
if (isRaceOver() || isStartPhase())
if (isRaceOver() || isStartPhase() ||
(NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient()))
return;
setPhase(WorldStatus::GOAL_PHASE);
m_goal_sound->play();
m_ball->setEnabled(false);
if (m_ball_hitter != -1)
{
if (UserConfigParams::m_arena_ai_stats)
@ -256,6 +292,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/);
}
float score_time = 0.0f;
if (first_goal)
{
// Notice: true first_goal means it's blue goal being shoot,
@ -263,28 +300,146 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
m_red_scorers.push_back(sd);
if (race_manager->hasTimeTarget())
{
m_red_score_times.push_back(race_manager->getTimeTarget()
- getTime());
score_time = race_manager->getTimeTarget() - getTime();
}
else
m_red_score_times.push_back(getTime());
score_time = getTime();
m_red_score_times.push_back(score_time);
}
else
{
m_blue_scorers.push_back(sd);
if (race_manager->hasTimeTarget())
{
m_blue_score_times.push_back(race_manager->getTimeTarget()
- getTime());
score_time = race_manager->getTimeTarget() - getTime();
}
else
m_blue_score_times.push_back(getTime());
score_time = getTime();
m_blue_score_times.push_back(score_time);
}
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isServer())
{
NetworkString p(PROTOCOL_GAME_EVENTS);
p.setSynchronous(true);
p.addUInt8(GameEventsProtocol::GE_PLAYER_GOAL)
.addUInt8((uint8_t)sd.m_id).addUInt8(sd.m_correct_goal)
.addUInt8(first_goal).addFloat(score_time)
.addTime(World::getWorld()->getTicksSinceStart() +
stk_config->time2Ticks(3.0f));
STKHost::get()->sendPacketToAllPeers(&p, true);
}
}
m_ball->reset();
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
if (kart->isEliminated())
continue;
kart->getBody()->setLinearVelocity(Vec3(0.0f));
kart->getBody()->setAngularVelocity(Vec3(0.0f));
m_goal_transforms[i] = kart->getBody()->getWorldTransform();
}
} // onCheckGoalTriggered
//-----------------------------------------------------------------------------
void SoccerWorld::handleResetBallFromServer(const NetworkString& ns)
{
int ticks_now = World::getWorld()->getTicksSinceStart();
int ticks_back_to_own_goal = ns.getTime();
if (ticks_now >= ticks_back_to_own_goal)
{
Log::warn("SoccerWorld", "Server ticks %d is too close to client ticks "
"%d when reset player", ticks_back_to_own_goal, ticks_now);
return;
}
RewindManager::get()->getRewindQueue().insertRewindInfo(new
RewindInfoEventFunction(ticks_back_to_own_goal,
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
} // handleResetBallFromServer
//-----------------------------------------------------------------------------
void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
{
ScorerData sd;
sd.m_id = ns.getUInt8();
sd.m_correct_goal = ns.getUInt8() == 1;
bool first_goal = ns.getUInt8() == 1;
float score_time = ns.getFloat();
if (sd.m_correct_goal)
{
m_karts[sd.m_id]->getKartModel()
->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/);
}
else if (!sd.m_correct_goal)
{
m_karts[sd.m_id]->getKartModel()
->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/);
}
if (first_goal)
{
m_red_scorers.push_back(sd);
m_red_score_times.push_back(score_time);
}
else
{
m_blue_scorers.push_back(sd);
m_blue_score_times.push_back(score_time);
}
int ticks_now = World::getWorld()->getTicksSinceStart();
int ticks_back_to_own_goal = ns.getTime();
if (ticks_now >= ticks_back_to_own_goal)
{
Log::warn("SoccerWorld", "Server ticks %d is too close to client ticks "
"%d when goal", ticks_back_to_own_goal, ticks_now);
return;
}
setPhase(WorldStatus::GOAL_PHASE);
m_goal_sound->play();
m_ball->setEnabled(false);
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
if (kart->isEliminated())
continue;
btTransform transform_now = kart->getBody()->getWorldTransform();
kart->getBody()->setLinearVelocity(Vec3(0.0f));
kart->getBody()->setAngularVelocity(Vec3(0.0f));
kart->getBody()->proceedToTransform(transform_now);
kart->setTrans(transform_now);
m_goal_transforms[i] = transform_now;
}
RewindManager::get()->getRewindQueue().insertRewindInfo(new
RewindInfoEventFunction(ticks_back_to_own_goal,
[](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
} // handlePlayerGoalFromServer
//-----------------------------------------------------------------------------
void SoccerWorld::resetKartsToSelfGoals()
{
m_ball->setEnabled(true);
m_ball->reset();
m_bgd.resetCheckGoal(Track::getCurrentTrack());
setPhase(WorldStatus::RACE_PHASE);
for (unsigned i = 0; i < m_karts.size(); i++)
{
AbstractKart* kart = m_karts[i];
if (kart->isEliminated())
continue;
kart->getBody()->setLinearVelocity(Vec3(0.0f));
kart->getBody()->setAngularVelocity(Vec3(0.0f));
unsigned index = m_kart_position_map.at(kart->getWorldKartId());
btTransform t = Track::getCurrentTrack()->getStartTransform(index);
moveKartTo(kart, t);
}
} // resetKartsToSelfGoals
//-----------------------------------------------------------------------------
/** Sets the last kart that hit the ball, to be able to
* identify the scorer later.
@ -299,16 +454,15 @@ void SoccerWorld::setBallHitter(unsigned int kart_id)
*/
bool SoccerWorld::isRaceOver()
{
if(race_manager->hasTimeTarget())
if (race_manager->hasTimeTarget())
{
return m_count_down_reached_zero;
}
// One team scored the target goals ...
else
{
return (getScore(SOCCER_TEAM_BLUE) >= m_goal_target ||
getScore(SOCCER_TEAM_RED) >= m_goal_target);
return (getScore(SOCCER_TEAM_BLUE) >= m_goal_target ||
getScore(SOCCER_TEAM_RED) >= m_goal_target);
}
} // isRaceOver
@ -492,22 +646,46 @@ void SoccerWorld::updateBallPosition(int ticks)
{
m_ball_track_sector
->update(getBallPosition(), true/*ignore_vertical*/);
if (!m_ball_track_sector->isOnRoad() && getPhase() == RACE_PHASE)
if (!m_ball_track_sector->isOnRoad() && getPhase() == RACE_PHASE &&
m_reset_ball_ticks == -1)
{
m_ball_invalid_timer += ticks;
// Reset the ball and karts if out of navmesh after 2 seconds
if (m_ball_invalid_timer >= stk_config->time2Ticks(2.0f))
{
m_ball_invalid_timer = 0;
m_ball->reset();
for (unsigned int i = 0; i < m_karts.size(); i++)
moveKartAfterRescue(m_karts[i]);
if (UserConfigParams::m_arena_ai_stats)
getKart(8)->flyUp();
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isServer())
{
// Reset the ball 2 seconds in the future to make sure it's
// after all clients time
m_reset_ball_ticks =
World::getWorld()->getTicksSinceStart() +
stk_config->time2Ticks(2.0f);
NetworkString p(PROTOCOL_GAME_EVENTS);
p.setSynchronous(true);
p.addUInt8(GameEventsProtocol::GE_RESET_BALL)
.addTime(m_reset_ball_ticks);
STKHost::get()->sendPacketToAllPeers(&p, true);
}
else if (!NetworkConfig::get()->isNetworking())
{
m_ball_invalid_timer = 0;
resetKartsToSelfGoals();
if (UserConfigParams::m_arena_ai_stats)
getKart(8)->flyUp();
}
}
}
else
m_ball_invalid_timer = 0;
if (m_reset_ball_ticks == World::getWorld()->getTicksSinceStart())
{
assert(NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isServer());
resetKartsToSelfGoals();
m_reset_ball_ticks = -1;
}
}
} // updateBallPosition

View File

@ -30,6 +30,7 @@
class AbstractKart;
class Controller;
class NetworkString;
class TrackObject;
class TrackSector;
@ -248,7 +249,11 @@ private:
return (reverse ? m_trans(Vec3(-x, 0, -y)) :
m_trans(Vec3(x, 0, y)));
} // getAimPosition
void resetCheckGoal(const Track* t)
{
m_red_check_goal->reset(*t);
m_blue_check_goal->reset(*t);
}
}; // BallGoalData
std::vector<KartDistanceMap> m_red_kdm;
@ -290,6 +295,7 @@ private:
float m_ball_heading;
std::vector<btTransform> m_goal_transforms;
/** Set the team for the karts */
void initKartList();
/** Function to update the location the ball on the polygon map */
@ -303,16 +309,21 @@ private:
int m_frame_count;
std::vector<int> m_goal_frame;
int m_reset_ball_ticks;
void resetKartsToSelfGoals();
public:
SoccerWorld();
virtual ~SoccerWorld();
virtual void init() OVERRIDE;
virtual void onGo() OVERRIDE;
// clock events
virtual bool isRaceOver() OVERRIDE;
virtual void countdownReachedZero() OVERRIDE;
virtual void terminateRace() OVERRIDE;
// overriding World methods
virtual void reset() OVERRIDE;
@ -394,6 +405,9 @@ public:
// ------------------------------------------------------------------------
void setAITeam();
// ------------------------------------------------------------------------
void handlePlayerGoalFromServer(const NetworkString& ns);
// ------------------------------------------------------------------------
void handleResetBallFromServer(const NetworkString& ns);
}; // SoccerWorld

View File

@ -1,17 +1,18 @@
#include "network/protocols/game_events_protocol.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "modes/soccer_world.hpp"
#include "network/event.hpp"
#include "network/game_setup.hpp"
#include "network/network_config.hpp"
#include "network/rewind_manager.hpp"
#include "network/stk_host.hpp"
#include "network/stk_peer.hpp"
#include <stdint.h>
/** This class handles all 'major' game events. E.g.
* finishing a race etc. The game events manager is notified from the
* finishing a race or goal etc. The game events manager is notified from the
* game code, and it calls the corresponding function in this class.
* The server then notifies all clients. Clients receive the message
* in the synchronous notifyEvent function here, decode the message
@ -43,12 +44,27 @@ bool GameEventsProtocol::notifyEvent(Event* event)
return true;
}
uint8_t type = data.getUInt8();
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
switch (type)
{
case GE_KART_FINISHED_RACE:
kartFinishedRace(data); break;
case GE_PLAYER_DISCONNECT:
eliminatePlayer(data); break;
case GE_RESET_BALL:
{
if (!sw)
throw("No soccer world");
sw->handleResetBallFromServer(data);
break;
}
case GE_PLAYER_GOAL:
{
if (!sw)
throw("No soccer world");
sw->handlePlayerGoalFromServer(data);
break;
}
default:
Log::warn("GameEventsProtocol", "Unkown message type.");
break;

View File

@ -12,7 +12,9 @@ public:
enum GameEventType : uint8_t
{
GE_KART_FINISHED_RACE = 1,
GE_PLAYER_DISCONNECT = 2
GE_PLAYER_DISCONNECT = 2,
GE_RESET_BALL = 3,
GE_PLAYER_GOAL = 4
}; // GameEventType
private:
void eliminatePlayer(const NetworkString &ns);