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 CcGame,
00051 };
00052
00058 void CommandQueue::Append(CommandPacket *p)
00059 {
00060 CommandPacket *add = MallocT<CommandPacket>(1);
00061 *add = *p;
00062 add->next = NULL;
00063 if (this->first == NULL) {
00064 this->first = add;
00065 } else {
00066 this->last->next = add;
00067 }
00068 this->last = add;
00069 this->count++;
00070 }
00071
00077 CommandPacket *CommandQueue::Pop(bool ignore_paused)
00078 {
00079 CommandPacket **prev = &this->first;
00080 CommandPacket *ret = this->first;
00081 CommandPacket *prev_item = NULL;
00082 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00083 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00084 prev_item = ret;
00085 prev = &ret->next;
00086 ret = ret->next;
00087 }
00088 }
00089 if (ret != NULL) {
00090 if (ret == this->last) this->last = prev_item;
00091 *prev = ret->next;
00092 this->count--;
00093 }
00094 return ret;
00095 }
00096
00102 CommandPacket *CommandQueue::Peek(bool ignore_paused)
00103 {
00104 if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first;
00105
00106 for (CommandPacket *p = this->first; p != NULL; p = p->next) {
00107 if (IsCommandAllowedWhilePaused(p->cmd)) return p;
00108 }
00109 return NULL;
00110 }
00111
00113 void CommandQueue::Free()
00114 {
00115 CommandPacket *cp;
00116 while ((cp = this->Pop()) != NULL) {
00117 free(cp);
00118 }
00119 assert(this->count == 0);
00120 }
00121
00123 static CommandQueue _local_wait_queue;
00125 static CommandQueue _local_execution_queue;
00126
00137 void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company)
00138 {
00139 assert((cmd & CMD_FLAGS_MASK) == 0);
00140
00141 CommandPacket c;
00142 c.company = company;
00143 c.tile = tile;
00144 c.p1 = p1;
00145 c.p2 = p2;
00146 c.cmd = cmd;
00147 c.callback = callback;
00148
00149 strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
00150
00151 if (_network_server) {
00152
00153
00154
00155
00156
00157
00158 c.frame = _frame_counter_max + 1;
00159 c.my_cmd = true;
00160
00161 _local_wait_queue.Append(&c);
00162 return;
00163 }
00164
00165 c.frame = 0;
00166
00167
00168 MyClient::SendCommand(&c);
00169 }
00170
00180 void NetworkSyncCommandQueue(NetworkClientSocket *cs)
00181 {
00182 for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) {
00183 CommandPacket c = *p;
00184 c.callback = 0;
00185 cs->outgoing_queue.Append(&c);
00186 }
00187 }
00188
00192 void NetworkExecuteLocalCommandQueue()
00193 {
00194 assert(IsLocalCompany());
00195
00196 CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue);
00197
00198 CommandPacket *cp;
00199 while ((cp = queue.Peek()) != NULL) {
00200
00201
00202 if (_frame_counter < cp->frame) break;
00203
00204 if (_frame_counter > cp->frame) {
00205
00206
00207 error("[net] Trying to execute a packet in the past!");
00208 }
00209
00210
00211 _current_company = cp->company;
00212 cp->cmd |= CMD_NETWORK_COMMAND;
00213 DoCommandP(cp, cp->my_cmd);
00214
00215 queue.Pop();
00216 free(cp);
00217 }
00218
00219
00220 _current_company = _local_company;
00221 }
00222
00226 void NetworkFreeLocalCommandQueue()
00227 {
00228 _local_wait_queue.Free();
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 NetworkAdminCmdLogging(owner, cp);
00271 free(cp);
00272 }
00273 }
00274
00276 void NetworkDistributeCommands()
00277 {
00278
00279 DistributeQueue(&_local_wait_queue, NULL);
00280
00281
00282 NetworkClientSocket *cs;
00283 FOR_ALL_CLIENT_SOCKETS(cs) {
00284 DistributeQueue(&cs->incoming_queue, cs);
00285 }
00286 }
00287
00294 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00295 {
00296 cp->company = (CompanyID)p->Recv_uint8();
00297 cp->cmd = p->Recv_uint32();
00298 if (!IsValidCommand(cp->cmd)) return "invalid command";
00299 if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
00300 if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
00301
00302 cp->p1 = p->Recv_uint32();
00303 cp->p2 = p->Recv_uint32();
00304 cp->tile = p->Recv_uint32();
00305 p->Recv_string(cp->text, lengthof(cp->text), (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK);
00306
00307 byte callback = p->Recv_uint8();
00308 if (callback >= lengthof(_callback_table)) return "invalid callback";
00309
00310 cp->callback = _callback_table[callback];
00311 return NULL;
00312 }
00313
00319 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00320 {
00321 p->Send_uint8 (cp->company);
00322 p->Send_uint32(cp->cmd);
00323 p->Send_uint32(cp->p1);
00324 p->Send_uint32(cp->p2);
00325 p->Send_uint32(cp->tile);
00326 p->Send_string(cp->text);
00327
00328 byte callback = 0;
00329 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00330 callback++;
00331 }
00332
00333 if (callback == lengthof(_callback_table)) {
00334 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00335 callback = 0;
00336 }
00337 p->Send_uint8 (callback);
00338 }
00339
00340 #endif