Replaced kart update message with race_state (which gets send

from the server to the clients). Started to implement synchronising
of herrings and projectiles.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2242 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk
2008-09-07 14:42:37 +00:00
parent de72e53199
commit ecac04b1bc
29 changed files with 468 additions and 214 deletions

View File

@@ -17,6 +17,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define _WINSOCKAPI_
#include <plib/ssg.h>
#include "attachment.hpp"
@@ -28,6 +29,8 @@
#include "sound_manager.hpp"
#include "stk_config.hpp"
#include "user_config.hpp"
#include "network/race_state.hpp"
#include "network/network_manager.hpp"
Attachment::Attachment(Kart* _kart)
{
@@ -62,17 +65,18 @@ void Attachment::set(attachmentType _type, float time, Kart *current_kart)
} // set
// -----------------------------------------------------------------------------
void Attachment::hitGreenHerring()
void Attachment::hitGreenHerring(const Herring &herring, int random_attachment)
{
if(user_config->m_profile) return;
int random_attachment;
float leftover_time = 0.0f;
switch(getType()) // If there already is an attachment, make it worse :)
{
case ATTACH_BOMB: projectile_manager->newExplosion(m_kart->getXYZ());
m_kart->handleExplosion(m_kart->getXYZ(), /*direct_hit*/ true);
clear();
random_attachment = m_random.get(3);
if(random_attachment==-1)
random_attachment = m_random.get(3);
break;
case ATTACH_ANVIL :// if the kart already has an anvil, attach a new anvil,
// and increase the overall time
@@ -83,9 +87,19 @@ void Attachment::hitGreenHerring()
random_attachment = 2; // anvil
leftover_time = m_time_left;
break;
default: random_attachment = m_random.get(3);
default: if(random_attachment==-1)
random_attachment = m_random.get(3);
} // switch
// Save the information about the attachment in the race state
// so that the clients can be updated.
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
race_state->herringCollected(m_kart->getWorldKartId(),
herring.getHerringId(),
random_attachment);
}
switch (random_attachment)
{
case 0: set( ATTACH_PARACHUTE, stk_config->m_parachute_time+leftover_time);

View File

@@ -21,6 +21,7 @@
#define HEADER_ATTACHMENT_H
#include "stk_config.hpp"
#include "herring.hpp"
#include "utils/random_generator.hpp"
class Kart;
@@ -74,7 +75,13 @@ public:
return m_type==ATTACH_ANVIL
?stk_config->m_anvil_speed_factor:1.0f;
}
void hitGreenHerring();
/** Randomly selects the new attachment. For a server process, the
* attachment can be passed into this function.
\param herring The herring that was collected.
\param random_attachment Optional: only used on the clients, it
specifies the new attachment to use
*/
void hitGreenHerring(const Herring &herring, int random_attachment=-1);
void update (float dt);
void moveBombFromTo(Kart *from, Kart *to);
};

View File

@@ -17,6 +17,8 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network/network_manager.hpp"
#include "network/race_state.hpp"
#include "collectable.hpp"
#include "user_config.hpp"
#include "race_manager.hpp"
@@ -143,8 +145,25 @@ void Collectable::use()
} // use
//-----------------------------------------------------------------------------
void Collectable::hitRedHerring(int n)
void Collectable::hitRedHerring(int n, const Herring &herring, int add_info)
{
// On the client this is called when update information is received
// from the server:
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
if(m_type==COLLECT_NOTHING)
{
m_type = (CollectableType)add_info;
m_number = n;
}
else if((CollectableType)add_info==m_type)
{
m_number+=n;
if(m_number > MAX_COLLECTABLES) m_number = MAX_COLLECTABLES;
}
// Ignore new collectable if it is different from the current one
return;
}
//The probabilities of getting the anvil or the parachute increase
//depending on how bad the owner's position is. For the first
//driver the posibility is none, for the last player is 15 %.
@@ -192,6 +211,15 @@ void Collectable::hitRedHerring(int n)
simpleCounter++;
newC = (CollectableType)(simpleCounter%(COLLECT_MAX - 1 - 2) + 1);
}
// Save the information about the collectable in the race state
// so that the clients can be updated.
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
race_state->herringCollected(m_owner->getWorldKartId(),
herring.getHerringId(),
newC);
}
if(m_type==COLLECT_NOTHING)
{
m_type=newC;

View File

@@ -26,6 +26,7 @@
#include "utils/random_generator.hpp"
class Kart;
class Herring;
class Collectable
{
@@ -42,7 +43,7 @@ public:
void reset ();
int getNum () const {return m_number;}
CollectableType getType () const {return m_type; }
void hitRedHerring(int n);
void hitRedHerring(int n, const Herring &herring, int newC=-1);
Material* getIcon ();
void use ();
};

View File

@@ -49,7 +49,6 @@ Flyable::Flyable(Kart *kart, CollectableType type, float mass) : Moveable(false)
m_owner = kart;
m_has_hit_something = false;
m_last_radar_beep = -1;
m_exploded = false;
m_shape = NULL;
m_mass = mass;
@@ -185,6 +184,14 @@ void Flyable::update (float dt)
Moveable::update(dt);
} // update
// -----------------------------------------------------------------------------
void Flyable::updateFromServer(const FlyableInfo &f)
{
setXYZ(f.m_xyz);
setRotation(f.m_rotation);
m_exploded = f.m_exploded;
} // updateFromServer
// -----------------------------------------------------------------------------
void Flyable::explode(Kart *kart_hit, MovingPhysics* moving_physics)
{

View File

@@ -27,9 +27,23 @@
class Flyable : public Moveable, public TerrainInfo
{
sgCoord m_last_pos;
public:
/** FlyableInfo stores information for updating flyables on the clients.
* It contains only the coordinates, rotation, and explosion state. */
// -----------------------------------------------------------------------
class FlyableInfo
{
public:
Vec3 m_xyz;
btQuaternion m_rotation;
bool m_exploded;
FlyableInfo(const Vec3& xyz, const btQuaternion &rotation, bool exploded) :
m_xyz(xyz), m_rotation(rotation), m_exploded(exploded)
{};
FlyableInfo() {};
};
private:
bool m_has_hit_something;
int m_last_radar_beep;
bool m_exploded;
protected:
@@ -72,6 +86,7 @@ public:
static void init (const lisp::Lisp* lisp, ssgEntity *model,
CollectableType type);
virtual void update (float);
void updateFromServer(const FlyableInfo &f);
virtual void hitTrack () {};
void explode (Kart* kart, MovingPhysics* moving_physics=NULL);

View File

@@ -24,9 +24,11 @@
#include "scene.hpp"
#include "coord.hpp"
Herring::Herring(herringType type, const Vec3& xyz, ssgEntity* model)
Herring::Herring(herringType type, const Vec3& xyz, ssgEntity* model,
unsigned int herring_id)
: m_coord(xyz, Vec3(0, 0, 0))
{
m_herring_id = herring_id;
m_type = type;
m_eaten = false;
m_time_till_return = 0.0f; // not strictly necessary, see isEaten()

View File

@@ -30,7 +30,7 @@ class ssgTransform;
class ssgEntity;
// HE_RED must be the first, HE_SILVER the last entry. See HerringManager
enum herringType { HE_RED, HE_GREEN, HE_GOLD, HE_SILVER };
enum herringType { HE_RED, HE_GREEN, HE_GOLD, HE_SILVER, HE_NONE };
// -----------------------------------------------------------------------------
class Herring
@@ -42,10 +42,12 @@ private:
Coord m_coord; // Original coordinates, used mainly when
// eaten herrings reappear.
ssgTransform* m_root; // The actual root of the herring
unsigned int m_herring_id; // index in herring_manager field
public:
Herring (herringType type, const Vec3& xyz, ssgEntity* model);
Herring (herringType type, const Vec3& xyz, ssgEntity* model,
unsigned int herring_id);
~Herring ();
unsigned int getHerringId() const {return m_herring_id; }
void update (float delta);
void isEaten ();
int hitKart (Kart* kart );

View File

@@ -20,6 +20,8 @@
#include <stdexcept>
#include <string>
#include <sstream>
#include "network/network_manager.hpp"
#include "user_config.hpp"
#include "herring_manager.hpp"
#include "file_manager.hpp"
@@ -29,6 +31,7 @@
#include "kart.hpp"
#include "string_utils.hpp"
#include "translation.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
@@ -197,22 +200,36 @@ void HerringManager::setDefaultHerringStyle()
//-----------------------------------------------------------------------------
Herring* HerringManager::newHerring(herringType type, const Vec3& xyz)
{
Herring* h = new Herring(type, xyz, m_herring_model[type]);
Herring* h = new Herring(type, xyz, m_herring_model[type], m_all_herrings.size());
m_all_herrings.push_back(h);
return h;
} // newHerring
//-----------------------------------------------------------------------------
/** Set a herring as eaten.
* This function is called on the server when a herring is eaten, or on the
* client upon receiving information about eaten herrings. */
void HerringManager::eatenHerring(int herring_id, Kart *kart,
int add_info)
{
Herring *herring=m_all_herrings[herring_id];
herring->isEaten();
kart->collectedHerring(*herring, add_info);
} // eatenHerring
//-----------------------------------------------------------------------------
void HerringManager::hitHerring(Kart* kart)
{
// Only do this on the server
if(network_manager->getMode()!=NetworkManager::NW_SERVER) return;
for(AllHerringType::iterator i =m_all_herrings.begin();
i!=m_all_herrings.end(); i++)
{
if((*i)->wasEaten()) continue;
if((*i)->hitKart(kart))
{
(*i)->isEaten();
kart->collectedHerring(*i);
eatenHerring(i-m_all_herrings.begin(), kart);
} // if hit
} // for m_all_herrings
} // hitHerring

View File

@@ -64,6 +64,8 @@ public:
void reset ();
void removeTextures ();
void setUserFilename (char *s) {m_user_filename=s;}
void eatenHerring (int herring_id, Kart *kart,
int add_info=-1);
ssgEntity* getHerringModel (herringType type)
{return m_herring_model[type];}
};

View File

@@ -1090,10 +1090,6 @@
RelativePath="..\..\network\kart_control_message.cpp"
>
</File>
<File
RelativePath="..\..\network\kart_packet.cpp"
>
</File>
<File
RelativePath="..\..\network\kart_update_message.cpp"
>
@@ -1114,6 +1110,10 @@
RelativePath="..\..\network\race_info_message.cpp"
>
</File>
<File
RelativePath="..\..\network\race_state.cpp"
>
</File>
</Filter>
<Filter
Name="utils"
@@ -1648,6 +1648,10 @@
RelativePath="..\..\network\race_start_message.hpp"
>
</File>
<File
RelativePath="..\..\network\race_state.hpp"
>
</File>
<File
RelativePath="..\..\network\remote_kart_info.hpp"
>

View File

@@ -19,6 +19,8 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <math.h>
#include <iostream>
#define _WINSOCKAPI_
#include "network/network_manager.hpp"
#include <plib/ssg.h>
#include "bullet/Demos/OpenGL/GL_ShapeDrawer.h"
@@ -42,6 +44,9 @@
#include "translation.hpp"
#include "smoke.hpp"
#include "material_manager.hpp"
#include "network/race_state.hpp"
// num_players triggers 'already defined' messages without the WINSOCKAPI define. Don't ask me :(
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
@@ -329,6 +334,7 @@ void Kart::reset()
m_num_herrings_gobbled = 0;
m_wheel_rotation = 0;
m_wheelie_angle = 0.0f;
m_bounce_back_time = 0.0f;
m_controls.lr = 0.0f;
m_controls.accel = 0.0f;
@@ -464,20 +470,29 @@ void Kart::raceFinished(float time)
} // raceFinished
//-----------------------------------------------------------------------------
void Kart::collectedHerring(Herring* herring)
void Kart::collectedHerring(const Herring &herring, int random_attachment)
{
const herringType TYPE = herring->getType();
const herringType type = herring.getType();
const int OLD_HERRING_GOBBLED = m_num_herrings_gobbled;
switch (TYPE)
switch (type)
{
case HE_GREEN : m_attachment.hitGreenHerring(); break;
case HE_SILVER : m_num_herrings_gobbled++ ; break;
case HE_GOLD : m_num_herrings_gobbled += 3 ; break;
case HE_GREEN : m_attachment.hitGreenHerring(herring); break;
case HE_SILVER : m_num_herrings_gobbled++ ; break;
case HE_GOLD : m_num_herrings_gobbled += 3 ; break;
case HE_RED : int n=1 + 4*getNumHerring() / MAX_HERRING_EATEN;
m_collectable.hitRedHerring(n); break;
m_collectable.hitRedHerring(n, herring); break;
} // switch TYPE
// Attachments and collectables are stored in the corresponding
// functions (hit{Red,Green}Herring), so only coins need to be
// stored here.
if(network_manager->getMode()==NetworkManager::NW_SERVER &&
(type==HE_SILVER || type==HE_GOLD) )
{
race_state->herringCollected(getWorldKartId(), herring.getHerringId());
}
if ( m_num_herrings_gobbled > MAX_HERRING_EATEN )
m_num_herrings_gobbled = MAX_HERRING_EATEN;
@@ -567,6 +582,7 @@ void Kart::update(float dt)
m_rescue_pitch = getHPR().getPitch();
m_rescue_roll = getHPR().getRoll();
world->getPhysics()->removeKart(this);
race_state->herringCollected(getWorldKartId(), -1, -1);
}
btQuaternion q_roll (btVector3(0.f, 1.f, 0.f),
-m_rescue_roll*dt/rescue_time*M_PI/180.0f);
@@ -780,13 +796,24 @@ void Kart::resetBrakes()
for(int i=0; i<4; i++) m_vehicle->setBrake(0.0f, i);
} // resetBrakes
// -----------------------------------------------------------------------------
void Kart::crashed(Kart *k)
{
// After a collision disable the engine for a short time so that karts
// can 'bounce back' a bit (without this the engine force will prevent
// karts from bouncing back, they will instead stuck towards the obstable).
m_bounce_back_time = 0.5f;
} // crashed
// -----------------------------------------------------------------------------
void Kart::updatePhysics (float dt)
{
m_bounce_back_time-=dt;
float engine_power = getActualWheelForce() + handleWheelie(dt);
if(m_attachment.getType()==ATTACH_PARACHUTE) engine_power*=0.2f;
if(m_controls.accel)
{ // accelerating
if(m_controls.accel) // accelerating
{ // For a short time after a collision disable the engine,
// so that the karts can bounce back a bit from the obstacle.
if(m_bounce_back_time>0.0f) engine_power = 0.0f;
m_vehicle->applyEngineForce(engine_power, 2);
m_vehicle->applyEngineForce(engine_power, 3);
}

View File

@@ -41,6 +41,7 @@ private:
btTransform m_reset_transform; // reset position
Vec3 m_curr_track_coords;
Vec3 m_last_track_coords;
unsigned int m_world_kart_id; // index of kart in world
protected:
bool m_on_road; // true if the kart is on top of the
@@ -60,6 +61,8 @@ protected:
float m_zipper_time_left; // zipper time left
float m_lap_start_time; // Time at start of a new lap
char m_fastest_lap_message[255];
float m_bounce_back_time; // a short time after a collision acceleration
// is disabled to allow the karts to bounce back
int m_shortcut_sector; // segment on which the shortcut was started
@@ -107,6 +110,8 @@ public:
Kart(const std::string& kart_name, int position,
const btTransform& init_transform);
virtual ~Kart();
unsigned int getWorldKartId() const { return m_world_kart_id; }
void setWorldKartId(unsigned int n) { m_world_kart_id=n; }
void loadData();
virtual void updateGraphics (const Vec3& off_xyz, const Vec3& off_hpr);
const KartProperties*
@@ -207,10 +212,10 @@ public:
virtual int isPlayerKart () const {return 0; }
// addMessages gets called by world to add messages to the gui
virtual void addMessages () {};
virtual void collectedHerring (Herring* herring);
virtual void collectedHerring (const Herring &herring, int random_attachment);
virtual void reset ();
virtual void handleZipper ();
virtual void crashed (Kart *k) {};
virtual void crashed (Kart *k);
virtual void doLapCounting ();
virtual void update (float dt);
virtual void raceFinished (float time);

View File

@@ -28,13 +28,13 @@ class CharacterInfoMessage : public Message
public:
CharacterInfoMessage(int hostid) :Message(Message::MT_CHARACTER_INFO)
{
allocate(getLength(hostid));
add(hostid);
allocate(getCharLength());
addChar(hostid);
}
// ------------------------------------------------------------------------
CharacterInfoMessage(ENetPacket* pkt):Message(pkt, MT_CHARACTER_INFO)
{
int hostid=getInt();
int hostid=getChar();
network_manager->setHostId(hostid);
}
}; // CharacterInfoMessage

View File

@@ -37,23 +37,23 @@ public:
m_kart_info = race_manager->getLocalKartInfo(player_id);
m_num_local_players = race_manager->getNumLocalPlayers();
allocate(getLength(m_kart_info.getLocalPlayerId())
+getLength(m_kart_info.getKartName())
+getLength(m_kart_info.getPlayerName())
+getLength(m_num_local_players) );
add(m_kart_info.getLocalPlayerId());
add(m_kart_info.getKartName());
add(m_kart_info.getPlayerName());
allocate(getCharLength() // m_kart_info.getLocalPlayerId())
+getStringLength(m_kart_info.getKartName())
+getStringLength(m_kart_info.getPlayerName())
+getCharLength()); // m_num_local_players)
addChar(m_kart_info.getLocalPlayerId());
addString(m_kart_info.getKartName());
addString(m_kart_info.getPlayerName());
// Piggy backing this information saves sending it as a separate
// message. It is actually only required in the first message
add(race_manager->getNumLocalPlayers());
addChar(race_manager->getNumLocalPlayers());
}
CharacterSelectedMessage(ENetPacket* pkt):Message(pkt, MT_CHARACTER_INFO)
{
m_kart_info.setLocalPlayerId(getInt());
m_kart_info.setLocalPlayerId(getChar());
m_kart_info.setKartName(getString());
m_kart_info.setPlayerName(getString());
m_num_local_players = getInt();
m_num_local_players = getChar();
}
const RemoteKartInfo& getKartInfo () const { return m_kart_info; }
int getNumPlayers() const { return m_num_local_players; }

View File

@@ -40,8 +40,8 @@ private:
const std::string& id=user_config->m_player[0].getName();
std::ostringstream o;
o << id << '@' << hostname;
allocate(getLength(o.str()));
add(o.str());
allocate(getStringLength(o.str()));
addString(o.str());
}
public:
ConnectMessage():Message(Message::MT_CONNECT) { setId(); }

View File

@@ -33,7 +33,7 @@ KartControlMessage::KartControlMessage()
const KartControl& controls = kart->getControls();
char c[9];
controls.compress(c);
add(c, control_size);
addCharArray(c, control_size);
}
} // KartControlMessage
// ----------------------------------------------------------------------------
@@ -47,7 +47,7 @@ KartControlMessage::KartControlMessage(ENetPacket* pkt, int kart_id_offset,
for(int i=kart_id_offset; i<kart_id_offset+num_local_players; i++)
{
char c[9];
getChar(c, KartControl::getCompressedSize());
getCharArray(c, KartControl::getCompressedSize());
KartControl kc;
kc.uncompress(c);
NetworkKart *kart=world->getNetworkKart(i);

View File

@@ -27,9 +27,10 @@ KartUpdateMessage::KartUpdateMessage()
KartControl c;
// Send the number of karts and for each kart the compressed
// control structure (3 ints) and xyz,hpr (4 floats: quaternion:
allocate(getLength(num_karts)+
num_karts*(KartControl::getCompressedSize() + 7*getLength(1.0f)) );
add(num_karts);
allocate(getCharLength()+
num_karts*(KartControl::getCompressedSize() + getVec3Length()
+getQuaternionLength()) );
addChar(num_karts);
for(unsigned int i=0; i<num_karts; i++)
{
const Kart* kart=world->getKart(i);
@@ -37,9 +38,9 @@ KartUpdateMessage::KartUpdateMessage()
assert(KartControl::getCompressedSize()<=9);
char compressed[9]; // avoid the new/delete overhead
kc.compress(compressed);
add(compressed, KartControl::getCompressedSize());
add(kart->getXYZ());
add(kart->getRotation());
addCharArray(compressed, KartControl::getCompressedSize());
addVec3(kart->getXYZ());
addQuaternion(kart->getRotation());
} // for i
} // KartUpdateMessage
// ----------------------------------------------------------------------------
@@ -51,9 +52,10 @@ KartUpdateMessage::KartUpdateMessage(ENetPacket* pkt)
{
assert(KartControl::getCompressedSize()<=9);
char compressed[9]; // avoid new/delete overhead
getChar(compressed, KartControl::getCompressedSize());
getCharArray(compressed, KartControl::getCompressedSize());
KartControl kc;
kc.uncompress(compressed);
// Currently not used
Vec3 xyz = getVec3();
btQuaternion q = getQuaternion();
Kart *kart = world->getKart(i);

View File

@@ -21,15 +21,13 @@
#include <string>
#include <math.h>
#include <stdexcept>
// need a more elegant way of setting the data_size, esp when strings are being used
// also, looking at how the packets are actually used, we can probably serialise as
// part of the constructor, it seems packets to be sent are always created in a
// single line
#include <assert.h>
/** Creates a message to be sent.
* This only initialised the data structures, it does not reserve any memory.
* A call to allocate() is therefore necessary.
* \param type The type of the message
*/
Message::Message(MessageType type)
{
assert(sizeof(int)==4);
@@ -41,7 +39,24 @@ Message::Message(MessageType type)
} // Message
// ----------------------------------------------------------------------------
/** Handles a received message.
* The message in pkt is received, and the message type is checked.
* \param pkt The ENetPacket
* \param m The type of the message. The type is checked via an assert!
*/
Message::Message(ENetPacket* pkt, MessageType m)
{
receive(pkt, m);
}
// ----------------------------------------------------------------------------
/** Loads the message in pkt, and checks for the correct message type.
* Paramaters:
* \param pkt The ENetPacket
* \param m The type of the message. The type is checked via an assert!
*/
void Message::receive(ENetPacket* pkt, MessageType m)
{
assert(sizeof(int)==4);
m_pkt = pkt;
@@ -54,13 +69,27 @@ Message::Message(ENetPacket* pkt, MessageType m)
} // Message
// ----------------------------------------------------------------------------
/** Frees the memory allocated for this message. */
Message::~Message()
{
if(m_needs_destroy)
enet_packet_destroy(m_pkt);
clear();
} // ~Message
// ----------------------------------------------------------------------------
/** Frees the memory for a received message.
* Calls enet_packet_destroy if necessary (i.e. if the message was received).
* The memory for a message created to be sent does not need to be freed, it
* is handled by enet. */
void Message::clear()
{
if(m_needs_destroy)
enet_packet_destroy(m_pkt);
} // clear
// ----------------------------------------------------------------------------
/** Reserves the memory for a message.
* \param size Number of bytes to reserve.
*/
void Message::allocate(int size)
{
m_data_size = size+1;
@@ -71,23 +100,49 @@ void Message::allocate(int size)
} // allocate
// ----------------------------------------------------------------------------
bool Message::add(int data)
/** Adds an integer value to the message.
* \param data The integer value to add.
*/
void Message::addInt(int data)
{
if ((int)(m_pos + sizeof(int)) > m_data_size)
return false;
assert((int)(m_pos + sizeof(int)) <= m_data_size);
int l=htonl(data);
memcpy(m_data+m_pos, &l, sizeof(int));
m_pos+=sizeof(int);
return true;
} // add<int>
} // addInt
// ----------------------------------------------------------------------------
/** Extracts an integer value from a message.
* \return The extracted integer.
*/
int Message::getInt()
{
m_pos+=sizeof(int);
return ntohl(*(int*)(&m_data[m_pos-sizeof(int)]));
} // getInt
// ----------------------------------------------------------------------------
/** Adds a short value to the message.
* \param data The integer value to add.
*/
void Message::addShort(short data)
{
assert((int)(m_pos + sizeof(short)) <= m_data_size);
int l=htons(data);
memcpy(m_data+m_pos, &l, sizeof(short));
m_pos+=sizeof(short);
} // addShort
// ----------------------------------------------------------------------------
/** Extracts a short value from a message.
* \return The short value.
*/
short Message::getShort()
{
m_pos+=sizeof(short);
return ntohs(*(short*)(&m_data[m_pos-sizeof(short)]));
} // getShort
// ----------------------------------------------------------------------------
float Message::getFloat()
{
@@ -103,14 +158,13 @@ float Message::getFloat()
} // getFloat
// ----------------------------------------------------------------------------
bool Message::add(const std::string &data)
void Message::addString(const std::string &data)
{
int len = data.size()+1; // copy 0 end byte
assert((int)(m_pos+len) <=m_data_size);
memcpy (&(m_data[m_pos]), data.c_str(), len);
m_pos += len;
return true;
} // add<string>
} // addString
// ----------------------------------------------------------------------------
std::string Message::getString()
@@ -122,28 +176,33 @@ std::string Message::getString()
} // getString
// ----------------------------------------------------------------------------
int Message::getLength(const std::vector<std::string>& vs)
/** Returns the number of bytes necessary to store a string vector.
* \param vs std::vector<std::string>
*/
int Message::getStringVectorLength(const std::vector<std::string>& vs)
{
int len=getLength(vs.size());
int len=getShortLength();
for(unsigned int i=0; i<vs.size(); i++)
len += getLength(vs[i]);
len += getStringLength(vs[i]);
return len;
} // getLength(vector<string>)
} // getStringVectorLength
// ----------------------------------------------------------------------------
bool Message::add(const std::vector<std::string>& vs)
/** Adds a std::vector<std::string> to the message.
*/
void Message::addStringVector(const std::vector<std::string>& vs)
{
bool result = add(vs.size());
if(!result) return false;
for(unsigned int i=0; i<vs.size(); i++)
if(!add(vs[i])) return false;
return true;
} // add(vector<string>)
assert(vs.size()<32767);
addShort(vs.size());
for(unsigned short i=0; i<vs.size(); i++)
addString(vs[i]);
} // addStringVector
// ----------------------------------------------------------------------------
std::vector<std::string> Message::getStringVector()
{
std::vector<std::string> vs;
vs.resize(getInt());
vs.resize(getShort());
for(unsigned int i=0; i<vs.size(); i++)
vs[i]=getString();
return vs;

View File

@@ -34,13 +34,21 @@
// sjl: when a message is received, need to work out what kind of message it
// is and therefore what to do with it
// Collects and serialises/deserialises kart info to send
/** Base class to serialises/deserialises messages.
* This is the base class for all messages being exchange between client
* and server. It handles the interface to enet, and adds a message type
* (which is checked via an assert to help finding bugs by receiving a
* message of an incorrect type). It also takes care of endianess (though
* floats are converted via a byte swap, too - so it must be guaranteed
* that the float representation between all machines is identical).
*/
class Message
{
public:
enum MessageType {MT_CONNECT=1, MT_CHARACTER_INFO,
MT_RACE_INFO, MT_RACE_START, MT_WORLD_LOADED,
MT_KART_INFO, MT_KART_CONTROL};
MT_KART_INFO, MT_KART_CONTROL,
MT_RACE_STATE};
private:
ENetPacket *m_pkt;
char *m_data;
@@ -50,38 +58,42 @@ private:
bool m_needs_destroy; // only received messages need to be destroyed
protected:
bool add(int data);
bool add(const std::string &data);
bool add(const std::vector<std::string>& vs);
bool add(float data) { return add(*(int*)&data); }
bool add(char *c, unsigned int n)
{ if((int)(m_pos+n)>m_data_size)
return false;
void addInt(int data);
void addShort(short data);
void addString(const std::string &data);
void addStringVector(const std::vector<std::string>& vs);
void addUInt(unsigned int data) { addInt(*(int*)&data); }
void addFloat(float data) { addInt(*(int*)&data); }
void addBool(bool data) { addChar(data?1:0); }
void addChar(char data) { addCharArray((char*)&data,1);}
void addCharArray(char *c, unsigned int n=1)
{ assert((int)(m_pos+n)<=m_data_size);
memcpy(m_data+m_pos,c,n);
m_pos+=n;
return true; }
m_pos+=n; }
#ifndef WIN32 // on windows size_t is unsigned int
bool add(size_t data) { return add((int)data); }
void addSizeT(size_t data) { addInt((int)data); }
#endif
bool add(unsigned int data) { return add(*(int*)&data); }
bool add(int *d, unsigned int n)
void addIntArray(int *d, unsigned int n)
{ for(unsigned int i=0;
i<n-1; i++)
add(d[i]);
return add(d[n-1]); }
bool add(const Vec3& v) { add(v.getX());
add(v.getY());
return add(v.getZ()); }
bool add(const btQuaternion& q) { add(q.getX());
add(q.getY());
add(q.getZ());
return add(q.getW()); }
i<n; i++)
addInt(d[i]); }
void addVec3(const Vec3& v) { addFloat(v.getX());
addFloat(v.getY());
addFloat(v.getZ()); }
void addQuaternion(const btQuaternion& q) { addFloat(q.getX());
addFloat(q.getY());
addFloat(q.getZ());
addFloat(q.getW()); }
int getInt();
bool getBool() { return getChar()==1; }
short getShort();
float getFloat();
std::string getString();
std::vector<std::string>
getStringVector();
void getChar(char *c, int n) {memcpy(c,m_data+m_pos,n);
char getChar() {char c;getCharArray(&c,1);
return c; }
void getCharArray(char *c, int n=1) {memcpy(c,m_data+m_pos,n);
m_pos+=n;
return; }
Vec3 getVec3() { Vec3 v;
@@ -95,26 +107,30 @@ protected:
q.setZ(getFloat());
q.setW(getFloat());
return q; }
int getLength(int n) { return sizeof(int); }
int getLength(unsigned int n) { return sizeof(int); }
int getLength(float f) { return sizeof(float); }
int getLength(const std::string& s) { return s.size()+1; }
int getLength(const Vec3& v) { return 3*sizeof(float); }
int getLength(const btQuaternion &q){ return 4*sizeof(float); }
int getIntLength() const { return sizeof(int); }
int getUIntLength() const { return sizeof(int); }
int getShortLength() const { return sizeof(short); }
int getCharLength() const { return sizeof(char); }
int getFloatLength() { return sizeof(float); }
int getStringLength(const std::string& s) { return s.size()+1; }
int getVec3Length() { return 3*sizeof(float); }
int getQuaternionLength() { return 4*sizeof(float); }
int getLength(const std::vector<std::string>& vs);
int getStringVectorLength(const std::vector<std::string>& vs);
#ifndef WIN32
int getLength(size_t n) { return sizeof(int); }
int getSizeTLength(size_t n) { return sizeof(int); }
#endif
public:
Message(MessageType m); // create from scratch (to send)
Message(ENetPacket *pkt, MessageType m); // create from (received) packet
Message(MessageType m);
Message(ENetPacket *pkt, MessageType m);
void receive(ENetPacket *pkt, MessageType m);
~Message();
void clear();
void allocate(int size);
MessageType getType() const { return m_type; }
ENetPacket* getPacket() const { assert(m_data_size>-1); return m_pkt; }
// Return the type of a message without unserialising the message
/** Return the type of a message without unserialising the message */
static MessageType peekType(ENetPacket *pkt)
{ return (MessageType)pkt->data[0];}

View File

@@ -27,7 +27,7 @@ class NetworkKart : public Kart
private:
int m_global_player_id; // to identify this kart to the network manager
public:
NetworkKart(const std::string& kart_name, int position,
NetworkKart(const std::string& kart_name, int position,
const btTransform& init_transform,
int global_player_id);
void setControl(const KartControl& kc);

View File

@@ -18,14 +18,14 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network_manager.hpp"
#include "connect_message.hpp"
#include "character_info_message.hpp"
#include "character_selected_message.hpp"
#include "race_info_message.hpp"
#include "race_start_message.hpp"
#include "world_loaded_message.hpp"
#include "kart_update_message.hpp"
#include "kart_control_message.hpp"
#include "network/connect_message.hpp"
#include "network/character_info_message.hpp"
#include "network/character_selected_message.hpp"
#include "network/race_info_message.hpp"
#include "network/race_start_message.hpp"
#include "network/world_loaded_message.hpp"
#include "network/race_state.hpp"
#include "network/kart_control_message.hpp"
#include "stk_config.hpp"
#include "user_config.hpp"
#include "race_manager.hpp"
@@ -277,7 +277,7 @@ void NetworkManager::handleMessageAtClient(ENetEvent *event)
}
case NS_RACING:
{
KartUpdateMessage k(event->packet);
assert(false); // should never be here while racing
break;
}
default:
@@ -454,10 +454,10 @@ void NetworkManager::sendUpdates()
{
if(m_mode==NW_SERVER)
{
KartUpdateMessage m;
broadcastToClients(m);
race_state->serialise();
broadcastToClients(*race_state);
}
else
else if(m_mode==NW_CLIENT)
{
KartControlMessage m;
sendToServer(m);
@@ -467,6 +467,7 @@ void NetworkManager::sendUpdates()
// ----------------------------------------------------------------------------
void NetworkManager::receiveUpdates()
{
if(m_mode==NW_NONE) return; // do nothing if not networking
// The server receives m_num_clients messages, each client one message
int num_messages = m_mode==NW_SERVER ? m_num_clients : 1;
ENetEvent event;
@@ -502,7 +503,7 @@ void NetworkManager::receiveUpdates()
}
else
{
KartUpdateMessage(event.packet);
race_state->receive(event.packet);
}
} // for i<num_messages
if(!correct)

View File

@@ -25,64 +25,62 @@ RaceInfoMessage::RaceInfoMessage(const std::vector<RemoteKartInfo>& kart_info)
: Message(Message::MT_RACE_INFO)
{
const GrandPrixData *cup=NULL;
int len = getLength(race_manager->getMajorMode() )
+ getLength(race_manager->getMinorMode() )
+ getLength(race_manager->getDifficulty())
+ getLength(race_manager->getNumKarts() );
int len = 3*getCharLength() // major, minor, difficulty
+ getCharLength(); // num karts
if(race_manager->getMajorMode()==RaceManager::RM_GRAND_PRIX)
{
cup = race_manager->getGrandPrix();
len += getLength(cup->getId());
len += getStringLength(cup->getId());
}
else
{
len += getLength(race_manager->getTrackName());
len += getLength(race_manager->getNumLaps());
len += getStringLength(race_manager->getTrackName());
len += getCharLength(); // num laps
}
len += getLength(kart_info.size());
len += getCharLength(); // kart_info.size()
for(unsigned int i=0; i<kart_info.size(); i++)
{
len += getLength(kart_info[i].getGlobalPlayerId())
+ getLength(kart_info[i].getHostId())
+ getLength(kart_info[i].getKartName())
+ getLength(kart_info[i].getLocalPlayerId())
+ getLength(kart_info[i].getPlayerName());
len += getCharLength() // kart_info[i].getGlobalPlayerId())
+ getCharLength() // kart_info[i].getHostId())
+ getStringLength(kart_info[i].getKartName())
+ getCharLength() // kart_info[i].getLocalPlayerId())
+ getStringLength(kart_info[i].getPlayerName());
}
const std::vector<std::string>& rkl=race_manager->getRandomKartList();
len += getLength(rkl);
len += getStringVectorLength(rkl);
allocate(len);
add(race_manager->getMajorMode() );
add(race_manager->getMinorMode() );
add(race_manager->getDifficulty());
add(race_manager->getNumKarts() );
addChar(race_manager->getMajorMode() );
addChar(race_manager->getMinorMode() );
addChar(race_manager->getDifficulty());
addChar(race_manager->getNumKarts() );
if(race_manager->getMajorMode()==RaceManager::RM_GRAND_PRIX)
add(cup->getName());
addString(cup->getName());
else
{
add(race_manager->getTrackName());
add(race_manager->getNumLaps());
addString(race_manager->getTrackName());
addChar(race_manager->getNumLaps());
}
add(kart_info.size());
addChar(kart_info.size());
for(unsigned int i=0; i<kart_info.size(); i++)
{
add(kart_info[i].getGlobalPlayerId());
add(kart_info[i].getHostId());
add(kart_info[i].getKartName());
add(kart_info[i].getLocalPlayerId());
add(kart_info[i].getPlayerName());
addChar(kart_info[i].getGlobalPlayerId());
addChar(kart_info[i].getHostId());
addString(kart_info[i].getKartName());
addChar(kart_info[i].getLocalPlayerId());
addString(kart_info[i].getPlayerName());
}
add(rkl);
addStringVector(rkl);
} // RaceInfoMessage
// ----------------------------------------------------------------------------
RaceInfoMessage::RaceInfoMessage(ENetPacket* pkt):Message(pkt, MT_RACE_INFO)
{
race_manager->setMajorMode ( RaceManager::RaceModeType(getInt()) );
race_manager->setMinorMode ( RaceManager::RaceModeType(getInt()) );
race_manager->setDifficulty( RaceManager::Difficulty (getInt()) );
race_manager->setNumKarts ( getInt() );
race_manager->setMajorMode ( RaceManager::RaceModeType(getChar()) );
race_manager->setMinorMode ( RaceManager::RaceModeType(getChar()) );
race_manager->setDifficulty( RaceManager::Difficulty (getChar()) );
race_manager->setNumKarts ( getChar() );
if(race_manager->getMajorMode()==RaceManager::RM_GRAND_PRIX)
{
GrandPrixData cup;
@@ -92,18 +90,18 @@ RaceInfoMessage::RaceInfoMessage(ENetPacket* pkt):Message(pkt, MT_RACE_INFO)
else
{
race_manager->setTrack(getString());
race_manager->setNumLaps(getInt());
race_manager->setNumLaps(getChar());
}
std::vector<RemoteKartInfo> kart_info;
kart_info.resize(getInt());
kart_info.resize(getChar());
for(unsigned int i=0; i<kart_info.size(); i++)
{
kart_info[i].setGlobalPlayerId(getInt());
kart_info[i].setHostId(getInt());
kart_info[i].setGlobalPlayerId(getChar());
kart_info[i].setHostId(getChar());
kart_info[i].setKartName(getString());
kart_info[i].setLocalPlayerId(getInt());
kart_info[i].setLocalPlayerId(getChar());
kart_info[i].setPlayerName(getString());
}

View File

@@ -246,10 +246,10 @@ void PlayerKart::handleZipper()
} // handleZipper
//-----------------------------------------------------------------------------
void PlayerKart::collectedHerring(Herring* herring)
void PlayerKart::collectedHerring(const Herring &herring, int add_info)
{
Kart::collectedHerring(herring);
sound_manager->playSfx ( ( herring->getType()==HE_GREEN ) ? SOUND_UGH:SOUND_GRAB);
Kart::collectedHerring(herring, add_info);
sound_manager->playSfx ( ( herring.getType()==HE_GREEN ) ? SOUND_UGH:SOUND_GRAB);
} // collectedHerring
//-----------------------------------------------------------------------------

View File

@@ -42,27 +42,23 @@ private:
void steer(float, int);
public:
PlayerKart(const std::string& kart_name,
int position, Player *_player,
const btTransform& init_pos, int player_index);
PlayerKart(const std::string& kart_name,
int position, Player *_player,
const btTransform& init_pos, int player_index);
int earlyStartPenalty () {return m_penalty_time>0; }
Player* getPlayer () {return m_player; }
void update (float);
void addMessages ();
void action (KartAction action, int value);
void crashed (Kart *k);
void handleZipper ();
void collectedHerring (Herring* herring);
int earlyStartPenalty () {return m_penalty_time>0; }
Player *getPlayer () {return m_player; }
void update (float);
void addMessages ();
void action (KartAction action, int value);
void handleZipper ();
void collectedHerring (const Herring &herring, int add_info=-1);
virtual void crashed (Kart *k);
virtual void setPosition (int p);
virtual void raceFinished (float time);
int isPlayerKart () const {return 1;}
Camera* getCamera () {return m_camera;}
void reset();
int isPlayerKart () const {return 1;}
Camera* getCamera () {return m_camera;}
void reset();
};
#endif
/* EOF */

View File

@@ -17,6 +17,8 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network/network_manager.hpp"
#include "network/race_state.hpp"
#include "loader.hpp"
#include "projectile_manager.hpp"
#include "bowling.hpp"
@@ -81,12 +83,15 @@ void ProjectileManager::cleanup()
/** General projectile update call. */
void ProjectileManager::update(float dt)
{
// First update all projectiles on the track
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i)
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
(*i)->update(dt);
updateClient();
}
else
{
updateServer(dt);
}
// Then check if any projectile hit something
if(m_something_was_hit)
{
@@ -124,6 +129,50 @@ void ProjectileManager::update(float dt)
m_something_was_hit=false;
} // update
// -----------------------------------------------------------------------------
/** Updates all rockets on the server (or no networking). */
void ProjectileManager::updateServer(float dt)
{
// First update all projectiles on the track
if(network_manager->getMode()!=NetworkManager::NW_NONE)
{
race_state->setNumFlyables(m_active_projectiles.size());
}
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i)
{
(*i)->update(dt);
// Store the state information on the server
if(network_manager->getMode()!=NetworkManager::NW_NONE)
{
race_state->setFlyableInfo(i-m_active_projectiles.begin(),
(*i)->getXYZ(), (*i)->getRotation(),
(*i)->hasHit());
}
}
} // updateServer
// -----------------------------------------------------------------------------
/** Updates all rockets and explosions on the client.
* updateClient takes the information in race_state and updates all rockets
* (i.e. position, explosion etc) */
void ProjectileManager::updateClient()
{
m_something_was_hit = false;
unsigned int num_projectiles = race_state->getNumFlyables();
// Race_state must contain at least as many entries as the current number
// of projectiles. It can contain more if new projectiles have been added.
assert(m_active_projectiles.size()<=num_projectiles);
int indx=0;
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i, ++indx)
{
const Flyable::FlyableInfo &f = race_state->getFlyable(indx);
(*i)->updateFromServer(f);
if(f.m_exploded) m_something_was_hit = true;
} // for i in m_active_projectiles
} // updateClient
// -----------------------------------------------------------------------------
Flyable *ProjectileManager::newProjectile(Kart *kart, CollectableType type)
{

View File

@@ -32,8 +32,8 @@ class Flyable;
class ProjectileManager
{
private:
typedef std::vector<Flyable*> Projectiles;
typedef std::vector<Explosion* > Explosions;
typedef std::vector<Flyable*> Projectiles;
typedef std::vector<Explosion*> Explosions;
// The list of all active projectiles, i.e. projectiles
// which are currently moving on the track
@@ -46,16 +46,18 @@ private:
ssgSelector* m_explosion_model;
bool m_something_was_hit;
bool m_explosion_ended;
void updateClient();
void updateServer(float dt);
public:
ProjectileManager() {m_something_was_hit=false;};
~ProjectileManager() {};
void explode () {m_something_was_hit=true;}
void FinishedExplosion() {m_explosion_ended =true;}
ProjectileManager() {m_something_was_hit=false;}
~ProjectileManager() {}
void explode () {m_something_was_hit=true; }
void FinishedExplosion() {m_explosion_ended =true; }
ssgSelector* getExplosionModel()
{
return (ssgSelector*)m_explosion_model->clone();
}
unsigned int getNumProjectiles() const {return m_active_explosions.size();}
int getProjectileId (const std::string ident);
void loadData ();
void cleanup ();

View File

@@ -58,6 +58,7 @@ void RaceManager::reset()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
m_player_karts.clear();
} // reset
//-----------------------------------------------------------------------------

View File

@@ -46,6 +46,8 @@
#include "robots/default_robot.hpp"
#include "unlock_manager.hpp"
#include "network/network_manager.hpp"
#include "network/race_state.hpp"
#ifdef HAVE_GHOST_REPLAY
# include "replay_player.hpp"
#endif
@@ -63,6 +65,7 @@ World::World()
{
delete world;
world = this;
race_state = new RaceState();
m_phase = SETUP_PHASE;
m_previous_phase = SETUP_PHASE; // initialise it just in case
m_track = NULL;
@@ -131,16 +134,8 @@ World::World()
m_local_player_karts[local_player_id] = static_cast<PlayerKart*>(newkart);
break;
case RaceManager::KT_NETWORK_PLAYER:
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
newkart = new NetworkKart(kart_name, position, init_pos,
global_player_id);
}
else
{
newkart = new NetworkKart(kart_name, position, init_pos,
global_player_id);
}
newkart = new NetworkKart(kart_name, position, init_pos,
global_player_id);
m_network_karts[global_player_id] = static_cast<NetworkKart*>(newkart);
break;
case RaceManager::KT_AI:
@@ -160,6 +155,7 @@ World::World()
scene->add ( newkart -> getModelTransform() ) ;
m_kart.push_back(newkart);
newkart->setWorldKartId(m_kart.size()-1);
} // for i
resetAllKarts();
@@ -201,6 +197,7 @@ World::~World()
#ifdef HAVE_GHOST_REPLAY
saveReplayHumanReadable( "test" );
#endif
delete race_state;
m_track->cleanup();
// Clear all callbacks
callback_manager->clear(CB_TRACK);
@@ -292,6 +289,8 @@ void World::resetAllKarts()
//-----------------------------------------------------------------------------
void World::update(float dt)
{
// Clear race state so that new information can be stored
race_state->clear();
if(user_config->m_replay_history) dt=history->GetNextDelta();
updateRaceStatus(dt);