00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifdef ENABLE_NETWORK
00013
00014 #include "../stdafx.h"
00015 #include "../debug.h"
00016 #include "network_client.h"
00017 #include "network_server.h"
00018 #include "network.h"
00019 #include "../command_func.h"
00020 #include "../company_func.h"
00021 #include "../settings_type.h"
00022
00024 static CommandCallback * const _callback_table[] = {
00025 NULL,
00026 CcBuildPrimaryVehicle,
00027 CcBuildAirport,
00028 CcBuildBridge,
00029 CcBuildCanal,
00030 CcBuildDocks,
00031 CcFoundTown,
00032 CcBuildRoadTunnel,
00033 CcBuildRailTunnel,
00034 CcBuildWagon,
00035 CcRoadDepot,
00036 CcRailDepot,
00037 CcPlaceSign,
00038 CcPlaySound10,
00039 CcPlaySound1D,
00040 CcPlaySound1E,
00041 CcStation,
00042 CcTerraform,
00043 #ifdef ENABLE_AI
00044 CcAI,
00045 #else
00046 NULL,
00047 #endif
00048 CcCloneVehicle,
00049 CcGiveMoney,
00050 CcCreateGroup,
00051 CcFoundRandomTown,
00052 CcRoadStop,
00053 CcBuildIndustry,
00054 CcStartStopVehicle,
00055 };
00056
00062 void CommandQueue::Append(CommandPacket *p)
00063 {
00064 CommandPacket *add = MallocT<CommandPacket>(1);
00065 *add = *p;
00066 add->next = NULL;
00067 if (this->first == NULL) {
00068 this->first = add;
00069 } else {
00070 this->last->next = add;
00071 }
00072 this->last = add;
00073 this->count++;
00074 }
00075
00081 CommandPacket *CommandQueue::Pop(bool ignore_paused)
00082 {
00083 CommandPacket **prev = &this->first;
00084 CommandPacket *ret = this->first;
00085 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00086 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00087 prev = &ret->next;
00088 ret = ret->next;
00089 }
00090 }
00091 if (ret != NULL) {
00092 *prev = ret->next;
00093 this->count--;
00094 }
00095 return ret;
00096 }
00097
00103 CommandPacket *CommandQueue::Peek(bool ignore_paused)
00104 {
00105 if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first;
00106
00107 for (CommandPacket *p = this->first; p != NULL; p = p->next) {
00108 if (IsCommandAllowedWhilePaused(p->cmd)) return p;
00109 }
00110 return NULL;
00111 }
00112
00114 void CommandQueue::Free()
00115 {
00116 CommandPacket *cp;
00117 while ((cp = this->Pop()) != NULL) {
00118 free(cp);
00119 }
00120 assert(this->count == 0);
00121 }
00122
00124 static CommandQueue _local_wait_queue;
00126 static CommandQueue _local_execution_queue;
00127
00138 void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company)
00139 {
00140 assert((cmd & CMD_FLAGS_MASK) == 0);
00141
00142 CommandPacket c;
00143 c.company = company;
00144 c.tile = tile;
00145 c.p1 = p1;
00146 c.p2 = p2;
00147 c.cmd = cmd;
00148 c.callback = callback;
00149
00150 strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
00151
00152 if (_network_server) {
00153
00154
00155
00156
00157
00158
00159 c.frame = _frame_counter_max + 1;
00160 c.my_cmd = true;
00161
00162 _local_wait_queue.Append(&c);
00163 return;
00164 }
00165
00166 c.frame = 0;
00167
00168
00169 MyClient::SendCommand(&c);
00170 }
00171
00181 void NetworkSyncCommandQueue(NetworkClientSocket *cs)
00182 {
00183 for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) {
00184 CommandPacket c = *p;
00185 c.callback = 0;
00186 cs->outgoing_queue.Append(&c);
00187 }
00188 }
00189
00193 void NetworkExecuteLocalCommandQueue()
00194 {
00195 assert(IsLocalCompany());
00196
00197 CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue);
00198
00199 CommandPacket *cp;
00200 while ((cp = queue.Peek()) != NULL) {
00201
00202
00203 if (_frame_counter < cp->frame) break;
00204
00205 if (_frame_counter > cp->frame) {
00206
00207
00208 error("[net] Trying to execute a packet in the past!");
00209 }
00210
00211
00212 _current_company = cp->company;
00213 cp->cmd |= CMD_NETWORK_COMMAND;
00214 DoCommandP(cp, cp->my_cmd);
00215
00216 queue.Pop();
00217 free(cp);
00218 }
00219
00220
00221 _current_company = _local_company;
00222 }
00223
00227 void NetworkFreeLocalCommandQueue()
00228 {
00229 _local_execution_queue.Free();
00230 }
00231
00237 static void DistributeCommandPacket(CommandPacket cp, const NetworkClientSocket *owner)
00238 {
00239 CommandCallback *callback = cp.callback;
00240 cp.frame = _frame_counter_max + 1;
00241
00242 NetworkClientSocket *cs;
00243 FOR_ALL_CLIENT_SOCKETS(cs) {
00244 if (cs->status >= NetworkClientSocket::STATUS_MAP) {
00245
00246
00247 cp.callback = (cs != owner) ? NULL : callback;
00248 cp.my_cmd = (cs == owner);
00249 cs->outgoing_queue.Append(&cp);
00250 }
00251 }
00252
00253 cp.callback = (cs != owner) ? NULL : callback;
00254 cp.my_cmd = (cs == owner);
00255 _local_execution_queue.Append(&cp);
00256 }
00257
00263 static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner)
00264 {
00265 int to_go = _settings_client.network.commands_per_frame;
00266
00267 CommandPacket *cp;
00268 while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) {
00269 DistributeCommandPacket(*cp, owner);
00270 free(cp);
00271 }
00272 }
00273
00274 void NetworkDistributeCommands()
00275 {
00276
00277 DistributeQueue(&_local_wait_queue, NULL);
00278
00279
00280 NetworkClientSocket *cs;
00281 FOR_ALL_CLIENT_SOCKETS(cs) {
00282 DistributeQueue(&cs->incoming_queue, cs);
00283 }
00284 }
00285
00292 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00293 {
00294 cp->company = (CompanyID)p->Recv_uint8();
00295 cp->cmd = p->Recv_uint32();
00296 cp->p1 = p->Recv_uint32();
00297 cp->p2 = p->Recv_uint32();
00298 cp->tile = p->Recv_uint32();
00299 p->Recv_string(cp->text, lengthof(cp->text));
00300
00301 byte callback = p->Recv_uint8();
00302
00303 if (!IsValidCommand(cp->cmd)) return "invalid command";
00304 if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
00305 if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
00306 if (callback > lengthof(_callback_table)) return "invalid callback";
00307
00308 cp->callback = _callback_table[callback];
00309 return NULL;
00310 }
00311
00317 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00318 {
00319 p->Send_uint8 (cp->company);
00320 p->Send_uint32(cp->cmd);
00321 p->Send_uint32(cp->p1);
00322 p->Send_uint32(cp->p2);
00323 p->Send_uint32(cp->tile);
00324 p->Send_string(cp->text);
00325
00326 byte callback = 0;
00327 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00328 callback++;
00329 }
00330
00331 if (callback == lengthof(_callback_table)) {
00332 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00333 callback = 0;
00334 }
00335 p->Send_uint8 (callback);
00336 }
00337
00338 #endif