From 2f08ee890286c4025adc0e9f320bd070f50ff507 Mon Sep 17 00:00:00 2001 From: hilnius Date: Sat, 13 Jul 2013 23:16:40 +0000 Subject: [PATCH] had forgot to add new files git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13209 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- .../controller/network_player_controller.cpp | 366 ++++++++++++++++++ .../controller/network_player_controller.hpp | 48 +++ src/network/client_network_manager.cpp | 1 + src/network/network_world.cpp | 17 + src/network/network_world.hpp | 28 ++ src/network/protocols/start_game_protocol.cpp | 37 ++ src/network/protocols/start_game_protocol.hpp | 29 ++ .../protocols/synchronization_protocol.cpp | 107 +++++ .../protocols/synchronization_protocol.hpp | 28 ++ 9 files changed, 661 insertions(+) create mode 100644 src/karts/controller/network_player_controller.cpp create mode 100644 src/karts/controller/network_player_controller.hpp create mode 100644 src/network/network_world.cpp create mode 100644 src/network/network_world.hpp create mode 100644 src/network/protocols/start_game_protocol.cpp create mode 100644 src/network/protocols/start_game_protocol.hpp create mode 100644 src/network/protocols/synchronization_protocol.cpp create mode 100644 src/network/protocols/synchronization_protocol.hpp diff --git a/src/karts/controller/network_player_controller.cpp b/src/karts/controller/network_player_controller.cpp new file mode 100644 index 000000000..a66e9d318 --- /dev/null +++ b/src/karts/controller/network_player_controller.cpp @@ -0,0 +1,366 @@ +#include "karts/controller/network_player_controller.hpp" + +#include "config/player.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/post_processing.hpp" +#include "input/input_manager.hpp" +#include "items/attachment.hpp" +#include "items/item.hpp" +#include "items/powerup.hpp" +#include "karts/abstract_kart.hpp" +#include "karts/kart_properties.hpp" +#include "karts/skidding.hpp" +#include "karts/rescue_animation.hpp" +#include "modes/world.hpp" +#include "race/history.hpp" +#include "states_screens/race_gui_base.hpp" +#include "utils/constants.hpp" +#include "utils/log.hpp" +#include "utils/translation.hpp" + +NetworkPlayerController::NetworkPlayerController(AbstractKart *kart, + StateManager::ActivePlayer *player) + : Controller(kart) +{ + assert(player != NULL); + m_player = player; + m_player->setKart(kart); + m_penalty_time = 0.0f; + + reset(); +} // NetworkPlayerController + +//----------------------------------------------------------------------------- +/** Destructor for a player kart. + */ +NetworkPlayerController::~NetworkPlayerController() +{ +} // ~NetworkPlayerController + +//----------------------------------------------------------------------------- +/** Resets the player kart for a new or restarted race. + */ +void NetworkPlayerController::reset() +{ + m_steer_val_l = 0; + m_steer_val_r = 0; + m_steer_val = 0; + m_prev_brake = 0; + m_prev_accel = 0; + m_prev_nitro = false; + m_penalty_time = 0; +} // reset + +// ---------------------------------------------------------------------------- +/** Resets the state of control keys. This is used after the in-game menu to + * avoid that any keys pressed at the time the menu is opened are still + * considered to be pressed. + */ +void NetworkPlayerController::resetInputState() +{ + m_steer_val_l = 0; + m_steer_val_r = 0; + m_steer_val = 0; + m_prev_brake = 0; + m_prev_accel = 0; + m_prev_nitro = false; + m_controls->reset(); +} // resetInputState + +// ---------------------------------------------------------------------------- +/** This function interprets a kart action and value, and set the corresponding + * entries in the kart control data structure. This function handles esp. + * cases like 'press left, press right, release right' - in this case after + * releasing right, the steering must switch to left again. Similarly it + * handles 'press left, press right, release left' (in which case still + * right must be selected). Similarly for braking and acceleration. + * \param action The action to be executed. + * \param value If 32768, it indicates a digital value of 'fully set' + * if between 1 and 32767, it indicates an analog value, + * and if it's 0 it indicates that the corresponding button + * was released. + */ +void NetworkPlayerController::action(PlayerAction action, int value) +{ + switch (action) + { + case PA_STEER_LEFT: + m_steer_val_l = value; + if (value) + { + m_steer_val = value; + if(m_controls->m_skid==KartControl::SC_NO_DIRECTION) + m_controls->m_skid = KartControl::SC_LEFT; + } + else + m_steer_val = m_steer_val_r; + + break; + case PA_STEER_RIGHT: + m_steer_val_r = -value; + if (value) + { + m_steer_val = -value; + if(m_controls->m_skid==KartControl::SC_NO_DIRECTION) + m_controls->m_skid = KartControl::SC_RIGHT; + } + else + m_steer_val = m_steer_val_l; + + break; + case PA_ACCEL: + m_prev_accel = value; + if (value && !(m_penalty_time > 0.0f)) + { + m_controls->m_accel = value/32768.0f; + m_controls->m_brake = false; + m_controls->m_nitro = m_prev_nitro; + } + else + { + m_controls->m_accel = 0.0f; + m_controls->m_brake = m_prev_brake; + m_controls->m_nitro = false; + } + break; + case PA_BRAKE: + m_prev_brake = value!=0; + // let's consider below that to be a deadzone + if(value > 32768/2) + { + m_controls->m_brake = true; + m_controls->m_accel = 0.0f; + m_controls->m_nitro = false; + } + else + { + m_controls->m_brake = false; + m_controls->m_accel = m_prev_accel/32768.0f; + // Nitro still depends on whether we're accelerating + m_controls->m_nitro = (m_prev_nitro && m_prev_accel); + } + break; + case PA_NITRO: + // This basically keeps track whether the button still is being pressed + m_prev_nitro = (value != 0); + // Enable nitro only when also accelerating + m_controls->m_nitro = ((value!=0) && m_controls->m_accel); + break; + case PA_RESCUE: + m_controls->m_rescue = (value!=0); + break; + case PA_FIRE: + { + m_controls->m_fire = (value!=0); + break; + } + case PA_LOOK_BACK: + m_controls->m_look_back = (value!=0); + break; + case PA_DRIFT: + if(value==0) + m_controls->m_skid = KartControl::SC_NONE; + else + if(m_steer_val==0) + m_controls->m_skid = KartControl::SC_NO_DIRECTION; + else + m_controls->m_skid = m_steer_val<0 + ? KartControl::SC_RIGHT + : KartControl::SC_LEFT; + break; + case PA_PAUSE_RACE: + if (value != 0) StateManager::get()->escapePressed(); + break; + default: + break; + } + +} // action + +//----------------------------------------------------------------------------- +/** Handles steering for a player kart. + */ +void NetworkPlayerController::steer(float dt, int steer_val) +{ + if(stk_config->m_disable_steer_while_unskid && + m_controls->m_skid==KartControl::SC_NONE && + m_kart->getSkidding()->getVisualSkidRotation()!=0) + { + m_controls->m_steer = 0; + } + + + // Amount the steering is changed for digital devices. + // If the steering is 'back to straight', a different steering + // change speed is used. + const float STEER_CHANGE = ( (steer_val<=0 && m_controls->m_steer<0) || + (steer_val>=0 && m_controls->m_steer>0) ) + ? dt/m_kart->getKartProperties()->getTimeResetSteer() + : dt/m_kart->getTimeFullSteer(fabsf(m_controls->m_steer)); + if (steer_val < 0) + { + // If we got analog values do not cumulate. + if (steer_val > -32767) + m_controls->m_steer = -steer_val/32767.0f; + else + m_controls->m_steer += STEER_CHANGE; + } + else if(steer_val > 0) + { + // If we got analog values do not cumulate. + if (steer_val < 32767) + m_controls->m_steer = -steer_val/32767.0f; + else + m_controls->m_steer -= STEER_CHANGE; + } + else + { // no key is pressed + if(m_controls->m_steer>0.0f) + { + m_controls->m_steer -= STEER_CHANGE; + if(m_controls->m_steer<0.0f) m_controls->m_steer=0.0f; + } + else + { // m_controls->m_steer<=0.0f; + m_controls->m_steer += STEER_CHANGE; + if(m_controls->m_steer>0.0f) m_controls->m_steer=0.0f; + } // if m_controls->m_steer<=0.0f + } // no key is pressed + if(UserConfigParams::m_gamepad_debug) + { + Log::debug("PlayerController", " set to: %f\n", m_controls->m_steer); + } + + m_controls->m_steer = std::min(1.0f, std::max(-1.0f, m_controls->m_steer)); + +} // steer + +//----------------------------------------------------------------------------- +/** Callback when the skidding bonus is triggered. The player controller + * resets the current steering to 0, which makes the kart easier to control. + */ +void NetworkPlayerController::skidBonusTriggered() +{ + m_controls->m_steer = 0; +} // skidBonusTriggered + +//----------------------------------------------------------------------------- +/** Updates the player kart, called once each timestep. + */ +void NetworkPlayerController::update(float dt) +{ + if (UserConfigParams::m_gamepad_debug) + { + // Print a dividing line so that it's easier to see which events + // get received in which order in the one frame. + Log::debug("PlayerController", "irr_driver", "-------------------------------------\n"); + } + + // Don't do steering if it's replay. In position only replay it doesn't + // matter, but if it's physics replay the gradual steering causes + // incorrect results, since the stored values are already adjusted. + if (!history->replayHistory()) + steer(dt, m_steer_val); + + if (World::getWorld()->isStartPhase()) + { + if (m_controls->m_accel || m_controls->m_brake || + m_controls->m_fire || m_controls->m_nitro) + { + // Only give penalty time in SET_PHASE. + // Penalty time check makes sure it doesn't get rendered on every + // update. + if (m_penalty_time == 0.0 && + World::getWorld()->getPhase() == WorldStatus::SET_PHASE) + { + RaceGUIBase* m=World::getWorld()->getRaceGUI(); + if (m) + { + m->addMessage(_("Penalty time!!"), m_kart, 2.0f, + video::SColor(255, 255, 128, 0)); + m->addMessage(_("Don't accelerate before go"), m_kart, 2.0f, + video::SColor(255, 210, 100, 50)); + } + + m_penalty_time = stk_config->m_penalty_time; + } // if penalty_time = 0 + + m_controls->m_brake = false; + m_controls->m_accel = 0.0f; + } // if key pressed + + return; + } // if isStartPhase + + if (m_penalty_time>0.0) + { + m_penalty_time-=dt; + return; + } + + // We can't restrict rescue to fulfil isOnGround() (which would be more like + // MK), since e.g. in the City track it is possible for the kart to end + // up sitting on a brick wall, with all wheels in the air :(( + // Only accept rescue if there is no kart animation is already playing + // (e.g. if an explosion happens, wait till the explosion is over before + // starting any other animation). + if ( m_controls->m_rescue && !m_kart->getKartAnimation() ) + { + new RescueAnimation(m_kart); + m_controls->m_rescue=false; + } +} // update + +//----------------------------------------------------------------------------- +/** Checks if the kart was overtaken, and if so plays a sound +*/ +void NetworkPlayerController::setPosition(int p) +{ + if(m_kart->getPosition()getNumKarts(); i++ ) + { + AbstractKart *kart = world->getKart(i); + if(kart->getPosition() == p + 1) + { + kart->beep(); + break; + } + } + } +} // setPosition + +//----------------------------------------------------------------------------- +/** Called when a kart finishes race. + * /param time Finishing time for this kart. + d*/ +void NetworkPlayerController::finishedRace(float time) +{ + +} // finishedRace + +//----------------------------------------------------------------------------- +/** Called when a kart hits or uses a zipper. + */ +void NetworkPlayerController::handleZipper(bool play_sound) +{ + m_kart->showZipperFire(); +} // handleZipper + +//----------------------------------------------------------------------------- +/** Called when a kart hits an item. + * \param item Item that was collected. + * \param add_info Additional info to be used then handling the item. If + * this is -1 (default), the item type is selected + * randomly. Otherwise it contains the powerup or + * attachment for the kart. This is used in network mode to + * let the server determine the powerup/attachment for + * the clients. + */ +void NetworkPlayerController::collectedItem(const Item &item, int add_info, float old_energy) +{ + +} // collectedItem diff --git a/src/karts/controller/network_player_controller.hpp b/src/karts/controller/network_player_controller.hpp new file mode 100644 index 000000000..fba1f70ef --- /dev/null +++ b/src/karts/controller/network_player_controller.hpp @@ -0,0 +1,48 @@ +#ifndef NETWORK_PLAYER_CONTROLLER_HPP +#define NETWORK_PLAYER_CONTROLLER_HPP + +#include "karts/controller/controller.hpp" + +class AbstractKart; +class Player; + +class NetworkPlayerController : public Controller +{ +protected: + int m_steer_val, m_steer_val_l, m_steer_val_r; + int m_prev_accel; + bool m_prev_brake; + bool m_prev_nitro; + + float m_penalty_time; + + void steer(float, int); +public: + NetworkPlayerController (AbstractKart *kart, + StateManager::ActivePlayer *_player); + virtual ~NetworkPlayerController (); + void update (float); + void action (PlayerAction action, int value); + void handleZipper (bool play_sound); + void collectedItem (const Item &item, int add_info=-1, + float previous_energy=0); + virtual void skidBonusTriggered(); + virtual void setPosition (int p); + virtual bool isPlayerController() const { return false; } + virtual bool isNetworkController() const { return true; } + virtual void reset (); + void resetInputState (); + virtual void finishedRace (float time); + virtual void crashed (const AbstractKart *k) {} + virtual void crashed (const Material *m) {} + // ------------------------------------------------------------------------ + /** Callback whenever a new lap is triggered. Used by the AI + * to trigger a recomputation of the way to use, not used for players. */ + virtual void newLap(int lap) {} + // ------------------------------------------------------------------------ + /** Player will always be able to get a slipstream bonus. */ + virtual bool disableSlipstreamBonus() const { return false; } + +}; + +#endif // NETWORK_PLAYER_CONTROLLER_HPP diff --git a/src/network/client_network_manager.cpp b/src/network/client_network_manager.cpp index 81f33ddce..9b5aab6db 100644 --- a/src/network/client_network_manager.cpp +++ b/src/network/client_network_manager.cpp @@ -24,6 +24,7 @@ #include "network/protocols/get_peer_address.hpp" #include "network/protocols/connect_to_server.hpp" #include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/synchronization_protocol.hpp" #include "utils/log.hpp" diff --git a/src/network/network_world.cpp b/src/network/network_world.cpp new file mode 100644 index 000000000..8dce2af13 --- /dev/null +++ b/src/network/network_world.cpp @@ -0,0 +1,17 @@ +#include "network/network_world.hpp" + +#include "modes/world.hpp" + +NetworkWorld::NetworkWorld() +{ + m_running = false; +} + +NetworkWorld::~NetworkWorld() +{ +} + +void NetworkWorld::update(float dt) +{ + World::getWorld()->updateWorld(dt); +} diff --git a/src/network/network_world.hpp b/src/network/network_world.hpp new file mode 100644 index 000000000..c5f4a3bb2 --- /dev/null +++ b/src/network/network_world.hpp @@ -0,0 +1,28 @@ +#ifndef NETWORK_WORLD_HPP +#define NETWORK_WORLD_HPP + +#include "network/singleton.hpp" + +/*! \brief Manages the world updates during an online game + * This function's update is to be called instead of the normal World update +*/ +class NetworkWorld : public Singleton +{ + friend class Singleton; + public: + void update(float dt); + + void start() { m_running = true; } + void stop() { m_running = false; } + bool isRunning() { return m_running; } + + protected: + bool m_running; + float m_race_time; + + private: + NetworkWorld(); + virtual ~NetworkWorld(); +}; + +#endif // NETWORK_WORLD_HPP diff --git a/src/network/protocols/start_game_protocol.cpp b/src/network/protocols/start_game_protocol.cpp new file mode 100644 index 000000000..3ec343c31 --- /dev/null +++ b/src/network/protocols/start_game_protocol.cpp @@ -0,0 +1,37 @@ +#include "network/protocols/start_game_protocol.hpp" + +#include "network/game_setup.hpp" + +StartGameProtocol::StartGameProtocol(GameSetup* game_setup) : + Protocol(NULL, PROTOCOL_START_GAME) +{ + m_game_setup = game_setup; + std::vector players = m_game_setup->getPlayers(); + for (unsigned int i = 0; i < players.size(); i++) + { + m_player_states.push_back(std::pair(players[i], LOADING)); + } +} + +StartGameProtocol::~StartGameProtocol() +{ +} + +void StartGameProtocol::notifyEvent(Event* event) +{ +} + +void StartGameProtocol::setup() +{ + m_state = LOADING; +} + +void StartGameProtocol::update() +{ + if (m_state == LOADING) + { + } + else if (m_state == READY) + { + } +} diff --git a/src/network/protocols/start_game_protocol.hpp b/src/network/protocols/start_game_protocol.hpp new file mode 100644 index 000000000..02f8a4cc0 --- /dev/null +++ b/src/network/protocols/start_game_protocol.hpp @@ -0,0 +1,29 @@ +#ifndef START_GAME_PROTOCOL_HPP +#define START_GAME_PROTOCOL_HPP + +#include "network/protocol.hpp" + +class GameSetup; +class NetworkPlayerProfile; + +class StartGameProtocol : public Protocol +{ + protected: + enum STATE { LOADING, READY }; + std::vector > m_player_states; + + GameSetup* m_game_setup; + + STATE m_state; + + public: + StartGameProtocol(GameSetup* game_setup); + virtual ~StartGameProtocol(); + + virtual void notifyEvent(Event* event); + virtual void setup(); + virtual void update(); + +}; + +#endif // START_GAME_PROTOCOL_HPP diff --git a/src/network/protocols/synchronization_protocol.cpp b/src/network/protocols/synchronization_protocol.cpp new file mode 100644 index 000000000..56e53abc6 --- /dev/null +++ b/src/network/protocols/synchronization_protocol.cpp @@ -0,0 +1,107 @@ +#include "network/protocols/synchronization_protocol.hpp" + +#include "network/network_manager.hpp" +#include "utils/time.hpp" + +//----------------------------------------------------------------------------- + +SynchronizationProtocol::SynchronizationProtocol(uint32_t* ping, bool* successed) : Protocol(NULL, PROTOCOL_SYNCHRONIZATION) +{ + m_average_ping = ping; + m_successed = successed; + m_pings.resize(NetworkManager::getInstance()->getPeerCount(), std::vector >(0)); + m_pings_count = 0; + m_successed_pings = 0; + m_total_diff = 0; +} + +//----------------------------------------------------------------------------- + +SynchronizationProtocol::~SynchronizationProtocol() +{ +} + +//----------------------------------------------------------------------------- + +void SynchronizationProtocol::notifyEvent(Event* event) +{ + if (event->data.size() < 10) + { + Log::warn("SynchronizationProtocol", "Received a message too short."); + return; + } + uint8_t talk_id = event->data.gui8(0); + uint32_t token = event->data.gui32(1); + uint32_t request = event->data.gui8(5); + uint32_t sequence = event->data.gui32(6); + + std::vector peers = NetworkManager::getInstance()->getPeers(); + + if (m_listener->isServer()) + { + if (talk_id > peers.size()) + { + Log::warn("SynchronizationProtocol", "The ID isn't known."); + return; + } + } + + uint8_t peer_id = (m_listener->isServer() ? talk_id : 0); // on clients, peer index is 0 + if (peers[peer_id]->getClientServerToken() != token) + { + Log::warn("SynchronizationProtocol", "Bad token from peer %d", talk_id); + return; + } + + if (request) + { + NetworkString response; + response.ai8(event->data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence); + m_listener->sendMessage(this, peers[talk_id], response, false); + } + else // response + { + if (sequence < m_pings[peer_id].size()) + { + Log::warn("SynchronizationProtocol", "The sequence isn't known."); + return; + } + m_pings[peer_id][sequence].second = Time::getRealTime(); + m_total_diff += (m_pings[peer_id][sequence].second - m_pings[peer_id][sequence].first); + m_successed_pings++; + *m_average_ping = (int)((m_total_diff/m_successed_pings)*1000.0); + if ( *m_successed == false && m_successed_pings > 5) + { + *m_successed = true; // success after 5 pings (we have good idea of ping) + } + Log::info("SynchronizationProtocol", "Ping is %u", m_average_ping); + } +} + +//----------------------------------------------------------------------------- + +void SynchronizationProtocol::setup() +{ +} + +//----------------------------------------------------------------------------- + +void SynchronizationProtocol::update() +{ + static double timer = Time::getRealTime(); + if (Time::getRealTime() > timer+100 && m_pings_count < 100) // max 100 pings (10 seconds) + { + std::vector peers = NetworkManager::getInstance()->getPeers(); + for (unsigned int i = 0; i < peers.size(); i++) + { + NetworkString ns; + ns.ai8(i).addUInt32(peers[i]->getClientServerToken()).addUInt8(1).addUInt32(m_pings_count); + timer = Time::getRealTime(); + m_pings[i].push_back(std::pair(timer, 0.0)); + m_listener->sendMessage(this, peers[i], ns, false); + } + m_pings_count++; + } +} + +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/synchronization_protocol.hpp b/src/network/protocols/synchronization_protocol.hpp new file mode 100644 index 000000000..b14ec2587 --- /dev/null +++ b/src/network/protocols/synchronization_protocol.hpp @@ -0,0 +1,28 @@ +#ifndef SYNCHRONIZATION_PROTOCOL_HPP +#define SYNCHRONIZATION_PROTOCOL_HPP + +#include "network/protocol.hpp" +#include +#include + +class SynchronizationProtocol : public Protocol +{ + public: + SynchronizationProtocol(uint32_t* ping, bool* successed); + virtual ~SynchronizationProtocol(); + + virtual void notifyEvent(Event* event); + virtual void setup(); + virtual void update(); + + protected: + //!< stores the start time / arrival time of packets for each peer + std::vector > > m_pings; + uint32_t* m_average_ping; + uint32_t m_pings_count; + uint32_t m_successed_pings; + double m_total_diff; + bool* m_successed; +}; + +#endif // SYNCHRONIZATION_PROTOCOL_HPP