00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifdef ENABLE_NETWORK
00013
00014 #include "../stdafx.h"
00015 #include "../debug.h"
00016 #include "network_admin.h"
00017 #include "network_client.h"
00018 #include "network_server.h"
00019 #include "network.h"
00020 #include "../command_func.h"
00021 #include "../company_func.h"
00022 #include "../settings_type.h"
00023
00025 static CommandCallback * const _callback_table[] = {
00026 NULL,
00027 CcBuildPrimaryVehicle,
00028 CcBuildAirport,
00029 CcBuildBridge,
00030 CcBuildCanal,
00031 CcBuildDocks,
00032 CcFoundTown,
00033 CcBuildRoadTunnel,
00034 CcBuildRailTunnel,
00035 CcBuildWagon,
00036 CcRoadDepot,
00037 CcRailDepot,
00038 CcPlaceSign,
00039 CcPlaySound10,
00040 CcPlaySound1D,
00041 CcPlaySound1E,
00042 CcStation,
00043 CcTerraform,
00044 #ifdef ENABLE_AI
00045 CcAI,
00046 #else
00047 NULL,
00048 #endif
00049 CcCloneVehicle,
00050 CcGiveMoney,
00051 CcCreateGroup,
00052 CcFoundRandomTown,
00053 CcRoadStop,
00054 CcBuildIndustry,
00055 CcStartStopVehicle,
00056 };
00057
00063 void CommandQueue::Append(CommandPacket *p)
00064 {
00065 CommandPacket *add = MallocT<CommandPacket>(1);
00066 *add = *p;
00067 add->next = NULL;
00068 if (this->first == NULL) {
00069 this->first = add;
00070 } else {
00071 this->last->next = add;
00072 }
00073 this->last = add;
00074 this->count++;
00075 }
00076
00082 CommandPacket *CommandQueue::Pop(bool ignore_paused)
00083 {
00084 CommandPacket **prev = &this->first;
00085 CommandPacket *ret = this->first;
00086 if (ignore_paused && _pause_mode != PM_UNPAUSED) {
00087 while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) {
00088 prev = &ret->next;
00089 ret = ret->next;
00090 }
00091 }
00092 if (ret != NULL) {
00093 *prev = ret->next;
00094 this->count--;
00095 }
00096 return ret;
00097 }
00098
00104 CommandPacket *CommandQueue::Peek(bool ignore_paused)
00105 {
00106 if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first;
00107
00108 for (CommandPacket *p = this->first; p != NULL; p = p->next) {
00109 if (IsCommandAllowedWhilePaused(p->cmd)) return p;
00110 }
00111 return NULL;
00112 }
00113
00115 void CommandQueue::Free()
00116 {
00117 CommandPacket *cp;
00118 while ((cp = this->Pop()) != NULL) {
00119 free(cp);
00120 }
00121 assert(this->count == 0);
00122 }
00123
00125 static CommandQueue _local_wait_queue;
00127 static CommandQueue _local_execution_queue;
00128
00139 void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company)
00140 {
00141 assert((cmd & CMD_FLAGS_MASK) == 0);
00142
00143 CommandPacket c;
00144 c.company = company;
00145 c.tile = tile;
00146 c.p1 = p1;
00147 c.p2 = p2;
00148 c.cmd = cmd;
00149 c.callback = callback;
00150
00151 strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
00152
00153 if (_network_server) {
00154
00155
00156
00157
00158
00159
00160 c.frame = _frame_counter_max + 1;
00161 c.my_cmd = true;
00162
00163 _local_wait_queue.Append(&c);
00164 return;
00165 }
00166
00167 c.frame = 0;
00168
00169
00170 MyClient::SendCommand(&c);
00171 }
00172
00182 void NetworkSyncCommandQueue(NetworkClientSocket *cs)
00183 {
00184 for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) {
00185 CommandPacket c = *p;
00186 c.callback = 0;
00187 cs->outgoing_queue.Append(&c);
00188 }
00189 }
00190
00194 void NetworkExecuteLocalCommandQueue()
00195 {
00196 assert(IsLocalCompany());
00197
00198 CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue);
00199
00200 CommandPacket *cp;
00201 while ((cp = queue.Peek()) != NULL) {
00202
00203
00204 if (_frame_counter < cp->frame) break;
00205
00206 if (_frame_counter > cp->frame) {
00207
00208
00209 error("[net] Trying to execute a packet in the past!");
00210 }
00211
00212
00213 _current_company = cp->company;
00214 cp->cmd |= CMD_NETWORK_COMMAND;
00215 DoCommandP(cp, cp->my_cmd);
00216
00217 queue.Pop();
00218 free(cp);
00219 }
00220
00221
00222 _current_company = _local_company;
00223 }
00224
00228 void NetworkFreeLocalCommandQueue()
00229 {
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 int to_go = _settings_client.network.commands_per_frame;
00267
00268 CommandPacket *cp;
00269 while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) {
00270 DistributeCommandPacket(*cp, owner);
00271 NetworkAdminCmdLogging(owner, cp);
00272 free(cp);
00273 }
00274 }
00275
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 cp->p1 = p->Recv_uint32();
00299 cp->p2 = p->Recv_uint32();
00300 cp->tile = p->Recv_uint32();
00301 p->Recv_string(cp->text, lengthof(cp->text));
00302
00303 byte callback = p->Recv_uint8();
00304
00305 if (!IsValidCommand(cp->cmd)) return "invalid command";
00306 if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
00307 if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
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