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