3232#include " karts/controller/local_player_controller.hpp"
3333#include " karts/controller/network_player_controller.hpp"
3434#include " network/network_config.hpp"
35+ #include " network/network_string.hpp"
36+ #include " network/protocols/game_events_protocol.hpp"
3537#include " network/rewind_manager.hpp"
38+ #include " network/stk_host.hpp"
3639#include " physics/physics.hpp"
3740#include " states_screens/race_gui_base.hpp"
3841#include " tracks/track.hpp"
@@ -146,7 +149,8 @@ void SoccerWorld::reset()
146149 m_blue_kdm.clear ();
147150 m_ball_heading = 0 .0f ;
148151 m_ball_invalid_timer = 0 ;
149-
152+ m_goal_transforms.clear ();
153+ m_goal_transforms.resize (m_karts.size ());
150154 if (m_goal_sound != NULL &&
151155 m_goal_sound->getStatus () == SFXBase::SFX_PLAYING)
152156 {
@@ -158,9 +162,11 @@ void SoccerWorld::reset()
158162 m_ball_track_sector->reset ();
159163 }
160164
165+ m_reset_ball_ticks = -1 ;
161166 initKartList ();
162167 m_ball->reset ();
163168 m_bgd.reset ();
169+ m_ball->setEnabled (false );
164170
165171 // Make the player kart in profiling mode up
166172 // ie make this kart less likely to affect gaming result
@@ -169,6 +175,27 @@ void SoccerWorld::reset()
169175
170176} // reset
171177
178+ // -----------------------------------------------------------------------------
179+ void SoccerWorld::onGo ()
180+ {
181+ m_ball->setEnabled (true );
182+ m_ball->reset ();
183+ WorldWithRank::onGo ();
184+ } // onGo
185+
186+ // -----------------------------------------------------------------------------
187+ void SoccerWorld::terminateRace ()
188+ {
189+ const unsigned int kart_amount = getNumKarts ();
190+ for (unsigned int i = 0 ; i < kart_amount ; i++)
191+ {
192+ // Soccer mode use goal for race result, and each goal time is
193+ // handled by handlePlayerGoalFromServer already
194+ m_karts[i]->finishedRace (0 .0f , true /* from_server*/ );
195+ } // i<kart_amount
196+ WorldWithRank::terminateRace ();
197+ } // terminateRace
198+
172199// -----------------------------------------------------------------------------
173200/* * Returns the internal identifier for this race.
174201 */
@@ -196,23 +223,29 @@ void SoccerWorld::update(int ticks)
196223
197224 if (getPhase () == World::GOAL_PHASE)
198225 {
199- if (m_goal_timer == 0 )
226+ for ( unsigned int i = 0 ; i < m_karts. size (); i++ )
200227 {
201- // Stop all karts
202- for (unsigned int i = 0 ; i < m_karts.size (); i++)
203- m_karts[i]->setVelocity (btVector3 (0 , 0 , 0 ));
228+ AbstractKart* kart = m_karts[i];
229+ if (kart->isEliminated ())
230+ continue ;
231+ kart->getBody ()->setLinearVelocity (Vec3 (0 .0f ));
232+ kart->getBody ()->setAngularVelocity (Vec3 (0 .0f ));
233+ kart->getBody ()->proceedToTransform (m_goal_transforms[i]);
234+ kart->setTrans (m_goal_transforms[i]);
204235 }
205- m_goal_timer += ticks;
206236
237+ if (NetworkConfig::get ()->isNetworking () &&
238+ NetworkConfig::get ()->isClient ())
239+ return ;
240+
241+ m_goal_timer += ticks;
207242 if (m_goal_timer > stk_config->time2Ticks (3 .0f ))
208243 {
209- setPhase (WorldStatus::RACE_PHASE);
210244 m_goal_timer = 0 ;
211245 if (!isRaceOver ())
212246 {
213- // Reset all karts
214- for (unsigned int i = 0 ; i < m_karts.size (); i++)
215- moveKartAfterRescue (m_karts[i]);
247+ // Reset all karts and ball
248+ resetKartsToSelfGoals ();
216249 if (UserConfigParams::m_arena_ai_stats)
217250 getKart (8 )->flyUp ();
218251 }
@@ -226,11 +259,14 @@ void SoccerWorld::update(int ticks)
226259// -----------------------------------------------------------------------------
227260void SoccerWorld::onCheckGoalTriggered (bool first_goal)
228261{
229- if (isRaceOver () || isStartPhase ())
262+ if (isRaceOver () || isStartPhase () ||
263+ (NetworkConfig::get ()->isNetworking () &&
264+ NetworkConfig::get ()->isClient ()))
230265 return ;
231266
232267 setPhase (WorldStatus::GOAL_PHASE);
233268 m_goal_sound->play ();
269+ m_ball->setEnabled (false );
234270 if (m_ball_hitter != -1 )
235271 {
236272 if (UserConfigParams::m_arena_ai_stats)
@@ -256,35 +292,154 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
256292 ->setAnimation (KartModel::AF_LOSE_START, true /* play_non_loop*/ );
257293 }
258294
295+ float score_time = 0 .0f ;
259296 if (first_goal)
260297 {
261298 // Notice: true first_goal means it's blue goal being shoot,
262299 // so red team can score
263300 m_red_scorers.push_back (sd);
264301 if (race_manager->hasTimeTarget ())
265302 {
266- m_red_score_times.push_back (race_manager->getTimeTarget ()
267- - getTime ());
303+ score_time = race_manager->getTimeTarget () - getTime ();
268304 }
269305 else
270- m_red_score_times.push_back (getTime ());
306+ score_time = getTime ();
307+ m_red_score_times.push_back (score_time);
271308 }
272309 else
273310 {
274311 m_blue_scorers.push_back (sd);
275312 if (race_manager->hasTimeTarget ())
276313 {
277- m_blue_score_times.push_back (race_manager->getTimeTarget ()
278- - getTime ());
314+ score_time = race_manager->getTimeTarget () - getTime ();
279315 }
280316 else
281- m_blue_score_times.push_back (getTime ());
317+ score_time = getTime ();
318+ m_blue_score_times.push_back (score_time);
319+ }
320+ if (NetworkConfig::get ()->isNetworking () &&
321+ NetworkConfig::get ()->isServer ())
322+ {
323+ NetworkString p (PROTOCOL_GAME_EVENTS);
324+ p.setSynchronous (true );
325+ p.addUInt8 (GameEventsProtocol::GE_PLAYER_GOAL)
326+ .addUInt8 ((uint8_t )sd.m_id ).addUInt8 (sd.m_correct_goal )
327+ .addUInt8 (first_goal).addFloat (score_time)
328+ .addTime (World::getWorld ()->getTicksSinceStart () +
329+ stk_config->time2Ticks (3 .0f ));
330+ STKHost::get ()->sendPacketToAllPeers (&p, true );
282331 }
283332 }
284- m_ball->reset ();
333+ for (unsigned i = 0 ; i < m_karts.size (); i++)
334+ {
335+ AbstractKart* kart = m_karts[i];
336+ if (kart->isEliminated ())
337+ continue ;
338+ kart->getBody ()->setLinearVelocity (Vec3 (0 .0f ));
339+ kart->getBody ()->setAngularVelocity (Vec3 (0 .0f ));
340+ m_goal_transforms[i] = kart->getBody ()->getWorldTransform ();
341+ }
285342
286343} // onCheckGoalTriggered
287344
345+ // -----------------------------------------------------------------------------
346+ void SoccerWorld::handleResetBallFromServer (const NetworkString& ns)
347+ {
348+ int ticks_now = World::getWorld ()->getTicksSinceStart ();
349+ int ticks_back_to_own_goal = ns.getTime ();
350+ if (ticks_now >= ticks_back_to_own_goal)
351+ {
352+ Log::warn (" SoccerWorld" , " Server ticks %d is too close to client ticks "
353+ " %d when reset player" , ticks_back_to_own_goal, ticks_now);
354+ return ;
355+ }
356+ RewindManager::get ()->getRewindQueue ().insertRewindInfo (new
357+ RewindInfoEventFunction (ticks_back_to_own_goal,
358+ [](){}, std::bind (&SoccerWorld::resetKartsToSelfGoals, this )));
359+
360+ } // handleResetBallFromServer
361+
362+ // -----------------------------------------------------------------------------
363+ void SoccerWorld::handlePlayerGoalFromServer (const NetworkString& ns)
364+ {
365+ ScorerData sd;
366+ sd.m_id = ns.getUInt8 ();
367+ sd.m_correct_goal = ns.getUInt8 () == 1 ;
368+ bool first_goal = ns.getUInt8 () == 1 ;
369+ float score_time = ns.getFloat ();
370+ if (sd.m_correct_goal )
371+ {
372+ m_karts[sd.m_id ]->getKartModel ()
373+ ->setAnimation (KartModel::AF_WIN_START, true /* play_non_loop*/ );
374+ }
375+ else if (!sd.m_correct_goal )
376+ {
377+ m_karts[sd.m_id ]->getKartModel ()
378+ ->setAnimation (KartModel::AF_LOSE_START, true /* play_non_loop*/ );
379+ }
380+
381+ if (first_goal)
382+ {
383+ m_red_scorers.push_back (sd);
384+ m_red_score_times.push_back (score_time);
385+ }
386+ else
387+ {
388+ m_blue_scorers.push_back (sd);
389+ m_blue_score_times.push_back (score_time);
390+ }
391+ int ticks_now = World::getWorld ()->getTicksSinceStart ();
392+ int ticks_back_to_own_goal = ns.getTime ();
393+
394+ if (ticks_now >= ticks_back_to_own_goal)
395+ {
396+ Log::warn (" SoccerWorld" , " Server ticks %d is too close to client ticks "
397+ " %d when goal" , ticks_back_to_own_goal, ticks_now);
398+ return ;
399+ }
400+
401+ setPhase (WorldStatus::GOAL_PHASE);
402+ m_goal_sound->play ();
403+ m_ball->setEnabled (false );
404+ for (unsigned i = 0 ; i < m_karts.size (); i++)
405+ {
406+ AbstractKart* kart = m_karts[i];
407+ if (kart->isEliminated ())
408+ continue ;
409+ btTransform transform_now = kart->getBody ()->getWorldTransform ();
410+ kart->getBody ()->setLinearVelocity (Vec3 (0 .0f ));
411+ kart->getBody ()->setAngularVelocity (Vec3 (0 .0f ));
412+ kart->getBody ()->proceedToTransform (transform_now);
413+ kart->setTrans (transform_now);
414+ m_goal_transforms[i] = transform_now;
415+ }
416+ RewindManager::get ()->getRewindQueue ().insertRewindInfo (new
417+ RewindInfoEventFunction (ticks_back_to_own_goal,
418+ [](){}, std::bind (&SoccerWorld::resetKartsToSelfGoals, this )));
419+
420+ } // handlePlayerGoalFromServer
421+
422+ // -----------------------------------------------------------------------------
423+ void SoccerWorld::resetKartsToSelfGoals ()
424+ {
425+ m_ball->setEnabled (true );
426+ m_ball->reset ();
427+ m_bgd.resetCheckGoal (Track::getCurrentTrack ());
428+ setPhase (WorldStatus::RACE_PHASE);
429+ for (unsigned i = 0 ; i < m_karts.size (); i++)
430+ {
431+ AbstractKart* kart = m_karts[i];
432+ if (kart->isEliminated ())
433+ continue ;
434+
435+ kart->getBody ()->setLinearVelocity (Vec3 (0 .0f ));
436+ kart->getBody ()->setAngularVelocity (Vec3 (0 .0f ));
437+ unsigned index = m_kart_position_map.at (kart->getWorldKartId ());
438+ btTransform t = Track::getCurrentTrack ()->getStartTransform (index);
439+ moveKartTo (kart, t);
440+ }
441+ } // resetKartsToSelfGoals
442+
288443// -----------------------------------------------------------------------------
289444/* * Sets the last kart that hit the ball, to be able to
290445 * identify the scorer later.
@@ -299,16 +454,15 @@ void SoccerWorld::setBallHitter(unsigned int kart_id)
299454 */
300455bool SoccerWorld::isRaceOver ()
301456{
302-
303- if (race_manager->hasTimeTarget ())
457+ if (race_manager->hasTimeTarget ())
304458 {
305459 return m_count_down_reached_zero;
306460 }
307461 // One team scored the target goals ...
308462 else
309463 {
310- return (getScore (SOCCER_TEAM_BLUE) >= m_goal_target ||
311- getScore (SOCCER_TEAM_RED) >= m_goal_target);
464+ return (getScore (SOCCER_TEAM_BLUE) >= m_goal_target ||
465+ getScore (SOCCER_TEAM_RED) >= m_goal_target);
312466 }
313467
314468} // isRaceOver
@@ -492,22 +646,46 @@ void SoccerWorld::updateBallPosition(int ticks)
492646 {
493647 m_ball_track_sector
494648 ->update (getBallPosition (), true /* ignore_vertical*/ );
495- if (!m_ball_track_sector->isOnRoad () && getPhase () == RACE_PHASE)
649+ if (!m_ball_track_sector->isOnRoad () && getPhase () == RACE_PHASE &&
650+ m_reset_ball_ticks == -1 )
496651 {
497652 m_ball_invalid_timer += ticks;
498653 // Reset the ball and karts if out of navmesh after 2 seconds
499654 if (m_ball_invalid_timer >= stk_config->time2Ticks (2 .0f ))
500655 {
501- m_ball_invalid_timer = 0 ;
502- m_ball->reset ();
503- for (unsigned int i = 0 ; i < m_karts.size (); i++)
504- moveKartAfterRescue (m_karts[i]);
505- if (UserConfigParams::m_arena_ai_stats)
506- getKart (8 )->flyUp ();
656+ if (NetworkConfig::get ()->isNetworking () &&
657+ NetworkConfig::get ()->isServer ())
658+ {
659+ // Reset the ball 2 seconds in the future to make sure it's
660+ // after all clients time
661+ m_reset_ball_ticks =
662+ World::getWorld ()->getTicksSinceStart () +
663+ stk_config->time2Ticks (2 .0f );
664+
665+ NetworkString p (PROTOCOL_GAME_EVENTS);
666+ p.setSynchronous (true );
667+ p.addUInt8 (GameEventsProtocol::GE_RESET_BALL)
668+ .addTime (m_reset_ball_ticks);
669+ STKHost::get ()->sendPacketToAllPeers (&p, true );
670+ }
671+ else if (!NetworkConfig::get ()->isNetworking ())
672+ {
673+ m_ball_invalid_timer = 0 ;
674+ resetKartsToSelfGoals ();
675+ if (UserConfigParams::m_arena_ai_stats)
676+ getKart (8 )->flyUp ();
677+ }
507678 }
508679 }
509680 else
510681 m_ball_invalid_timer = 0 ;
682+ if (m_reset_ball_ticks == World::getWorld ()->getTicksSinceStart ())
683+ {
684+ assert (NetworkConfig::get ()->isNetworking () &&
685+ NetworkConfig::get ()->isServer ());
686+ resetKartsToSelfGoals ();
687+ m_reset_ball_ticks = -1 ;
688+ }
511689 }
512690
513691} // updateBallPosition
0 commit comments