1 /* 2 * network_messages.h - TCPMess message types for network game setup 3 4 Copyright (C) 2005 and beyond by Gregory Smith 5 and the "Aleph One" developers. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 This license is contained in the file "COPYING", 18 which is included with this source code; it is available online at 19 http://www.gnu.org/licenses/gpl.html 20 21 */ 22 23 #ifndef NETWORK_MESSAGES_H 24 #define NETWORK_MESSAGES_H 25 26 #include "cseries.h" 27 #include "AStream.h" 28 #include "Message.h" 29 30 #include "SDL_net.h" 31 32 #include "network_capabilities.h" 33 #include "network_private.h" 34 35 enum { 36 kHELLO_MESSAGE = 700, 37 kJOINER_INFO_MESSAGE, 38 kJOIN_PLAYER_MESSAGE, 39 kCAPABILITIES_MESSAGE, 40 kACCEPT_JOIN_MESSAGE, 41 kTOPOLOGY_MESSAGE, 42 kMAP_MESSAGE, 43 kPHYSICS_MESSAGE, 44 kLUA_MESSAGE, 45 kCHAT_MESSAGE, 46 kUNKNOWN_MESSAGE_MESSAGE, 47 kEND_GAME_DATA_MESSAGE, 48 kCHANGE_COLORS_MESSAGE, 49 kSERVER_WARNING_MESSAGE, 50 kCLIENT_INFO_MESSAGE, 51 kZIPPED_MAP_MESSAGE, 52 kZIPPED_PHYSICS_MESSAGE, 53 kZIPPED_LUA_MESSAGE, 54 kNETWORK_STATS_MESSAGE, 55 kGAME_SESSION_MESSAGE 56 }; 57 58 template <MessageTypeID tMessageType, typename tValueType> 59 class TemplatizedSimpleMessage : public SimpleMessage<tValueType> 60 { 61 public: 62 enum { kType = tMessageType }; 63 TemplatizedSimpleMessage()64 TemplatizedSimpleMessage() : SimpleMessage<tValueType>(tMessageType) { } 65 TemplatizedSimpleMessage(tValueType inValue)66 TemplatizedSimpleMessage(tValueType inValue) : SimpleMessage<tValueType>(tMessageType, inValue) { } 67 clone()68 TemplatizedSimpleMessage<tMessageType, tValueType>* clone () const { 69 return new TemplatizedSimpleMessage<tMessageType, tValueType>(*this); 70 } 71 type()72 MessageTypeID type() const { return kType; } 73 }; 74 75 class AcceptJoinMessage : public SmallMessageHelper 76 { 77 public: 78 enum { kType = kACCEPT_JOIN_MESSAGE }; 79 AcceptJoinMessage()80 AcceptJoinMessage() : SmallMessageHelper() { } 81 AcceptJoinMessage(bool accepted,NetPlayer * player)82 AcceptJoinMessage(bool accepted, NetPlayer *player) : SmallMessageHelper() { 83 mAccepted = accepted; 84 mPlayer = *player; 85 } 86 clone()87 AcceptJoinMessage *clone() const { 88 return new AcceptJoinMessage(*this); 89 } 90 accepted()91 bool accepted() { return mAccepted; } accepted(bool isAccepted)92 void accepted(bool isAccepted) { mAccepted = isAccepted; } player()93 NetPlayer *player() { return &mPlayer; } player(const NetPlayer * thePlayer)94 void player(const NetPlayer *thePlayer) { mPlayer = *thePlayer; } 95 type()96 MessageTypeID type() const { return kType; } 97 98 protected: 99 void reallyDeflateTo(AOStream& outputStream) const; 100 bool reallyInflateFrom(AIStream& inputStream); 101 102 private: 103 104 bool mAccepted = false; 105 NetPlayer mPlayer = {}; 106 }; 107 108 class CapabilitiesMessage : public SmallMessageHelper 109 { 110 public: 111 enum { kType = kCAPABILITIES_MESSAGE }; 112 CapabilitiesMessage()113 CapabilitiesMessage() : SmallMessageHelper() { } 114 CapabilitiesMessage(const Capabilities & capabilities)115 CapabilitiesMessage(const Capabilities &capabilities) : SmallMessageHelper() { 116 mCapabilities = capabilities; 117 } 118 clone()119 CapabilitiesMessage *clone() const { 120 return new CapabilitiesMessage(*this); 121 } 122 capabilities()123 const Capabilities *capabilities() { return &mCapabilities; } 124 type()125 MessageTypeID type() const { return kType; } 126 127 protected: 128 void reallyDeflateTo(AOStream& outputStream) const; 129 bool reallyInflateFrom(AIStream& inputStream); 130 131 private: 132 Capabilities mCapabilities; 133 }; 134 135 class ChangeColorsMessage : public SmallMessageHelper 136 { 137 public: 138 enum { kType = kCHANGE_COLORS_MESSAGE }; 139 ChangeColorsMessage()140 ChangeColorsMessage() : SmallMessageHelper() { } 141 ChangeColorsMessage(int16 color,int16 team)142 ChangeColorsMessage(int16 color, int16 team) : SmallMessageHelper() { 143 mColor = color; 144 mTeam = team; 145 } 146 clone()147 ChangeColorsMessage *clone() const { 148 return new ChangeColorsMessage(*this); 149 } 150 color()151 int16 color() { return mColor; } team()152 int16 team() { return mTeam; } 153 type()154 MessageTypeID type() const { return kType; } 155 156 protected: 157 void reallyDeflateTo(AOStream& outputStream) const; 158 bool reallyInflateFrom(AIStream& inputStream); 159 160 private: 161 162 int16 mColor = 0; 163 int16 mTeam = 0; 164 }; 165 166 class ClientInfoMessage : public SmallMessageHelper 167 { 168 public: 169 enum { kType = kCLIENT_INFO_MESSAGE }; 170 enum { kAdd, kUpdate, kRemove }; 171 ClientInfoMessage()172 ClientInfoMessage() : SmallMessageHelper() { } 173 ClientInfoMessage(int16 stream_id,const ClientChatInfo * clientChatInfo,int16 action)174 ClientInfoMessage(int16 stream_id, const ClientChatInfo *clientChatInfo, int16 action ) : mStreamID(stream_id), mAction(action), mClientChatInfo(*clientChatInfo) { } 175 clone()176 ClientInfoMessage *clone() const { 177 return new ClientInfoMessage(*this); 178 } 179 info()180 const ClientChatInfo *info() { return &mClientChatInfo; } action()181 const int16 action() { return mAction; } stream_id()182 const int16 stream_id() { return mStreamID; } 183 type()184 MessageTypeID type() const { return kType; } 185 186 protected: 187 void reallyDeflateTo(AOStream& outputStream) const; 188 bool reallyInflateFrom(AIStream& inputStream); 189 190 private: 191 ClientChatInfo mClientChatInfo = {}; 192 int16 mAction = kAdd; 193 int16 mStreamID = 0; 194 }; 195 196 197 typedef DatalessMessage<kEND_GAME_DATA_MESSAGE> EndGameDataMessage; 198 199 class HelloMessage : public SmallMessageHelper 200 { 201 public: 202 enum { kType = kHELLO_MESSAGE }; 203 HelloMessage()204 HelloMessage() : SmallMessageHelper() { } 205 HelloMessage(const std::string & version)206 HelloMessage(const std::string &version) : 207 SmallMessageHelper(), mVersion(version) { } 208 clone()209 HelloMessage *clone() const { 210 return new HelloMessage(*this); 211 } 212 version()213 std::string version() { return mVersion; } version(const std::string & version)214 void version(const std::string &version) { mVersion = version; } 215 type()216 MessageTypeID type() const { return kType; } 217 218 protected: 219 void reallyDeflateTo(AOStream& outputStream) const; 220 bool reallyInflateFrom(AIStream& inputStream); 221 222 private: 223 224 std::string mVersion; 225 }; 226 227 typedef TemplatizedSimpleMessage<kJOIN_PLAYER_MESSAGE, int16> JoinPlayerMessage; 228 229 class JoinerInfoMessage : public SmallMessageHelper 230 { 231 public: 232 enum { kType = kJOINER_INFO_MESSAGE }; 233 JoinerInfoMessage()234 JoinerInfoMessage() : SmallMessageHelper() { } 235 JoinerInfoMessage(prospective_joiner_info * info,const std::string & version)236 JoinerInfoMessage(prospective_joiner_info *info, const std::string &version) : SmallMessageHelper() { 237 238 mInfo = *info; 239 mVersion = version; 240 } 241 clone()242 JoinerInfoMessage *clone() const { 243 return new JoinerInfoMessage(*this); 244 } 245 info()246 prospective_joiner_info *info() { return &mInfo; } info(const prospective_joiner_info * theInfo)247 void info(const prospective_joiner_info *theInfo) { 248 mInfo = *theInfo; 249 } 250 version()251 std::string version() { return mVersion; } version(const std::string version)252 void version(const std::string version) { mVersion = version; } 253 type()254 MessageTypeID type() const { return kType; } 255 256 protected: 257 void reallyDeflateTo(AOStream& outputStream) const; 258 bool reallyInflateFrom(AIStream& inputStream); 259 260 private: 261 prospective_joiner_info mInfo = {}; 262 std::string mVersion; 263 }; 264 265 class BigChunkOfZippedDataMessage : public BigChunkOfDataMessage 266 // zips on deflate, unzips on inflate 267 { 268 public: BigChunkOfDataMessage(inType,inBuffer,inLength)269 BigChunkOfZippedDataMessage(MessageTypeID inType, const Uint8* inBuffer = NULL, size_t inLength = 0) : BigChunkOfDataMessage(inType, inBuffer, inLength) { } BigChunkOfZippedDataMessage(const BigChunkOfDataMessage & other)270 BigChunkOfZippedDataMessage(const BigChunkOfDataMessage& other) : BigChunkOfDataMessage(other) { } 271 272 bool inflateFrom(const UninflatedMessage& inUninflated); 273 UninflatedMessage* deflate() const; 274 }; 275 276 template<int messageType, class T> class TemplatizedDataMessage : public T 277 { 278 public: 279 enum { 280 kType = messageType 281 }; 282 283 TemplatizedDataMessage(const Uint8* inBuffer = NULL, size_t inLength = 0) : T(kType,inBuffer,inLength)284 T(kType, inBuffer, inLength) { }; TemplatizedDataMessage(const TemplatizedDataMessage & other)285 TemplatizedDataMessage(const TemplatizedDataMessage& other) : T(other) { } clone()286 TemplatizedDataMessage* clone () const { 287 return new TemplatizedDataMessage(*this); 288 } 289 }; 290 291 typedef TemplatizedDataMessage<kMAP_MESSAGE, BigChunkOfDataMessage> MapMessage; 292 typedef TemplatizedDataMessage<kZIPPED_MAP_MESSAGE, BigChunkOfZippedDataMessage> ZippedMapMessage; 293 294 typedef TemplatizedDataMessage<kPHYSICS_MESSAGE, BigChunkOfDataMessage> PhysicsMessage; 295 typedef TemplatizedDataMessage<kZIPPED_PHYSICS_MESSAGE, BigChunkOfZippedDataMessage> ZippedPhysicsMessage; 296 297 typedef TemplatizedDataMessage<kLUA_MESSAGE, BigChunkOfDataMessage> LuaMessage; 298 typedef TemplatizedDataMessage<kZIPPED_LUA_MESSAGE, BigChunkOfZippedDataMessage> ZippedLuaMessage; 299 300 301 class NetworkChatMessage : public SmallMessageHelper 302 { 303 public: 304 enum { kType = kCHAT_MESSAGE }; 305 enum { CHAT_MESSAGE_SIZE = 1024 }; 306 307 enum { kTargetPlayers = 0, 308 kTargetTeam = 1, 309 kTargetPlayer = 2, 310 kTargetClients = 3, 311 kTargetClient = 4 }; 312 313 NetworkChatMessage(const char *chatText = NULL, int16 senderID = 0, 314 int16 target = 0, int16 targetID = -1) mSenderID(senderID)315 : mSenderID(senderID), mTarget(target), mTargetID(targetID) 316 { 317 strncpy(mChatText, (chatText == NULL) ? "" : chatText, CHAT_MESSAGE_SIZE); 318 mChatText[CHAT_MESSAGE_SIZE - 1] = '\0'; 319 } 320 clone()321 NetworkChatMessage * clone() const { 322 return new NetworkChatMessage(*this); 323 } 324 type()325 MessageTypeID type() const { return kType; } chatText()326 const char *chatText() const { return mChatText; } senderID()327 int16 senderID() const { return mSenderID; } target()328 int16 target() const { return mTarget; } targetID()329 int16 targetID() const { return mTargetID; } 330 331 protected: 332 void reallyDeflateTo(AOStream& outputStream) const; 333 bool reallyInflateFrom(AIStream& includeStream); 334 335 private: 336 char mChatText[CHAT_MESSAGE_SIZE]; 337 int16 mSenderID; 338 int16 mTarget; 339 int16 mTargetID; 340 }; 341 342 class NetworkStatsMessage : public SmallMessageHelper 343 { 344 public: 345 enum { kType = kNETWORK_STATS_MESSAGE }; 346 NetworkStatsMessage()347 NetworkStatsMessage() : SmallMessageHelper() { } NetworkStatsMessage(const std::vector<NetworkStats> & stats)348 NetworkStatsMessage(const std::vector<NetworkStats>& stats) : SmallMessageHelper(), mStats(stats) { } 349 clone()350 NetworkStatsMessage* clone() const { 351 return new NetworkStatsMessage(*this); 352 } 353 type()354 MessageTypeID type() const { return kType; } 355 356 std::vector<NetworkStats> mStats; 357 protected: 358 void reallyDeflateTo(AOStream& outputStream) const; 359 bool reallyInflateFrom(AIStream& inputStream); 360 }; 361 362 class ServerWarningMessage : public SmallMessageHelper 363 { 364 public: 365 enum { kType = kSERVER_WARNING_MESSAGE }; 366 enum { kMaxStringSize = 1024 }; 367 368 enum Reason { 369 kNoReason, 370 kJoinerUngatherable 371 } ; 372 ServerWarningMessage()373 ServerWarningMessage() { } 374 ServerWarningMessage(std::string s,Reason reason)375 ServerWarningMessage(std::string s, Reason reason) : 376 mString(s), mReason(reason) { 377 assert(s.length() < kMaxStringSize); 378 } 379 clone()380 ServerWarningMessage *clone() const { 381 return new ServerWarningMessage(*this); 382 } 383 type()384 MessageTypeID type() const { return kType; } string(const std::string s)385 void string (const std::string s) { 386 assert(s.length() < kMaxStringSize); 387 mString = s; 388 } string()389 const std::string *string() { return &mString; } 390 391 protected: 392 void reallyDeflateTo(AOStream& outputStream) const; 393 bool reallyInflateFrom(AIStream& inputStream); 394 395 private: 396 std::string mString; 397 Reason mReason = kNoReason; 398 }; 399 400 401 class TopologyMessage : public SmallMessageHelper 402 { 403 public: 404 enum { kType = kTOPOLOGY_MESSAGE }; 405 TopologyMessage()406 TopologyMessage() : SmallMessageHelper() { } 407 TopologyMessage(NetTopology * topology)408 TopologyMessage(NetTopology *topology) : SmallMessageHelper() { 409 mTopology = *topology; 410 } 411 clone()412 TopologyMessage *clone() const { 413 return new TopologyMessage(*this); 414 } 415 topology()416 NetTopology *topology() { return &mTopology; } topology(const NetTopology * theTopology)417 void topology(const NetTopology *theTopology) { mTopology = *theTopology; } 418 type()419 MessageTypeID type() const { return kType; } 420 421 protected: 422 void reallyDeflateTo(AOStream& outputStream) const; 423 bool reallyInflateFrom(AIStream& inputStream); 424 425 private: 426 NetTopology mTopology = {}; 427 }; 428 429 struct Client { 430 Client(CommunicationsChannel *); 431 enum { 432 _connecting, 433 _connected_but_not_yet_shown, 434 _connected, 435 _awaiting_capabilities, 436 _ungatherable, 437 _joiner_didnt_accept, 438 _awaiting_accept_join, 439 _awaiting_map, 440 _ingame, 441 _disconnect 442 }; 443 444 CommunicationsChannel *channel; 445 short state; 446 uint16 network_version; 447 Capabilities capabilities; 448 char name[MAX_NET_PLAYER_NAME_LENGTH]; 449 450 static CheckPlayerProcPtr check_player; 451 452 ~Client(); 453 454 void drop(); 455 456 enum { 457 _dont_warn_joiner = false, 458 _warn_joiner = true 459 }; 460 bool capabilities_indicate_player_is_gatherable(bool warn_joiner); can_pregame_chatClient461 bool can_pregame_chat() { return ((state == _connected) || (state == _connected_but_not_yet_shown) || (state == _ungatherable) || (state == _joiner_didnt_accept) || (state == _awaiting_accept_join) || (state == _awaiting_map)); } 462 463 void handleJoinerInfoMessage(JoinerInfoMessage*, CommunicationsChannel*); 464 void unexpectedMessageHandler(Message *, CommunicationsChannel*); 465 void handleCapabilitiesMessage(CapabilitiesMessage*,CommunicationsChannel*); 466 void handleAcceptJoinMessage(AcceptJoinMessage*, CommunicationsChannel*); 467 void handleChatMessage(NetworkChatMessage*, CommunicationsChannel*); 468 void handleChangeColorsMessage(ChangeColorsMessage*, CommunicationsChannel*); 469 470 std::unique_ptr<MessageDispatcher> mDispatcher; 471 std::unique_ptr<MessageHandler> mJoinerInfoMessageHandler; 472 std::unique_ptr<MessageHandler> mUnexpectedMessageHandler; 473 std::unique_ptr<MessageHandler> mCapabilitiesMessageHandler; 474 std::unique_ptr<MessageHandler> mAcceptJoinMessageHandler; 475 std::unique_ptr<MessageHandler> mChatMessageHandler; 476 std::unique_ptr<MessageHandler> mChangeColorsMessageHandler; 477 }; 478 479 typedef TemplatizedDataMessage<kGAME_SESSION_MESSAGE, BigChunkOfDataMessage> GameSessionMessage; 480 481 482 #endif // NETWORK_MESSAGES_H 483