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