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
00278 void NetworkDistributeCommands()
00279 {
00280
00281 DistributeQueue(&_local_wait_queue, NULL);
00282
00283
00284 NetworkClientSocket *cs;
00285 FOR_ALL_CLIENT_SOCKETS(cs) {
00286 DistributeQueue(&cs->incoming_queue, cs);
00287 }
00288 }
00289
00296 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00297 {
00298 cp->company = (CompanyID)p->Recv_uint8();
00299 cp->cmd = p->Recv_uint32();
00300 cp->p1 = p->Recv_uint32();
00301 cp->p2 = p->Recv_uint32();
00302 cp->tile = p->Recv_uint32();
00303 p->Recv_string(cp->text, lengthof(cp->text));
00304
00305 byte callback = p->Recv_uint8();
00306
00307 if (!IsValidCommand(cp->cmd)) return "invalid command";
00308 if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
00309 if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
00310 if (callback >= lengthof(_callback_table)) return "invalid callback";
00311
00312 cp->callback = _callback_table[callback];
00313 return NULL;
00314 }
00315
00321 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00322 {
00323 p->Send_uint8 (cp->company);
00324 p->Send_uint32(cp->cmd);
00325 p->Send_uint32(cp->p1);
00326 p->Send_uint32(cp->p2);
00327 p->Send_uint32(cp->tile);
00328 p->Send_string(cp->text);
00329
00330 byte callback = 0;
00331 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00332 callback++;
00333 }
00334
00335 if (callback == lengthof(_callback_table)) {
00336 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00337 callback = 0;
00338 }
00339 p->Send_uint8 (callback);
00340 }
00341
00342 #endif