public void Load(string map) { string path = "PacMan/Map/" + map; GameLog.InfoFormat("Loading map [{0}]...", path); UnityEngine.Object prefab = Resources.Load(path); if (null == prefab) { iCarus.Exception.Throw <GameException>("Load map failed: " + path); } GameObject go = (GameObject)GameObject.Instantiate(prefab); go.transform.Reset(); spawnpoints = go.GetComponent <BeanSpawnpoints>(); if (null == spawnpoints) { string n = go.name; GameObject.Destroy(go); iCarus.Exception.Throw <GameException>("<BeanSpawnpoints> is not found on " + n); } GameLog.InfoFormat("Map [{0}] loaded", path); }
public static void DeregisterClient(Client client) { ConnectedClients.TryRemove(client.ConnectionId, out Client _); GameLog.InfoFormat("Deregistering {0}", client.ConnectionId); // Send a control message to clean up after World users; Lobby and Login handle themselves if (client.ServerType == ServerTypes.World) { if (!WorldClients.TryRemove(client.ConnectionId, out Client _)) { GameLog.Error("Couldn't deregister cid {id}", client.ConnectionId); } try { if (!World.ControlMessageQueue.IsCompleted) { World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.CleanupUser, CleanupType.ByConnectionId, client.ConnectionId)); } } catch (InvalidOperationException e) { Game.ReportException(e); if (!World.ControlMessageQueue.IsCompleted) { GameLog.ErrorFormat("Connection {id}: DeregisterClient failed", client.ConnectionId); } } } }
public Client(Socket socket, Server server) { ClientState = new ClientState(socket); Server = server; GameLog.InfoFormat("Connection {0} from {1}:{2}", ConnectionId, ((IPEndPoint)Socket.RemoteEndPoint).Address.ToString(), ((IPEndPoint)Socket.RemoteEndPoint).Port); if (server is Lobby) { EncryptionKey = Game.Config.ApiEndpoints.EncryptionEndpoint != null?GlobalConnectionManifest.RequestEncryptionKey(Game.Config.ApiEndpoints.EncryptionEndpoint.Url, ((IPEndPoint)socket.RemoteEndPoint).Address) : Encoding.ASCII.GetBytes("UrkcnItnI"); GameLog.InfoFormat($"EncryptionKey is {Encoding.ASCII.GetString(EncryptionKey)}"); var valid = Game.Config.ApiEndpoints.ValidationEndpoint != null?GlobalConnectionManifest.ValidateEncryptionKey(Game.Config.ApiEndpoints.ValidationEndpoint.Url, new ServerToken { Ip = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(), Seed = EncryptionKey }) : true; if (!valid) { GameLog.ErrorFormat("Invalid key from {IP}", ((IPEndPoint)Socket.RemoteEndPoint).Address.ToString()); socket.Disconnect(true); } } EncryptionKeyTable = new byte[1024]; _lastReceived = DateTime.Now.Ticks; GlobalConnectionManifest.RegisterClient(this); ConnectedSince = DateTime.Now.Ticks; }
public static void Execute(object obj, ElapsedEventArgs args) { GameLog.Debug("Job starting"); try { foreach (var connection in GlobalConnectionManifest.WorldClients) { var client = connection.Value; var connectionId = connection.Key; User user; if (Game.World.WorldData.TryGetValueByIndex(connectionId, out user)) { if (client.IsHeartbeatExpired()) { GameLog.InfoFormat("{0} (connection id {1}: heartbeat expired, disconnecting", user.Name, connectionId); GlobalConnectionManifest.DeregisterClient(client); World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.CleanupUser, CleanupType.ByConnectionId, connectionId)); } } } } catch (Exception e) { Game.ReportException(e); GameLog.ErrorFormat("Exception occurred in job:", e); } }
public void Invoke(User trigger) { // Run through all the different potential uses. We allow combinations of any // use specified in the item XML. GameLog.InfoFormat($"User {trigger.Name}: used item {Name}"); if (Use.Script != null) { Script invokeScript; if (!World.ScriptProcessor.TryGetScript(Use.Script, out invokeScript)) { trigger.SendSystemMessage("It doesn't work."); return; } if (!invokeScript.ExecuteFunction("OnUse", trigger, null, this)) { trigger.SendSystemMessage("It doesn't work."); return; } } if (Use.Effect != null) { trigger.SendEffect(trigger.Id, Use.Effect.Id, Use.Effect.Speed); } if (Use.PlayerEffect != null) { if (Use.PlayerEffect.Gold > 0) { trigger.AddGold(new Gold((uint)Use.PlayerEffect.Gold)); } if (Use.PlayerEffect.Hp > 0) { trigger.Heal(Use.PlayerEffect.Hp); } if (Use.PlayerEffect.Mp > 0) { trigger.RegenerateMp(Use.PlayerEffect.Mp); } if (Use.PlayerEffect.Xp > 0) { trigger.GiveExperience((uint)Use.PlayerEffect.Xp); } trigger.UpdateAttributes(StatUpdateFlags.Current | StatUpdateFlags.Experience); } if (Use.Sound != null) { trigger.SendSound((byte)Use.Sound.Id); } if (Use.Teleport != null) { trigger.Teleport(Use.Teleport.Value, Use.Teleport.X, Use.Teleport.Y); } if (Use.Consumed) { Count--; } }
public Lobby(int port, bool isDefault = false) : base(port, isDefault) { GameLog.InfoFormat("LobbyConstructor: port is {0}", port); PacketHandlers = new LobbyPacketHandler[256]; for (int i = 0; i < 256; ++i) { PacketHandlers[i] = (c, p) => GameLog.WarningFormat("Lobby: Unhandled opcode 0x{0:X2}", p.Opcode); } PacketHandlers[0x00] = PacketHandler_0x00_ClientVersion; PacketHandlers[0x57] = PacketHandler_0x57_ServerTable; }
public bool StartExchange() { GameLog.InfoFormat("Starting exchange between {0} and {1}", _source.Name, _target.Name); _active = true; _source.Condition.InExchange = true; _target.Condition.InExchange = true; _source.ActiveExchange = this; _target.ActiveExchange = this; // Send "open window" packet to both clients _target.SendExchangeInitiation(_source); _source.SendExchangeInitiation(_target); return(true); }
public UserGroup(User founder) { Founder = founder; Members = new List <User>(); ClassCount = new Dictionary <Xml.Class, uint>(); foreach (var cl in Enum.GetValues(typeof(Xml.Class)).Cast <Xml.Class>()) { ClassCount[cl] = 0; } GameLog.InfoFormat("Creating new group with {0} as founder.", founder.Name); // Distribute full experience to everyone with a bonus if a member of each // class is present. ExperienceDistributionFunc = Distribution_AllClassBonus; Add(founder); CreatedOn = DateTime.Now; }
private void PacketHandler_0x57_ServerTable(Client client, ClientPacket packet) { var mismatch = packet.ReadByte(); if (mismatch == 1) { var x56 = new ServerPacket(0x56); x56.WriteUInt16((ushort)Game.ServerTable.Length); x56.Write(Game.ServerTable); GameLog.InfoFormat("ServerTable: Sent: {0}", BitConverter.ToString(x56.ToArray())); client.Enqueue(x56); } else { var server = packet.ReadByte(); var redirect = new Redirect(client, this, Game.Login, "socket", client.EncryptionSeed, client.EncryptionKey); client.Redirect(redirect); } }
// Chart for all error password-related error codes were provided by kojasou@ on // https://github.com/hybrasyl/server/pull/11. private void PacketHandler_0x26_ChangePassword(Client client, ClientPacket packet) { var name = packet.ReadString8(); var currentPass = packet.ReadString8(); // Clientside validation ensures that the same string is typed twice for the new // password, and the new password is only sent to the server once. We can assume // that they matched if 0x26 request is sent from the client. var newPass = packet.ReadString8(); if (!Game.World.WorldData.TryGetAuthInfo(name, out AuthInfo login)) { client.LoginMessage(GetPasswordError(0x0E), 0x0E); GameLog.InfoFormat("cid {0}: Password change attempt on nonexistent player {1}", client.ConnectionId, name); return; } if (login.VerifyPassword(currentPass)) { // Check if the password is valid. if (ValidPassword(newPass, out byte err)) { login.PasswordHash = HashPassword(newPass); login.LastPasswordChange = DateTime.Now; login.LastPasswordChangeFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); login.Save(); // Let the user know the good news. client.LoginMessage("Your password has been changed successfully.", 0x0); GameLog.InfoFormat("Password successfully changed for `{0}`", name); } else { client.LoginMessage(GetPasswordError(err), err); GameLog.ErrorFormat("Invalid new password proposed during password change attempt for `{0}`", name); } } // The current password is incorrect. Don't allow any changes to happen. else { client.LoginMessage(GetPasswordError(0x0F), 0x0F); GameLog.ErrorFormat("Invalid current password during password change attempt for `{0}`", name); } }
public Login(int port, bool isDefault = false) : base(port, isDefault) { GameLog.InfoFormat("LoginConstructor: port is {0}", port); PacketHandlers = new LoginPacketHandler[256]; for (int i = 0; i < 256; ++i) { PacketHandlers[i] = (c, p) => GameLog.WarningFormat("Login: Unhandled opcode 0x{0:X2}", p.Opcode); } PacketHandlers[0x02] = PacketHandler_0x02_CreateA; PacketHandlers[0x03] = PacketHandler_0x03_Login; PacketHandlers[0x04] = PacketHandler_0x04_CreateB; PacketHandlers[0x10] = PacketHandler_0x10_ClientJoin; PacketHandlers[0x26] = PacketHandler_0x26_ChangePassword; PacketHandlers[0x4B] = PacketHandler_0x4B_RequestNotification; PacketHandlers[0x68] = PacketHandler_0x68_RequestHomepage; }
public void Redirect(Redirect redirect, bool isLogoff = false, int transmitDelay = 0) { GameLog.InfoFormat("Processing redirect"); GlobalConnectionManifest.RegisterRedirect(this, redirect); GameLog.InfoFormat("Redirect: cid {0}", this.ConnectionId); GameLog.Info($"Redirect EncryptionKey is {Encoding.ASCII.GetString(redirect.EncryptionKey)}"); if (isLogoff) { GlobalConnectionManifest.DeregisterClient(this); } redirect.Destination.ExpectedConnections.TryAdd(redirect.Id, redirect); var endPoint = Socket.RemoteEndPoint as IPEndPoint; byte[] addressBytes; if (Game.RedirectTarget != null) { addressBytes = Game.RedirectTarget.GetAddressBytes(); } else { addressBytes = IPAddress.IsLoopback(endPoint.Address) ? IPAddress.Loopback.GetAddressBytes() : Game.IpAddress.GetAddressBytes(); } Array.Reverse(addressBytes); var x03 = new ServerPacket(0x03); x03.Write(addressBytes); x03.WriteUInt16((ushort)redirect.Destination.Port); x03.WriteByte((byte)(redirect.EncryptionKey.Length + Encoding.ASCII.GetBytes(redirect.Name).Length + 7)); x03.WriteByte(redirect.EncryptionSeed); x03.WriteByte((byte)redirect.EncryptionKey.Length); x03.Write(redirect.EncryptionKey); x03.WriteString8(redirect.Name); x03.WriteUInt32(redirect.Id); x03.TransmitDelay = transmitDelay == 0 ? 250 : transmitDelay; Enqueue(x03); }
/// <summary> /// Confirm the exchange. Once both sides confirm, perform the exchange. /// </summary> /// <returns>Boolean indicating success.</returns> public void ConfirmExchange(User requestor) { if (_source == requestor) { GameLog.InfoFormat("Exchange: source ({0}) confirmed", _source.Name); _sourceConfirmed = true; _target.SendExchangeConfirmation(false); } if (_target == requestor) { GameLog.InfoFormat("Exchange: target ({0}) confirmed", _target.Name); _targetConfirmed = true; _source.SendExchangeConfirmation(false); } if (_sourceConfirmed && _targetConfirmed) { GameLog.Info("Exchange: Both sides confirmed"); _source.SendExchangeConfirmation(); _target.SendExchangeConfirmation(); PerformExchange(); } }
/// <summary> /// Determine whether either heartbeat has "expired" (meaning REAP_HEARTBEAT_INTERVAL has /// passed since we received a heartbeat response). /// </summary> /// <returns>True or false, indicating expiration.</returns> public bool IsHeartbeatExpired() { // If we have no record of sending a heartbeat, obviously it hasn't expired if (_tickHeartbeatSent == 0 && _byteHeartbeatSent == 0) { return(false); } var tickSpan = new TimeSpan(_tickHeartbeatReceived - _tickHeartbeatSent); var byteSpan = new TimeSpan(_byteHeartbeatReceived - _byteHeartbeatSent); GameLog.DebugFormat("cid {0}: tick heartbeat elapsed seconds {1}, byte heartbeat elapsed seconds {2}", ConnectionId, tickSpan.TotalSeconds, byteSpan.TotalSeconds); if (tickSpan.TotalSeconds > Constants.REAP_HEARTBEAT_INTERVAL || byteSpan.TotalSeconds > Constants.REAP_HEARTBEAT_INTERVAL) { // DON'T FEAR THE REAPER GameLog.InfoFormat("cid {0}: heartbeat expired", ConnectionId); return(true); } return(false); }
void OnNetStatusChanged(UdpConnector connector, NetConnectionStatus status, string reason) { GameLog.InfoFormat("Connection status changed {0} {1}", status, reason); }
void OnConnectionStatusChanged(NetConnection connection, string reason) { GameLog.InfoFormat("Connection status changed {0} {1} {2}", connection.RemoteEndPoint, connection.Status, reason); }
private void PacketHandler_0x03_Login(Client client, ClientPacket packet) { var name = packet.ReadString8(); var password = packet.ReadString8(); GameLog.DebugFormat("cid {0}: Login request for {1}", client.ConnectionId, name); if (Game.World.WorldData.TryGetAuthInfo(name, out AuthInfo login)) { if (string.IsNullOrEmpty(login.PasswordHash)) { client.LoginMessage("ERROR: Authentication information corrupt [HYB-LOGIN-01]", 3); return; } if (login.VerifyPassword(password)) { GameLog.DebugFormat("cid {0}: password verified for {1}", client.ConnectionId, name); if (login.CurrentState == UserState.Redirect && login.StateChangeDuration < 1000) { client.LoginMessage("That character is already logging in. Please try again.", 3); return; } if (login.IsLoggedIn) { login.CurrentState = UserState.Disconnected; // Is the user actually in world? if (Game.World.TryGetActiveUser(login.Username, out _)) { GameLog.InfoFormat("cid {0}: {1} logging on again, disconnecting previous connection", client.ConnectionId, name); client.LoginMessage("That character is already online. Please try again.", 3); World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.LogoffUser, name)); login.Save(); return; } } // Make sure user can be deserialized without errors if (!Game.World.WorldData.TryGetUser(name, out _)) { // Something bad has happened client.LoginMessage("An unknown error occurred. Please contact Hybrasyl support.", 3); return; } GameLog.DebugFormat("cid {0} ({1}): logging in", client.ConnectionId, name); client.LoginMessage("\0", 0); client.SendMessage("Welcome to Hybrasyl!", 3); GameLog.DebugFormat("cid {0} ({1}): sending redirect to world", client.ConnectionId, name); var redirect = new Redirect(client, this, Game.World, name, client.EncryptionSeed, client.EncryptionKey); GameLog.InfoFormat("cid {0} ({1}): login successful, redirecting to world server", client.ConnectionId, name); login.LastLogin = DateTime.Now; login.LastLoginFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); login.CurrentState = UserState.Redirect; login.LastStateChange = login.LastLogin; login.Save(); client.Redirect(redirect); } else { GameLog.WarningFormat("cid {0} ({1}): password incorrect", client.ConnectionId, name); client.LoginMessage("Incorrect password", 3); login.LastLoginFailure = DateTime.Now; login.LoginFailureCount++; login.LastLoginFailureFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); login.CurrentState = UserState.Login; login.LastStateChange = login.LastLoginFailure; login.Save(); } } else { client.LoginMessage("That character does not exist", 3); GameLog.InfoFormat("cid {0}: attempt to login as nonexistent character {1}", client.ConnectionId, name); return; } }
public static ServerPacketStructures.MessagingResponse SendMessage(GuidReference senderRef, ushort boardId, string recipient, string subject, string body) { var response = string.Empty; var success = true; var senderSentMail = Game.World.WorldData.GetOrCreate <SentMail>(senderRef); // Don't allow blank title or subject if (string.IsNullOrWhiteSpace(subject)) { success = false; response = "The message had no subject."; } else if (string.IsNullOrWhiteSpace(body)) { success = false; response = "You can't send empty messages."; } else if (!body.IsAscii() || !subject.IsAscii()) { success = false; response = "You can't use special characters in a message (ASCII only)."; } else if (boardId == ushort.MaxValue - 1) { success = false; response = "You can't post messages here."; } // Handle plugin response if (!Game.World.TryGetActiveUser(senderRef.UserName, out _)) { // Currently a user must be online to send mail, so if we get here, something really wacky is happening return(UnknownError); } try { IMessageHandler handler; Xml.MessageType type; if (boardId == 0) { type = Xml.MessageType.Mail; } else { type = Xml.MessageType.BoardMessage; } var message = new Plugins.Message(type, senderRef.UserName, recipient, subject, body); handler = Game.World.ResolveMessagingPlugin(type, message); if (handler is IProcessingMessageHandler pmh && success) { var msg = new Plugins.Message(Xml.MessageType.Mail, senderRef.UserName, recipient, subject, body); var resp = pmh.Process(msg); if (!pmh.Passthrough) { // TODO: implement cast / resolve duplication var hmsg = new Message(recipient, senderRef.UserName, subject, body); senderSentMail.ReceiveMessage((Message)hmsg); // Plugin is "last destination" for message return(new ServerPacketStructures.MessagingResponse() { ResponseType = BoardResponseType.EndResult, ResponseSuccess = resp.Success, ResponseString = resp.PluginResponse }); } else if (resp.Transformed) { // Update message if transformed, and keep going recipient = resp.Message.Recipient; subject = resp.Message.Subject; body = resp.Message.Text; } } } catch (Exception e) { Game.ReportException(e); success = false; response = "An unknown error occurred. Sorry!"; } // Annoyingly board replies use the same packet path as sending mail replies, so we need to handle // both here if (boardId == 0 && success) { var receiverRef = Game.World.WorldData.GetGuidReference(recipient); if (receiverRef == null) { success = false; response = "Sadly, no record of that person exists in the realm."; } else { var mailbox = Game.World.WorldData.GetOrCreate <Mailbox>(receiverRef); var msg = new Message(recipient, senderRef.UserName, subject, body); try { if ((DateTime.Now - senderSentMail.LastMailMessageSent).TotalSeconds < Constants.MAIL_MESSAGE_COOLDOWN && senderSentMail.LastMailRecipient == recipient) { success = false; response = $"You've sent too much mail to {recipient} recently. Give it a rest."; } else if (mailbox.ReceiveMessage(msg)) { response = $"Your letter to {recipient} was sent."; GameLog.InfoFormat("mail: {0} sent message to {1}", senderRef.UserName, recipient); World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.MailNotifyUser, recipient)); senderSentMail.LastMailRecipient = recipient; senderSentMail.LastMailMessageSent = DateTime.Now; } else { success = false; response = $"{recipient}'s mailbox is full or locked. A copy was kept in your sent mailbox. Sorry!"; } } catch (MessageStoreLocked e) { Game.ReportException(e); success = false; response = $"{recipient} cannot receive mail at this time. Sorry!"; } senderSentMail.ReceiveMessage((Message)msg.Clone()); } } else if (success) { if (Game.World.WorldData.TryGetValueByIndex(boardId, out Board board)) { if (Game.World.WorldData.TryGetAuthInfo(senderRef.UserName, out AuthInfo ainfo)) { if (ainfo.IsPrivileged || board.CheckAccessLevel(ainfo.Username, BoardAccessLevel.Write)) { var msg = new Message(board.DisplayName, senderRef.UserName, subject, body); if (board.ReceiveMessage(msg)) { response = "The message was sent."; success = true; var sentMsg = (Message)msg.Clone(); sentMsg.Recipient = board.DisplayName; senderSentMail.ReceiveMessage(sentMsg); } else { response = "The message could not be sent."; } } else { response = "You don't have permission to do that."; } } else { response = "Authentication information could not be verified."; } } else { response = "Board not found."; } } return(new ServerPacketStructures.MessagingResponse() { ResponseType = BoardResponseType.EndResult, ResponseString = response, ResponseSuccess = success }); }