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 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00085 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00086 prev = &ret->next;
00087 ret = ret->next;
00088 }
00089 }
00090 if (ret != NULL) {
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_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
00274 void NetworkDistributeCommands()
00275 {
00276
00277 DistributeQueue(&_local_wait_queue, NULL);
00278
00279
00280 NetworkClientSocket *cs;
00281 FOR_ALL_CLIENT_SOCKETS(cs) {
00282 DistributeQueue(&cs->incoming_queue, cs);
00283 }
00284 }
00285
00292 const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp)
00293 {
00294 cp->company = (CompanyID)p->Recv_uint8();
00295 cp->cmd = p->Recv_uint32();
00296 cp->p1 = p->Recv_uint32();
00297 cp->p2 = p->Recv_uint32();
00298 cp->tile = p->Recv_uint32();
00299 p->Recv_string(cp->text, lengthof(cp->text));
00300
00301 byte callback = p->Recv_uint8();
00302
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 if (callback > lengthof(_callback_table)) return "invalid callback";
00307
00308 cp->callback = _callback_table[callback];
00309 return NULL;
00310 }
00311
00317 void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
00318 {
00319 p->Send_uint8 (cp->company);
00320 p->Send_uint32(cp->cmd);
00321 p->Send_uint32(cp->p1);
00322 p->Send_uint32(cp->p2);
00323 p->Send_uint32(cp->tile);
00324 p->Send_string(cp->text);
00325
00326 byte callback = 0;
00327 while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
00328 callback++;
00329 }
00330
00331 if (callback == lengthof(_callback_table)) {
00332 DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback);
00333 callback = 0;
00334 }
00335 p->Send_uint8 (callback);
00336 }
00337
00338 #endif