1 /*
2  *  StarGameProtocol.cpp
3 
4 	Copyright (C) 2003 and beyond by Woody Zenfell, III
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  *  Created by Woody Zenfell, III on Sat May 17 2003.
22  *
23  *  Glue to make the star network protocol code interface with the rest of A1.
24  *
25  *  May 27, 2003 (Woody Zenfell):
26  *	Support for lossy streaming data distribution.
27  */
28 
29 #if !defined(DISABLE_NETWORKING)
30 
31 #include "cseries.h"
32 
33 #include "StarGameProtocol.h"
34 
35 #include "network_star.h"
36 #include "TickBasedCircularQueue.h"
37 #include "player.h" // GetRealActionQueues
38 #include "interface.h" // process_action_flags (despite paf() being defined in vbl.*)
39 #include "InfoTree.h"
40 
41 // This is a bit hacky yeah, we really ought to check both RealActionQueues and the recording queues, etc.
42 template <typename tValueType>
43 class LegacyActionQueueToTickBasedQueueAdapter : public WritableTickBasedCircularQueue<tValueType> {
44 public:
LegacyActionQueueToTickBasedQueueAdapter(int inTargetPlayerIndex)45         explicit LegacyActionQueueToTickBasedQueueAdapter(int inTargetPlayerIndex) : mPlayerIndex(inTargetPlayerIndex) { reset(0); }
reset(int32 inTick)46         void reset(int32 inTick) { mWriteTick = inTick; GetRealActionQueues()->resetQueue(mPlayerIndex); }
availableCapacity() const47         int32 availableCapacity() const { return GetRealActionQueues()->availableCapacity(mPlayerIndex); }
enqueue(const tValueType & inFlags)48         void enqueue(const tValueType& inFlags) { process_action_flags(mPlayerIndex, static_cast<const uint32 *>(&inFlags), 1);  ++mWriteTick; }
getWriteTick() const49         int32 getWriteTick() const { return mWriteTick; }
50 
51 protected:
52         int 	mPlayerIndex;
53         int32	mWriteTick;
54 };
55 
56 
57 static WritableTickBasedActionQueue* sStarQueues[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
58 static bool		sHubIsLocal;
59 static NetTopology*	sTopology = NULL;
60 static short*		sNetStatePtr = NULL;
61 
62 
63 bool
Enter(short * inNetStatePtr)64 StarGameProtocol::Enter(short* inNetStatePtr)
65 {
66 	sNetStatePtr = inNetStatePtr;
67 	return true;
68 }
69 
70 
71 
72 void
Exit1()73 StarGameProtocol::Exit1()
74 {
75 //	return true;
76 }
77 
78 
79 
80 void
Exit2()81 StarGameProtocol::Exit2()
82 {
83 //	return true;
84 }
85 
86 
87 
88 void
DistributeInformation(short type,void * buffer,short buffer_size,bool send_to_self,bool only_send_to_team)89 StarGameProtocol::DistributeInformation(short type, void *buffer, short buffer_size, bool send_to_self, bool only_send_to_team)
90 {
91 	const NetDistributionInfo* theInfo = NetGetDistributionInfoForType(type);
92 	if(theInfo != NULL && theInfo->lossy)
93 		spoke_distribute_lossy_streaming_bytes_to_everyone(type, static_cast<byte*>(buffer), buffer_size, !send_to_self, only_send_to_team);
94 }
95 
96 
97 
98 void
PacketHandler(DDPPacketBufferPtr packet)99 StarGameProtocol::PacketHandler(DDPPacketBufferPtr packet)
100 {
101         if(sHubIsLocal)
102                 hub_received_network_packet(packet);
103         else
104                 spoke_received_network_packet(packet);
105 }
106 
107 
108 
109 bool
Sync(NetTopology * inTopology,int32 inSmallestGameTick,size_t inLocalPlayerIndex,size_t inServerPlayerIndex)110 StarGameProtocol::Sync(NetTopology* inTopology, int32 inSmallestGameTick, size_t inLocalPlayerIndex, size_t inServerPlayerIndex)
111 {
112 	assert(inTopology != NULL);
113 
114 	sTopology = inTopology;
115 
116         bool theConnectedPlayerStatus[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
117 
118         for(int i = 0; i < sTopology->player_count; i++)
119         {
120                 if(sTopology->players[i].identifier == NONE)
121                         sStarQueues[i] = NULL;
122                 else
123                         sStarQueues[i] = new LegacyActionQueueToTickBasedQueueAdapter<action_flags_t>(i);
124 
125                 theConnectedPlayerStatus[i] = ((sTopology->players[i].identifier != NONE) && !sTopology->players[i].net_dead);
126         }
127 
128         if(inLocalPlayerIndex == inServerPlayerIndex)
129         {
130 		sHubIsLocal = true;
131 
132                 NetAddrBlock* theAddresses[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
133 
134                 for(int i = 0; i < sTopology->player_count; i++)
135                         theAddresses[i] = (theConnectedPlayerStatus[i] ? &(sTopology->players[i].ddpAddress) : NULL);
136 
137                 hub_initialize(inSmallestGameTick, sTopology->player_count, theAddresses, inLocalPlayerIndex);
138         }
139 	else
140 		sHubIsLocal = false;
141 
142         spoke_initialize(sTopology->players[inServerPlayerIndex].ddpAddress, inSmallestGameTick, sTopology->player_count,
143                          sStarQueues, theConnectedPlayerStatus, inLocalPlayerIndex, sHubIsLocal);
144 
145         *sNetStatePtr = netActive;
146 
147         return true;
148 }
149 
150 
151 
152 bool
UnSync(bool inGraceful,int32 inSmallestPostgameTick)153 StarGameProtocol::UnSync(bool inGraceful, int32 inSmallestPostgameTick)
154 {
155         if(*sNetStatePtr == netStartingUp || *sNetStatePtr == netActive)
156         {
157                 spoke_cleanup(inGraceful);
158                 if(sHubIsLocal)
159                         hub_cleanup(inGraceful, inSmallestPostgameTick);
160 
161                 for(int i = 0; i < sTopology->player_count; i++)
162                 {
163                         if(sStarQueues[i] != NULL)
164                         {
165                                 delete sStarQueues[i];
166                                 sStarQueues[i] = NULL;
167                         }
168                 }
169         }
170 
171         *sNetStatePtr = netDown;
172 
173         return true;
174 }
175 
176 
177 
178 int32
GetNetTime(void)179 StarGameProtocol::GetNetTime(void)
180 {
181         return spoke_get_net_time();
182 }
183 
184 int32
GetUnconfirmedActionFlagsCount()185 StarGameProtocol::GetUnconfirmedActionFlagsCount()
186 {
187 	TickBasedActionQueue *q = spoke_get_unconfirmed_flags_queue();
188 	return q->getWriteTick() - q->getReadTick();
189 }
190 
191 uint32
PeekUnconfirmedActionFlag(int32 offset)192 StarGameProtocol::PeekUnconfirmedActionFlag(int32 offset)
193 {
194 	TickBasedActionQueue *q = spoke_get_unconfirmed_flags_queue();
195 	return q->peek(q->getReadTick() + offset);
196 }
197 
198 void
UpdateUnconfirmedActionFlags()199 StarGameProtocol::UpdateUnconfirmedActionFlags()
200 {
201 	TickBasedActionQueue *q = spoke_get_unconfirmed_flags_queue();
202 	while (q->getReadTick() < spoke_get_smallest_unconfirmed_tick() && q->getReadTick() < q->getWriteTick())
203 	{
204 		q->dequeue();
205 	}
206 }
207 
208 /* ZZZ addition:
209 ---------------------------
210 	make_player_really_net_dead
211 ---------------------------
212 
213 ---> player index of newly net-dead player
214 
215 	sets up our housekeeping here to mark a player as net-dead.
216 	*/
217 
218 void
make_player_really_net_dead(size_t inPlayerIndex)219 make_player_really_net_dead(size_t inPlayerIndex)
220 {
221         assert(inPlayerIndex < static_cast<size_t>(sTopology->player_count));
222         sTopology->players[inPlayerIndex].net_dead = true;
223 }
224 
225 
226 
227 void
call_distribution_response_function_if_available(byte * inBuffer,uint16 inBufferSize,int16 inDistributionType,uint8 inSendingPlayerIndex)228 call_distribution_response_function_if_available(byte* inBuffer, uint16 inBufferSize, int16 inDistributionType, uint8 inSendingPlayerIndex)
229 {
230 	const NetDistributionInfo* theInfo = NetGetDistributionInfoForType(inDistributionType);
231 	if(theInfo != NULL)
232 		theInfo->distribution_proc(inBuffer, inBufferSize, inSendingPlayerIndex);
233 }
234 
235 
236 
237 void
ParsePreferencesTree(InfoTree prefs,std::string version)238 StarGameProtocol::ParsePreferencesTree(InfoTree prefs, std::string version)
239 {
240 	BOOST_FOREACH(InfoTree child, prefs.children_named("hub"))
241 		HubParsePreferencesTree(child, version);
242 	BOOST_FOREACH(InfoTree child, prefs.children_named("spoke"))
243 		SpokeParsePreferencesTree(child, version);
244 }
245 
246 
247 
248 void
DefaultStarPreferences()249 DefaultStarPreferences()
250 {
251 	DefaultHubPreferences();
252 	DefaultSpokePreferences();
253 }
254 
255 
256 
StarPreferencesTree()257 InfoTree StarPreferencesTree()
258 {
259 	InfoTree root;
260 	root.put_child("hub", HubPreferencesTree());
261 	root.put_child("spoke", SpokePreferencesTree());
262 	return root;
263 }
264 
265 #endif // !defined(DISABLE_NETWORKING)
266