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 #ifdef DEBUG_DUMP_COMMANDS
00266
00267 int to_go = UINT16_MAX;
00268 #else
00269 int to_go = _settings_client.network.commands_per_frame;
00270 #endif
00271
00272 CommandPacket *cp;
00273 while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) {
00274 DistributeCommandPacket(*cp, owner);
00275 NetworkAdminCmdLogging(owner, cp);
00276 free(cp);
00277 }
00278 }
00279
00281 void NetworkDistributeCommands()
00282 {
00283
00284 DistributeQueue(&_local_wait_queue, NULL);
00285
00286
00287 NetworkClientSocket *cs;
00288 FOR_ALL_CLIENT_SOCKETS(cs) {
00289 DistributeQueue(&cs->incoming_queue, cs);
00290 }
00291 }
00292
00299 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00300 {
00301 cp->company = (CompanyID)p->Recv_uint8();
00302 cp->cmd = p->Recv_uint32();
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
00307 cp->p1 = p->Recv_uint32();
00308 cp->p2 = p->Recv_uint32();
00309 cp->tile = p->Recv_uint32();
00310 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);
00311
00312 byte callback = p->Recv_uint8();
00313 if (callback >= lengthof(_callback_table)) return "invalid callback";
00314
00315 cp->callback = _callback_table[callback];
00316 return NULL;
00317 }
00318
00324 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00325 {
00326 p->Send_uint8 (cp->company);
00327 p->Send_uint32(cp->cmd);
00328 p->Send_uint32(cp->p1);
00329 p->Send_uint32(cp->p2);
00330 p->Send_uint32(cp->tile);
00331 p->Send_string(cp->text);
00332
00333 byte callback = 0;
00334 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00335 callback++;
00336 }
00337
00338 if (callback == lengthof(_callback_table)) {
00339 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00340 callback = 0;
00341 }
00342 p->Send_uint8 (callback);
00343 }
00344
00345 #endif