|
@@ -12,24 +12,26 @@
|
|
|
#include "vehicle.h"
|
|
|
#include "station.h"
|
|
|
#include "settings.h"
|
|
|
|
|
|
// This file handles all the server-commands
|
|
|
|
|
|
void NetworkHandleCommandQueue(ClientState *cs);
|
|
|
void NetworkHandleCommandQueue(NetworkClientState *cs);
|
|
|
void NetworkPopulateCompanyInfo(void);
|
|
|
void NetworkSendPatchSettings(ClientState *cs);
|
|
|
void NetworkSendPatchSettings(NetworkClientState *cs);
|
|
|
|
|
|
extern const char _openttd_revision[];
|
|
|
|
|
|
// Is the network enabled?
|
|
|
|
|
|
// **********
|
|
|
// Sending functions
|
|
|
// DEF_SERVER_SEND_COMMAND has parameter: ClientState *cs
|
|
|
// DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs
|
|
|
// **********
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(ClientState *cs, NetworkClientInfo *ci)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_CLIENT_INFO
|
|
|
// Function: Sends info about a client
|
|
|
// Data:
|
|
|
// uint16: The index of the client (always unique on a server. 1 = server)
|
|
@@ -116,22 +118,22 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_CO
|
|
|
NetworkSend_string(p, _network_player_info[player->index].players);
|
|
|
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(ClientState *cs, NetworkErrorCode error)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_ERROR
|
|
|
// Function: The client made an error
|
|
|
// Data:
|
|
|
// uint8: ErrorID (see network_data.h, NetworkErrorCode)
|
|
|
//
|
|
|
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
char str1[100], str2[100];
|
|
|
char client_name[NETWORK_NAME_LENGTH];
|
|
|
|
|
|
Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR);
|
|
|
NetworkSend_uint8(p, error);
|
|
|
NetworkSend_Packet(p, cs);
|
|
@@ -164,16 +166,16 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
|
|
|
cs->quited = true;
|
|
|
|
|
|
// Make sure the data get's there before we close the connection
|
|
|
NetworkSend_Packets(cs);
|
|
|
|
|
|
// The client made a mistake, so drop his connection now!
|
|
|
CloseClient(cs);
|
|
|
NetworkCloseClient(cs);
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(ClientState *cs, NetworkPasswordType type)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_NEED_PASSWORD
|
|
|
// Function: Indication to the client that the server needs a password
|
|
|
// Data:
|
|
|
// uint8: Type of password
|
|
@@ -191,13 +193,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WE
|
|
|
// Function: The client is joined and ready to receive his map
|
|
|
// Data:
|
|
|
// uint16: Own ClientID
|
|
|
//
|
|
|
|
|
|
Packet *p;
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
|
|
|
// Invalid packet when status is AUTH or higher
|
|
|
if (cs->status >= STATUS_AUTH)
|
|
|
return;
|
|
|
|
|
|
cs->status = STATUS_AUTH;
|
|
@@ -223,13 +225,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WA
|
|
|
// Function: The client can not receive the map at the moment because
|
|
|
// someone else is already receiving the map
|
|
|
// Data:
|
|
|
// uint8: Clients awaiting map
|
|
|
//
|
|
|
int waiting = 0;
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
Packet *p;
|
|
|
|
|
|
// Count how many players are waiting in the queue
|
|
|
FOR_ALL_CLIENTS(new_cs) {
|
|
|
if (new_cs->status == STATUS_MAP_WAIT)
|
|
|
waiting++;
|
|
@@ -324,13 +326,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA
|
|
|
// Set the status to DONE_MAP, no we will wait for the client
|
|
|
// to send it is ready (maybe that happens like never ;))
|
|
|
cs->status = STATUS_DONE_MAP;
|
|
|
fclose(file_pointer);
|
|
|
|
|
|
{
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
bool new_map_client = false;
|
|
|
// Check if there is a client waiting for receiving the map
|
|
|
// and start sending him the map
|
|
|
FOR_ALL_CLIENTS(new_cs) {
|
|
|
if (new_cs->status == STATUS_MAP_WAIT) {
|
|
|
// Check if we already have a new client to send the map to
|
|
@@ -361,13 +363,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA
|
|
|
// Not everything is sent, decrease the sent_packets
|
|
|
if (sent_packets > 1) sent_packets /= 2;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(ClientState *cs, uint16 client_index)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_JOIN
|
|
|
// Function: A client is joined (all active clients receive this after a
|
|
|
// PACKET_CLIENT_MAP_OK) Mostly what directly follows is a
|
|
|
// PACKET_SERVER_CLIENT_INFO
|
|
@@ -427,13 +429,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SY
|
|
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
|
|
NetworkSend_uint32(p, _sync_seed_2);
|
|
|
#endif
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(ClientState *cs, CommandPacket *cp)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_COMMAND
|
|
|
// Function: Sends a DoCommand to the client
|
|
|
// Data:
|
|
|
// uint8: PlayerID (0..MAX_PLAYERS-1)
|
|
@@ -467,13 +469,13 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
|
|
|
NetworkSend_uint8(p, cp->callback);
|
|
|
NetworkSend_uint32(p, cp->frame);
|
|
|
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(ClientState *cs, NetworkAction action, uint16 client_index, const char *msg)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, const char *msg)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_CHAT
|
|
|
// Function: Sends a chat-packet to the client
|
|
|
// Data:
|
|
|
// uint8: ActionID (see network_data.h, NetworkAction)
|
|
@@ -487,13 +489,13 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
|
|
|
NetworkSend_uint16(p, client_index);
|
|
|
NetworkSend_string(p, msg);
|
|
|
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(ClientState *cs, uint16 client_index, NetworkErrorCode errorno)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_ERROR_QUIT
|
|
|
// Function: One of the clients made an error and is quiting the game
|
|
|
// This packet informs the other clients of that.
|
|
|
// Data:
|
|
@@ -506,13 +508,13 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
|
|
|
NetworkSend_uint16(p, client_index);
|
|
|
NetworkSend_uint8(p, errorno);
|
|
|
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(ClientState *cs, uint16 client_index, const char *leavemsg)
|
|
|
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg)
|
|
|
{
|
|
|
//
|
|
|
// Packet: SERVER_ERROR_QUIT
|
|
|
// Function: A client left the game, and this packets informs the other clients
|
|
|
// of that.
|
|
|
// Data:
|
|
@@ -553,22 +555,20 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NE
|
|
|
Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME);
|
|
|
NetworkSend_Packet(p, cs);
|
|
|
}
|
|
|
|
|
|
// **********
|
|
|
// Receiving functions
|
|
|
// DEF_SERVER_RECEIVE_COMMAND has parameter: ClientState *cs, Packet *p
|
|
|
// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p
|
|
|
// **********
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO)
|
|
|
{
|
|
|
SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs);
|
|
|
}
|
|
|
|
|
|
extern const char _openttd_revision[];
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
|
|
|
{
|
|
|
char name[NETWORK_NAME_LENGTH];
|
|
|
char unique_id[NETWORK_NAME_LENGTH];
|
|
|
NetworkClientInfo *ci;
|
|
|
char test_name[NETWORK_NAME_LENGTH];
|
|
@@ -679,13 +679,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP)
|
|
|
{
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
|
|
|
// The client was never joined.. so this is impossible, right?
|
|
|
// Ignore the packet, give the client a warning, and close his connection
|
|
|
if (cs->status < STATUS_AUTH || cs->quited) {
|
|
|
SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
|
|
|
return;
|
|
@@ -708,13 +708,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK)
|
|
|
{
|
|
|
// Client has the map, now start syncing
|
|
|
if (cs->status == STATUS_DONE_MAP && !cs->quited) {
|
|
|
char client_name[NETWORK_NAME_LENGTH];
|
|
|
char str[100];
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
GetString(str, STR_NETWORK_CLIENT_JOINED);
|
|
|
|
|
|
NetworkGetClientName(client_name, sizeof(client_name), cs);
|
|
|
|
|
|
NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, str);
|
|
|
|
|
@@ -744,13 +744,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
|
|
|
{
|
|
|
// The client has done a command and wants us to handle it
|
|
|
int i;
|
|
|
byte callback;
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
NetworkClientInfo *ci;
|
|
|
char *dparam_char;
|
|
|
|
|
|
CommandPacket *cp = malloc(sizeof(CommandPacket));
|
|
|
|
|
|
// The client was never joined.. so this is impossible, right?
|
|
@@ -829,13 +829,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
|
|
|
{
|
|
|
// This packets means a client noticed an error and is reporting this
|
|
|
// to us. Display the error and report it to the other clients
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
byte errorno = NetworkRecv_uint8(p);
|
|
|
char str1[100], str2[100];
|
|
|
char client_name[NETWORK_NAME_LENGTH];
|
|
|
|
|
|
// The client was never joined.. thank the client for the packet, but ignore it
|
|
|
if (cs->status < STATUS_DONE_MAP || cs->quited) {
|
|
@@ -862,13 +862,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
}
|
|
|
|
|
|
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
|
|
|
{
|
|
|
// The client wants to leave. Display this and report it to the other
|
|
|
// clients.
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
char str1[100], str2[100];
|
|
|
char client_name[NETWORK_NAME_LENGTH];
|
|
|
|
|
|
// The client was never joined.. thank the client for the packet, but ignore it
|
|
|
if (cs->status < STATUS_DONE_MAP || cs->quited) {
|
|
|
cs->quited = true;
|
|
@@ -905,13 +905,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, byte from_index)
|
|
|
{
|
|
|
ClientState *cs;
|
|
|
NetworkClientState *cs;
|
|
|
NetworkClientInfo *ci, *ci_own, *ci_to;
|
|
|
|
|
|
switch (desttype) {
|
|
|
case DESTTYPE_CLIENT:
|
|
|
if (dest == 1) {
|
|
|
ci = NetworkFindClientInfoFromIndex(from_index);
|
|
@@ -1033,13 +1033,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
|
|
|
NetworkUpdateClientInfo(ci->client_index);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// The layout for the receive-functions by the server
|
|
|
typedef void NetworkServerPacket(ClientState *cs, Packet *p);
|
|
|
typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p);
|
|
|
|
|
|
|
|
|
// This array matches PacketType. At an incoming
|
|
|
// packet it is matches against this array
|
|
|
// and that way the right function to handle that
|
|
|
// packet is found.
|
|
@@ -1081,13 +1081,13 @@ assert_compile(lengthof(_network_server_
|
|
|
|
|
|
extern const SettingDesc patch_settings[];
|
|
|
|
|
|
// This is a TEMPORARY solution to get the patch-settings
|
|
|
// to the client. When the patch-settings are saved in the savegame
|
|
|
// this should be removed!!
|
|
|
void NetworkSendPatchSettings(ClientState *cs)
|
|
|
void NetworkSendPatchSettings(NetworkClientState *cs)
|
|
|
{
|
|
|
const SettingDesc *item;
|
|
|
Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
|
|
|
NetworkSend_uint8(p, MAP_PACKET_PATCH);
|
|
|
// Now send all the patch-settings in a pretty order..
|
|
|
|
|
@@ -1119,13 +1119,13 @@ void NetworkSendPatchSettings(ClientStat
|
|
|
void NetworkPopulateCompanyInfo(void)
|
|
|
{
|
|
|
char password[NETWORK_PASSWORD_LENGTH];
|
|
|
Player *p;
|
|
|
Vehicle *v;
|
|
|
Station *s;
|
|
|
ClientState *cs;
|
|
|
NetworkClientState *cs;
|
|
|
NetworkClientInfo *ci;
|
|
|
int i;
|
|
|
uint16 months_empty;
|
|
|
|
|
|
FOR_ALL_PLAYERS(p) {
|
|
|
if (!p->is_active) {
|
|
@@ -1219,13 +1219,13 @@ void NetworkPopulateCompanyInfo(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Send a packet to all clients with updated info about this client_index
|
|
|
void NetworkUpdateClientInfo(uint16 client_index)
|
|
|
{
|
|
|
ClientState *cs;
|
|
|
NetworkClientState *cs;
|
|
|
NetworkClientInfo *ci;
|
|
|
|
|
|
ci = NetworkFindClientInfoFromIndex(client_index);
|
|
|
|
|
|
if (ci == NULL)
|
|
|
return;
|
|
@@ -1239,13 +1239,13 @@ void NetworkUpdateClientInfo(uint16 clie
|
|
|
Two things happen:
|
|
|
1) If a company is not protected, it is closed after 1 year (for example)
|
|
|
2) If a company is protected, protection is disabled after 3 years (for example)
|
|
|
(and item 1. happens a year later) */
|
|
|
static void NetworkAutoCleanCompanies()
|
|
|
{
|
|
|
ClientState *cs;
|
|
|
NetworkClientState *cs;
|
|
|
NetworkClientInfo *ci;
|
|
|
Player *p;
|
|
|
bool clients_in_company[MAX_PLAYERS];
|
|
|
|
|
|
if (!_network_autoclean_companies)
|
|
|
return;
|
|
@@ -1297,13 +1297,13 @@ static void NetworkAutoCleanCompanies()
|
|
|
}
|
|
|
|
|
|
// This function changes new_name to a name that is unique (by adding #1 ...)
|
|
|
// and it returns true if that succeeded.
|
|
|
bool NetworkFindName(char new_name[NETWORK_NAME_LENGTH])
|
|
|
{
|
|
|
ClientState *new_cs;
|
|
|
NetworkClientState *new_cs;
|
|
|
NetworkClientInfo *ci;
|
|
|
bool found_name = false;
|
|
|
byte number = 0;
|
|
|
char original_name[NETWORK_NAME_LENGTH];
|
|
|
|
|
|
// We use NETWORK_NAME_LENGTH in here, because new_name is really a pointer
|
|
@@ -1338,13 +1338,13 @@ bool NetworkFindName(char new_name[NETWO
|
|
|
}
|
|
|
|
|
|
return found_name;
|
|
|
}
|
|
|
|
|
|
// Reads a packet from the stream
|
|
|
bool NetworkServer_ReadPackets(ClientState *cs)
|
|
|
bool NetworkServer_ReadPackets(NetworkClientState *cs)
|
|
|
{
|
|
|
Packet *p;
|
|
|
NetworkRecvStatus res;
|
|
|
while((p = NetworkRecv_Packet(cs, &res)) != NULL) {
|
|
|
byte type = NetworkRecv_uint8(p);
|
|
|
if (type < PACKET_END && _network_server_packet[type] != NULL)
|
|
@@ -1355,13 +1355,13 @@ bool NetworkServer_ReadPackets(ClientSta
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// Handle the local command-queue
|
|
|
void NetworkHandleCommandQueue(ClientState *cs) {
|
|
|
void NetworkHandleCommandQueue(NetworkClientState *cs) {
|
|
|
if (cs->command_queue != NULL) {
|
|
|
CommandPacket *cp;
|
|
|
CommandPacket *cp_prev;
|
|
|
|
|
|
cp = cs->command_queue;
|
|
|
cp_prev = NULL;
|
|
@@ -1386,13 +1386,13 @@ void NetworkHandleCommandQueue(ClientSta
|
|
|
// This is called every tick if this is a _network_server
|
|
|
void NetworkServer_Tick(void)
|
|
|
{
|
|
|
#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
|
|
|
static uint32 last_sync_frame = 0;
|
|
|
#endif
|
|
|
ClientState *cs;
|
|
|
NetworkClientState *cs;
|
|
|
bool send_frame = false;
|
|
|
|
|
|
// Update max-frame-counter
|
|
|
if (_frame_counter > _frame_counter_max) {
|
|
|
_frame_counter_max = _frame_counter + _network_frame_freq;
|
|
|
send_frame = true;
|
|
@@ -1407,13 +1407,13 @@ void NetworkServer_Tick(void)
|
|
|
int lag = NetworkCalculateLag(cs) / DAY_TICKS;
|
|
|
if (lag > 0) {
|
|
|
if (lag > 3) {
|
|
|
// Client did still not report in after 4 game-day, drop him
|
|
|
// (that is, the 3 of above, + 1 before any lag is counted)
|
|
|
IConsolePrintF(_iconsole_color_error,"Client #%d is dropped because the client did not respond for more then 4 game-days", cs->index);
|
|
|
CloseClient(cs);
|
|
|
NetworkCloseClient(cs);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// Report once per time we detect the lag
|
|
|
if (cs->lag_test == 0) {
|
|
|
IConsolePrintF(_iconsole_color_warning,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
|
|
@@ -1450,12 +1450,12 @@ void NetworkServer_Tick(void)
|
|
|
#endif
|
|
|
|
|
|
/* See if we need to advertise */
|
|
|
NetworkUDPAdvertise();
|
|
|
}
|
|
|
|
|
|
void NetworkServerMonthlyLoop()
|
|
|
void NetworkServerMonthlyLoop(void)
|
|
|
{
|
|
|
NetworkAutoCleanCompanies();
|
|
|
}
|
|
|
|
|
|
#endif /* ENABLE_NETWORK */
|