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