Наследование: CLRScriptFramework.CLRScriptBase, ICLRScriptImplementation
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                string FormattedMessage = String.Format(
                    "</c><c=#FFFF00>{0}</c>",
                    Message);

                NWScript.Vector3 v;
                v.x = v.y = v.z = 0.0f;

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                Script.FloatingTextStringOnCreature(FormattedMessage,
                                                    PlayerObject,
                                                    CLRScriptBase.FALSE,
                                                    5.0f,
                                                    CLRScriptBase.COLOR_WHITE,
                                                    CLRScriptBase.COLOR_WHITE,
                                                    0.0f,
                                                    v);
            }

            Database.ACR_IncrementStatistic("BROADCAST_MESSAGE");
            Script.WriteTimestampedLogEntry("Received broadcast notification: " + Message);
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                string FormattedMessage = String.Format(
                    "</c><c=#FFFF00>{0}</c>",
                    Message);

                NWScript.Vector3 v;
                v.x = v.y = v.z = 0.0f;

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                Script.FloatingTextStringOnCreature(FormattedMessage,
                    PlayerObject,
                    CLRScriptBase.FALSE,
                    5.0f,
                    CLRScriptBase.COLOR_WHITE,
                    CLRScriptBase.COLOR_WHITE,
                    0.0f,
                    v);
            }

            Database.ACR_IncrementStatistic("BROADCAST_MESSAGE");
            Script.WriteTimestampedLogEntry("Received broadcast notification: " + Message);
        }
Пример #3
0
        /// <summary>
        /// Initialize the socket subsystem.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <returns>True if socket I/O is connected.</returns>
        public static bool Initialize(ACR_ServerCommunicator Script)
        {
            if (Initialized)
                return true;

            try
            {
                RecvfromDelegate = new RecvfromCallout(OnLowLevelReceive);
                RecvfromDelegateHandle = GCHandle.Alloc(RecvfromDelegate);

                try
                {
                    SetRecvfromCallout(Marshal.GetFunctionPointerForDelegate(RecvfromDelegate));
                }
                catch (Exception e)
                {
                    Script.WriteTimestampedLogEntry(String.Format("SocketIo.Initialize: Exception: {0}", e));
                    RecvfromDelegate = null;
                    RecvfromDelegateHandle.Free();
                    throw;
                }
            }
            catch
            {
                return false;
            }

            Initialized = true;
            return true;
        }
        /// <summary>
        /// This method is called when the ClientEnter event fires for a
        /// player.  Its purpose is to check whether the player has a pending
        /// resync request, and, if so, to execute the resync operation.
        /// </summary>
        /// <param name="State">Supplies the player object of the incoming
        /// player.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void OnClientEnter(uint PCObject, ACR_ServerCommunicator Script)
        {
            PlayerState State = Script.TryGetPlayerState(PCObject);

            if (State == null)
            {
                return;
            }

            var ResyncInfo = (from RS in PlayerResyncStates
                              where RS.PlayerId == State.PlayerId
                              select RS).FirstOrDefault();

            if (ResyncInfo == null)
            {
                return;
            }

            //
            // Dequeue the resync state and start attempting to apply it to the
            // player object once the player has loaded.
            //

            PlayerResyncStates.Remove(ResyncInfo);
            ResynchronizePlayerState(ResyncInfo, PCObject, Script);
        }
Пример #5
0
        /// <summary>
        /// Initialize the socket subsystem.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <returns>True if socket I/O is connected.</returns>
        public static bool Initialize(ACR_ServerCommunicator Script)
        {
            if (Initialized)
            {
                return(true);
            }

            try
            {
                RecvfromDelegate       = new RecvfromCallout(OnLowLevelReceive);
                RecvfromDelegateHandle = GCHandle.Alloc(RecvfromDelegate);

                try
                {
                    SetRecvfromCallout(Marshal.GetFunctionPointerForDelegate(RecvfromDelegate));
                }
                catch (Exception e)
                {
                    Script.WriteTimestampedLogEntry(String.Format("SocketIo.Initialize: Exception: {0}", e));
                    RecvfromDelegate = null;
                    RecvfromDelegateHandle.Free();
                    throw;
                }
            }
            catch
            {
                return(false);
            }

            Initialized = true;
            return(true);
        }
Пример #6
0
        /// <summary>
        /// This routine handles ALFA datagram protocol messages that have been
        /// received over the network.
        /// </summary>
        /// <param name="buf">Supplies the received data payload.</param>
        /// <param name="len">Supplies the length of received data.</param>
        /// <param name="Sender">Supplies the sender's address.</param>
        private static void OnDatagramReceive(IntPtr buf, int len, sockaddr_in Sender)
        {
            IPAddress            Address        = new IPAddress(Sender.sin_addr);
            int                  Port           = (int)IPAddress.NetworkToHostOrder((short)Sender.sin_port);
            ServerNetworkManager NetworkManager = ACR_ServerCommunicator.GetNetworkManager();

            byte[] Data = new byte[len];
            Marshal.Copy(buf, Data, 0, len);

            NetworkManager.OnDatagramReceive(Data, Address, Port);
        }
Пример #7
0
        /// <summary>
        /// Run the event queue down.  All events in the queue are given a
        /// chance to run.
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void RunQueue(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(String.Format("ACR_ServerCommunicator: Running queue of {0} entries", EventQueue.Count));
#endif

            while (!Empty())
            {
                IGameEventQueueEvent Event = EventQueue.Dequeue();

                Event.DispatchEvent(Script, Database);
            }
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            string FormattedMessage = String.Format(
                "ACR_ServerCommunicator: Received unsupported IPC event {0}: {1}.{2}.{3}.{4}.  Record ID was {5}.",
                EventType,
                P0,
                P1,
                P2,
                P3,
                RecordId);

            Script.WriteTimestampedLogEntry(FormattedMessage);
        }
        /// <summary>
        /// Run the event queue down.  All events in the queue are given a
        /// chance to run.
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void RunQueue(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(String.Format("ACR_ServerCommunicator: Running queue of {0} entries", EventQueue.Count));
#endif

            while (!Empty())
            {
                IGameEventQueueEvent Event = EventQueue.Dequeue();

                Event.DispatchEvent(Script, Database);
            }
        }
Пример #10
0
        /// <summary>
        /// This method is called to request an IPC channel latency measurement
        /// to a target server.
        /// </summary>
        /// <param name="PCObjectId">Supplies the PC object id of the
        /// requesting player.</param>
        /// <param name="ServerId">Supplies the server id to send the ping
        /// request to.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void SendPingToServer(uint PCObjectId, int ServerId, ACR_ServerCommunicator Script)
        {
            //
            // Package and serialize the ping state for transmission to the
            // remote server.  The remote server will echo the ping back, and
            // HandleServerPingResponse will then be invoked via a reply
            // run script request for acr_ping_server_response.
            //

            PingState State = new PingState(PCObjectId, Environment.TickCount);

            Script.RunScriptOnServer(ServerId, "acr_server_ping_request", State.ToString());
        }
Пример #11
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            string FormattedMessage = String.Format(
                "ACR_ServerCommunicator: Received unsupported IPC event {0}: {1}.{2}.{3}.{4}.  Record ID was {5}.",
                EventType,
                P0,
                P1,
                P2,
                P3,
                RecordId);

            Script.WriteTimestampedLogEntry(FormattedMessage);
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            //
            // If the event was for the local server, then don't re-broadcast
            // it.
            //

            if (Database.ACR_GetServerID() == Server.ServerId)
            {
                return;
            }

            string Message = String.Format(
                "<c=#FFFF00>Server {0} is now online.</c>",
                Server.Name);
            string ChatMessage = "</c>" + Message;

            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                {
                    continue;
                }

                if (!Script.IsCrossServerNotificationEnabled(PlayerObject))
                {
                    continue;
                }

                if ((Player.Flags & PlayerStateFlags.SendCrossServerNotificationsToCombatLog) != 0)
                {
                    Script.SendMessageToPC(PlayerObject, Message);
                }
                else
                {
                    Script.SendChatMessage(
                        CLRScriptBase.OBJECT_INVALID,
                        PlayerObject,
                        CLRScriptBase.CHAT_MODE_SERVER,
                        ChatMessage,
                        CLRScriptBase.FALSE);
                }
            }

#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(Message);
#endif
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            int SourceServerId = (SourceServer != null) ? SourceServer.ServerId : 0;

            Script.WriteTimestampedLogEntry(String.Format("RunScriptEvent.DispatchEvent: Executing script {0} ({1}) on request from {2}.",
                ScriptName,
                ScriptArgument,
                SourceServerId));
            Script.AddScriptParameterInt(SourceServerId);
            Script.AddScriptParameterString(ScriptArgument);
            Script.ExecuteScriptEnhanced(ScriptName, Script.GetModule(), CLRScriptBase.TRUE);

            Database.ACR_IncrementStatistic("RUN_REMOTE_SCRIPT");
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Player.PlayerId)
                    continue;

                Database.ACR_IncrementStatistic("DISCONNECT_PLAYER");
                Script.WriteTimestampedLogEntry("DisconnectPlayerEvent.DispatchEvent: Disconnecting player " + Script.GetPCPlayerName(PlayerObject) + " due to IPC request.");
                Script.BootPC(PlayerObject);
                return;
            }

            Script.WriteTimestampedLogEntry("DisconnectPlayerEvent.DispatchEvent: No player '" + Player.PlayerName + "' found locally connected to disconnect.");
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            int SourceServerId = (SourceServer != null) ? SourceServer.ServerId : 0;

            Script.WriteTimestampedLogEntry(String.Format("RunScriptEvent.DispatchEvent: Executing script {0} ({1}) on request from {2}.",
                                                          ScriptName,
                                                          ScriptArgument,
                                                          SourceServerId));
            Script.ClearScriptParams();
            Script.AddScriptParameterInt(SourceServerId);
            Script.AddScriptParameterString(ScriptArgument);
            Script.ExecuteScriptEnhanced(ScriptName, Script.GetModule(), CLRScriptBase.TRUE);

            Database.ACR_IncrementStatistic("RUN_REMOTE_SCRIPT");
        }
Пример #16
0
        /// <summary>
        /// Initialize the server vault connector subsystem.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <param name="ConnectionString">Supplies the connection string for
        /// the server vault.</param>
        /// <param name="VerboseLogging">Supplies true if verbose logging is
        /// enabled.</param>
        /// <returns>True if the server vault connector is
        /// initialized.</returns>
        public static bool Initialize(ACR_ServerCommunicator Script, string ConnectionString, bool VerboseLogging)
        {
            if (Initialized)
            {
                return(true);
            }

            try
            {
                StoreConnectionString = ConnectionString;

                FileStoreProvider.DefaultVaultConnectionString = ConnectionString;

                SynchronizeAccountFromVaultDelegate = new SynchronizeAccountFromVault(OnSynchronizeAccountFromVault);
                SynchronizeAccountFromVaultHandle   = GCHandle.Alloc(SynchronizeAccountFromVaultDelegate);

                SynchronizeAccountFileToVaultDelegate = new SynchronizeAccountFileToVault(OnSynchronizeAccountFileToVault);
                SynchronizeAccountFileToVaultHandle   = GCHandle.Alloc(SynchronizeAccountFileToVaultDelegate);

                try
                {
                    if (SetStoragePluginCallbacks(Marshal.GetFunctionPointerForDelegate(SynchronizeAccountFromVaultDelegate),
                                                  Marshal.GetFunctionPointerForDelegate(SynchronizeAccountFileToVaultDelegate),
                                                  IntPtr.Zero) == 0)
                    {
                        throw new ApplicationException("Failed to install storage plugin callbacks.");
                    }
                }
                catch (Exception e)
                {
                    Script.WriteTimestampedLogEntry(String.Format("ServerVaultConnector.Initialize: Exception: {0}", e));
                    SynchronizeAccountFileToVaultDelegate = null;
                    SynchronizeAccountFileToVaultHandle.Free();
                    SynchronizeAccountFromVaultDelegate = null;
                    SynchronizeAccountFromVaultHandle.Free();
                    throw;
                }
            }
            catch
            {
                return(false);
            }

            Initialized = true;
            return(true);
        }
Пример #17
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Player.PlayerId)
                {
                    continue;
                }

                Database.ACR_IncrementStatistic("DISCONNECT_PLAYER");
                Script.WriteTimestampedLogEntry("DisconnectPlayerEvent.DispatchEvent: Disconnecting player " + Script.GetPCPlayerName(PlayerObject) + " due to IPC request.");
                Script.BootPC(PlayerObject);
                return;
            }

            Script.WriteTimestampedLogEntry("DisconnectPlayerEvent.DispatchEvent: No player '" + Player.PlayerName + "' found locally connected to disconnect.");
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            //
            // If the event was for the local server, then don't re-broadcast
            // it.
            //

            if (Database.ACR_GetServerID() == Server.ServerId)
                return;

            string Message = String.Format(
                "<c=#FFFF00>Server {0} is now offline.</c>",
                Server.Name);
            string ChatMessage = "</c>" + Message;

            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                    continue;

                if (!Script.IsCrossServerNotificationEnabled(PlayerObject))
                    continue;

                if ((Player.Flags & PlayerStateFlags.SendCrossServerNotificationsToCombatLog) != 0)
                {
                    Script.SendMessageToPC(PlayerObject, Message);
                }
                else
                {
                    Script.SendChatMessage(
                        CLRScriptBase.OBJECT_INVALID,
                        PlayerObject,
                        CLRScriptBase.CHAT_MODE_SERVER,
                        ChatMessage,
                        CLRScriptBase.FALSE);
                }
            }

#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(Message);
#endif
        }
        /// <summary>
        /// Initialize the server vault connector subsystem.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <param name="ConnectionString">Supplies the connection string for
        /// the server vault.</param>
        /// <param name="VerboseLogging">Supplies true if verbose logging is
        /// enabled.</param>
        /// <returns>True if the server vault connector is
        /// initialized.</returns>
        public static bool Initialize(ACR_ServerCommunicator Script, string ConnectionString, bool VerboseLogging)
        {
            if (Initialized)
                return true;

            try
            {
                StoreConnectionString = ConnectionString;

                FileStoreProvider.DefaultVaultConnectionString = ConnectionString;

                SynchronizeAccountFromVaultDelegate = new SynchronizeAccountFromVault(OnSynchronizeAccountFromVault);
                SynchronizeAccountFromVaultHandle = GCHandle.Alloc(SynchronizeAccountFromVaultDelegate);

                SynchronizeAccountFileToVaultDelegate = new SynchronizeAccountFileToVault(OnSynchronizeAccountFileToVault);
                SynchronizeAccountFileToVaultHandle = GCHandle.Alloc(SynchronizeAccountFileToVaultDelegate);

                try
                {
                    if (SetStoragePluginCallbacks(Marshal.GetFunctionPointerForDelegate(SynchronizeAccountFromVaultDelegate),
                        Marshal.GetFunctionPointerForDelegate(SynchronizeAccountFileToVaultDelegate),
                        IntPtr.Zero) == 0)
                    {
                        throw new ApplicationException("Failed to install storage plugin callbacks.");
                    }
                }
                catch (Exception e)
                {
                    Script.WriteTimestampedLogEntry(String.Format("ServerVaultConnector.Initialize: Exception: {0}", e));
                    SynchronizeAccountFileToVaultDelegate = null;
                    SynchronizeAccountFileToVaultHandle.Free();
                    SynchronizeAccountFromVaultDelegate = null;
                    SynchronizeAccountFromVaultHandle.Free();
                    throw;
                }
            }
            catch
            {
                return false;
            }

            Initialized = true;
            return true;
        }
        /// <summary>
        /// This when a cross-server ping response is received.  Its purpose is
        /// to compute the channel latency and send a message to that effect to
        /// the requesting player.
        /// </summary>
        /// <param name="SourceServerId">Supplies the server id of the server
        /// that completed the ping request.</param>
        /// <param name="Arguments">Supplies the serialized state arguments
        /// string.</param>
        /// <param name="Script">Supplies the current script object.</param>
        /// <returns>TRUE on success, else FALSE on failure.</returns>
        public static int HandleServerPingResponse(int SourceServerId, string Arguments, ACR_ServerCommunicator Script)
        {
            int Tick = Environment.TickCount;

            try
            {
                PingState RemoteState;

                //
                // Deserialize the remote ping state.  If null, a protocol
                // violation has occurred.
                //

                if ((RemoteState = PingState.FromString(Arguments)) == null)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                        "ACR_ServerCommunicator.ServerLatencyMeasurer.HandleServerPingResponse({0}, {1}): Invalid request.",
                        SourceServerId,
                        Arguments));
                    return ACR_ServerCommunicator.FALSE;
                }

                string ServerName = Script.GetServerName(SourceServerId);

                if (ServerName == null)
                    return ACR_ServerCommunicator.FALSE;

                Script.SendMessageToPC(RemoteState.PCObjectId, String.Format(
                    "IPC channel latency to {0}: {1}ms", ServerName, Tick - RemoteState.TickCount));
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "ACR_ServerCommunicator.ServerLatencyMeasurer.HandleServerPingResponse({0}, {1}): Exception: {0}",
                    SourceServerId,
                    Arguments,
                    e));
                return ACR_ServerCommunicator.FALSE;
            }

            return ACR_ServerCommunicator.TRUE;
        }
Пример #21
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                string FormattedMessage = String.Format(
                    "</c><c=#FFFF00>Server shutting down: {0}</c>",
                    Message);

                NWScript.Vector3 v;
                v.x = v.y = v.z = 0.0f;

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                Script.FloatingTextStringOnCreature(FormattedMessage,
                                                    PlayerObject,
                                                    CLRScriptBase.FALSE,
                                                    5.0f,
                                                    CLRScriptBase.COLOR_WHITE,
                                                    CLRScriptBase.COLOR_WHITE,
                                                    0.0f,
                                                    v);
            }

            Script.WriteTimestampedLogEntry("Received shutdown request: " + Message);

            Database.ACR_IncrementStatistic("SERVER_SHUTDOWN");
            Script.SendInfrastructureIrcMessage(String.Format(
                                                    "Server '{0}' shutting down or restarting: {1}",
                                                    Script.GetName(Script.GetModule()),
                                                    Message));

            Script.DelayCommand(5.0f, delegate()
            {
                Database.ACR_FlushAllQueryQueues();
                SystemInfo.ShutdownGameServer(Script);
            });
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                string FormattedMessage = String.Format(
                    "</c><c=#FFFF00>Server shutting down: {0}</c>",
                    Message);

                NWScript.Vector3 v;
                v.x = v.y = v.z = 0.0f;

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                Script.FloatingTextStringOnCreature(FormattedMessage,
                    PlayerObject,
                    CLRScriptBase.FALSE,
                    5.0f,
                    CLRScriptBase.COLOR_WHITE,
                    CLRScriptBase.COLOR_WHITE,
                    0.0f,
                    v);
            }

            Script.WriteTimestampedLogEntry("Received shutdown request: " + Message);

            Database.ACR_IncrementStatistic("SERVER_SHUTDOWN");
            Script.SendInfrastructureIrcMessage(String.Format(
                "Server '{0}' shutting down or restarting: {1}",
                Script.GetName(Script.GetModule()),
                Message));

            Script.DelayCommand(5.0f, delegate()
            {
                Database.ACR_FlushAllQueryQueues();
                SystemInfo.ShutdownGameServer(Script);
            });
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            string VaultPath = SystemInfo.GetServerVaultPathForAccount(Player.Name);

            if (VaultPath == null)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "PurgeCachedCharacterEvent.DispatchEvent: Could not resolve vault path for player '{0}'.",
                    Player.PlayerName));
                return;
            }

            VaultPath += CharacterFileName;

            if (!File.Exists(VaultPath))
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "PurgeCachedCharacterEvent.DispatchEvent: Character file '{0}' for player '{1}' was not locally cached.",
                    CharacterFileName,
                    Player.PlayerName));
                return;
            }

            try
            {
                File.Delete(VaultPath);
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "PurgeCachedCharacterEvent.DispatchEvent: Exception '{0}' removing cached character '{1}' for player '{2}'.",
                    e,
                    CharacterFileName,
                    Player.PlayerName));
                return;
            }

            Script.WriteTimestampedLogEntry(String.Format(
                "PurgeCachedCharacterEvent.DispatchEvent: Removed cached character '{0}' from player '{1}' vault cache.",
                CharacterFileName,
                Player.PlayerName));
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            PlayerState State = Script.TryGetPlayerState(PlayerObject);
            string RequestURL;

            //
            // If the player is logged off, then there's nothing to do.
            //

            if (State == null || State.IsDM)
                return;

            if (String.IsNullOrEmpty(AccountAssociationSecret))
                return;

            RequestURL = AccountAssociator.GenerateAssociationURL(Script.GetPCPlayerName(PlayerObject), AccountAssociationSecret, AccountAssociationURL);

            Script.DisplayGuiScreen(PlayerObject, "acr_account_association", CLRScriptBase.FALSE, "acr_account_association.XML", CLRScriptBase.FALSE);
            Script.SetLocalGUIVariable(PlayerObject, "acr_account_association", 0, RequestURL);
        }
Пример #25
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Recipient.PlayerId)
                    continue;

                string FormattedMessage = String.Format(
                    "</c><c=#FFCC99>{0}: </c><c=#30DDCC>[Page] {1}</c>",
                    Sender.PlayerName,
                    Message);

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);
                break;
            }
        }
Пример #26
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Recipient.PlayerId)
                {
                    continue;
                }

                string FormattedMessage = String.Format(
                    "</c><c=#FFCC99>{0}: </c><c=#30DDCC>[ServerTell] {1}</c>",
                    Sender.CharacterName,
                    Message);

                Script.SetLastTellFromPlayerId(PlayerObject, Sender.Player.PlayerId);
                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                //
                // If this is the first time that we have delivered a
                // cross-server tell to this player (since login), remind them
                // of how to respond.
                //

                if ((Database.ACR_GetPCLocalFlags(PlayerObject) & ALFA.Database.ACR_PC_LOCAL_FLAG_SERVER_TELL_HELP) == 0)
                {
                    Script.SendMessageToPC(
                        PlayerObject,
                        "To respond to a [ServerTell] from a player on a different server, type: #re [message], or #t \"character name\" [message], or #tp \"player name\" [message].  Quotes are optional unless the name has spaces.  The #rt [message] command will send a tell to the last player that you had sent a tell to.");
                    Database.ACR_SetPCLocalFlags(
                        PlayerObject,
                        Database.ACR_GetPCLocalFlags(PlayerObject) | ALFA.Database.ACR_PC_LOCAL_FLAG_SERVER_TELL_HELP);
                }
                break;
            }
        }
        /// <summary>
        /// Construct a new PlayerState object.
        /// </summary>
        /// <param name="ObjectId">Supplies the NWScript object id of the PC
        /// object.</param>
        /// <param name="Communicator">Supplies the server communicator
        /// instance that the PlayerState object is bound to.</param>
        public PlayerState(uint ObjectId, ACR_ServerCommunicator Communicator)
        {
            ALFA.Database Database = Communicator.GetDatabase();

            this.Communicator                 = Communicator;
            this.PCObjectId                   = ObjectId;
            this.PCCharacterId                = Database.ACR_GetCharacterID(ObjectId);
            this.PCPlayerId                   = Database.ACR_GetPlayerID(ObjectId);
            this.StateFlags                   = (PlayerStateFlags)Database.ACR_GetPersistentInt(ObjectId, "ACR_COMMUNICATOR_STATE_FLAGS");
            this.LatencyTickCount             = 0;
            this.LatencyToServer              = 0;
            this.ChatSelectLocalPlayersShown  = 0;
            this.ChatSelectLocalDMsShown      = 0;
            this.ChatSelectRemotePlayersShown = 0;
            this.ChatSelectRemoteDMsShown     = 0;

            //
            // Upgrade any legacy database settings to their new format.
            //

            UpgradeLegacySettings();
        }
        /// <summary>
        /// Construct a new PlayerState object.
        /// </summary>
        /// <param name="ObjectId">Supplies the NWScript object id of the PC
        /// object.</param>
        /// <param name="Communicator">Supplies the server communicator
        /// instance that the PlayerState object is bound to.</param>
        public PlayerState(uint ObjectId, ACR_ServerCommunicator Communicator)
        {
            ALFA.Database Database = Communicator.GetDatabase();

            this.Communicator = Communicator;
            this.PCObjectId = ObjectId;
            this.PCCharacterId = Database.ACR_GetCharacterID(ObjectId);
            this.PCPlayerId = Database.ACR_GetPlayerID(ObjectId);
            this.StateFlags = (PlayerStateFlags) Database.ACR_GetPersistentInt(ObjectId, "ACR_COMMUNICATOR_STATE_FLAGS");
            this.LatencyTickCount = 0;
            this.LatencyToServer = 0;
            this.ChatSelectLocalPlayersShown = 0;
            this.ChatSelectLocalDMsShown = 0;
            this.ChatSelectRemotePlayersShown = 0;
            this.ChatSelectRemoteDMsShown = 0;

            //
            // Upgrade any legacy database settings to their new format.
            //

            UpgradeLegacySettings();
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Recipient.PlayerId)
                    continue;

                string FormattedMessage = String.Format(
                    "</c><c=#FFCC99>{0}: </c><c=#30DDCC>[ServerTell] {1}</c>",
                    Sender.CharacterName,
                    Message);

                Script.SetLastTellFromPlayerId(PlayerObject, Sender.Player.PlayerId);
                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);

                //
                // If this is the first time that we have delivered a
                // cross-server tell to this player (since login), remind them
                // of how to respond.
                //

                if ((Database.ACR_GetPCLocalFlags(PlayerObject) & ALFA.Database.ACR_PC_LOCAL_FLAG_SERVER_TELL_HELP) == 0)
                {
                    Script.SendMessageToPC(
                        PlayerObject,
                        "To respond to a [ServerTell] from a player on a different server, type: #re [message], or #t \"character name\" [message], or #tp \"player name\" [message].  Quotes are optional unless the name has spaces.  The #rt [message] command will send a tell to the last player that you had sent a tell to.");
                    Database.ACR_SetPCLocalFlags(
                        PlayerObject,
                        Database.ACR_GetPCLocalFlags(PlayerObject) | ALFA.Database.ACR_PC_LOCAL_FLAG_SERVER_TELL_HELP);
                }
                break;
            }
        }
Пример #30
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                if (Database.ACR_GetPlayerID(PlayerObject) != Recipient.PlayerId)
                {
                    continue;
                }

                string FormattedMessage = String.Format(
                    "</c><c=#FFCC99>{0}: </c><c=#30DDCC>[Page] {1}</c>",
                    Sender.PlayerName,
                    Message);

                Script.SendChatMessage(
                    CLRScriptBase.OBJECT_INVALID,
                    PlayerObject,
                    CLRScriptBase.CHAT_MODE_SERVER,
                    FormattedMessage,
                    CLRScriptBase.FALSE);
                break;
            }
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            PlayerState State = Script.TryGetPlayerState(PlayerObject);
            string      RequestURL;

            //
            // If the player is logged off, then there's nothing to do.
            //

            if (State == null || State.IsDM)
            {
                return;
            }

            if (String.IsNullOrEmpty(AccountAssociationSecret))
            {
                return;
            }

            RequestURL = AccountAssociator.GenerateAssociationURL(Script.GetPCPlayerName(PlayerObject), AccountAssociationSecret, AccountAssociationURL);

            Script.DisplayGuiScreen(PlayerObject, "acr_account_association", CLRScriptBase.FALSE, "acr_account_association.XML", CLRScriptBase.FALSE);
            Script.SetLocalGUIVariable(PlayerObject, "acr_account_association", 0, RequestURL);
        }
        /// <summary>
        /// This method is called to request an IPC channel latency measurement
        /// to a target server.
        /// </summary>
        /// <param name="PCObjectId">Supplies the PC object id of the
        /// requesting player.</param>
        /// <param name="ServerId">Supplies the server id to send the ping
        /// request to.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void SendPingToServer(uint PCObjectId, int ServerId, ACR_ServerCommunicator Script)
        {
            //
            // Package and serialize the ping state for transmission to the
            // remote server.  The remote server will echo the ping back, and
            // HandleServerPingResponse will then be invoked via a reply
            // run script request for acr_ping_server_response.
            //

            PingState State = new PingState(PCObjectId, Environment.TickCount);

            Script.RunScriptOnServer(ServerId, "acr_server_ping_request", State.ToString());
        }
        /// <summary>
        /// Initialize the ServerNetworkManager instance.
        /// </summary>
        /// <param name="WorldManager">Supplies the game world manager to which
        /// the network manager instance is bound.</param>
        /// <param name="LocalServerId">Supplies the server id of the local
        /// server.</param>
        /// <param name="Script">Supplies the main script object.</param>
        public ServerNetworkManager(GameWorldManager WorldManager, int LocalServerId, ACR_ServerCommunicator Script)
        {
            SocketIo.Initialize(Script);

            this.WorldManager  = WorldManager;
            this.LocalServerId = LocalServerId;
        }
 /// <summary>
 /// Dispatch the event (in a script context).
 /// </summary>
 /// <param name="Script">Supplies the script object.</param>
 /// <param name="Database">Supplies the database connection.</param>
 public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
 {
     Script.SendMessageToPC(PlayerObject, Message);
 }
        /// <summary>
        /// Process and apply content patches.  A server restart is scheduled
        /// if required for the content patch.
        /// </summary>
        /// <param name="ContentPatchPath">Supplies the configured content
        /// patch base path, from the database config table.</param>
        /// <param name="Database">Supplies the database object.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <returns>True if a patch was applied and a reboot is required for
        /// it to take effect.</returns>
        public static bool ProcessContentPatches(string ContentPatchPath, ALFA.Database Database, ACR_ServerCommunicator Script)
        {
            bool ContentChanged = false;
            string Version = Database.ACR_GetHAKVersion();
            List<ContentPatchFile> PatchFiles = new List<ContentPatchFile>();
            string LocalContentPatchPath = ALFA.SystemInfo.GetOverrideDirectory() + "ACR_ContentPatches";
            string LocalContentPatchHakPath = ALFA.SystemInfo.GetHakDirectory();
            string RemoteContentPatchPath = String.Format("{0}{1}\\{2}", ALFA.SystemInfo.GetCentralVaultPath(), ContentPatchPath, Version);

            Database.ACR_SQLQuery(String.Format(
                "SELECT `FileName`, `Location`, `Checksum` FROM `content_patch_files` WHERE `HakVersion` = '{0}'",
                Database.ACR_SQLEncodeSpecialChars(Version)));

            while (Database.ACR_SQLFetch())
            {
                ContentPatchFile PatchFile = new ContentPatchFile();

                PatchFile.FileName = Database.ACR_SQLGetData(0);
                PatchFile.Location = Database.ACR_SQLGetData(1);
                PatchFile.Checksum = Database.ACR_SQLGetData(2);

                if (PatchFile.Location != "override" &&
                    PatchFile.Location != "hak")
                {
                    continue;
                }

                if (!ALFA.SystemInfo.IsSafeFileName(PatchFile.FileName))
                    continue;

                PatchFiles.Add(PatchFile);
            }

            if (!Directory.Exists(LocalContentPatchPath))
                Directory.CreateDirectory(LocalContentPatchPath);

            //
            // Remove entries in the ACR patch override directory that are not
            // listed in the patch table.  These may be patches for a previous
            // version, and are not applicable.
            //

            foreach (string DirFile in Directory.GetFiles(LocalContentPatchPath))
            {
                ContentPatchFile FoundPatch = (from PF in PatchFiles
                                               where (PF.FileName.Equals(Path.GetFileName(DirFile), StringComparison.InvariantCultureIgnoreCase) && PF.Location == "override")
                                               select PF).FirstOrDefault();
                if (FoundPatch == null)
                {
                    Database.ACR_IncrementStatistic("CONTENT_PATCH_REMOVE_FILE");

                    Script.WriteTimestampedLogEntry(String.Format(
                        "ModuleContentPatcher.ProcessContentPatches: Removing extraneous file {0} from {1}", Path.GetFileName(DirFile), LocalContentPatchPath));

                    File.Delete(DirFile);
                    ContentChanged = true;
                }
            }

            //
            // Verify that the MD5 checksum of each of the content files in the
            // ACR patch override directory matches the database's expected
            // checksum.  If not (or if the file in question didn't exist),
            // then copy the new version over from the central vault.
            //

            using (MD5CryptoServiceProvider MD5Csp = new MD5CryptoServiceProvider())
            {
                foreach (ContentPatchFile PatchFile in PatchFiles)
                {
                    bool Matched = false;
                    string LocalPath = PatchFile.GetLocalPath(LocalContentPatchPath, LocalContentPatchHakPath);
                    string RemotePath = String.Format("{0}\\{1}", RemoteContentPatchPath, PatchFile.FileName);
                    string LocalHashString = "<no such file>";

                    if (File.Exists(LocalPath) && File.Exists(RemotePath))
                    {
                        LocalHashString = GetFileChecksum(LocalPath, MD5Csp);

                        Matched = (LocalHashString.ToString() == PatchFile.Checksum.ToLower());
                    }

                    if (Matched)
                    {
                        Script.WriteTimestampedLogEntry(String.Format(
                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} is up to date (checksum {1}).",
                            PatchFile.FileName,
                            LocalHashString));
                    }
                    else
                    {
                        Script.WriteTimestampedLogEntry(String.Format(
                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} needs to be updated (local checksum {1}, remote checksum {2}).  Copying file...",
                            PatchFile.FileName,
                            LocalHashString,
                            PatchFile.Checksum));

                        //
                        // The file needs to be updated.  Copy it over and
                        // re-validate the checksum.  If the checksum did not
                        // match, log an error and delete the file.
                        //

                        try
                        {
                            //
                            // If we are patching a hak, rename it away so that
                            // the file can be written to.
                            //

                            if (PatchFile.Location == "hak" && File.Exists(LocalPath))
                            {
                                string OldFileName = LocalPath + ".old";

                                if (File.Exists(OldFileName))
                                    File.Delete(OldFileName);

                                File.Move(LocalPath, OldFileName);

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_HAK");
                            }
                            else if (PatchFile.Location == "override")
                            {
                                Database.ACR_IncrementStatistic("CONTENT_PATCH_OVERRIDE");
                            }

                            try
                            {
                                File.Copy(RemotePath, LocalPath, true);
                            }
                            catch
                            {
                                if (PatchFile.Location == "hak" && File.Exists(LocalPath))
                                {
                                    string OldFileName = LocalPath + ".old";

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                throw;
                            }

                            if (GetFileChecksum(LocalPath, MD5Csp) != PatchFile.Checksum.ToLower())
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} was copied, but checksum did not match {1}!  This may indicate a configuration error in the database, or file corruption in transit.",
                                    PatchFile.FileName,
                                    PatchFile.Checksum));

                                if (PatchFile.Location == "hak")
                                {
                                    string OldFileName = LocalPath + ".old";

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_INCORRECT_CHECKSUM");
                            }
                            else
                            {
                                ContentChanged = true;

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_UPDATED_FILE");

                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessContentPatches: Successfully updated content patch file {0}.",
                                    PatchFile.FileName));
                            }
                        }
                        catch (Exception e)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                "ModuleContentPatcher.ProcessContentPatches: Exception {0} updating content patch file {1}.",
                                e,
                                PatchFile.FileName));
                        }
                    }
                }
            }

            if (ContentChanged)
                Database.ACR_IncrementStatistic("CONTENT_PATCH_REBOOT");

            return ContentChanged;
        }
Пример #36
0
 /// <summary>
 /// Dispatch the event (in a script context).
 /// </summary>
 /// <param name="Script">Supplies the script object.</param>
 /// <param name="Database">Supplies the database connection.</param>
 public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
 {
     Script.SendMessageToPC(PlayerObject, Message);
 }
        /// <summary>
        /// This method is called to resynchronize the GUI state of a player
        /// that executed a server to server portal, if the player is in an
        /// area.
        /// </summary>
        /// <param name="ResyncInfo">Supplies the resync block for the
        /// player.  This contains the deserialized resynchronization command
        /// data.</param>
        /// <param name="PCObject">Supplies the player object id.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Tries">Supplies the count of retries.</param>
        private static void ResynchronizePlayerState(ResyncState ResyncInfo, uint PCObject, ACR_ServerCommunicator Script, int Tries = 0)
        {
            if (Script.GetIsObjectValid(PCObject) == ACR_ServerCommunicator.FALSE)
            {
                //
                // The player logged out while a resync request was pending.
                // Throw away the state as it is no longer needed on a full log
                // out and log in sequence.
                //

                return;
            }

            if ((Script.GetArea(PCObject) == ACR_ServerCommunicator.OBJECT_INVALID) ||
                (Script.GetScriptHidden(PCObject) != ACR_ServerCommunicator.FALSE))
            {
                //
                // The player may still be in transition or is not yet loaded.
                // Queue the request.
                //

                if (Tries < MAX_RESYNC_RETRIES)
                {
                    Script.DelayCommand(RESYNC_RETRY_INTERVAL, delegate()
                    {
                        ResynchronizePlayerState(ResyncInfo, PCObject, Script, Tries + 1);
                    });
                }

                return;
            }

            PlayerState State = Script.TryGetPlayerState(PCObject);

            if (State == null)
                return;

            //
            // Area transition has finished.  Apply the GUI state now.
            //

            State.ChatSelectGUIExpanded = ((ResyncInfo.ResyncFlags & RESYNC_FLAG_CHAT_SELECT_EXPANDED) != 0);
            State.UpdateChatSelectGUIHeaders();

            Script.SendMessageToPC(PCObject, "Server to server portal completed.");
            Script.WriteTimestampedLogEntry(String.Format(
                "ACR_ServerCommunicator.GUIResynchronizer.ResynchronizePlayerState: Resynchronized player GUI state for player {0} after server-to-server portal.",
                Script.GetName(PCObject)));
        }
Пример #38
0
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            //
            // If the event was for a player logging on to the local server,
            // then don't re-broadcast it.
            //
            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                {
                    continue;
                }

                if (!Player.CharacterIdsShown.Contains(Character.CharacterId))
                {
                    string sPlayerListBox = "";

                    if (Server.ServerId == Script.GetDatabase().ACR_GetServerID() || Script.GetLocalInt(PlayerObject, "chatselect_expanded") == 0)
                    {
                        if (IsDM == true)
                        {
                            sPlayerListBox = "LocalDMList";
                            Player.ChatSelectLocalDMsShown += 1;
                        }
                        else
                        {
                            sPlayerListBox = "LocalPlayerList";
                            Player.ChatSelectLocalPlayersShown += 1;
                        }

                        if (Server.ServerId == Script.GetDatabase().ACR_GetServerID())
                        {
                            Script.AddListBoxRow(Player.ObjectId, "ChatSelect", sPlayerListBox, Character.CharacterName, "RosterData=/t \"" + Character.CharacterName + "\"", "", "5=/t \"" + Character.CharacterName + "\" ", "");
                        }
                        else
                        {
                            if (Player.Flags.HasFlag(PlayerStateFlags.ChatSelectShowLocalPlayersOnlyWhenCollapsed))
                            {
                                continue;
                            }

                            Script.AddListBoxRow(Player.ObjectId, "ChatSelect", sPlayerListBox, Character.CharacterName, "RosterData=#t \"" + Character.CharacterName + "\"", "", "5=#t \"" + Character.CharacterName + "\" ", "");
                        }
                    }
                    else
                    {
                        if (IsDM == true)
                        {
                            sPlayerListBox = "RemoteDMList";
                            Player.ChatSelectRemoteDMsShown += 1;
                        }
                        else
                        {
                            sPlayerListBox = "RemotePlayerList";
                            Player.ChatSelectRemotePlayersShown += 1;
                        }

                        Script.AddListBoxRow(Player.ObjectId, "ChatSelect", sPlayerListBox, Character.CharacterName, "RosterData=#t \"" + Character.CharacterName + "\"", "", "5=#t \"" + Character.CharacterName + "\" ", "");
                    }

                    Player.CharacterIdsShown.Add(Character.CharacterId);
                    Player.UpdateChatSelectGUIHeaders();
                }
            }

            if (Database.ACR_GetServerID() == Server.ServerId)
            {
                return;
            }

            string Message = String.Format(
                "{0}<c=#FFA500>{1} ({2}) joined {3}.</c>", // <c=Orange...>
                IsDM ? "<c=#99CCFF>[DM] </c>": "",
                Character.Name,
                Character.Player.Name,
                Server.Name);
            string ChatMessage = "</c>" + Message;

            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                {
                    continue;
                }

                if (!Script.IsCrossServerNotificationEnabled(PlayerObject))
                {
                    continue;
                }

                if ((Player.Flags & PlayerStateFlags.SendCrossServerNotificationsToCombatLog) != 0)
                {
                    Script.SendMessageToPC(PlayerObject, Message);
                }
                else
                {
                    Script.SendChatMessage(
                        CLRScriptBase.OBJECT_INVALID,
                        PlayerObject,
                        CLRScriptBase.CHAT_MODE_SERVER,
                        ChatMessage,
                        CLRScriptBase.FALSE);
                }
            }

#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(Message);
#endif
        }
        /// <summary>
        /// Process and apply content patches.  A server restart is scheduled
        /// if required for the content patch.
        /// </summary>
        /// <param name="ContentPatchPath">Supplies the configured content
        /// patch base path, from the database config table.</param>
        /// <param name="Database">Supplies the database object.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="ConnectionString">Supplies the updater file store
        /// connection string.</param>
        /// <returns>True if a patch was applied and a reboot is required for
        /// it to take effect.</returns>
        public static bool ProcessContentPatches(string ContentPatchPath, ALFA.Database Database, ACR_ServerCommunicator Script, string ConnectionString)
        {
            bool ContentChanged = false;
            string Version = Database.ACR_GetHAKVersion();
            List<ContentPatchFile> PatchFiles = new List<ContentPatchFile>();
            ContentPatchPaths LocalPaths = new ContentPatchPaths()
            {
                HakPath = ALFA.SystemInfo.GetHakDirectory(),
                OverridePath = ALFA.SystemInfo.GetOverrideDirectory() + "ACR_ContentPatches"
            };
            string RemoteContentPatchPath = String.Format("{0}{1}\\{2}", ALFA.SystemInfo.GetCentralVaultPath(), ContentPatchPath, Version);
            string FileStoreContentPatchPath = String.Format("{0}/{1}", ContentPatchPath, Version).Replace('\\', '/');
            bool RecompileModule = false;
            bool SentNotification = false;

            Database.ACR_SQLQuery(String.Format(
                "SELECT `FileName`, `Location`, `Checksum`, `RecompileModule` FROM `content_patch_files` WHERE `HakVersion` = '{0}'",
                Database.ACR_SQLEncodeSpecialChars(Version)));

            while (Database.ACR_SQLFetch())
            {
                ContentPatchFile PatchFile = new ContentPatchFile();

                PatchFile.FileName = Database.ACR_SQLGetData(0);
                PatchFile.Location = Database.ACR_SQLGetData(1);
                PatchFile.Checksum = Database.ACR_SQLGetData(2);
                PatchFile.RecompileModule = ALFA.Database.ACR_ConvertDatabaseStringToBoolean(Database.ACR_SQLGetData(3));

                if (PatchFile.Location != "override" &&
                    PatchFile.Location != "hak")
                {
                    continue;
                }

                if (!ALFA.SystemInfo.IsSafeFileName(PatchFile.FileName))
                    continue;

                PatchFiles.Add(PatchFile);
            }

            if (!Directory.Exists(LocalPaths.OverridePath))
                Directory.CreateDirectory(LocalPaths.OverridePath);

            //
            // Remove entries in the ACR patch override directory that are not
            // listed in the patch table.  These may be patches for a previous
            // version, and are not applicable.
            //

            foreach (string DirFile in Directory.GetFiles(LocalPaths.OverridePath))
            {
                ContentPatchFile FoundPatch = (from PF in PatchFiles
                                               where (PF.FileName.Equals(Path.GetFileName(DirFile), StringComparison.InvariantCultureIgnoreCase) && PF.Location == "override")
                                               select PF).FirstOrDefault();
                if (FoundPatch == null)
                {
                    Database.ACR_IncrementStatistic("CONTENT_PATCH_REMOVE_FILE");

                    Script.WriteTimestampedLogEntry(String.Format(
                        "ModuleContentPatcher.ProcessContentPatches: Removing extraneous file {0} from {1}", Path.GetFileName(DirFile), LocalPaths.OverridePath));

                    File.Delete(DirFile);
                    ContentChanged = true;
                }
            }

            //
            // Verify that the MD5 checksum of each of the content files in the
            // ACR patch override directory matches the database's expected
            // checksum.  If not (or if the file in question didn't exist),
            // then copy the new version over from the central vault.
            //

            using (MD5CryptoServiceProvider MD5Csp = new MD5CryptoServiceProvider())
            {
                foreach (ContentPatchFile PatchFile in PatchFiles)
                {
                    bool Matched = false;
                    bool Rename = false;
                    FileUpdateMethod UpdateMethod;
                    string LocalPath = PatchFile.GetLocalPath(LocalPaths);
                    string RemotePath = String.Format("{0}\\{1}", RemoteContentPatchPath, PatchFile.FileName);
                    string FileStorePath = String.Format("{0}/{1}", FileStoreContentPatchPath, PatchFile.FileName).Replace('\\', '/');
                    string LocalHashString = "<no such file>";
                    string TransferTempFilePath = LocalPath + ".patchxfer";

                    if (File.Exists(LocalPath))
                    {
                        LocalHashString = GetFileChecksum(LocalPath, MD5Csp);

                        Matched = (LocalHashString.ToString() == PatchFile.Checksum.ToLower());
                    }

                    if (Matched)
                    {
                        Script.WriteTimestampedLogEntry(String.Format(
                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} is up to date (checksum {1}).",
                            PatchFile.FileName,
                            LocalHashString));
                    }
                    else
                    {
                        if (File.Exists(TransferTempFilePath))
                        {
                            try
                            {
                                File.Delete(TransferTempFilePath);
                            }
                            catch (Exception e)
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} removing transfer temp file {1} for transfer file {2}.",
                                    e,
                                    TransferTempFilePath,
                                    PatchFile.FileName));
                            }
                        }

                        Script.WriteTimestampedLogEntry(String.Format(
                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} needs to be updated (local checksum {1}, remote checksum {2}).  Copying file...",
                            PatchFile.FileName,
                            LocalHashString,
                            PatchFile.Checksum));

                        if (PatchFile.RecompileModule)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} requires a module recompile, flagging module for recompilation.",
                                PatchFile.FileName));
                            RecompileModule = true;
                        }

                        if (!SentNotification)
                        {
                            Script.SendInfrastructureIrcMessage(String.Format(
                                "Server '{0}' is applying a content patch, and will restart shortly.",
                                Script.GetName(Script.GetModule())));
                            SentNotification = true;
                        }

                        Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                            "Server '{0}' is updating content file '{1}'.",
                            Script.GetName(Script.GetModule()),
                            PatchFile.FileName));

                        //
                        // The file needs to be updated.  Copy it over and
                        // re-validate the checksum.  If the checksum did not
                        // match, log an error and delete the file.
                        //

                        try
                        {
                            try
                            {
                                //
                                // Try first to download via the file store
                                // provider.  If that fails (e.g. the file
                                // store is not supported), then fall back to
                                // the traditional remote vault share transfer
                                // mechanism.
                                //

                                try
                                {
                                    DownloadContentPatchFromFileStore(FileStorePath, TransferTempFilePath, ConnectionString, Script);
                                }
                                catch (Exception e)
                                {
                                    Script.WriteTimestampedLogEntry(String.Format("ModuleContentPatcher.ProcessContentPatches: Couldn't retrieve uncompressed file {0} from Azure, falling back to file share, due to exception: {1}", FileStorePath, e));
                                    File.Copy(RemotePath, TransferTempFilePath, true);
                                }
                            }
                            catch
                            {
                                throw;
                            }

                            UpdateMethod = PatchFile.UpdateMethod;

                            //
                            // If we are patching a hak, rename it away so that
                            // the file can be written to.
                            //

                            switch (UpdateMethod)
                            {

                                case FileUpdateMethod.FileUpdateMethodRename:
                                    if (File.Exists(LocalPath))
                                    {
                                        string OldFileName = LocalPath + ".old";

                                        if (File.Exists(OldFileName))
                                            File.Delete(OldFileName);

                                        File.Move(LocalPath, OldFileName);
                                        Rename = true;
                                    }
                                    break;

                                case FileUpdateMethod.FileUpdateMethodDirectReplace:
                                    break;

                            }

                            Database.ACR_IncrementStatistic("CONTENT_PATCH_" + PatchFile.Location.ToUpper());

                            try
                            {
                                if (Rename)
                                    File.Move(TransferTempFilePath, LocalPath);
                                else
                                    File.Copy(TransferTempFilePath, LocalPath, true);
                            }
                            catch
                            {
                                if (UpdateMethod == FileUpdateMethod.FileUpdateMethodRename)
                                {
                                    string OldFileName = LocalPath + ".old";

                                    try
                                    {
                                        if (File.Exists(LocalPath))
                                            File.Delete(LocalPath);
                                    }
                                    catch
                                    {
                                    }

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                throw;
                            }

                            if (GetFileChecksum(LocalPath, MD5Csp) != PatchFile.Checksum.ToLower())
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} was copied, but checksum did not match {1}!  This may indicate a configuration error in the database, or file corruption in transit.",
                                    PatchFile.FileName,
                                    PatchFile.Checksum));
                                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                    "Server '{0}' had checksum mismatch for content patch file {1} after hotfix file deployment, rolling back file.",
                                    Script.GetName(Script.GetModule()),
                                    PatchFile.FileName));

                                if (UpdateMethod == FileUpdateMethod.FileUpdateMethodRename)
                                {
                                    string OldFileName = LocalPath + ".old";

                                    try
                                    {
                                        if (File.Exists(LocalPath))
                                            File.Delete(LocalPath);
                                    }
                                    catch
                                    {
                                    }

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_INCORRECT_CHECKSUM");
                            }
                            else
                            {
                                ContentChanged = true;

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_UPDATED_FILE");

                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessContentPatches: Successfully updated content patch file {0}.",
                                    PatchFile.FileName));
                            }
                        }
                        catch (Exception e)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                "ModuleContentPatcher.ProcessContentPatches: Exception {0} updating content patch file {1}.",
                                e,
                                PatchFile.FileName));

                            Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                "Server '{0}' encountered exception deploying content patch file {1}, rolling back file.",
                                Script.GetName(Script.GetModule()),
                                PatchFile.FileName));
                        }
                    }

                    if (File.Exists(TransferTempFilePath))
                    {
                        try
                        {
                            File.Delete(TransferTempFilePath);
                        }
                        catch (Exception e)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} removing transfer temp file {1} for transfer file {2} after patching completed.",
                                e,
                                TransferTempFilePath,
                                PatchFile.FileName));
                        }
                    }
                }
            }

            //
            // Update autodownloader configuration, as necessary.
            //

            try
            {
                if (ProcessModuleDownloaderResourcesUpdates(Database, Script))
                {
                    Script.WriteTimestampedLogEntry("ModuleContentPatcher.ProcessContentPatches: Autodownloader configuration updated.");
                    ContentChanged = true;
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} updating autodownloader configuration.",
                    e));

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                    "Server '{0}' encountered exception updating autodownloader configuration.",
                    Script.GetName(Script.GetModule())));
            }

            if (ContentChanged)
            {
                if (RecompileModule)
                {
                    Script.WriteTimestampedLogEntry("ModuleContentPatcher.ProcessContentPatches: A module recompile is required; recompiling module...");
                    CompileModuleScripts(Script, Database);
                }

                Database.ACR_IncrementStatistic("CONTENT_PATCH_REBOOT");

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                    "Server '{0}' restarting after content patch deployment (old HAK ACR version {1} build date {2}, old module ACR version {3}).",
                    Script.GetName(Script.GetModule()),
                    Database.ACR_GetHAKVersion(),
                    Database.ACR_GetHAKBuildDate(),
                    Database.ACR_GetVersion()));
            }

            return ContentChanged;
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            //
            // If the event was for a player logging off of the local server,
            // then don't re-broadcast it.
            //

            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                    continue;

                if (Player.CharacterIdsShown.Contains(Character.CharacterId))
                {
                    string sPlayerListBox = "";

                    if (Server.ServerId == Script.GetDatabase().ACR_GetServerID() || Script.GetLocalInt(PlayerObject, "chatselect_expanded") == 0)
                    {
                        if (IsDM == true)
                        {
                            sPlayerListBox = "LocalDMList";
                            Player.ChatSelectLocalDMsShown -= 1;
                        }
                        else
                        {
                            sPlayerListBox = "LocalPlayerList";
                            Player.ChatSelectLocalPlayersShown -= 1;
                        }
                    }
                    else
                    {
                        if (IsDM == true)
                        {
                            sPlayerListBox = "RemoteDMList";
                            Player.ChatSelectRemoteDMsShown -= 1;
                        }
                        else
                        {
                            sPlayerListBox = "RemotePlayerList";
                            Player.ChatSelectRemotePlayersShown -= 1;
                        }
                    }

                    Script.RemoveListBoxRow(Player.ObjectId, "ChatSelect", sPlayerListBox, Character.CharacterName);
                    Player.CharacterIdsShown.Remove(Character.CharacterId);
                    Player.UpdateChatSelectGUIHeaders();
                }
            }

            if (Database.ACR_GetServerID() == Server.ServerId)
                return;

            string Message = String.Format(
                "{0}<c=#FFDAB9>{1} ({2}) left {3}.</c>", // <c=Peachpuff...>
                IsDM ? "<c=#99CCFF>[DM] </c>" : "",
                Character.Name,
                Character.Player.Name,
                Server.Name);
            string ChatMessage = "</c>" + Message;

            foreach (uint PlayerObject in Script.GetPlayers(true))
            {
                PlayerState Player = Script.TryGetPlayerState(PlayerObject);

                if (Player == null)
                    continue;

                if (!Script.IsCrossServerNotificationEnabled(PlayerObject))
                    continue;

                if ((Player.Flags & PlayerStateFlags.SendCrossServerNotificationsToCombatLog) != 0)
                {
                    Script.SendMessageToPC(PlayerObject, Message);
                }
                else
                {
                    Script.SendChatMessage(
                        CLRScriptBase.OBJECT_INVALID,
                        PlayerObject,
                        CLRScriptBase.CHAT_MODE_SERVER,
                        ChatMessage,
                        CLRScriptBase.FALSE);
                }
            }

#if DEBUG_MODE
            Script.WriteTimestampedLogEntry(Message);
#endif
        }
        /// <summary>
        /// Process any updates to moduledownloaderresources.xml.
        /// </summary>
        /// <param name="Database">Supplies the database object.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <returns>True if a patch was applied and a reboot is required for
        /// it to take effect.</returns>
        public static bool ProcessModuleDownloaderResourcesUpdates(ALFA.Database Database, ACR_ServerCommunicator Script)
        {
            bool ContentChanged = false;

            //
            // Check the database for the expected download server configurations.
            //

            Database.ACR_SQLQuery("SELECT `Hash`, `DownloadHash`, `Name`, `DLSize`, `Size` FROM `content_download_config`");

            List<DownloadConfiguration> hakConfigs = new List<DownloadConfiguration>();

            //
            // Build a list of expected download configurations.
            //

            while (Database.ACR_SQLFetch())
            {
                DownloadConfiguration downloadConfig = new DownloadConfiguration();

                downloadConfig.Hash = Database.ACR_SQLGetData(0);
                downloadConfig.DownloadHash = Database.ACR_SQLGetData(1);
                downloadConfig.Name = Database.ACR_SQLGetData(2);
                downloadConfig.DLSize = Database.ACR_SQLGetData(3);
                downloadConfig.Size = Database.ACR_SQLGetData(4);

                if (String.IsNullOrEmpty(downloadConfig.Hash) ||
                    String.IsNullOrEmpty(downloadConfig.DownloadHash) ||
                    String.IsNullOrEmpty(downloadConfig.Name) ||
                    String.IsNullOrEmpty(downloadConfig.DLSize) ||
                    String.IsNullOrEmpty(downloadConfig.Size))
                {
                    continue;
                }

                hakConfigs.Add(downloadConfig);
            }

            //
            // If we have any configuration to do, we loop through and compare the 
            // configuration on the database with the configuration on the server,
            // updating the downloadresources xml if it is new.
            //

            if (hakConfigs.Count > 0)
            {
                XmlDocument moduleDownloadResources = new XmlDocument();
                moduleDownloadResources.Load(ALFA.SystemInfo.GetModuleDirectory() + "\\moduledownloaderresources.xml");
                XmlElement downloadResources = moduleDownloadResources.DocumentElement;

                foreach (DownloadConfiguration config in hakConfigs)
                {
                    foreach (XmlNode node in downloadResources.ChildNodes)
                    {
                        if (node.Attributes["name"].Value == config.Name)
                        {
                            if (node.Attributes["hash"].Value != config.Hash)
                            {
                                node.Attributes["hash"].Value = config.Hash;
                                ContentChanged = true;
                            }
                            if (node.Attributes["downloadHash"].Value != config.DownloadHash)
                            {
                                node.Attributes["downloadHash"].Value = config.DownloadHash;
                                ContentChanged = true;
                            }
                            if (node.Attributes["dlsize"].Value != config.DLSize)
                            {
                                node.Attributes["dlsize"].Value = config.DLSize;
                                ContentChanged = true;
                            }
                            if (node.Attributes["size"].Value != config.Size)
                            {
                                node.Attributes["size"].Value = config.Size;
                                ContentChanged = true;
                            }

                            if (ContentChanged)
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                    "ModuleContentPatcher.ProcessModuleDownloaderResourcesUpdates: Updated downloader resource {0} (hash {1}).",
                                    config.Name,
                                    config.Hash));
                            }
                        }
                    }
                }

                if (ContentChanged)
                    moduleDownloadResources.Save(ALFA.SystemInfo.GetModuleDirectory() + "\\moduledownloaderresources.xml");
            }

            return ContentChanged;
        }
 /// <summary>
 /// Run the event queue down.  All events in the queue are given a
 /// chance to run.
 /// </summary>
 /// <param name="Script">Supplies the script object.</param>
 /// <param name="Database">Supplies the database connection.</param>
 public void RunQueue(ACR_ServerCommunicator Script, ALFA.Database Database)
 {
     EventQueue.RunQueue(Script, Database);
     EventsQueued = false;
 }
        /// <summary>
        /// This method is called to resynchronize the GUI state of a player
        /// that executed a server to server portal, if the player is in an
        /// area.
        /// </summary>
        /// <param name="ResyncInfo">Supplies the resync block for the
        /// player.  This contains the deserialized resynchronization command
        /// data.</param>
        /// <param name="PCObject">Supplies the player object id.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Tries">Supplies the count of retries.</param>
        private static void ResynchronizePlayerState(ResyncState ResyncInfo, uint PCObject, ACR_ServerCommunicator Script, int Tries = 0)
        {
            if (Script.GetIsObjectValid(PCObject) == ACR_ServerCommunicator.FALSE)
            {
                //
                // The player logged out while a resync request was pending.
                // Throw away the state as it is no longer needed on a full log
                // out and log in sequence.
                //

                return;
            }

            if ((Script.GetArea(PCObject) == ACR_ServerCommunicator.OBJECT_INVALID) ||
                (Script.GetScriptHidden(PCObject) != ACR_ServerCommunicator.FALSE))
            {
                //
                // The player may still be in transition or is not yet loaded.
                // Queue the request.
                //

                if (Tries < MAX_RESYNC_RETRIES)
                {
                    Script.DelayCommand(RESYNC_RETRY_INTERVAL, delegate()
                    {
                        ResynchronizePlayerState(ResyncInfo, PCObject, Script, Tries + 1);
                    });
                }

                return;
            }

            PlayerState State = Script.TryGetPlayerState(PCObject);

            if (State == null)
            {
                return;
            }

            //
            // Area transition has finished.  Apply the GUI state now.
            //

            State.ChatSelectGUIExpanded = ((ResyncInfo.ResyncFlags & RESYNC_FLAG_CHAT_SELECT_EXPANDED) != 0);
            State.UpdateChatSelectGUIHeaders();

            Script.SendMessageToPC(PCObject, "Server to server portal completed.");
            Script.WriteTimestampedLogEntry(String.Format(
                                                "ACR_ServerCommunicator.GUIResynchronizer.ResynchronizePlayerState: Resynchronized player GUI state for player {0} after server-to-server portal.",
                                                Script.GetName(PCObject)));
        }
        /// <summary>
        /// Recompile all scripts in the module.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        private static void CompileModuleScripts(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            ALFA.ScriptCompiler.CompilerResult Result;
            string CompilerOptions = Script.GetLocalString(Script.GetModule(), "ACR_MOD_COMPILER_OPTIONS");
            List<string> CompilerOutput = new List<string>();

            Script.WriteTimestampedLogEntry(String.Format(
                "ModuleContentPatcher.CompileModuleScripts: Compiling module scripts with compiler options '{0}'...", CompilerOptions));
            Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                "Server '{0}' is recompiling module scripts.",
                Script.GetName(Script.GetModule())));

            Result = ALFA.ScriptCompiler.CompileScript("*.nss", CompilerOptions, delegate(string Line)
            {
                if (!String.IsNullOrWhiteSpace(Line))
                {
                    Script.WriteTimestampedLogEntry(Line);
                }
                return false;
            });

            foreach (string Message in Result.Warnings)
            {
                try
                {
                    CompilerOutput.Add(Message);
                }
                catch (Exception)
                {
                }
            }

            if (Result.Compiled)
            {
                Script.WriteTimestampedLogEntry("ModuleContentPatcher.CompileModuleScripts: Module successfully recompiled.");
                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE");

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                    "Server '{0}' successfully recompiled module with {1} warning(s) for content patch deployment.",
                    Script.GetName(Script.GetModule()),
                    Result.Warnings.Count));
            }
            else
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "ModuleContentPatcher.CompileModuleScripts: {0} error(s) compiling module!", Result.Errors.Count));

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                    "Server '{0}' had {1} error(s), {2} warning(s) recompiling module for content patch deployment.",
                    Script.GetName(Script.GetModule()),
                    Result.Errors.Count,
                    Result.Warnings.Count));

                foreach (string Message in Result.Errors)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                        "ModuleContentPatcher.CompileModuleScripts: Error '{0}'.", Message));

                    try
                    {
                        CompilerOutput.Add(Message);
                    }
                    catch (Exception)
                    {
                    }
                }

                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE_FAILED");
            }

            //
            // Save compiler output to a temporary file for later retrieval.
            //

            try
            {
                string FileName = String.Format("{0}{1}ALFAModuleRecompile.log", Path.GetTempPath(), Path.DirectorySeparatorChar);

                File.WriteAllLines(FileName, CompilerOutput);
            }
            catch (Exception)
            {

            }

        }
        /// <summary>
        /// Download a content patch file from a file store.  Currently, Azure
        /// file stores are assumed.  Both compressed and uncompressed versions
        /// of the file are tried in respective order.
        /// </summary>
        /// <param name="FileStorePath">Supplies the remote file name that
        /// designates the file to download.</param>
        /// <param name="LocalFileName">Supplies the local file name to
        /// download to.</param>
        /// <param name="ConnectionString">Supplies the file store connection
        /// string.</param>
        /// <param name="Script">Supplies the script object.</param>
        private static void DownloadContentPatchFromFileStore(string FileStorePath, string LocalFileName, string ConnectionString, ACR_ServerCommunicator Script)
        {
            if (String.IsNullOrEmpty(ConnectionString))
                throw new NotSupportedException();

            //
            // Initialize the file store provider.
            //

            FileStore UpdaterStore = FileStoreProvider.CreateAzureFileStore(ConnectionString);
            FileStoreContainer UpdaterContainer = UpdaterStore.GetContainerReference(FileStoreNamespace.ACRUpdater);
            FileStoreFile UpdaterFile = UpdaterContainer.GetFileReference(FileStorePath + ".gzip");

            //
            // First attempt to retrieve a gzip compressed version of the file
            // to patch.  If that fails then fall back to a plaintext version.
            //

            try
            {
                using (MemoryStream MemStream = new MemoryStream())
                {
                    UpdaterFile.Read(MemStream);

                    MemStream.Position = 0;

                    using (FileStream OutStream = File.Create(LocalFileName))
                    {
                        using (GZipStream CompressedStream = new GZipStream(MemStream, CompressionMode.Decompress))
                        {
                            CompressedStream.CopyTo(OutStream);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format("ModuleContentPatcher.DownloadContentPatchFromFileStore: Couldn't retrieve compressed file {0} from Azure, trying uncompressed file, due to exception: {1}",
                    FileStorePath,
                    e));

                UpdaterFile = UpdaterContainer.GetFileReference(FileStorePath);

                using (FileStream OutStream = File.Create(LocalFileName))
                {
                    UpdaterFile.Read(OutStream);
                }
            }
        }
        /// <summary>
        /// This method is called when the ClientEnter event fires for a
        /// player.  Its purpose is to check whether the player has a pending
        /// resync request, and, if so, to execute the resync operation.
        /// </summary>
        /// <param name="State">Supplies the player object of the incoming
        /// player.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void OnClientEnter(uint PCObject, ACR_ServerCommunicator Script)
        {
            PlayerState State = Script.TryGetPlayerState(PCObject);

            if (State == null)
                return;

            var ResyncInfo = (from RS in PlayerResyncStates
                              where RS.PlayerId == State.PlayerId
                              select RS).FirstOrDefault();

            if (ResyncInfo == null)
                return;

            //
            // Dequeue the resync state and start attempting to apply it to the
            // player object once the player has loaded.
            //

            PlayerResyncStates.Remove(ResyncInfo);
            ResynchronizePlayerState(ResyncInfo, PCObject, Script);
        }
        /// <summary>
        /// This method is called when a cross-server chat select
        /// resynchronization request is received.  Its purpose is to scan the
        /// player list to check whether the argument player is online, and to
        /// activate chat select GUI resynchronization if appropriate, else to
        /// queue the resynchronization until the player does log in.
        /// </summary>
        /// <param name="SourceServerId">Supplies the server id of the server
        /// that requested the GUI resynchronization.</param>
        /// <param name="ResyncCommand">Supplies the GUI resynchronizer command
        /// line as generated by SendGUIStateToServer().</param>
        /// <param name="Script">Supplies the current script object.</param>
        /// <returns>TRUE on success, else FALSE on failure.</returns>
        public static int HandleGUIResync(int SourceServerId, string ResyncCommand, ACR_ServerCommunicator Script)
        {
            try
            {
                ResyncState RemoteResyncInfo;

                //
                // Deserialize the remote resynchronization state.  On null, an
                // obviously invalid request was received.  Otherwise a protocol
                // violation that is atypical was received and an exception is
                // raised.
                //

                if ((RemoteResyncInfo = ResyncState.FromString(ResyncCommand)) == null)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                                                        "ACR_ServerCommunicator.GUIResynchronizer.HandleGUIResync({0}, {1}): Invalid request.",
                                                        SourceServerId,
                                                        ResyncCommand));
                    return(ACR_ServerCommunicator.FALSE);
                }

                //
                // If a request was not already enqueued for this player, then
                // enqueue it.
                //

                var ResyncInfo = (from RS in PlayerResyncStates
                                  where RS.PlayerId == RemoteResyncInfo.PlayerId
                                  select RS).FirstOrDefault();

                if (ResyncInfo == null)
                {
                    //
                    // If the player is logged on, directly enqueue the execute
                    // request now.  Otherwise, wait for the ClientEnter event
                    // as the player might still reside on the remote server.
                    //

                    foreach (uint PCObject in Script.GetPlayers(true))
                    {
                        PlayerState State;

                        if ((State = Script.TryGetPlayerState(PCObject)) == null)
                        {
                            continue;
                        }

                        if (State.PlayerId != RemoteResyncInfo.PlayerId)
                        {
                            continue;
                        }

                        ResynchronizePlayerState(RemoteResyncInfo, PCObject, Script);

                        return(ACR_ServerCommunicator.TRUE);
                    }

                    //
                    // Enqueue the request so that it can be processed at
                    // ClientEnter time.
                    //

                    PlayerResyncStates.Add(RemoteResyncInfo);
                }
                else
                {
                    //
                    // Update the resync flags to match the new request.
                    //

                    ResyncInfo.ResyncFlags = RemoteResyncInfo.ResyncFlags;
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "ACR_ServerCommunicator.GUIResynchronizer.HandleGUIResync({0}, {1}): Exception: {0}",
                                                    SourceServerId,
                                                    ResyncCommand,
                                                    e));
                return(ACR_ServerCommunicator.FALSE);
            }

            return(ACR_ServerCommunicator.TRUE);
        }
        /// <summary>
        /// This method is called when a portal transition has been committed
        /// to send a player to a remote server.
        /// </summary>
        /// <param name="State">Supplies the local state for the player that is
        /// committed to a portal transition.
        /// </param>
        /// <param name="Server">Supplies the destination server for the portal
        /// event.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void SendGUIStateToServer(PlayerState State, GameServer Server, ACR_ServerCommunicator Script)
        {
            //
            // Build the resynchronization command.  The resynchronization
            // command is parsed by HandleGUIResync().  Note that the remote
            // and local servers may not be of the same version, i.e. the
            // remote server may not understand fields that are created by the
            // local server if it is of a newer version.
            //

            ResyncState ResyncInfo = new ResyncState(State.PlayerId, 0);

            if (State.ChatSelectGUIExpanded)
                ResyncInfo.ResyncFlags |= RESYNC_FLAG_CHAT_SELECT_EXPANDED;

            //
            // Dispatch the resync script execution request to the remote
            // server.  The remote server will process it when the request has
            // been received.
            //

            Script.RunScriptOnServer(Server.ServerId, "acr_resync_gui", ResyncInfo.ToString());
        }
Пример #49
0
        /// <summary>
        /// Process any updates to moduledownloaderresources.xml.
        /// </summary>
        /// <param name="Database">Supplies the database object.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <returns>True if a patch was applied and a reboot is required for
        /// it to take effect.</returns>
        public static bool ProcessModuleDownloaderResourcesUpdates(ALFA.Database Database, ACR_ServerCommunicator Script)
        {
            bool ContentChanged = false;

            //
            // Check the database for the expected download server configurations.
            //

            Database.ACR_SQLQuery("SELECT `Hash`, `DownloadHash`, `Name`, `DLSize`, `Size` FROM `content_download_config`");

            List <DownloadConfiguration> hakConfigs = new List <DownloadConfiguration>();

            //
            // Build a list of expected download configurations.
            //

            while (Database.ACR_SQLFetch())
            {
                DownloadConfiguration downloadConfig = new DownloadConfiguration();

                downloadConfig.Hash         = Database.ACR_SQLGetData(0);
                downloadConfig.DownloadHash = Database.ACR_SQLGetData(1);
                downloadConfig.Name         = Database.ACR_SQLGetData(2);
                downloadConfig.DLSize       = Database.ACR_SQLGetData(3);
                downloadConfig.Size         = Database.ACR_SQLGetData(4);

                if (String.IsNullOrEmpty(downloadConfig.Hash) ||
                    String.IsNullOrEmpty(downloadConfig.DownloadHash) ||
                    String.IsNullOrEmpty(downloadConfig.Name) ||
                    String.IsNullOrEmpty(downloadConfig.DLSize) ||
                    String.IsNullOrEmpty(downloadConfig.Size))
                {
                    continue;
                }

                hakConfigs.Add(downloadConfig);
            }

            //
            // If we have any configuration to do, we loop through and compare the
            // configuration on the database with the configuration on the server,
            // updating the downloadresources xml if it is new.
            //

            if (hakConfigs.Count > 0)
            {
                XmlDocument moduleDownloadResources = new XmlDocument();
                moduleDownloadResources.Load(ALFA.SystemInfo.GetModuleDirectory() + "\\moduledownloaderresources.xml");
                XmlElement downloadResources = moduleDownloadResources.DocumentElement;

                foreach (DownloadConfiguration config in hakConfigs)
                {
                    foreach (XmlNode node in downloadResources.ChildNodes)
                    {
                        if (node.Attributes["name"].Value == config.Name)
                        {
                            if (node.Attributes["hash"].Value != config.Hash)
                            {
                                node.Attributes["hash"].Value = config.Hash;
                                ContentChanged = true;
                            }
                            if (node.Attributes["downloadHash"].Value != config.DownloadHash)
                            {
                                node.Attributes["downloadHash"].Value = config.DownloadHash;
                                ContentChanged = true;
                            }
                            if (node.Attributes["dlsize"].Value != config.DLSize)
                            {
                                node.Attributes["dlsize"].Value = config.DLSize;
                                ContentChanged = true;
                            }
                            if (node.Attributes["size"].Value != config.Size)
                            {
                                node.Attributes["size"].Value = config.Size;
                                ContentChanged = true;
                            }

                            if (ContentChanged)
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                                                    "ModuleContentPatcher.ProcessModuleDownloaderResourcesUpdates: Updated downloader resource {0} (hash {1}).",
                                                                    config.Name,
                                                                    config.Hash));
                            }
                        }
                    }
                }

                if (ContentChanged)
                {
                    moduleDownloadResources.Save(ALFA.SystemInfo.GetModuleDirectory() + "\\moduledownloaderresources.xml");
                }
            }

            return(ContentChanged);
        }
        /// <summary>
        /// This method is called when a cross-server chat select
        /// resynchronization request is received.  Its purpose is to scan the
        /// player list to check whether the argument player is online, and to
        /// activate chat select GUI resynchronization if appropriate, else to
        /// queue the resynchronization until the player does log in.
        /// </summary>
        /// <param name="SourceServerId">Supplies the server id of the server
        /// that requested the GUI resynchronization.</param>
        /// <param name="ResyncCommand">Supplies the GUI resynchronizer command
        /// line as generated by SendGUIStateToServer().</param>
        /// <param name="Script">Supplies the current script object.</param>
        /// <returns>TRUE on success, else FALSE on failure.</returns>
        public static int HandleGUIResync(int SourceServerId, string ResyncCommand, ACR_ServerCommunicator Script)
        {
            try
            {
                ResyncState RemoteResyncInfo;

                //
                // Deserialize the remote resynchronization state.  On null, an
                // obviously invalid request was received.  Otherwise a protocol
                // violation that is atypical was received and an exception is
                // raised.
                //

                if ((RemoteResyncInfo = ResyncState.FromString(ResyncCommand)) == null)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                        "ACR_ServerCommunicator.GUIResynchronizer.HandleGUIResync({0}, {1}): Invalid request.",
                        SourceServerId,
                        ResyncCommand));
                    return ACR_ServerCommunicator.FALSE;
                }

                //
                // If a request was not already enqueued for this player, then
                // enqueue it.
                //

                var ResyncInfo = (from RS in PlayerResyncStates
                                  where RS.PlayerId == RemoteResyncInfo.PlayerId
                                  select RS).FirstOrDefault();

                if (ResyncInfo == null)
                {
                    //
                    // If the player is logged on, directly enqueue the execute
                    // request now.  Otherwise, wait for the ClientEnter event
                    // as the player might still reside on the remote server.
                    //

                    foreach (uint PCObject in Script.GetPlayers(true))
                    {
                        PlayerState State;

                        if ((State = Script.TryGetPlayerState(PCObject)) == null)
                            continue;

                        if (State.PlayerId != RemoteResyncInfo.PlayerId)
                            continue;

                        ResynchronizePlayerState(RemoteResyncInfo, PCObject, Script);

                        return ACR_ServerCommunicator.TRUE;
                    }

                    //
                    // Enqueue the request so that it can be processed at
                    // ClientEnter time.
                    //

                    PlayerResyncStates.Add(RemoteResyncInfo);
                }
                else
                {
                    //
                    // Update the resync flags to match the new request.
                    //

                    ResyncInfo.ResyncFlags = RemoteResyncInfo.ResyncFlags;
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "ACR_ServerCommunicator.GUIResynchronizer.HandleGUIResync({0}, {1}): Exception: {0}",
                    SourceServerId,
                    ResyncCommand,
                    e));
                return ACR_ServerCommunicator.FALSE;
            }

            return ACR_ServerCommunicator.TRUE;
        }
Пример #51
0
        /// <summary>
        /// Process and apply content patches.  A server restart is scheduled
        /// if required for the content patch.
        /// </summary>
        /// <param name="ContentPatchPath">Supplies the configured content
        /// patch base path, from the database config table.</param>
        /// <param name="Database">Supplies the database object.</param>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="ConnectionString">Supplies the updater file store
        /// connection string.</param>
        /// <returns>True if a patch was applied and a reboot is required for
        /// it to take effect.</returns>
        public static bool ProcessContentPatches(string ContentPatchPath, ALFA.Database Database, ACR_ServerCommunicator Script, string ConnectionString)
        {
            bool   ContentChanged = false;
            string Version        = Database.ACR_GetHAKVersion();
            List <ContentPatchFile> PatchFiles = new List <ContentPatchFile>();
            ContentPatchPaths       LocalPaths = new ContentPatchPaths()
            {
                HakPath      = ALFA.SystemInfo.GetHakDirectory(),
                OverridePath = ALFA.SystemInfo.GetOverrideDirectory() + "ACR_ContentPatches"
            };
            string RemoteContentPatchPath    = String.Format("{0}{1}\\{2}", ALFA.SystemInfo.GetCentralVaultPath(), ContentPatchPath, Version);
            string FileStoreContentPatchPath = String.Format("{0}/{1}", ContentPatchPath, Version).Replace('\\', '/');
            bool   RecompileModule           = false;
            bool   SentNotification          = false;

            Database.ACR_SQLQuery(String.Format(
                                      "SELECT `FileName`, `Location`, `Checksum`, `RecompileModule` FROM `content_patch_files` WHERE `HakVersion` = '{0}'",
                                      Database.ACR_SQLEncodeSpecialChars(Version)));

            while (Database.ACR_SQLFetch())
            {
                ContentPatchFile PatchFile = new ContentPatchFile();

                PatchFile.FileName        = Database.ACR_SQLGetData(0);
                PatchFile.Location        = Database.ACR_SQLGetData(1);
                PatchFile.Checksum        = Database.ACR_SQLGetData(2);
                PatchFile.RecompileModule = ALFA.Database.ACR_ConvertDatabaseStringToBoolean(Database.ACR_SQLGetData(3));

                if (PatchFile.Location != "override" &&
                    PatchFile.Location != "hak")
                {
                    continue;
                }

                if (!ALFA.SystemInfo.IsSafeFileName(PatchFile.FileName))
                {
                    continue;
                }

                PatchFiles.Add(PatchFile);
            }

            if (!Directory.Exists(LocalPaths.OverridePath))
            {
                Directory.CreateDirectory(LocalPaths.OverridePath);
            }

            //
            // Remove entries in the ACR patch override directory that are not
            // listed in the patch table.  These may be patches for a previous
            // version, and are not applicable.
            //

            foreach (string DirFile in Directory.GetFiles(LocalPaths.OverridePath))
            {
                ContentPatchFile FoundPatch = (from PF in PatchFiles
                                               where (PF.FileName.Equals(Path.GetFileName(DirFile), StringComparison.InvariantCultureIgnoreCase) && PF.Location == "override")
                                               select PF).FirstOrDefault();
                if (FoundPatch == null)
                {
                    Database.ACR_IncrementStatistic("CONTENT_PATCH_REMOVE_FILE");

                    Script.WriteTimestampedLogEntry(String.Format(
                                                        "ModuleContentPatcher.ProcessContentPatches: Removing extraneous file {0} from {1}", Path.GetFileName(DirFile), LocalPaths.OverridePath));

                    File.Delete(DirFile);
                    ContentChanged = true;
                }
            }

            //
            // Verify that the MD5 checksum of each of the content files in the
            // ACR patch override directory matches the database's expected
            // checksum.  If not (or if the file in question didn't exist),
            // then copy the new version over from the central vault.
            //

            using (MD5CryptoServiceProvider MD5Csp = new MD5CryptoServiceProvider())
            {
                foreach (ContentPatchFile PatchFile in PatchFiles)
                {
                    bool             Matched = false;
                    bool             Rename  = false;
                    FileUpdateMethod UpdateMethod;
                    string           LocalPath            = PatchFile.GetLocalPath(LocalPaths);
                    string           RemotePath           = String.Format("{0}\\{1}", RemoteContentPatchPath, PatchFile.FileName);
                    string           FileStorePath        = String.Format("{0}/{1}", FileStoreContentPatchPath, PatchFile.FileName).Replace('\\', '/');
                    string           LocalHashString      = "<no such file>";
                    string           TransferTempFilePath = LocalPath + ".patchxfer";

                    if (File.Exists(LocalPath))
                    {
                        LocalHashString = GetFileChecksum(LocalPath, MD5Csp);

                        Matched = (LocalHashString.ToString() == PatchFile.Checksum.ToLower());
                    }

                    if (Matched)
                    {
                        Script.WriteTimestampedLogEntry(String.Format(
                                                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} is up to date (checksum {1}).",
                                                            PatchFile.FileName,
                                                            LocalHashString));
                    }
                    else
                    {
                        if (File.Exists(TransferTempFilePath))
                        {
                            try
                            {
                                File.Delete(TransferTempFilePath);
                            }
                            catch (Exception e)
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                                                    "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} removing transfer temp file {1} for transfer file {2}.",
                                                                    e,
                                                                    TransferTempFilePath,
                                                                    PatchFile.FileName));
                            }
                        }

                        Script.WriteTimestampedLogEntry(String.Format(
                                                            "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} needs to be updated (local checksum {1}, remote checksum {2}).  Copying file...",
                                                            PatchFile.FileName,
                                                            LocalHashString,
                                                            PatchFile.Checksum));

                        if (PatchFile.RecompileModule)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                                                "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} requires a module recompile, flagging module for recompilation.",
                                                                PatchFile.FileName));
                            RecompileModule = true;
                        }

                        if (!SentNotification)
                        {
                            Script.SendInfrastructureIrcMessage(String.Format(
                                                                    "Server '{0}' is applying a content patch, and will restart shortly.",
                                                                    Script.GetName(Script.GetModule())));
                            SentNotification = true;
                        }

                        Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                          "Server '{0}' is updating content file '{1}'.",
                                                                          Script.GetName(Script.GetModule()),
                                                                          PatchFile.FileName));

                        //
                        // The file needs to be updated.  Copy it over and
                        // re-validate the checksum.  If the checksum did not
                        // match, log an error and delete the file.
                        //

                        try
                        {
                            try
                            {
                                //
                                // Try first to download via the file store
                                // provider.  If that fails (e.g. the file
                                // store is not supported), then fall back to
                                // the traditional remote vault share transfer
                                // mechanism.
                                //

                                try
                                {
                                    DownloadContentPatchFromFileStore(FileStorePath, TransferTempFilePath, ConnectionString, Script);
                                }
                                catch (Exception e)
                                {
                                    Script.WriteTimestampedLogEntry(String.Format("ModuleContentPatcher.ProcessContentPatches: Couldn't retrieve uncompressed file {0} from Azure, falling back to file share, due to exception: {1}", FileStorePath, e));
                                    File.Copy(RemotePath, TransferTempFilePath, true);
                                }
                            }
                            catch
                            {
                                throw;
                            }

                            UpdateMethod = PatchFile.UpdateMethod;

                            //
                            // If we are patching a hak, rename it away so that
                            // the file can be written to.
                            //

                            switch (UpdateMethod)
                            {
                            case FileUpdateMethod.FileUpdateMethodRename:
                                if (File.Exists(LocalPath))
                                {
                                    string OldFileName = LocalPath + ".old";

                                    if (File.Exists(OldFileName))
                                    {
                                        File.Delete(OldFileName);
                                    }

                                    File.Move(LocalPath, OldFileName);
                                    Rename = true;
                                }
                                break;

                            case FileUpdateMethod.FileUpdateMethodDirectReplace:
                                break;
                            }

                            Database.ACR_IncrementStatistic("CONTENT_PATCH_" + PatchFile.Location.ToUpper());

                            try
                            {
                                if (Rename)
                                {
                                    File.Move(TransferTempFilePath, LocalPath);
                                }
                                else
                                {
                                    File.Copy(TransferTempFilePath, LocalPath, true);
                                }
                            }
                            catch
                            {
                                if (UpdateMethod == FileUpdateMethod.FileUpdateMethodRename)
                                {
                                    string OldFileName = LocalPath + ".old";

                                    try
                                    {
                                        if (File.Exists(LocalPath))
                                        {
                                            File.Delete(LocalPath);
                                        }
                                    }
                                    catch
                                    {
                                    }

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                throw;
                            }

                            if (GetFileChecksum(LocalPath, MD5Csp) != PatchFile.Checksum.ToLower())
                            {
                                Script.WriteTimestampedLogEntry(String.Format(
                                                                    "ModuleContentPatcher.ProcessContentPatches: Content patch file {0} was copied, but checksum did not match {1}!  This may indicate a configuration error in the database, or file corruption in transit.",
                                                                    PatchFile.FileName,
                                                                    PatchFile.Checksum));
                                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                                  "Server '{0}' had checksum mismatch for content patch file {1} after hotfix file deployment, rolling back file.",
                                                                                  Script.GetName(Script.GetModule()),
                                                                                  PatchFile.FileName));

                                if (UpdateMethod == FileUpdateMethod.FileUpdateMethodRename)
                                {
                                    string OldFileName = LocalPath + ".old";

                                    try
                                    {
                                        if (File.Exists(LocalPath))
                                        {
                                            File.Delete(LocalPath);
                                        }
                                    }
                                    catch
                                    {
                                    }

                                    File.Move(OldFileName, LocalPath);
                                }
                                else
                                {
                                    File.Delete(LocalPath);
                                }

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_INCORRECT_CHECKSUM");
                            }
                            else
                            {
                                ContentChanged = true;

                                Database.ACR_IncrementStatistic("CONTENT_PATCH_UPDATED_FILE");

                                Script.WriteTimestampedLogEntry(String.Format(
                                                                    "ModuleContentPatcher.ProcessContentPatches: Successfully updated content patch file {0}.",
                                                                    PatchFile.FileName));
                            }
                        }
                        catch (Exception e)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                                                "ModuleContentPatcher.ProcessContentPatches: Exception {0} updating content patch file {1}.",
                                                                e,
                                                                PatchFile.FileName));

                            Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                              "Server '{0}' encountered exception deploying content patch file {1}, rolling back file.",
                                                                              Script.GetName(Script.GetModule()),
                                                                              PatchFile.FileName));
                        }
                    }

                    if (File.Exists(TransferTempFilePath))
                    {
                        try
                        {
                            File.Delete(TransferTempFilePath);
                        }
                        catch (Exception e)
                        {
                            Script.WriteTimestampedLogEntry(String.Format(
                                                                "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} removing transfer temp file {1} for transfer file {2} after patching completed.",
                                                                e,
                                                                TransferTempFilePath,
                                                                PatchFile.FileName));
                        }
                    }
                }
            }

            //
            // Update autodownloader configuration, as necessary.
            //

            try
            {
                if (ProcessModuleDownloaderResourcesUpdates(Database, Script))
                {
                    Script.WriteTimestampedLogEntry("ModuleContentPatcher.ProcessContentPatches: Autodownloader configuration updated.");
                    ContentChanged = true;
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "ModuleContentPatcher.ProcessContentPatches: Warning: Exception {0} updating autodownloader configuration.",
                                                    e));

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                  "Server '{0}' encountered exception updating autodownloader configuration.",
                                                                  Script.GetName(Script.GetModule())));
            }

            if (ContentChanged)
            {
                if (RecompileModule)
                {
                    Script.WriteTimestampedLogEntry("ModuleContentPatcher.ProcessContentPatches: A module recompile is required; recompiling module...");
                    CompileModuleScripts(Script, Database);
                }

                Database.ACR_IncrementStatistic("CONTENT_PATCH_REBOOT");

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                  "Server '{0}' restarting after content patch deployment (old HAK ACR version {1} build date {2}, old module ACR version {3}).",
                                                                  Script.GetName(Script.GetModule()),
                                                                  Database.ACR_GetHAKVersion(),
                                                                  Database.ACR_GetHAKBuildDate(),
                                                                  Database.ACR_GetVersion()));
            }

            return(ContentChanged);
        }
        /// <summary>
        /// Dispatch the event (in a script context).
        /// </summary>
        /// <param name="Script">Supplies the script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            string PlayerName = Player.Name;

            if (!SystemInfo.IsSafeFileName(PlayerName))
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "PurgeCachedCharacterEvent.DispatchEvent: Invalid player name '{0}'.", PlayerName));
                return;
            }

            string VaultPath = SystemInfo.GetServerVaultPathForAccount(PlayerName);

            if (VaultPath == null)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "PurgeCachedCharacterEvent.DispatchEvent: Could not resolve vault path for player '{0}'.",
                                                    Player.PlayerName));
                return;
            }

            VaultPath += CharacterFileName;

            if (!File.Exists(VaultPath))
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "PurgeCachedCharacterEvent.DispatchEvent: Character file '{0}' for player '{1}' was not locally cached.",
                                                    CharacterFileName,
                                                    Player.PlayerName));
                return;
            }

            try
            {
                File.Delete(VaultPath);
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "PurgeCachedCharacterEvent.DispatchEvent: Exception '{0}' removing cached character '{1}' for player '{2}'.",
                                                    e,
                                                    CharacterFileName,
                                                    Player.PlayerName));
                return;
            }

            try
            {
                if (SystemInfo.GetVaultStoragePluginInUse())
                {
                    VaultPath = SystemInfo.GetCentralVaultPathForAccount(PlayerName);

                    VaultPath += CharacterFileName;

                    if (File.Exists(VaultPath))
                    {
                        File.Delete(VaultPath);
                    }
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "PurgeCachedCharacterEvent.DispatchEvent: Exception '{0}' removing cached character from Azure vault temporary local storage '{1}' for player '{2}'.",
                                                    e,
                                                    CharacterFileName,
                                                    Player.PlayerName));
                return;
            }

            Script.WriteTimestampedLogEntry(String.Format(
                                                "PurgeCachedCharacterEvent.DispatchEvent: Removed cached character '{0}' from player '{1}' vault cache.",
                                                CharacterFileName,
                                                Player.PlayerName));
        }
 /// <summary>
 /// Dispatch the event (in a script context).
 /// </summary>
 /// <param name="Script">Supplies the script object.</param>
 /// <param name="Database">Supplies the database connection.</param>
 public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
 {
     Script.WriteTimestampedLogEntry("ACR_ServerCommunicator: " + Message);
 }
Пример #54
0
        /// <summary>
        /// This when a cross-server ping response is received.  Its purpose is
        /// to compute the channel latency and send a message to that effect to
        /// the requesting player.
        /// </summary>
        /// <param name="SourceServerId">Supplies the server id of the server
        /// that completed the ping request.</param>
        /// <param name="Arguments">Supplies the serialized state arguments
        /// string.</param>
        /// <param name="Script">Supplies the current script object.</param>
        /// <returns>TRUE on success, else FALSE on failure.</returns>
        public static int HandleServerPingResponse(int SourceServerId, string Arguments, ACR_ServerCommunicator Script)
        {
            int Tick = Environment.TickCount;

            try
            {
                PingState RemoteState;

                //
                // Deserialize the remote ping state.  If null, a protocol
                // violation has occurred.
                //

                if ((RemoteState = PingState.FromString(Arguments)) == null)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                                                        "ACR_ServerCommunicator.ServerLatencyMeasurer.HandleServerPingResponse({0}, {1}): Invalid request.",
                                                        SourceServerId,
                                                        Arguments));
                    return(ACR_ServerCommunicator.FALSE);
                }

                string ServerName = Script.GetServerName(SourceServerId);

                if (ServerName == null)
                {
                    return(ACR_ServerCommunicator.FALSE);
                }

                Script.SendMessageToPC(RemoteState.PCObjectId, String.Format(
                                           "IPC channel latency to {0}: {1}ms", ServerName, Tick - RemoteState.TickCount));
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "ACR_ServerCommunicator.ServerLatencyMeasurer.HandleServerPingResponse({0}, {1}): Exception: {0}",
                                                    SourceServerId,
                                                    Arguments,
                                                    e));
                return(ACR_ServerCommunicator.FALSE);
            }

            return(ACR_ServerCommunicator.TRUE);
        }
        /// <summary>
        /// This method is called when a portal transition has been committed
        /// to send a player to a remote server.
        /// </summary>
        /// <param name="State">Supplies the local state for the player that is
        /// committed to a portal transition.
        /// </param>
        /// <param name="Server">Supplies the destination server for the portal
        /// event.</param>
        /// <param name="Script">Supplies the script object.</param>
        public static void SendGUIStateToServer(PlayerState State, GameServer Server, ACR_ServerCommunicator Script)
        {
            //
            // Build the resynchronization command.  The resynchronization
            // command is parsed by HandleGUIResync().  Note that the remote
            // and local servers may not be of the same version, i.e. the
            // remote server may not understand fields that are created by the
            // local server if it is of a newer version.
            //

            ResyncState ResyncInfo = new ResyncState(State.PlayerId, 0);

            if (State.ChatSelectGUIExpanded)
            {
                ResyncInfo.ResyncFlags |= RESYNC_FLAG_CHAT_SELECT_EXPANDED;
            }

            //
            // Dispatch the resync script execution request to the remote
            // server.  The remote server will process it when the request has
            // been received.
            //

            Script.RunScriptOnServer(Server.ServerId, "acr_resync_gui", ResyncInfo.ToString());
        }
Пример #56
0
        /// <summary>
        /// Recompile all scripts in the module.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        private static void CompileModuleScripts(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            ALFA.ScriptCompiler.CompilerResult Result;
            string        CompilerOptions = Script.GetLocalString(Script.GetModule(), "ACR_MOD_COMPILER_OPTIONS");
            List <string> CompilerOutput  = new List <string>();

            Script.WriteTimestampedLogEntry(String.Format(
                                                "ModuleContentPatcher.CompileModuleScripts: Compiling module scripts with compiler options '{0}'...", CompilerOptions));
            Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                              "Server '{0}' is recompiling module scripts.",
                                                              Script.GetName(Script.GetModule())));

            Result = ALFA.ScriptCompiler.CompileScript("*.nss", CompilerOptions, delegate(string Line)
            {
                if (!String.IsNullOrWhiteSpace(Line))
                {
                    Script.WriteTimestampedLogEntry(Line);
                }
                return(false);
            });

            foreach (string Message in Result.Warnings)
            {
                try
                {
                    CompilerOutput.Add(Message);
                }
                catch (Exception)
                {
                }
            }

            if (Result.Compiled)
            {
                Script.WriteTimestampedLogEntry("ModuleContentPatcher.CompileModuleScripts: Module successfully recompiled.");
                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE");

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                  "Server '{0}' successfully recompiled module with {1} warning(s) for content patch deployment.",
                                                                  Script.GetName(Script.GetModule()),
                                                                  Result.Warnings.Count));
            }
            else
            {
                Script.WriteTimestampedLogEntry(String.Format(
                                                    "ModuleContentPatcher.CompileModuleScripts: {0} error(s) compiling module!", Result.Errors.Count));

                Script.SendInfrastructureDiagnosticIrcMessage(String.Format(
                                                                  "Server '{0}' had {1} error(s), {2} warning(s) recompiling module for content patch deployment.",
                                                                  Script.GetName(Script.GetModule()),
                                                                  Result.Errors.Count,
                                                                  Result.Warnings.Count));

                foreach (string Message in Result.Errors)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                                                        "ModuleContentPatcher.CompileModuleScripts: Error '{0}'.", Message));

                    try
                    {
                        CompilerOutput.Add(Message);
                    }
                    catch (Exception)
                    {
                    }
                }

                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE_FAILED");
            }

            //
            // Save compiler output to a temporary file for later retrieval.
            //

            try
            {
                string FileName = String.Format("{0}{1}ALFAModuleRecompile.log", Path.GetTempPath(), Path.DirectorySeparatorChar);

                File.WriteAllLines(FileName, CompilerOutput);
            }
            catch (Exception)
            {
            }
        }
 /// <summary>
 /// Dispatch the event (in a script context).
 /// </summary>
 /// <param name="Script">Supplies the script object.</param>
 /// <param name="Database">Supplies the database connection.</param>
 public void DispatchEvent(ACR_ServerCommunicator Script, ALFA.Database Database)
 {
     Script.WriteTimestampedLogEntry("ACR_ServerCommunicator: " + Message);
 }
Пример #58
0
        /// <summary>
        /// Download a content patch file from a file store.  Currently, Azure
        /// file stores are assumed.  Both compressed and uncompressed versions
        /// of the file are tried in respective order.
        /// </summary>
        /// <param name="FileStorePath">Supplies the remote file name that
        /// designates the file to download.</param>
        /// <param name="LocalFileName">Supplies the local file name to
        /// download to.</param>
        /// <param name="ConnectionString">Supplies the file store connection
        /// string.</param>
        /// <param name="Script">Supplies the script object.</param>
        private static void DownloadContentPatchFromFileStore(string FileStorePath, string LocalFileName, string ConnectionString, ACR_ServerCommunicator Script)
        {
            if (String.IsNullOrEmpty(ConnectionString))
            {
                throw new NotSupportedException();
            }

            //
            // Initialize the file store provider.
            //

            FileStore          UpdaterStore     = FileStoreProvider.CreateAzureFileStore(ConnectionString);
            FileStoreContainer UpdaterContainer = UpdaterStore.GetContainerReference(FileStoreNamespace.ACRUpdater);
            FileStoreFile      UpdaterFile      = UpdaterContainer.GetFileReference(FileStorePath + ".gzip");

            //
            // First attempt to retrieve a gzip compressed version of the file
            // to patch.  If that fails then fall back to a plaintext version.
            //

            try
            {
                using (MemoryStream MemStream = new MemoryStream())
                {
                    UpdaterFile.Read(MemStream);

                    MemStream.Position = 0;

                    using (FileStream OutStream = File.Create(LocalFileName))
                    {
                        using (GZipStream CompressedStream = new GZipStream(MemStream, CompressionMode.Decompress))
                        {
                            CompressedStream.CopyTo(OutStream);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format("ModuleContentPatcher.DownloadContentPatchFromFileStore: Couldn't retrieve compressed file {0} from Azure, trying uncompressed file, due to exception: {1}",
                                                              FileStorePath,
                                                              e));

                UpdaterFile = UpdaterContainer.GetFileReference(FileStorePath);

                using (FileStream OutStream = File.Create(LocalFileName))
                {
                    UpdaterFile.Read(OutStream);
                }
            }
        }
        /// <summary>
        /// Recompile all scripts in the module.
        /// </summary>
        /// <param name="Script">Supplies the main script object.</param>
        /// <param name="Database">Supplies the database connection.</param>
        private static void CompileModuleScripts(ACR_ServerCommunicator Script, ALFA.Database Database)
        {
            ALFA.ScriptCompiler.CompilerResult Result;
            string CompilerOptions = Script.GetLocalString(Script.GetModule(), "ACR_MOD_COMPILER_OPTIONS");

            Script.WriteTimestampedLogEntry(String.Format(
                "ModuleContentPatcher.CompileModuleScripts: Compiling module scripts with compiler options '{0}'...", CompilerOptions));

            Result = ALFA.ScriptCompiler.CompileScript("*.nss", CompilerOptions, delegate(string Line)
            {
                Script.WriteTimestampedLogEntry(Line);
                return false;
            });

            if (Result.Compiled)
            {
                Script.WriteTimestampedLogEntry("ModuleContentPatcher.CompileModuleScripts: Module successfully recompiled.");
                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE");
            }
            else
            {
                Script.WriteTimestampedLogEntry(String.Format(
                    "ModuleContentPatcher.CompileModuleScripts: {0} error(s) compiling module!", Result.Errors.Count));

                foreach (string Message in Result.Errors)
                {
                    Script.WriteTimestampedLogEntry(String.Format(
                        "ModuleContentPatcher.CompileModuleScripts: Error '{0}'.", Message));
                }

                Database.ACR_IncrementStatistic("CONTENT_PATCH_RECOMPILE_FAILED");
            }

        }