private void PacketHandler_0x02_CreateA(Client client, ClientPacket packet) { var name = packet.ReadString8(); var password = packet.ReadString8(); var email = packet.ReadString8(); // This string will contain a client-ready message if the provided password // isn't valid. byte passwordErr = 0x0; if (Game.World.PlayerExists(name)) { client.LoginMessage("That name is unavailable.", 3); } else if (name.Length < 4 || name.Length > 12) { client.LoginMessage("Names must be between 4 to 12 characters long.", 3); } else if (!ValidPassword(password, out passwordErr)) { client.LoginMessage(GetPasswordError(passwordErr), 3); } else if (Regex.IsMatch(name, "^[A-Za-z]{4,12}$")) { client.NewCharacterName = name; client.NewCharacterPassword = HashPassword(password); client.LoginMessage("\0", 0); } else { client.LoginMessage("Names may only contain letters.", 3); } }
private static void EndReceive(IAsyncResult ar) { var client = (Client)ar.AsyncState; var socket = client.Socket; try { int count = socket.EndReceive(ar); for (int i = 0; i < count; ++i) { client.fullRecvBuffer.Add(client.recvBuffer[i]); } if (count == 0 || client.fullRecvBuffer[0] != 0xAA) { Logger.DebugFormat("cid {0}: client is disconnected or corrupt packets received", client.ConnectionId); client.Connected = false; return; } while (client.fullRecvBuffer.Count > 3) { Logger.Debug("in fullRecvBuffer loop"); int length = client.fullRecvBuffer[1]*256 + client.fullRecvBuffer[2] + 3; if (length > client.fullRecvBuffer.Count) break; var range = client.fullRecvBuffer.GetRange(0, length); var buffer = range.ToArray(); client.fullRecvBuffer.RemoveRange(0, length); var packet = new ClientPacket(buffer); if (packet.ShouldEncrypt) packet.Decrypt(client); if (packet.Opcode == 0x39 || packet.Opcode == 0x3A) packet.DecryptDialog(); if (client.Connected) { if (Constants.PACKET_THROTTLES.ContainsKey(packet.Opcode)) { ThrottleInfo tinfo; if (client.Throttle.TryGetValue(packet.Opcode, out tinfo)) { tinfo.Received(); if (tinfo.IsThrottled) { Logger.InfoFormat("cid {0}: opcode 0x{0:X2} throttled", client.ConnectionId, packet.Opcode); if (tinfo.TotalThrottled > tinfo.Throttle.DisconnectAfter) { Logger.InfoFormat("cid {0}: opcode 0x{0:X2} throttle limit reached: disconnected", client.ConnectionId, packet.Opcode); client.Connected = false; break; } client.recving = false; continue; } } else { // We've never seen this packet before on this client. And obviously, as a result, // we can be neither squelched nor throttled. Logger.DebugFormat("cid {0}: creating throttle for opcode 0x{0:X2}", client.ConnectionId, packet.Opcode); client.Throttle[packet.Opcode] = new ThrottleInfo(packet.Opcode); } } Logger.Debug("Proceeding to packet processing"); // For Lobby and Login, we simply process the packet as we can do so in a // thread safe manner. // For World, which involves game logic, we queue the packet for processing by // the world consumer thread. try { if (client.Server is Lobby) { Logger.DebugFormat("Lobby: 0x{0:X2}", packet.Opcode); var handler = (client.Server as Lobby).PacketHandlers[packet.Opcode]; handler.Invoke(client, packet); client.UpdateLastReceived(); } else if (client.Server is Login) { var handler = (client.Server as Login).PacketHandlers[packet.Opcode]; handler.Invoke(client, packet); Logger.DebugFormat("Login: 0x{0:X2}", packet.Opcode); client.UpdateLastReceived(); } else { if (packet.Opcode != 0x45 && packet.Opcode != 0x75) { // Heartbeats don't effect our idle calcuations client.UpdateLastReceived((packet.Opcode != 0x45 && packet.Opcode != 0x75)); } Logger.DebugFormat("Queuing: 0x{0:X2}", packet.Opcode); World.MessageQueue.Add(new HybrasylClientMessage(packet, client.ConnectionId)); } } catch (Exception e) { Logger.ErrorFormat("EXCEPTION IN HANDLING: {0}: {1}", packet.Opcode, e); } client.recving = false; } } } catch (Exception e) { client.Connected = false; Logger.ErrorFormat(e.ToString()); } }
private void PacketHandler_0x08_DropItem(Object obj, ClientPacket packet) { var user = (User) obj; var slot = packet.ReadByte(); var x = packet.ReadInt16(); var y = packet.ReadInt16(); var count = packet.ReadInt32(); Logger.DebugFormat("{0} {1} {2} {3}", slot, x, y, count); // Do a few sanity checks // // Is the distance valid? (Can't drop things beyond // MAXIMUM_DROP_DISTANCE tiles away) if (Math.Abs(x - user.X) > Constants.PICKUP_DISTANCE || Math.Abs(y - user.Y) > Constants.PICKUP_DISTANCE) { Logger.ErrorFormat("Request to drop item exceeds maximum distance {0}", Hybrasyl.Constants.MAXIMUM_DROP_DISTANCE); return; } // Is this a valid slot? if ((slot == 0) || (slot > Hybrasyl.Constants.MAXIMUM_INVENTORY)) { Logger.ErrorFormat("Slot not valid. Aborting"); return; } // Does the player actually have an item in the slot? Does the count in the packet exceed the // count in the player's inventory? Are they trying to drop the item on something that // is impassable (i.e. a wall)? if ((user.Inventory[slot] == null) || (count > user.Inventory[slot].Count) || (user.Map.IsWall[x, y] == true) || !user.Map.IsValidPoint(x, y)) { Logger.ErrorFormat( "Slot {0} is null, or count {1} exceeds count {2}, or {3},{4} is a wall, or {3},{4} is out of bounds", slot, count, user.Inventory[slot].Count, x, y); return; } Item toDrop = user.Inventory[slot]; if (toDrop.Stackable && count < toDrop.Count) { toDrop.Count -= count; user.SendItemUpdate(toDrop, slot); toDrop = new Item(toDrop); toDrop.Count = count; Insert(toDrop); } else { user.RemoveItem(slot); } // Are we dropping an item onto a reactor? Reactor reactor; var coordinates = new Tuple<byte, byte>((byte) x, (byte) y); if (user.Map.Reactors.TryGetValue(coordinates, out reactor)) { reactor.OnDrop(user, toDrop); } else user.Map.AddItem(x, y, toDrop); }
private void PacketHandler_0x05_RequestMap(Object obj, ClientPacket packet) { var user = (User) obj; int index = 0; for (ushort row = 0; row < user.Map.Y; ++row) { var x3C = new ServerPacket(0x3C); x3C.WriteUInt16(row); for (int col = 0; col < user.Map.X*6; col += 2) { x3C.WriteByte(user.Map.RawData[index + 1]); x3C.WriteByte(user.Map.RawData[index]); index += 2; } user.Enqueue(x3C); } }
private void MerchantMenuHandler_SellItemWithQuantity(User user, Merchant merchant, ClientPacket packet) { packet.ReadByte(); byte slot = packet.ReadByte(); string qStr = packet.ReadString8(); int quantity; if (!int.TryParse(qStr, out quantity) || quantity < 1) { user.ShowSellQuantity(merchant, slot); return; } var item = user.Inventory[slot]; if (item == null || !item.Stackable) return; if (!merchant.Inventory.ContainsKey(item.Name)) { user.ShowMerchantGoBack(merchant, "I do not want that item.", MerchantMenuItem.SellItemMenu); return; } if (item.Count < quantity) { user.ShowMerchantGoBack(merchant, "You don't have that many to sell.", MerchantMenuItem.SellItemMenu); return; } user.ShowSellConfirm(merchant, slot, quantity); }
private void MerchantMenuHandler_BuyItemWithQuantity(User user, Merchant merchant, ClientPacket packet) { string name = packet.ReadString8(); string qStr = packet.ReadString8(); if (!merchant.Inventory.ContainsKey(name)) { user.ShowMerchantGoBack(merchant, "I do not sell that item.", MerchantMenuItem.BuyItemMenu); return; } var template = merchant.Inventory[name]; if (!template.Stackable) return; int quantity; if (!int.TryParse(qStr, out quantity) || quantity < 1) { user.ShowBuyMenuQuantity(merchant, name); return; } uint cost = (uint) (template.value*quantity); if (user.Gold < cost) { user.ShowMerchantGoBack(merchant, "You do not have enough gold.", MerchantMenuItem.BuyItemMenu); return; } if (quantity > template.max_stack) { user.ShowMerchantGoBack(merchant, string.Format("You cannot hold that many {0}.", name), MerchantMenuItem.BuyItemMenu); return; } if (user.Inventory.Contains(name)) { byte slot = user.Inventory.SlotOf(name); if (user.Inventory[slot].Count + quantity > template.max_stack) { user.ShowMerchantGoBack(merchant, string.Format("You cannot hold that many {0}.", name), MerchantMenuItem.BuyItemMenu); return; } user.IncreaseItem(slot, quantity); } else { if (user.Inventory.IsFull) { user.ShowMerchantGoBack(merchant, "You cannot carry any more items.", MerchantMenuItem.BuyItemMenu); return; } var item = CreateItem(template.id, quantity); Insert(item); user.AddItem(item); } user.RemoveGold(cost); user.UpdateAttributes(StatUpdateFlags.Experience); user.ShowBuyMenu(merchant); }
private void MerchantMenuHandler_SellItemMenu(User user, Merchant merchant, ClientPacket packet) { user.ShowSellMenu(merchant); }
private void PacketHandler_0x68_RequestHomepage(Client client, ClientPacket packet) { var x03 = new ServerPacket(0x66); x03.WriteByte(0x03); x03.WriteString8("http://www.hybrasyl.com"); client.Enqueue(x03); }
private void PacketHandler_0x39_NPCMainMenu(Object obj, ClientPacket packet) { var user = (User) obj; if (user.CheckSquelch(0x38, null)) { Logger.InfoFormat("{0}: squelched (NPC main menu)", user.Name); return; } // We just ignore the header, because, really, what exactly is a 16-bit encryption // key plus CRC really doing for you var header = packet.ReadDialogHeader(); var objectType = packet.ReadByte(); var objectId = packet.ReadUInt32(); var pursuitId = packet.ReadUInt16(); Logger.DebugFormat("main menu packet: ObjectType {0}, ID {1}, pursuitID {2}", objectType, objectId, pursuitId); // Sanity checks WorldObject wobj; if (Game.World.Objects.TryGetValue(objectId, out wobj)) { // Are we handling a global sequence? DialogSequence pursuit; VisibleObject clickTarget = wobj as VisibleObject; if (pursuitId < Constants.DIALOG_SEQUENCE_SHARED) { // Does the sequence exist in the global catalog? try { pursuit = Game.World.GlobalSequences[pursuitId]; } catch { Logger.ErrorFormat("{0}: pursuit ID {1} doesn't exist in the global catalog?", wobj.Name, pursuitId); return; } } else if (pursuitId >= Constants.DIALOG_SEQUENCE_HARDCODED) { if (!(wobj is Merchant)) { Logger.ErrorFormat("{0}: attempt to use hardcoded merchant menu item on non-merchant", wobj.Name, pursuitId); return; } var menuItem = (MerchantMenuItem) pursuitId; var merchant = (Merchant) wobj; MerchantMenuHandler handler; if (!merchantMenuHandlers.TryGetValue(menuItem, out handler)) { Logger.ErrorFormat("{0}: merchant menu item {1} doesn't exist?", wobj.Name, menuItem); return; } if (!merchant.Jobs.HasFlag(handler.RequiredJob)) { Logger.ErrorFormat("{0}: merchant does not have required job {1}", wobj.Name, handler.RequiredJob); return; } handler.Callback(user, merchant, packet); return; } else { // This is a local pursuit try { pursuit = clickTarget.Pursuits[pursuitId - Constants.DIALOG_SEQUENCE_SHARED]; } catch { Logger.ErrorFormat("{0}: local pursuit {1} doesn't exist?", wobj.Name, pursuitId); return; } } Logger.DebugFormat("{0}: showing initial dialog for Pursuit {1} ({2})", clickTarget.Name, pursuit.Id, pursuit.Name); user.DialogState.StartDialog(clickTarget, pursuit); pursuit.ShowTo(user, clickTarget); } else { Logger.WarnFormat("specified object ID {0} doesn't exist?", objectId); return; } }
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 (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) { 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)); 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; } }
private void PacketHandler_0x04_CreateB(Client client, ClientPacket packet) { if (string.IsNullOrEmpty(client.NewCharacterName) || string.IsNullOrEmpty(client.NewCharacterPassword)) { return; } var hairStyle = packet.ReadByte(); var gender = packet.ReadByte(); var hairColor = packet.ReadByte(); if (hairStyle < 1) { hairStyle = 1; } if (hairStyle > 17) { hairStyle = 17; } if (hairColor > 13) { hairColor = 13; } if (gender < 1) { gender = 1; } if (gender > 2) { gender = 2; } // Try to get our map // TODO: replace with XML config for start map, x, y Map map; if (!Game.World.WorldData.TryGetValue(136, out map)) { map = Game.World.WorldData.GetDictionary <Map>().First().Value; } if (!World.PlayerExists(client.NewCharacterName)) { var newPlayer = new User(); newPlayer.Uuid = Guid.NewGuid().ToString(); newPlayer.Name = client.NewCharacterName; newPlayer.Gender = (Xml.Gender)gender; newPlayer.Location.Direction = Xml.Direction.South; newPlayer.Location.Map = map; newPlayer.Location.X = 10; newPlayer.Location.Y = 10; newPlayer.HairColor = hairColor; newPlayer.HairStyle = hairStyle; newPlayer.Class = Xml.Class.Peasant; newPlayer.Gold = 0; newPlayer.AuthInfo.CreatedTime = DateTime.Now; newPlayer.AuthInfo.FirstLogin = true; newPlayer.AuthInfo.PasswordHash = client.NewCharacterPassword; newPlayer.AuthInfo.LastPasswordChange = DateTime.Now; newPlayer.AuthInfo.LastPasswordChangeFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); newPlayer.AuthInfo.Save(); newPlayer.Nation = Game.World.DefaultNation; IDatabase cache = World.DatastoreConnection.GetDatabase(); cache.Set(User.GetStorageKey(newPlayer.Name), newPlayer); var vault = new Vault(newPlayer.Uuid); vault.Save(); var parcelStore = new ParcelStore(newPlayer.Uuid); parcelStore.Save(); client.LoginMessage("\0", 0); } }
private void PacketHandler_0x04_CreateB(Client client, ClientPacket packet) { if (string.IsNullOrEmpty(client.NewCharacterName) || string.IsNullOrEmpty(client.NewCharacterPassword)) { return; } var hairStyle = packet.ReadByte(); var sex = packet.ReadByte(); var hairColor = packet.ReadByte(); if (hairStyle < 1) { hairStyle = 1; } if (hairStyle > 17) { hairStyle = 17; } if (hairColor > 13) { hairColor = 13; } if (sex < 1) { sex = 1; } if (sex > 2) { sex = 2; } // Try to get our map // TODO: replace with XML config for start map, x, y Map map; if (!Game.World.WorldData.TryGetValue(136, out map)) { map = Game.World.WorldData.GetDictionary <Map>().First().Value; } if (!Game.World.PlayerExists(client.NewCharacterName)) { var newPlayer = new User(); newPlayer.Name = client.NewCharacterName; newPlayer.Sex = (Sex)sex; newPlayer.Location.Direction = Direction.South; newPlayer.Location.Map = map; newPlayer.Location.X = 10; newPlayer.Location.Y = 10; newPlayer.HairColor = hairColor; newPlayer.HairStyle = hairStyle; newPlayer.Class = Class.Peasant; newPlayer.Gold = 0; newPlayer.Login.CreatedTime = DateTime.Now; newPlayer.Password.Hash = client.NewCharacterPassword; newPlayer.Password.LastChanged = DateTime.Now; newPlayer.Password.LastChangedFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); newPlayer.Nation = Game.World.DefaultNation; IDatabase cache = World.DatastoreConnection.GetDatabase(); var myPerson = JsonConvert.SerializeObject(newPlayer); cache.Set(User.GetStorageKey(newPlayer.Name), myPerson); // Logger.ErrorFormat("Error saving new player!"); // Logger.ErrorFormat(e.ToString()); // client.LoginMessage("Unknown error. Contact [email protected]", 3); // } client.LoginMessage("\0", 0); } }
public bool ReceiveBufferTake(out ClientPacket packet) => _receiveBuffer.TryDequeue(out packet);
public void ReceiveBufferAdd(ClientPacket packet) => _receiveBuffer.Enqueue(packet);
private void PacketHandler_0x04_CreateB(Client client, ClientPacket packet) { if (string.IsNullOrEmpty(client.NewCharacterName) || string.IsNullOrEmpty(client.NewCharacterPassword)) return; var hairStyle = packet.ReadByte(); var sex = packet.ReadByte(); var hairColor = packet.ReadByte(); if (hairStyle < 1) hairStyle = 1; if (hairStyle > 17) hairStyle = 17; if (hairColor > 13) hairColor = 13; if (sex < 1) sex = 1; if (sex > 2) sex = 2; if (!Game.World.PlayerExists(client.NewCharacterName)) { var newPlayer = new User(); newPlayer.Name = client.NewCharacterName; newPlayer.Sex = (Sex) sex; newPlayer.Location.Direction = Direction.South; newPlayer.Location.MapId = 136; newPlayer.Location.X = 10; newPlayer.Location.Y = 10; newPlayer.HairColor = hairColor; newPlayer.HairStyle = hairStyle; newPlayer.Class = Class.Peasant; newPlayer.Level = 1; newPlayer.Experience = 1; newPlayer.Level = 1; newPlayer.Experience = 0; newPlayer.AbilityExp = 0; newPlayer.Gold = 0; newPlayer.Ability = 0; newPlayer.Hp = 50; newPlayer.Mp = 50; newPlayer.BaseHp = 50; newPlayer.BaseMp = 50; newPlayer.BaseStr = 3; newPlayer.BaseInt = 3; newPlayer.BaseWis = 3; newPlayer.BaseCon = 3; newPlayer.BaseDex = 3; newPlayer.Login.CreatedTime = DateTime.Now; newPlayer.Password.Hash = client.NewCharacterPassword; newPlayer.Password.LastChanged = DateTime.Now; newPlayer.Password.LastChangedFrom = ((IPEndPoint) client.Socket.RemoteEndPoint).Address.ToString(); IDatabase cache = World.DatastoreConnection.GetDatabase(); var myPerson = JsonConvert.SerializeObject(newPlayer); cache.Set(String.Format("{0}:{1}", User.DatastorePrefix, newPlayer.Name), myPerson); // Logger.ErrorFormat("Error saving new player!"); // Logger.ErrorFormat(e.ToString()); // client.LoginMessage("Unknown error. Contact [email protected]", 3); // } client.LoginMessage("\0", 0); } }
// 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(); // TODO: REDIS IDatabase cache = World.DatastoreConnection.GetDatabase(); var myPerson = cache.Get(name); if (myPerson == null) { client.LoginMessage(GetPasswordError(0x0E), 0x0E); Logger.DebugFormat("Password change attempt on invalid player `{0}`", name); } var player = JsonConvert.DeserializeObject(myPerson as String) as User; if (player.VerifyPassword(currentPass)) { // Check if the password is valid. byte err = 0x00; if (ValidPassword(newPass, out err)) { player.Password.Hash = HashPassword(newPass); player.Password.LastChanged = DateTime.Now; player.Password.LastChangedFrom = ((IPEndPoint) client.Socket.RemoteEndPoint).Address.ToString(); player.Save(); // Let the user know the good news. client.LoginMessage("Your password has been changed successfully.", 0x0); Logger.InfoFormat("Password successfully changed for `{0}`", name); } else { client.LoginMessage(GetPasswordError(err), err); Logger.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); Logger.ErrorFormat("Invalid current password during password change attempt for `{0}`", name); } }
private void PacketHandler_0x3A_DialogUse(Object obj, ClientPacket packet) { var user = (User) obj; if (user.CheckSquelch(0x38, null)) { Logger.InfoFormat("{0}: squelched (dialog use)", user.Name); return; } var header = packet.ReadDialogHeader(); var objectType = packet.ReadByte(); var objectID = packet.ReadUInt32(); var pursuitID = packet.ReadUInt16(); var pursuitIndex = packet.ReadUInt16(); Logger.DebugFormat("objectType {0}, objectID {1}, pursuitID {2}, pursuitIndex {3}", objectType, objectID, pursuitID, pursuitIndex); Logger.DebugFormat("active dialog via state object: pursuitID {0}, pursuitIndex {1}", user.DialogState.CurrentPursuitId, user.DialogState.CurrentPursuitIndex); if (pursuitID == user.DialogState.CurrentPursuitId && pursuitIndex == user.DialogState.CurrentPursuitIndex) { // If we get a packet back with the same index and ID, the dialog has been closed. Logger.DebugFormat("Dialog closed, resetting dialog state"); user.DialogState.EndDialog(); return; } if ((pursuitIndex > user.DialogState.CurrentPursuitIndex + 1) || (pursuitIndex < user.DialogState.CurrentPursuitIndex - 1)) { Logger.ErrorFormat("Dialog index is outside of acceptable limits (next/prev)"); return; } WorldObject wobj; if (user.World.Objects.TryGetValue(objectID, out wobj)) { VisibleObject clickTarget = wobj as VisibleObject; // Was the previous button clicked? Handle that first if (pursuitIndex == user.DialogState.CurrentPursuitIndex - 1) { Logger.DebugFormat("Handling prev: client passed index {0}, current index is {1}", pursuitIndex, user.DialogState.CurrentPursuitIndex); if (user.DialogState.SetDialogIndex(clickTarget, pursuitID, pursuitIndex)) { user.DialogState.ActiveDialog.ShowTo(user, clickTarget); return; } } // Is the active dialog an input or options dialog? if (user.DialogState.ActiveDialog is OptionsDialog) { var paramsLength = packet.ReadByte(); var option = packet.ReadByte(); var dialog = user.DialogState.ActiveDialog as OptionsDialog; dialog.HandleResponse(user, option, clickTarget); } if (user.DialogState.ActiveDialog is TextDialog) { var paramsLength = packet.ReadByte(); var response = packet.ReadString8(); var dialog = user.DialogState.ActiveDialog as TextDialog; dialog.HandleResponse(user, response, clickTarget); } // Did the handling of a response result in our active dialog sequence changing? If so, exit. if (user.DialogState.CurrentPursuitId != pursuitID) { Logger.DebugFormat("Dialog has changed, exiting"); return; } if (user.DialogState.SetDialogIndex(clickTarget, pursuitID, pursuitIndex)) { Logger.DebugFormat("Pursuit index is now {0}", pursuitIndex); user.DialogState.ActiveDialog.ShowTo(user, clickTarget); return; } else { Logger.DebugFormat("Sending close packet"); var p = new ServerPacket(0x30); p.WriteByte(0x0A); p.WriteByte(0x00); user.Enqueue(p); user.DialogState.EndDialog(); } } }
public void ReadCallback(IAsyncResult ar) { ClientState state = (ClientState)ar.AsyncState; Client client; SocketError errorCode; int bytesRead = 0; if (this is Login) { Logger.InfoFormat("This is a login ReadCallback"); } try { bytesRead = state.WorkSocket.EndReceive(ar, out errorCode); if (errorCode != SocketError.Success) { bytesRead = 0; } } catch (SocketException) { state.WorkSocket.Close(); } catch (ObjectDisposedException) { state.WorkSocket.Close(); } if (!GlobalConnectionManifest.ConnectedClients.TryGetValue(state.Id, out client)) { // Is this a redirect? Redirect redirect; if (!GlobalConnectionManifest.TryGetRedirect(state.Id, out redirect)) { Logger.ErrorFormat("Receive: data from unknown client (id {0}, closing connection", state.Id); state.WorkSocket.Close(); state.WorkSocket.Dispose(); return; } client = redirect.Client; client.ClientState = state; GlobalConnectionManifest.RegisterClient(client); } if (bytesRead > 0) { if (this is Login) { Logger.InfoFormat("Dafuq bro"); } var inboundBytes = state.ReceiveBufferTake(bytesRead).ToArray(); if (inboundBytes[0] != 0xAA) { Logger.DebugFormat("cid {0}: client is wat", client.ConnectionId); state.ResetReceive(); } else { while (inboundBytes.Length > 3) { Logger.InfoFormat("Inside while loop"); var packetLength = ((int)inboundBytes[1] << 8) + (int)inboundBytes[2] + 3; if (packetLength > inboundBytes.Length) { // We haven't received the entire packet yet; read more bytes break; } else { // We've received an intact packet, pop it off ClientPacket receivedPacket = new ClientPacket(state.ReceiveBufferPop(packetLength).ToArray()); // Also remove it from our local buffer...this seems kinda gross to me inboundBytes = new List <byte>(inboundBytes).GetRange(packetLength, inboundBytes.Length - packetLength) .ToArray(); if (receivedPacket.ShouldEncrypt) { receivedPacket.Decrypt(client); } if (receivedPacket.Opcode == 0x39 || receivedPacket.Opcode == 0x3A) { receivedPacket.DecryptDialog(); } try { if (this is Lobby) { Logger.InfoFormat("Lobby: 0x{0:X2}", receivedPacket.Opcode); var handler = (this as Lobby).PacketHandlers[receivedPacket.Opcode]; handler.Invoke(client, receivedPacket); Logger.InfoFormat("Lobby packet done"); client.UpdateLastReceived(); } else if (this is Login) { Logger.InfoFormat("Login: 0x{0:X2}", receivedPacket.Opcode); var handler = (this as Login).PacketHandlers[receivedPacket.Opcode]; handler.Invoke(client, receivedPacket); Logger.InfoFormat("Login packet done"); client.UpdateLastReceived(); } else { client.UpdateLastReceived(receivedPacket.Opcode != 0x45 && receivedPacket.Opcode != 0x75); Logger.InfoFormat("Queuing: 0x{0:X2}", receivedPacket.Opcode); World.MessageQueue.Add(new HybrasylClientMessage(receivedPacket, client.ConnectionId)); Logger.InfoFormat("World packet done"); } } catch (Exception e) { Logger.ErrorFormat("EXCEPTION IN HANDLING: 0x{0:X2}: {1}", receivedPacket.Opcode, e); } } } } } else { Logger.DebugFormat("cid {0}: client is disconnected or corrupt packets received", client.ConnectionId); client.Disconnect(); return; } // Continue getting dem bytes try { state.WorkSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, new AsyncCallback(this.ReadCallback), state); Logger.InfoFormat("Triggering receive callback"); } catch (ObjectDisposedException) { //client.Disconnect(); state.WorkSocket.Close(); } catch (SocketException) { client.Disconnect(); } }
private void PacketHandler_0x43_PointClick(Object obj, ClientPacket packet) { var user = (User) obj; var clickType = packet.ReadByte(); Rectangle commonViewport = user.GetViewport(); // User has clicked an X,Y point if (clickType == 3) { var x = (byte) packet.ReadUInt16(); var y = (byte) packet.ReadUInt16(); var coords = new Tuple<byte, byte>(x, y); Logger.DebugFormat("coordinates were {0}, {1}", x, y); if (user.Map.Doors.ContainsKey(coords)) { if (user.Map.Doors[coords].Closed) user.SendMessage("It's open.", 0x1); else user.SendMessage("It's closed.", 0x1); user.Map.ToggleDoors(x, y); } else if (user.Map.Signposts.ContainsKey(coords)) { user.Map.Signposts[coords].OnClick(user); } else { Logger.DebugFormat("User clicked {0}@{1},{2} but no door/signpost is present", user.Map.Name, x, y); } } // User has clicked on another entity else if (clickType == 1) { var entityId = packet.ReadUInt32(); Logger.DebugFormat("User {0} clicked ID {1}: ", user.Name, entityId); WorldObject clickTarget = new WorldObject(); if (user.World.Objects.TryGetValue(entityId, out clickTarget)) { if (clickTarget is User || clickTarget is Merchant) { Type type = clickTarget.GetType(); MethodInfo methodInfo = type.GetMethod("OnClick"); methodInfo.Invoke(clickTarget, new[] {user}); } } } else { Logger.DebugFormat("Unsupported clickType {0}", clickType); Logger.DebugFormat("Packet follows:"); packet.DumpPacket(); } }
private void MerchantMenuHandler_BuyItem(User user, Merchant merchant, ClientPacket packet) { string name = packet.ReadString8(); if (!merchant.Inventory.ContainsKey(name)) { user.ShowMerchantGoBack(merchant, "I do not sell that item.", MerchantMenuItem.BuyItemMenu); return; } var template = merchant.Inventory[name]; if (template.Stackable) { user.ShowBuyMenuQuantity(merchant, name); return; } if (user.Gold < template.value) { user.ShowMerchantGoBack(merchant, "You do not have enough gold.", MerchantMenuItem.BuyItemMenu); return; } if (user.CurrentWeight + template.weight > user.MaximumWeight) { user.ShowMerchantGoBack(merchant, "That item is too heavy for you to carry.", MerchantMenuItem.BuyItemMenu); return; } if (user.Inventory.IsFull) { user.ShowMerchantGoBack(merchant, "You cannot carry any more items.", MerchantMenuItem.BuyItemMenu); return; } user.RemoveGold((uint) template.value); var item = CreateItem(template.id); Insert(item); user.AddItem(item); user.UpdateAttributes(StatUpdateFlags.Experience); user.ShowBuyMenu(merchant); }
private void PacketHandler_0x44_EquippedItemClick(Object obj, ClientPacket packet) { var user = (User) obj; // This packet is received when a client unequips an item from the detail (a) screen. var slot = packet.ReadByte(); Logger.DebugFormat("Removing equipment from slot {0}", slot); var item = user.Equipment[slot]; if (item != null) { Logger.DebugFormat("actually removing item"); user.RemoveEquipment(slot); // Add our removed item to our first empty inventory slot Logger.DebugFormat("Player weight is currently {0}", user.CurrentWeight); Logger.DebugFormat("Adding item {0}, count {1} to inventory", item.Name, item.Count); user.AddItem(item); Logger.DebugFormat("Player weight is now {0}", user.CurrentWeight); } else { Logger.DebugFormat("Ignoring useless click on slot {0}", slot); return; } }
private void MerchantMenuHandler_SellItem(User user, Merchant merchant, ClientPacket packet) { byte slot = packet.ReadByte(); var item = user.Inventory[slot]; if (item == null) return; if (!merchant.Inventory.ContainsKey(item.Name)) { user.ShowMerchantGoBack(merchant, "I do not want that item.", MerchantMenuItem.SellItemMenu); return; } if (item.Stackable && item.Count > 1) { user.ShowSellQuantity(merchant, slot); return; } user.ShowSellConfirm(merchant, slot, 1); }
private void PacketHandler_0x45_ByteHeartbeat(object obj, ClientPacket packet) { var user = (User) obj; // Client sends 0x45 response in the reverse order of what the server sends... var byteB = packet.ReadByte(); var byteA = packet.ReadByte(); if (!user.IsHeartbeatValid(byteA, byteB)) { Logger.InfoFormat("{0}: byte heartbeat not valid, disconnecting", user.Name); user.Logoff(); } else { Logger.DebugFormat("{0}: byte heartbeat valid", user.Name); } }
private void MerchantMenuHandler_SellItemConfirmation(User user, Merchant merchant, ClientPacket packet) { packet.ReadByte(); byte slot = packet.ReadByte(); byte quantity = packet.ReadByte(); var item = user.Inventory[slot]; if (item == null) return; if (!merchant.Inventory.ContainsKey(item.Name)) { user.ShowMerchantGoBack(merchant, "I do not want that item.", MerchantMenuItem.SellItemMenu); return; } if (item.Count < quantity) { user.ShowMerchantGoBack(merchant, "You don't have that many to sell.", MerchantMenuItem.SellItemMenu); return; } uint profit = (uint) (Math.Round(item.Value*0.50)*quantity); if (item.Stackable && quantity < item.Count) user.DecreaseItem(slot, quantity); else user.RemoveItem(slot); user.AddGold(profit); merchant.DisplayPursuits(user); }
private void PacketHandler_0x47_StatPoint(Object obj, ClientPacket packet) { var user = (User) obj; if (user.LevelPoints > 0) { switch (packet.ReadByte()) { case 0x01: user.BaseStr++; break; case 0x04: user.BaseInt++; break; case 0x08: user.BaseWis++; break; case 0x10: user.BaseCon++; break; case 0x02: user.BaseDex++; break; default: return; } user.LevelPoints--; user.UpdateAttributes(StatUpdateFlags.Primary); } }
private void PacketHandler_0x07_PickupItem(Object obj, ClientPacket packet) { var user = (User) obj; var slot = packet.ReadByte(); var x = packet.ReadInt16(); var y = packet.ReadInt16(); //var user = client.User; //var map = user.Map; // Is the player within PICKUP_DISTANCE tiles of what they're trying to pick up? if (Math.Abs(x - user.X) > Constants.PICKUP_DISTANCE || Math.Abs(y - user.Y) > Constants.PICKUP_DISTANCE) return; // Check if inventory slot is valid and empty if (slot == 0 || slot > user.Inventory.Size || user.Inventory[slot] != null) return; // Find the items that are at the pickup area var tile = new Rectangle(x, y, 1, 1); // We don't want to pick up people var pickupObject = user.Map.EntityTree.GetObjects(tile).FindLast(i => i is Gold || i is Item); // If the add is successful, remove the item from the map quadtree if (pickupObject is Gold) { var gold = (Gold) pickupObject; if (user.AddGold(gold)) { Logger.DebugFormat("Removing {0}, qty {1} from {2}@{3},{4}", gold.Name, gold.Amount, user.Map.Name, x, y); user.Map.RemoveGold(gold); } } else if (pickupObject is Item) { var item = (Item) pickupObject; if (item.Stackable && user.Inventory.Contains(item.TemplateId)) { byte existingSlot = user.Inventory.SlotOf(item.TemplateId); var existingItem = user.Inventory[existingSlot]; int maxCanGive = existingItem.MaximumStack - existingItem.Count; int quantity = Math.Min(item.Count, maxCanGive); item.Count -= quantity; existingItem.Count += quantity; Logger.DebugFormat("Removing {0}, qty {1} from {2}@{3},{4}", item.Name, item.Count, user.Map.Name, x, y); user.Map.Remove(item); user.SendItemUpdate(existingItem, existingSlot); if (item.Count == 0) Remove(item); else { user.Map.Insert(item, user.X, user.Y); user.SendMessage(string.Format("You can't carry any more {0}.", item.Name), 3); } } else { Logger.DebugFormat("Removing {0}, qty {1} from {2}@{3},{4}", item.Name, item.Count, user.Map.Name, x, y); user.Map.Remove(item); user.AddItem(item, slot); } } }
private void PacketHandler_0x4A_Trade(object obj, ClientPacket packet) { var user = (User) obj; var tradeStage = packet.ReadByte(); if (tradeStage == 0 && user.ActiveExchange != null) return; if (tradeStage != 0 && user.ActiveExchange == null) return; if (user.ActiveExchange != null && !user.ActiveExchange.ConditionsValid) return; switch (tradeStage) { case 0x00: { // Starting trade var x0PlayerId = packet.ReadInt32(); WorldObject target; if (Objects.TryGetValue((uint)x0PlayerId, out target)) { if (target is User) { var playerTarget = (User)target; if (Exchange.StartConditionsValid(user, playerTarget)) { user.SendMessage("That can't be done right now.", MessageTypes.SYSTEM); return; } // Initiate exchange var exchange = new Exchange(user, playerTarget); exchange.StartExchange(); } } } break; case 0x01: // Add item to trade { // We ignore playerId because we only allow one exchange at a time and we // keep track of the participants on both sides var x1playerId = packet.ReadInt32(); var x1ItemSlot = packet.ReadByte(); if (user.Inventory[x1ItemSlot] != null && user.Inventory[x1ItemSlot].Count > 1) { // Send quantity request user.SendExchangeQuantityPrompt(x1ItemSlot); } else user.ActiveExchange.AddItem(user, x1ItemSlot); } break; case 0x02: // Add item with quantity var x2PlayerId = packet.ReadInt32(); var x2ItemSlot = packet.ReadByte(); var x2ItemQuantity = packet.ReadByte(); user.ActiveExchange.AddItem(user, x2ItemSlot, x2ItemQuantity); break; case 0x03: // Add gold to trade var x3PlayerId = packet.ReadInt32(); var x3GoldQuantity = packet.ReadUInt32(); user.ActiveExchange.AddGold(user, x3GoldQuantity); break; case 0x04: // Cancel trade Logger.Debug("Cancelling trade"); user.ActiveExchange.CancelExchange(user); break; case 0x05: // Confirm trade Logger.Debug("Confirming trade"); user.ActiveExchange.ConfirmExchange(user); break; default: return; } }
private void PacketHandler_0x11_Turn(Object obj, ClientPacket packet) { var user = (User) obj; var direction = packet.ReadByte(); if (direction > 3) return; user.Turn((Direction) direction); }
private void PacketHandler_0x4F_ProfileTextPortrait(Object obj, ClientPacket packet) { var user = (User) obj; var totalLength = packet.ReadUInt16(); var portraitLength = packet.ReadUInt16(); var portraitData = packet.Read(portraitLength); var profileText = packet.ReadString16(); user.PortraitData = portraitData; user.ProfileText = profileText; }
private void PacketHandler_0x03_Login(Client client, ClientPacket packet) { var name = packet.ReadString8(); var password = packet.ReadString8(); Logger.DebugFormat("cid {0}: Login request for {1}", client.ConnectionId, name); User loginUser; if (!World.TryGetUser(name, out loginUser)) { client.LoginMessage("That character does not exist", 3); Logger.InfoFormat("cid {0}: attempt to login as nonexistent character {1}", client.ConnectionId, name); } else if (loginUser.VerifyPassword(password)) { Logger.DebugFormat("cid {0}: password verified for {1}", client.ConnectionId, name); if (Game.World.ActiveUsersByName.ContainsKey(name)) { Logger.InfoFormat("cid {0}: {1} logging on again, disconnecting previous connection", client.ConnectionId, name); World.MessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.LogoffUser, name)); } Logger.DebugFormat("cid {0} ({1}): logging in", client.ConnectionId, name); client.LoginMessage("\0", 0); client.SendMessage("Welcome to Hybrasyl!", 3); Logger.DebugFormat("cid {0} ({1}): sending redirect to world", client.ConnectionId, name); var redirect = new Redirect(client, this, Game.World, name, client.EncryptionSeed, client.EncryptionKey); Logger.InfoFormat("cid {0} ({1}): login successful, redirecting to world server", client.ConnectionId, name); client.Redirect(redirect); loginUser.Login.LastLogin = DateTime.Now; loginUser.Login.LastLoginFrom = ((IPEndPoint) client.Socket.RemoteEndPoint).Address.ToString(); loginUser.Save(); } else { Logger.WarnFormat("cid {0} ({1}): password incorrect", client.ConnectionId, name); client.LoginMessage("Incorrect password", 3); loginUser.Login.LastLoginFailure = DateTime.Now; loginUser.Login.LoginFailureCount++; loginUser.Save(); } }
private void PacketHandler_0x75_TickHeartbeat(object obj, ClientPacket packet) { var user = (User) obj; var serverTick = packet.ReadInt32(); var clientTick = packet.ReadInt32(); // Dunno what to do with this right now, so we just store it if (!user.IsHeartbeatValid(serverTick, clientTick)) { Logger.InfoFormat("{0}: tick heartbeat not valid, disconnecting", user.Name); user.Logoff(); } else { Logger.DebugFormat("{0}: tick heartbeat valid", user.Name); } }
private void PacketHandler_0x10_ClientJoin(Client client, ClientPacket packet) { var seed = packet.ReadByte(); var keyLength = packet.ReadByte(); var key = packet.Read(keyLength); var name = packet.ReadString8(); var id = packet.ReadUInt32(); var redirect = ExpectedConnections[id]; if (redirect.Matches(name, key, seed)) { ((IDictionary)ExpectedConnections).Remove(id); client.EncryptionKey = key; client.EncryptionSeed = seed; if (redirect.Source is Lobby) { var x60 = new ServerPacket(0x60); x60.WriteByte(0x00); x60.WriteUInt32(Game.NotificationCrc); client.Enqueue(x60); } } }
private void PacketHandler_0x79_Status(Object obj, ClientPacket packet) { var user = (User) obj; var status = packet.ReadByte(); if (status <= 7) { user.GroupStatus = (UserStatus) status; } }
private void PacketHandler_0x4B_RequestNotification(Client client, ClientPacket packet) { var x60 = new ServerPacket(0x60); x60.WriteByte(0x01); x60.WriteUInt16((ushort)Game.Notification.Length); x60.Write(Game.Notification); client.Enqueue(x60); }
private void PacketHandler_0x7B_RequestMetafile(Object obj, ClientPacket packet) { var user = (User) obj; var all = packet.ReadBoolean(); if (all) { var x6F = new ServerPacket(0x6F); x6F.WriteBoolean(all); x6F.WriteUInt16((ushort) Metafiles.Count); foreach (var metafile in Metafiles.Values) { x6F.WriteString8(metafile.Name); x6F.WriteUInt32(metafile.Checksum); } user.Enqueue(x6F); } else { var name = packet.ReadString8(); if (Metafiles.ContainsKey(name)) { var file = Metafiles[name]; var x6F = new ServerPacket(0x6F); x6F.WriteBoolean(all); x6F.WriteString8(file.Name); x6F.WriteUInt32(file.Checksum); x6F.WriteUInt16((ushort) file.Data.Length); x6F.Write(file.Data); user.Enqueue(x6F); } } }
private void MerchantMenuHandler_MainMenu(User user, Merchant merchant, ClientPacket packet) { merchant.DisplayPursuits(user); }
private void PacketHandler_0x04_CreateB(Client client, ClientPacket packet) { if (string.IsNullOrEmpty(client.NewCharacterName) || string.IsNullOrEmpty(client.NewCharacterPassword)) { return; } var hairStyle = packet.ReadByte(); var sex = packet.ReadByte(); var hairColor = packet.ReadByte(); if (hairStyle < 1) { hairStyle = 1; } if (hairStyle > 17) { hairStyle = 17; } if (hairColor > 13) { hairColor = 13; } if (sex < 1) { sex = 1; } if (sex > 2) { sex = 2; } if (!Game.World.PlayerExists(client.NewCharacterName)) { var newPlayer = new User(); newPlayer.Name = client.NewCharacterName; newPlayer.Sex = (Sex)sex; newPlayer.Location.Direction = Direction.South; newPlayer.Location.MapId = 136; newPlayer.Location.X = 10; newPlayer.Location.Y = 10; newPlayer.HairColor = hairColor; newPlayer.HairStyle = hairStyle; newPlayer.Class = Class.Peasant; newPlayer.Level = 1; newPlayer.Experience = 1; newPlayer.Level = 1; newPlayer.Experience = 0; newPlayer.AbilityExp = 0; newPlayer.Gold = 0; newPlayer.Ability = 0; newPlayer.Hp = 50; newPlayer.Mp = 50; newPlayer.BaseHp = 50; newPlayer.BaseMp = 50; newPlayer.BaseStr = 3; newPlayer.BaseInt = 3; newPlayer.BaseWis = 3; newPlayer.BaseCon = 3; newPlayer.BaseDex = 3; newPlayer.Login.CreatedTime = DateTime.Now; newPlayer.Password.Hash = client.NewCharacterPassword; newPlayer.Password.LastChanged = DateTime.Now; newPlayer.Password.LastChangedFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString(); newPlayer.Nation = Game.World.DefaultNation; IDatabase cache = World.DatastoreConnection.GetDatabase(); var myPerson = JsonConvert.SerializeObject(newPlayer); cache.Set(User.GetStorageKey(newPlayer.Name), myPerson); // Logger.ErrorFormat("Error saving new player!"); // Logger.ErrorFormat(e.ToString()); // client.LoginMessage("Unknown error. Contact [email protected]", 3); // } client.LoginMessage("\0", 0); } }