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 CcAddVehicleNewGroup,
00052 };
00053
00059 void CommandQueue::Append(CommandPacket *p)
00060 {
00061 CommandPacket *add = MallocT<CommandPacket>(1);
00062 *add = *p;
00063 add->next = NULL;
00064 if (this->first == NULL) {
00065 this->first = add;
00066 } else {
00067 this->last->next = add;
00068 }
00069 this->last = add;
00070 this->count++;
00071 }
00072
00078 CommandPacket *CommandQueue::Pop(bool ignore_paused)
00079 {
00080 CommandPacket **prev = &this->first;
00081 CommandPacket *ret = this->first;
00082 CommandPacket *prev_item = NULL;
00083 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00084 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00085 prev_item = ret;
00086 prev = &ret->next;
00087 ret = ret->next;
00088 }
00089 }
00090 if (ret != NULL) {
00091 if (ret == this->last) this->last = prev_item;
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_wait_queue.Free();
00230 _local_execution_queue.Free();
00231 }
00232
00238 static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket *owner)
00239 {
00240 CommandCallback *callback = cp.callback;
00241 cp.frame = _frame_counter_max + 1;
00242
00243 NetworkClientSocket *cs;
00244 FOR_ALL_CLIENT_SOCKETS(cs) {
00245 if (cs->status >= NetworkClientSocket::STATUS_MAP) {
00246
00247
00248 cp.callback = (cs != owner) ? NULL : callback;
00249 cp.my_cmd = (cs == owner);
00250 cs->outgoing_queue.Append(&cp);
00251 }
00252 }
00253
00254 cp.callback = (cs != owner) ? NULL : callback;
00255 cp.my_cmd = (cs == owner);
00256 _local_execution_queue.Append(&cp);
00257 }
00258
00264 static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner)
00265 {
00266 #ifdef DEBUG_DUMP_COMMANDS
00267
00268 int to_go = UINT16_MAX;
00269 #else
00270 int to_go = _settings_client.network.commands_per_frame;
00271 #endif
00272
00273 CommandPacket *cp;
00274 while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) {
00275 DistributeCommandPacket(*cp, owner);
00276 NetworkAdminCmdLogging(owner, cp);
00277 free(cp);
00278 }
00279 }
00280
00282 void NetworkDistributeCommands()
00283 {
00284
00285 DistributeQueue(&_local_wait_queue, NULL);
00286
00287
00288 NetworkClientSocket *cs;
00289 FOR_ALL_CLIENT_SOCKETS(cs) {
00290 DistributeQueue(&cs->incoming_queue, cs);
00291 }
00292 }
00293
00300 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00301 {
00302 cp->company = (CompanyID)p->Recv_uint8();
00303 cp->cmd = p->Recv_uint32();
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
00308 cp->p1 = p->Recv_uint32();
00309 cp->p2 = p->Recv_uint32();
00310 cp->tile = p->Recv_uint32();
00311 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);
00312
00313 byte callback = p->Recv_uint8();
00314 if (callback >= lengthof(_callback_table)) return "invalid callback";
00315
00316 cp->callback = _callback_table[callback];
00317 return NULL;
00318 }
00319
00325 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00326 {
00327 p->Send_uint8 (cp->company);
00328 p->Send_uint32(cp->cmd);
00329 p->Send_uint32(cp->p1);
00330 p->Send_uint32(cp->p2);
00331 p->Send_uint32(cp->tile);
00332 p->Send_string(cp->text);
00333
00334 byte callback = 0;
00335 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00336 callback++;
00337 }
00338
00339 if (callback == lengthof(_callback_table)) {
00340 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00341 callback = 0;
00342 }
00343 p->Send_uint8 (callback);
00344 }
00345
00346 #endif