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 CcAI,
00043 CcCloneVehicle,
00044 CcGiveMoney,
00045 CcCreateGroup,
00046 CcFoundRandomTown,
00047 CcRoadStop,
00048 CcBuildIndustry,
00049 CcStartStopVehicle,
00050 };
00051
00057 void CommandQueue::Append(CommandPacket *p)
00058 {
00059 CommandPacket *add = MallocT<CommandPacket>(1);
00060 *add = *p;
00061 add->next = NULL;
00062 if (this->first == NULL) {
00063 this->first = add;
00064 } else {
00065 this->last->next = add;
00066 }
00067 this->last = add;
00068 this->count++;
00069 }
00070
00076 CommandPacket *CommandQueue::Pop(bool ignore_paused)
00077 {
00078 CommandPacket **prev = &this->first;
00079 CommandPacket *ret = this->first;
00080 CommandPacket *prev_item = NULL;
00081 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00082 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00083 prev_item = ret;
00084 prev = &ret->next;
00085 ret = ret->next;
00086 }
00087 }
00088 if (ret != NULL) {
00089 if (ret == this->last) this->last = prev_item;
00090 *prev = ret->next;
00091 this->count--;
00092 }
00093 return ret;
00094 }
00095
00101 CommandPacket *CommandQueue::Peek(bool ignore_paused)
00102 {
00103 if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first;
00104
00105 for (CommandPacket *p = this->first; p != NULL; p = p->next) {
00106 if (IsCommandAllowedWhilePaused(p->cmd)) return p;
00107 }
00108 return NULL;
00109 }
00110
00112 void CommandQueue::Free()
00113 {
00114 CommandPacket *cp;
00115 while ((cp = this->Pop()) != NULL) {
00116 free(cp);
00117 }
00118 assert(this->count == 0);
00119 }
00120
00122 static CommandQueue _local_wait_queue;
00124 static CommandQueue _local_execution_queue;
00125
00136 void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company)
00137 {
00138 assert((cmd & CMD_FLAGS_MASK) == 0);
00139
00140 CommandPacket c;
00141 c.company = company;
00142 c.tile = tile;
00143 c.p1 = p1;
00144 c.p2 = p2;
00145 c.cmd = cmd;
00146 c.callback = callback;
00147
00148 strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
00149
00150 if (_network_server) {
00151
00152
00153
00154
00155
00156
00157 c.frame = _frame_counter_max + 1;
00158 c.my_cmd = true;
00159
00160 _local_wait_queue.Append(&c);
00161 return;
00162 }
00163
00164 c.frame = 0;
00165
00166
00167 MyClient::SendCommand(&c);
00168 }
00169
00179 void NetworkSyncCommandQueue(NetworkClientSocket *cs)
00180 {
00181 for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) {
00182 CommandPacket c = *p;
00183 c.callback = 0;
00184 cs->outgoing_queue.Append(&c);
00185 }
00186 }
00187
00191 void NetworkExecuteLocalCommandQueue()
00192 {
00193 assert(IsLocalCompany());
00194
00195 CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue);
00196
00197 CommandPacket *cp;
00198 while ((cp = queue.Peek()) != NULL) {
00199
00200
00201 if (_frame_counter < cp->frame) break;
00202
00203 if (_frame_counter > cp->frame) {
00204
00205
00206 error("[net] Trying to execute a packet in the past!");
00207 }
00208
00209
00210 _current_company = cp->company;
00211 cp->cmd |= CMD_NETWORK_COMMAND;
00212 DoCommandP(cp, cp->my_cmd);
00213
00214 queue.Pop();
00215 free(cp);
00216 }
00217
00218
00219 _current_company = _local_company;
00220 }
00221
00225 void NetworkFreeLocalCommandQueue()
00226 {
00227 _local_wait_queue.Free();
00228 _local_execution_queue.Free();
00229 }
00230
00236 static void DistributeCommandPacket(CommandPacket cp, const NetworkClientSocket *owner)
00237 {
00238 CommandCallback *callback = cp.callback;
00239 cp.frame = _frame_counter_max + 1;
00240
00241 NetworkClientSocket *cs;
00242 FOR_ALL_CLIENT_SOCKETS(cs) {
00243 if (cs->status >= NetworkClientSocket::STATUS_MAP) {
00244
00245
00246 cp.callback = (cs != owner) ? NULL : callback;
00247 cp.my_cmd = (cs == owner);
00248 cs->outgoing_queue.Append(&cp);
00249 }
00250 }
00251
00252 cp.callback = (cs != owner) ? NULL : callback;
00253 cp.my_cmd = (cs == owner);
00254 _local_execution_queue.Append(&cp);
00255 }
00256
00262 static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner)
00263 {
00264 int to_go = _settings_client.network.commands_per_frame;
00265
00266 CommandPacket *cp;
00267 while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) {
00268 DistributeCommandPacket(*cp, owner);
00269 NetworkAdminCmdLogging(owner, cp);
00270 free(cp);
00271 }
00272 }
00273
00275 void NetworkDistributeCommands()
00276 {
00277
00278 DistributeQueue(&_local_wait_queue, NULL);
00279
00280
00281 NetworkClientSocket *cs;
00282 FOR_ALL_CLIENT_SOCKETS(cs) {
00283 DistributeQueue(&cs->incoming_queue, cs);
00284 }
00285 }
00286
00293 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00294 {
00295 cp->company = (CompanyID)p->Recv_uint8();
00296 cp->cmd = p->Recv_uint32();
00297 cp->p1 = p->Recv_uint32();
00298 cp->p2 = p->Recv_uint32();
00299 cp->tile = p->Recv_uint32();
00300 p->Recv_string(cp->text, lengthof(cp->text));
00301
00302 byte callback = p->Recv_uint8();
00303
00304 if (!IsValidCommand(cp->cmd)) return "invalid command";
00305 if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
00306 if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
00307 if (callback >= lengthof(_callback_table)) return "invalid callback";
00308
00309 cp->callback = _callback_table[callback];
00310 return NULL;
00311 }
00312
00318 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00319 {
00320 p->Send_uint8 (cp->company);
00321 p->Send_uint32(cp->cmd);
00322 p->Send_uint32(cp->p1);
00323 p->Send_uint32(cp->p2);
00324 p->Send_uint32(cp->tile);
00325 p->Send_string(cp->text);
00326
00327 byte callback = 0;
00328 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00329 callback++;
00330 }
00331
00332 if (callback == lengthof(_callback_table)) {
00333 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00334 callback = 0;
00335 }
00336 p->Send_uint8 (callback);
00337 }
00338
00339 #endif