public static void HeaderChange(NetState state, CircularBufferReader reader, ref int packetLength) { var from = state.Mobile; if (!(World.FindItem(reader.ReadUInt32()) is BaseBook book) || !book.Writable || !from.InRange(book.GetWorldLocation(), 1) || !book.IsAccessibleTo(from)) { return; } reader.Seek(4, SeekOrigin.Current); // Skip flags and page count int titleLength = reader.ReadUInt16(); if (titleLength > 60) { return; } // TODO: Read string to a Span<char> stackalloc instead of a returned value // This way we can avoid an allocation and do Utility.FixHtml against it by searching/replacing characters var title = reader.ReadUTF8Safe(titleLength); int authorLength = reader.ReadUInt16(); if (authorLength > 30) { return; } var author = reader.ReadUTF8Safe(authorLength); book.Title = Utility.FixHtml(title); book.Author = Utility.FixHtml(author); }
public static void LiftReq(NetState state, CircularBufferReader reader, int packetLength) { var serial = (Serial)reader.ReadUInt32(); int amount = reader.ReadUInt16(); var item = World.FindItem(serial); state.Mobile.Lift(item, amount, out _, out _); }
public static void BBRequestHeader(Mobile from, BaseBulletinBoard board, CircularBufferReader reader) { if (!(World.FindItem(reader.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board) { return; } from.Send(new BBMessageHeader(board, msg)); }
public static void QuestArrow(NetState state, CircularBufferReader reader, ref int packetLength) { if (state.Mobile is PlayerMobile from) { var rightClick = reader.ReadBoolean(); from.QuestArrow?.OnClick(rightClick); } }
public static void MobileNameRequest(NetState state, CircularBufferReader reader, int packetLength) { var m = World.FindMobile((Serial)reader.ReadUInt32()); if (m != null && Utility.InUpdateRange(state.Mobile.Location, m.Location) && state.Mobile.CanSee(m)) { state.SendMobileName(m); } }
public static void BBPostMessage(Mobile from, BaseBulletinBoard board, CircularBufferReader reader) { var thread = World.FindItem(reader.ReadUInt32()) as BulletinMessage; if (thread != null && thread.Parent != board) { thread = null; } var breakout = 0; while (thread?.Thread != null && breakout++ < 10) { thread = thread.Thread; } var lastPostTime = DateTime.MinValue; if (board.GetLastPostTime(from, thread == null, ref lastPostTime)) { if (!CheckTime(lastPostTime, thread == null ? ThreadCreateTime : ThreadReplyTime)) { if (thread == null) { from.SendMessage("You must wait {0} before creating a new thread.", FormatTS(ThreadCreateTime)); } else { from.SendMessage("You must wait {0} before replying to another thread.", FormatTS(ThreadReplyTime)); } return; } } var subject = reader.ReadUTF8Safe(reader.ReadByte()); if (subject.Length == 0) { return; } var lines = new string[reader.ReadByte()]; if (lines.Length == 0) { return; } for (var i = 0; i < lines.Length; ++i) { lines[i] = reader.ReadUTF8Safe(reader.ReadByte()); } board.PostMessage(from, thread, subject, lines); }
public static void RenameRequest(NetState state, CircularBufferReader reader, int packetLength) { var from = state.Mobile; var targ = World.FindMobile((Serial)reader.ReadUInt32()); if (targ != null) { EventSink.InvokeRenameRequest(from, targ, reader.ReadAsciiSafe()); } }
public static void QueryPartyMemberLocations(NetState state, CircularBufferReader reader, int packetLength) { Mobile from = state.Mobile; var party = Party.Get(from); if (party != null) { state.SendPartyMemberLocations(from, party); } }
public static void ChatAction(NetState state, CircularBufferReader reader, int packetLength) { if (!ChatSystem.Enabled) { return; } try { var from = state.Mobile; var user = ChatUser.GetChatUser(from); if (user == null) { return; } var lang = reader.ReadAsciiSafe(4); int actionID = reader.ReadInt16(); var param = reader.ReadBigUniSafe(); var handler = ChatActionHandlers.GetHandler(actionID); if (handler == null) { state.LogInfo($"Unknown chat action 0x{actionID:X}: {param}"); return; } var channel = user.CurrentChannel; if (handler.RequireConference && channel == null) { // You must be in a conference to do this. // To join a conference, select one from the Conference menu. user.SendMessage(31); return; } if (handler.RequireModerator && !user.IsModerator) { user.SendMessage(29); // You must have operator status to do this. return; } handler.Callback(user, channel, param); } catch (Exception e) { Console.WriteLine(e); } }
public static void BBRemoveMessage(Mobile from, BaseBulletinBoard board, CircularBufferReader reader) { if (!(World.FindItem(reader.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board) { return; } if (from.AccessLevel < AccessLevel.GameMaster && msg.Poster != from) { return; } msg.Delete(); }
public static void SystemInfo(NetState state, CircularBufferReader reader, int packetLength) { int v1 = reader.ReadByte(); int v2 = reader.ReadUInt16(); int v3 = reader.ReadByte(); var s1 = reader.ReadAscii(32); var s2 = reader.ReadAscii(32); var s3 = reader.ReadAscii(32); var s4 = reader.ReadAscii(32); int v4 = reader.ReadUInt16(); int v5 = reader.ReadUInt16(); var v6 = reader.ReadInt32(); var v7 = reader.ReadInt32(); var v8 = reader.ReadInt32(); }
private static void OnPartyTrack(NetState state, CircularBufferReader reader) { var from = state.Mobile; var party = Party.Get(from); if (party != null) { var packet = new Packets.PartyTrack(from, party); if (packet.Stream.Length > 8) { state.Send(packet); } } }
public static void LookReq(NetState state, CircularBufferReader reader, ref int packetLength) { var from = state.Mobile; Serial s = reader.ReadUInt32(); if (s.IsMobile) { var m = World.FindMobile(s); if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m)) { if (SingleClickProps) { m.OnAosSingleClick(from); } else { if (from.Region.OnSingleClick(from, m)) { m.OnSingleClick(from); } } } } else if (s.IsItem) { var item = World.FindItem(s); if (item?.Deleted == false && from.CanSee(item) && Utility.InUpdateRange(from.Location, item.GetWorldLocation())) { if (SingleClickProps) { item.OnAosSingleClick(from); } else if (from.Region.OnSingleClick(from, item)) { if (item.Parent is Item parentItem) { parentItem.OnSingleClickContained(from, item); } item.OnSingleClick(from); } } } }
public static void ContentChange(NetState state, CircularBufferReader reader, ref int packetLength) { var from = state.Mobile; if (!(World.FindItem(reader.ReadUInt32()) is BaseBook book) || !book.Writable || !from.InRange(book.GetWorldLocation(), 1) || !book.IsAccessibleTo(from)) { return; } int pageCount = reader.ReadUInt16(); if (pageCount > book.PagesCount) { return; } for (var i = 0; i < pageCount; ++i) { int index = reader.ReadUInt16(); if (index < 1 || index > book.PagesCount) { return; } --index; int lineCount = reader.ReadUInt16(); if (lineCount > 8) { return; } var lines = new string[lineCount]; for (var j = 0; j < lineCount; ++j) { if ((lines[j] = reader.ReadUTF8Safe()).Length >= 80) { return; } } book.Pages[index].Lines = lines; } }
// TODO: Throttle/make this more safe public static void Resynchronize(NetState state, CircularBufferReader reader, int packetLength) { var from = state.Mobile; if (from == null) { return; } state.SendMobileUpdate(from); state.SendMobileIncoming(from, from); from.SendEverything(); state.Sequence = 0; }
public static void AttackReq(NetState state, CircularBufferReader reader, int packetLength) { var from = state.Mobile; if (from == null) { return; } var m = World.FindMobile((Serial)reader.ReadUInt32()); if (m != null) { from.Attack(m); } }
public static void HuePickerResponse(NetState state, CircularBufferReader reader, int packetLength) { var serial = reader.ReadUInt32(); _ = reader.ReadInt16(); // Item ID var hue = Utility.ClipDyedHue(reader.ReadInt16() & 0x3FFF); foreach (var huePicker in state.HuePickers) { if (huePicker.Serial == serial) { state.RemoveHuePicker(huePicker); huePicker.OnResponse(hue); break; } } }
public static void NewMovementReq(NetState ns, CircularBufferReader reader) { var from = ns.Mobile; if (from == null) { return; } var steps = reader.ReadByte(); for (int i = 0; i < steps; i++) { var t1 = reader.ReadUInt64(); // start time? var t2 = reader.ReadUInt64(); // end time? int seq = reader.ReadByte(); var dir = (Direction)reader.ReadByte(); var mode = reader.ReadInt32(); // 1 = walk, 2 = run if (mode == 2) { dir |= Direction.Running; } // Location reader.ReadInt32(); // x reader.ReadInt32(); // y reader.ReadInt32(); // z if (ns.Sequence == 0 && seq != 0 || !from.Move(dir)) { ns.SendMovementRej(seq, from); ns.Sequence = 0; } else { ++seq; if (seq == 256) { seq = 1; } ns.Sequence = seq; } } }
public static void OldHeaderChange(NetState state, CircularBufferReader reader, ref int packetLength) { var from = state.Mobile; if (!(World.FindItem(reader.ReadUInt32()) is BaseBook book) || !book.Writable || !from.InRange(book.GetWorldLocation(), 1) || !book.IsAccessibleTo(from)) { return; } reader.Seek(4, SeekOrigin.Current); // Skip flags and page count var title = reader.ReadAsciiSafe(60); var author = reader.ReadAsciiSafe(30); book.Title = Utility.FixHtml(title); book.Author = Utility.FixHtml(author); }
public static void UseReq(NetState state, CircularBufferReader reader, ref int packetLength) { var from = state.Mobile; if (from.AccessLevel >= AccessLevel.Counselor || Core.TickCount - from.NextActionTime >= 0) { var value = reader.ReadUInt32(); if ((value & ~0x7FFFFFFF) != 0) { from.OnPaperdollRequest(); } else { Serial s = value; if (s.IsMobile) { var m = World.FindMobile(s); if (m?.Deleted == false) { from.Use(m); } } else if (s.IsItem) { var item = World.FindItem(s); if (item?.Deleted == false) { from.Use(item); } } } from.NextActionTime = Core.TickCount + Mobile.ActionDelay; } else { from.SendActionMessage(); } }
private static void OnGuildTrack(NetState state, CircularBufferReader reader) { var from = state.Mobile; if (from.Guild is Guild guild) { var locations = reader.ReadByte() != 0; var packet = new Packets.GuildTrack(from, guild, locations); if (packet.Stream.Length > (locations ? 9 : 5)) { state.Send(packet); } } else { state.Send(new Packets.GuildTrack()); } }
public static void OpenChatWindowRequest(NetState state, CircularBufferReader reader, int packetLength) { var from = state.Mobile; if (!ChatSystem.Enabled) { from.SendMessage("The chat system has been disabled."); return; } // Newer clients don't send chat username anymore so we are ignoring the rest of this packet. // TODO: How does OSI handle incognito/disguise kits? // TODO: Does OSI still allow duplicate names? // For now we assume they should use their raw name. var chatName = from.RawName ?? $"Unknown User {Utility.RandomMinMax(1000000, 9999999)}"; ChatSystem.SendCommandTo(from, ChatCommand.OpenChatWindow, chatName); ChatUser.AddChatUser(from, chatName); }
public static void VendorSellReply(NetState state, CircularBufferReader reader, int packetLength) { var serial = (Serial)reader.ReadUInt32(); var vendor = World.FindMobile(serial); if (vendor == null) { return; } if (vendor.Deleted || !Utility.InRange(vendor.Location, state.Mobile.Location, 10)) { state.SendEndVendorSell(vendor.Serial); return; } int count = reader.ReadUInt16(); if (count >= 100 || reader.Remaining != count * 6) { return; } var sellList = new List <SellItemResponse>(count); for (var i = 0; i < count; i++) { var item = World.FindItem((Serial)reader.ReadUInt32()); int amount = reader.ReadInt16(); if (item != null && amount > 0) { sellList.Add(new SellItemResponse(item, amount)); } } if (sellList.Count > 0 && vendor is IVendor v && v.OnSellItems(state.Mobile, sellList)) { state.SendEndVendorSell(vendor.Serial); } }
public static void BatchQueryProperties(NetState state, CircularBufferReader reader, ref int packetLength) { if (!ObjectPropertyList.Enabled) { return; } var from = state.Mobile; var length = reader.Remaining; if (length % 4 != 0) { return; } while (reader.Remaining > 0) { Serial s = reader.ReadUInt32(); if (s.IsMobile) { var m = World.FindMobile(s); if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m)) { m.SendPropertiesTo(from); } } else if (s.IsItem) { var item = World.FindItem(s); if (item?.Deleted == false && from.CanSee(item) && Utility.InUpdateRange(from.Location, item.GetWorldLocation())) { item.SendPropertiesTo(from); } } } }
public static void OnPacket(NetState state, CircularBufferReader reader, ref int packetLength) { var game = World.FindItem((Serial)reader.ReadUInt32()) as MahjongGame; game?.Players.CheckPlayers(); reader.ReadByte(); int cmd = reader.ReadByte(); var onReceive = GetSubCommandDelegate(cmd); if (onReceive != null) { onReceive(game, state, reader); } else { reader.Trace(state); } }
public static void ProfileReq(NetState state, CircularBufferReader reader, int packetLength) { int type = reader.ReadByte(); var serial = (Serial)reader.ReadUInt32(); var beholder = state.Mobile; var beheld = World.FindMobile(serial); if (beheld == null) { return; } switch (type) { case 0x00: // display request { EventSink.InvokeProfileRequest(beholder, beheld); break; } case 0x01: // edit request { reader.ReadInt16(); // Skip int length = reader.ReadUInt16(); if (length > 511) { return; } var text = reader.ReadBigUni(length); EventSink.InvokeChangeProfileRequest(beholder, beheld, text); break; } } }
public static void VendorBuyReply(NetState state, CircularBufferReader reader, int packetLength) { var vendor = World.FindMobile((Serial)reader.ReadUInt32()); if (vendor == null) { return; } var flag = reader.ReadByte(); if (!vendor.Deleted && Utility.InRange(vendor.Location, state.Mobile.Location, 10) && flag == 0x02) { var msgSize = packetLength - 8; // Remaining bytes if (msgSize / 7 > 100) { return; } var buyList = new List <BuyItemResponse>(msgSize / 7); while (msgSize > 0) { var layer = reader.ReadByte(); var serial = (Serial)reader.ReadUInt32(); int amount = reader.ReadInt16(); buyList.Add(new BuyItemResponse(serial, amount)); msgSize -= 7; } if (buyList.Count <= 0 || (vendor as IVendor)?.OnBuyItems(state.Mobile, buyList) != true) { return; } } state.SendEndVendorBuy(vendor.Serial); }
public static void MobileQuery(NetState state, CircularBufferReader reader, int packetLength) { var from = state.Mobile; if (from == null) { return; } reader.ReadInt32(); // 0xEDEDEDED int type = reader.ReadByte(); var m = World.FindMobile((Serial)reader.ReadUInt32()); if (m == null) { return; } switch (type) { case 0x04: // Stats { m.OnStatsQuery(from); break; } case 0x05: { m.OnSkillsQuery(from); break; } default: { reader.Trace(state); break; } } }
public static void DropReq(NetState state, CircularBufferReader reader, int packetLength) { reader.ReadInt32(); // serial, ignored int x = reader.ReadInt16(); int y = reader.ReadInt16(); int z = reader.ReadSByte(); if (state.ContainerGridLines) { reader.ReadByte(); // Grid Location? } Serial dest = (Serial)reader.ReadUInt32(); var loc = new Point3D(x, y, z); var from = state.Mobile; if (dest.IsMobile) { from.Drop(World.FindMobile(dest), loc); } else if (dest.IsItem) { var item = World.FindItem(dest); if (item is BaseMulti multi && multi.AllowsRelativeDrop) { loc.m_X += multi.X; loc.m_Y += multi.Y; from.Drop(loc); } else { from.Drop(item, loc); } }
public static void EncodedCommand(NetState state, CircularBufferReader reader, int packetLength) { var e = World.FindEntity((Serial)reader.ReadUInt32()); int packetId = reader.ReadUInt16(); // We will add support if this is ever a real thing. if (packetId > 0xFF) { var reason = $"Sent unsupported encoded packet (0xD7x{packetId:X4}"; state.LogInfo(reason); state.Disconnect(reason); } var ph = IncomingPackets.GetEncodedHandler(packetId); if (ph == null) { reader.Trace(state); return; } if (ph.Ingame && state.Mobile == null) { var reason = $"Sent in-game packet (0xD7x{packetId:X4}) before being attached to a mobile."; state.LogInfo(reason); state.Disconnect(reason); } else if (ph.Ingame && state.Mobile.Deleted) { state.Disconnect($"Sent in-game packet(0xD7x{packetId:X4}) but mobile is deleted."); } else { ph.OnReceive(state, e, new EncodedReader(reader)); } }
/// <summary> /// Constructs a circular buffer of specified initial size /// </summary> /// <param name="size">Initial size of buffer</param> public CircularBuffer(int size) { this.internalData = new byte[ size+1 ]; this.writer = new CircularBufferWriter(this); this.reader = new CircularBufferReader(this); }