/*************************************************************************** * PacketHandlers.cs * ------------------- * begin : May 1, 2002 * copyright : (C) The RunUO Software Team * email : info@runuo.com * * $Id$ * ***************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ using System; using System.Text; using System.Collections; using System.Collections.Generic; using System.IO; using System.Net; using Server.Accounting; using Server.Gumps; using Server.Targeting; using Server.Items; using Server.Menus; using Server.Mobiles; using Server.Movement; using Server.Prompts; using Server.HuePickers; using Server.ContextMenus; using Server.Diagnostics; using CV = Server.ClientVersion; namespace Server.Network { public enum MessageType { Regular = 0x00, System = 0x01, Emote = 0x02, Label = 0x06, Focus = 0x07, Whisper = 0x08, Yell = 0x09, Spell = 0x0A, Guild = 0x0D, Alliance = 0x0E, Command = 0x0F, Encoded = 0xC0 } public static class PacketHandlers { private static PacketHandler[] m_Handlers; private static PacketHandler[] m_6017Handlers; private static PacketHandler[] m_ExtendedHandlersLow; private static Dictionary m_ExtendedHandlersHigh; private static EncodedPacketHandler[] m_EncodedHandlersLow; private static Dictionary m_EncodedHandlersHigh; public static PacketHandler[] Handlers { get{ return m_Handlers; } } static PacketHandlers() { m_Handlers = new PacketHandler[0x100]; m_6017Handlers = new PacketHandler[0x100]; m_ExtendedHandlersLow = new PacketHandler[0x100]; m_ExtendedHandlersHigh = new Dictionary(); m_EncodedHandlersLow = new EncodedPacketHandler[0x100]; m_EncodedHandlersHigh = new Dictionary(); Register( 0x00, 104, false, new OnPacketReceive( CreateCharacter ) ); Register( 0x01, 5, false, new OnPacketReceive( Disconnect ) ); Register( 0x02, 7, true, new OnPacketReceive( MovementReq ) ); Register( 0x03, 0, true, new OnPacketReceive( AsciiSpeech ) ); Register( 0x04, 2, true, new OnPacketReceive( GodModeRequest ) ); Register( 0x05, 5, true, new OnPacketReceive( AttackReq ) ); Register( 0x06, 5, true, new OnPacketReceive( UseReq ) ); Register( 0x07, 7, true, new OnPacketReceive( LiftReq ) ); Register( 0x08, 14, true, new OnPacketReceive( DropReq ) ); Register( 0x09, 5, true, new OnPacketReceive( LookReq ) ); Register( 0x0A, 11, true, new OnPacketReceive( Edit ) ); Register( 0x12, 0, true, new OnPacketReceive( TextCommand ) ); Register( 0x13, 10, true, new OnPacketReceive( EquipReq ) ); Register( 0x14, 6, true, new OnPacketReceive( ChangeZ ) ); Register( 0x22, 3, true, new OnPacketReceive( Resynchronize ) ); Register( 0x2C, 2, true, new OnPacketReceive( DeathStatusResponse ) ); Register( 0x34, 10, true, new OnPacketReceive( MobileQuery ) ); Register( 0x3A, 0, true, new OnPacketReceive( ChangeSkillLock ) ); Register( 0x3B, 0, true, new OnPacketReceive( VendorBuyReply ) ); Register( 0x47, 11, true, new OnPacketReceive( NewTerrain ) ); Register( 0x48, 73, true, new OnPacketReceive( NewAnimData ) ); Register( 0x58, 106, true, new OnPacketReceive( NewRegion ) ); Register( 0x5D, 73, false, new OnPacketReceive( PlayCharacter ) ); Register( 0x61, 9, true, new OnPacketReceive( DeleteStatic ) ); Register( 0x6C, 19, true, new OnPacketReceive( TargetResponse ) ); Register( 0x6F, 0, true, new OnPacketReceive( SecureTrade ) ); Register( 0x72, 5, true, new OnPacketReceive( SetWarMode ) ); Register( 0x73, 2, false, new OnPacketReceive( PingReq ) ); Register( 0x75, 35, true, new OnPacketReceive( RenameRequest ) ); Register( 0x79, 9, true, new OnPacketReceive( ResourceQuery ) ); Register( 0x7E, 2, true, new OnPacketReceive( GodviewQuery ) ); Register( 0x7D, 13, true, new OnPacketReceive( MenuResponse ) ); Register( 0x80, 62, false, new OnPacketReceive( AccountLogin ) ); Register( 0x83, 39, false, new OnPacketReceive( DeleteCharacter ) ); Register( 0x91, 65, false, new OnPacketReceive( GameLogin ) ); Register( 0x95, 9, true, new OnPacketReceive( HuePickerResponse ) ); Register( 0x96, 0, true, new OnPacketReceive( GameCentralMoniter ) ); Register( 0x98, 0, true, new OnPacketReceive( MobileNameRequest ) ); Register( 0x9A, 0, true, new OnPacketReceive( AsciiPromptResponse ) ); Register( 0x9B, 258, true, new OnPacketReceive( HelpRequest ) ); Register( 0x9D, 51, true, new OnPacketReceive( GMSingle ) ); Register( 0x9F, 0, true, new OnPacketReceive( VendorSellReply ) ); Register( 0xA0, 3, false, new OnPacketReceive( PlayServer ) ); Register( 0xA4, 149, false, new OnPacketReceive( SystemInfo ) ); Register( 0xA7, 4, true, new OnPacketReceive( RequestScrollWindow ) ); Register( 0xAD, 0, true, new OnPacketReceive( UnicodeSpeech ) ); Register( 0xB1, 0, true, new OnPacketReceive( DisplayGumpResponse ) ); Register( 0xB5, 64, true, new OnPacketReceive( ChatRequest ) ); Register( 0xB6, 9, true, new OnPacketReceive( ObjectHelpRequest ) ); Register( 0xB8, 0, true, new OnPacketReceive( ProfileReq ) ); Register( 0xBB, 9, false, new OnPacketReceive( AccountID ) ); Register( 0xBD, 0, false, new OnPacketReceive( ClientVersion ) ); Register( 0xBE, 0, true, new OnPacketReceive( AssistVersion ) ); Register( 0xBF, 0, true, new OnPacketReceive( ExtendedCommand ) ); Register( 0xC2, 0, true, new OnPacketReceive( UnicodePromptResponse ) ); Register( 0xC8, 2, true, new OnPacketReceive( SetUpdateRange ) ); Register( 0xC9, 6, true, new OnPacketReceive( TripTime ) ); Register( 0xCA, 6, true, new OnPacketReceive( UTripTime ) ); Register( 0xCF, 0, false, new OnPacketReceive( AccountLogin ) ); Register( 0xD0, 0, true, new OnPacketReceive( ConfigurationFile ) ); Register( 0xD1, 2, true, new OnPacketReceive( LogoutReq ) ); Register( 0xD6, 0, true, new OnPacketReceive( BatchQueryProperties ) ); Register( 0xD7, 0, true, new OnPacketReceive( EncodedCommand ) ); Register( 0xE1, 0, false, new OnPacketReceive( ClientType ) ); Register( 0xEF, 21, false, new OnPacketReceive( LoginServerSeed ) ); Register( 0xF8, 106, false, new OnPacketReceive( CreateCharacter70160 ) ); Register6017( 0x08, 15, true, new OnPacketReceive( DropReq6017 ) ); RegisterExtended( 0x05, false, new OnPacketReceive( ScreenSize ) ); RegisterExtended( 0x06, true, new OnPacketReceive( PartyMessage ) ); RegisterExtended( 0x07, true, new OnPacketReceive( QuestArrow ) ); RegisterExtended( 0x09, true, new OnPacketReceive( DisarmRequest ) ); RegisterExtended( 0x0A, true, new OnPacketReceive( StunRequest ) ); RegisterExtended( 0x0B, false, new OnPacketReceive( Language ) ); RegisterExtended( 0x0C, true, new OnPacketReceive( CloseStatus ) ); RegisterExtended( 0x0E, true, new OnPacketReceive( Animate ) ); RegisterExtended( 0x0F, false, new OnPacketReceive( Empty ) ); // What's this? RegisterExtended( 0x10, true, new OnPacketReceive( QueryProperties ) ); RegisterExtended( 0x13, true, new OnPacketReceive( ContextMenuRequest ) ); RegisterExtended( 0x15, true, new OnPacketReceive( ContextMenuResponse ) ); RegisterExtended( 0x1A, true, new OnPacketReceive( StatLockChange ) ); RegisterExtended( 0x1C, true, new OnPacketReceive( CastSpell ) ); RegisterExtended( 0x24, false, new OnPacketReceive( UnhandledBF ) ); RegisterEncoded( 0x19, true, new OnEncodedPacketReceive( SetAbility ) ); RegisterEncoded( 0x28, true, new OnEncodedPacketReceive( GuildGumpRequest ) ); RegisterEncoded( 0x32, true, new OnEncodedPacketReceive( QuestGumpRequest ) ); } public static void Register( int packetID, int length, bool ingame, OnPacketReceive onReceive ) { m_Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); if ( m_6017Handlers[packetID] == null ) m_6017Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); } public static PacketHandler GetHandler( int packetID ) { return m_Handlers[packetID]; } public static void Register6017( int packetID, int length, bool ingame, OnPacketReceive onReceive ) { m_6017Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); } public static PacketHandler Get6017Handler( int packetID ) { return m_6017Handlers[packetID]; } public static void RegisterExtended( int packetID, bool ingame, OnPacketReceive onReceive ) { if ( packetID >= 0 && packetID < 0x100 ) m_ExtendedHandlersLow[packetID] = new PacketHandler( packetID, 0, ingame, onReceive ); else m_ExtendedHandlersHigh[packetID] = new PacketHandler( packetID, 0, ingame, onReceive ); } public static PacketHandler GetExtendedHandler( int packetID ) { if ( packetID >= 0 && packetID < 0x100 ) return m_ExtendedHandlersLow[packetID]; else { PacketHandler handler; m_ExtendedHandlersHigh.TryGetValue( packetID, out handler ); return handler; } } public static void RemoveExtendedHandler( int packetID ) { if ( packetID >= 0 && packetID < 0x100 ) m_ExtendedHandlersLow[packetID] = null; else m_ExtendedHandlersHigh.Remove( packetID ); } public static void RegisterEncoded( int packetID, bool ingame, OnEncodedPacketReceive onReceive ) { if ( packetID >= 0 && packetID < 0x100 ) m_EncodedHandlersLow[packetID] = new EncodedPacketHandler( packetID, ingame, onReceive ); else m_EncodedHandlersHigh[packetID] = new EncodedPacketHandler( packetID, ingame, onReceive ); } public static EncodedPacketHandler GetEncodedHandler( int packetID ) { if ( packetID >= 0 && packetID < 0x100 ) return m_EncodedHandlersLow[packetID]; else { EncodedPacketHandler handler; m_EncodedHandlersHigh.TryGetValue( packetID, out handler ); return handler; } } public static void RemoveEncodedHandler( int packetID ) { if ( packetID >= 0 && packetID < 0x100 ) m_EncodedHandlersLow[packetID] = null; else m_EncodedHandlersHigh.Remove( packetID ); } public static void RegisterThrottler( int packetID, ThrottlePacketCallback t ) { PacketHandler ph = GetHandler( packetID ); if ( ph != null ) ph.ThrottleCallback = t; ph = Get6017Handler( packetID ); if ( ph != null ) ph.ThrottleCallback = t; } private static void UnhandledBF( NetState state, PacketReader pvSrc ) { } public static void Empty( NetState state, PacketReader pvSrc ) { } public static void SetAbility( NetState state, IEntity e, EncodedReader reader ) { EventSink.InvokeSetAbility( new SetAbilityEventArgs( state.Mobile, reader.ReadInt32() ) ); } public static void GuildGumpRequest( NetState state, IEntity e, EncodedReader reader ) { EventSink.InvokeGuildGumpRequest( new GuildGumpRequestArgs( state.Mobile ) ); } public static void QuestGumpRequest( NetState state, IEntity e, EncodedReader reader ) { EventSink.InvokeQuestGumpRequest( new QuestGumpRequestArgs( state.Mobile ) ); } public static void EncodedCommand( NetState state, PacketReader pvSrc ) { IEntity e = World.FindEntity( pvSrc.ReadInt32() ); int packetID = pvSrc.ReadUInt16(); EncodedPacketHandler ph = GetEncodedHandler( packetID ); if ( ph != null ) { if ( ph.Ingame && state.Mobile == null ) { Console.WriteLine( "Client: {0}: Sent ingame packet (0xD7x{1:X2}) before having been attached to a mobile", state, packetID ); state.Dispose(); } else if ( ph.Ingame && state.Mobile.Deleted ) { state.Dispose(); } else { ph.OnReceive( state, e, new EncodedReader( pvSrc ) ); } } else { pvSrc.Trace( state ); } } public static void RenameRequest( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; Mobile targ = World.FindMobile( pvSrc.ReadInt32() ); if ( targ != null ) EventSink.InvokeRenameRequest( new RenameRequestEventArgs( from, targ, pvSrc.ReadStringSafe() ) ); } public static void ChatRequest( NetState state, PacketReader pvSrc ) { EventSink.InvokeChatRequest( new ChatRequestEventArgs( state.Mobile ) ); } public static void SecureTrade( NetState state, PacketReader pvSrc ) { switch ( pvSrc.ReadByte() ) { case 1: // Cancel { Serial serial = pvSrc.ReadInt32(); SecureTradeContainer cont = World.FindItem( serial ) as SecureTradeContainer; if ( cont != null && cont.Trade != null && (cont.Trade.From.Mobile == state.Mobile || cont.Trade.To.Mobile == state.Mobile) ) cont.Trade.Cancel(); break; } case 2: // Check { Serial serial = pvSrc.ReadInt32(); SecureTradeContainer cont = World.FindItem( serial ) as SecureTradeContainer; if ( cont != null ) { SecureTrade trade = cont.Trade; bool value = ( pvSrc.ReadInt32() != 0 ); if ( trade != null && trade.From.Mobile == state.Mobile ) { trade.From.Accepted = value; trade.Update(); } else if ( trade != null && trade.To.Mobile == state.Mobile ) { trade.To.Accepted = value; trade.Update(); } } break; } } } public static void VendorBuyReply( NetState state, PacketReader pvSrc ) { pvSrc.Seek( 1, SeekOrigin.Begin ); int msgSize = pvSrc.ReadUInt16(); Mobile vendor = World.FindMobile( pvSrc.ReadInt32() ); byte flag = pvSrc.ReadByte(); if ( vendor == null ) { return; } else if ( vendor.Deleted || !Utility.RangeCheck( vendor.Location, state.Mobile.Location, 10 ) ) { state.Send( new EndVendorBuy( vendor ) ); return; } if ( flag == 0x02 ) { msgSize -= 1+2+4+1; if ( (msgSize / 7) > 100 ) return; List buyList = new List( msgSize / 7 ); for ( ;msgSize>0;msgSize-=7) { byte layer = pvSrc.ReadByte(); Serial serial = pvSrc.ReadInt32(); int amount = pvSrc.ReadInt16(); buyList.Add( new BuyItemResponse( serial, amount ) ); } if ( buyList.Count > 0 ) { IVendor v = vendor as IVendor; if ( v != null && v.OnBuyItems( state.Mobile, buyList ) ) state.Send( new EndVendorBuy( vendor ) ); } } else { state.Send( new EndVendorBuy( vendor ) ); } } public static void VendorSellReply( NetState state, PacketReader pvSrc ) { Serial serial = pvSrc.ReadInt32(); Mobile vendor = World.FindMobile( serial ); if ( vendor == null ) { return; } else if ( vendor.Deleted || !Utility.RangeCheck( vendor.Location, state.Mobile.Location, 10 ) ) { state.Send( new EndVendorSell( vendor ) ); return; } int count = pvSrc.ReadUInt16(); if ( count < 100 && pvSrc.Size == (1+2+4+2+(count*6)) ) { List sellList = new List( count ); for (int i=0;i 0 ) sellList.Add( new SellItemResponse( item, Amount ) ); } if ( sellList.Count > 0 ) { IVendor v = vendor as IVendor; if ( v != null && v.OnSellItems( state.Mobile, sellList ) ) state.Send( new EndVendorSell( vendor ) ); } } } public static void DeleteCharacter( NetState state, PacketReader pvSrc ) { pvSrc.Seek( 30, SeekOrigin.Current ); int index = pvSrc.ReadInt32(); EventSink.InvokeDeleteRequest( new DeleteRequestEventArgs( state, index ) ); } public static void ResourceQuery( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { } } public static void GameCentralMoniter( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { int type = pvSrc.ReadByte(); int num1 = pvSrc.ReadInt32(); Console.WriteLine( "God Client: {0}: Game central moniter", state ); Console.WriteLine( " - Type: {0}", type ); Console.WriteLine( " - Number: {0}", num1 ); pvSrc.Trace( state ); } } public static void GodviewQuery( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { Console.WriteLine( "God Client: {0}: Godview query 0x{1:X}", state, pvSrc.ReadByte() ); } } public static void GMSingle( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) pvSrc.Trace( state ); } public static void DeathStatusResponse( NetState state, PacketReader pvSrc ) { // Ignored } public static void ObjectHelpRequest( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; Serial serial = pvSrc.ReadInt32(); int unk = pvSrc.ReadByte(); string lang = pvSrc.ReadString( 3 ); if ( serial.IsItem ) { Item item = World.FindItem( serial ); if ( item != null && from.Map == item.Map && Utility.InUpdateRange( item.GetWorldLocation(), from.Location ) && from.CanSee( item ) ) item.OnHelpRequest( from ); } else if ( serial.IsMobile ) { Mobile m = World.FindMobile( serial ); if ( m != null && from.Map == m.Map && Utility.InUpdateRange( m.Location, from.Location ) && from.CanSee( m ) ) m.OnHelpRequest( m ); } } public static void MobileNameRequest( NetState state, PacketReader pvSrc ) { Mobile m = World.FindMobile( pvSrc.ReadInt32() ); if ( m != null && Utility.InUpdateRange( state.Mobile, m ) && state.Mobile.CanSee( m ) ) state.Send( new MobileName( m ) ); } public static void RequestScrollWindow( NetState state, PacketReader pvSrc ) { int lastTip = pvSrc.ReadInt16(); int type = pvSrc.ReadByte(); } public static void AttackReq( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; Mobile m = World.FindMobile( pvSrc.ReadInt32() ); if ( m != null ) from.Attack( m ); } public static void HuePickerResponse( NetState state, PacketReader pvSrc ) { int serial = pvSrc.ReadInt32(); int value = pvSrc.ReadInt16(); int hue = pvSrc.ReadInt16() & 0x3FFF; hue = Utility.ClipDyedHue( hue ); foreach ( HuePicker huePicker in state.HuePickers ) { if ( huePicker.Serial == serial ) { state.RemoveHuePicker( huePicker ); huePicker.OnResponse( hue ); break; } } } public static void TripTime( NetState state, PacketReader pvSrc ) { int unk1 = pvSrc.ReadByte(); int unk2 = pvSrc.ReadInt32(); state.Send( new TripTimeResponse( unk1 ) ); } public static void UTripTime( NetState state, PacketReader pvSrc ) { int unk1 = pvSrc.ReadByte(); int unk2 = pvSrc.ReadInt32(); state.Send( new UTripTimeResponse( unk1 ) ); } public static void ChangeZ( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int z = pvSrc.ReadSByte(); Console.WriteLine( "God Client: {0}: Change Z ({1}, {2}, {3})", state, x, y, z ); } } public static void SystemInfo( NetState state, PacketReader pvSrc ) { int v1 = pvSrc.ReadByte(); int v2 = pvSrc.ReadUInt16(); int v3 = pvSrc.ReadByte(); string s1 = pvSrc.ReadString( 32 ); string s2 = pvSrc.ReadString( 32 ); string s3 = pvSrc.ReadString( 32 ); string s4 = pvSrc.ReadString( 32 ); int v4 = pvSrc.ReadUInt16(); int v5 = pvSrc.ReadUInt16(); int v6 = pvSrc.ReadInt32(); int v7 = pvSrc.ReadInt32(); int v8 = pvSrc.ReadInt32(); } public static void Edit( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { int type = pvSrc.ReadByte(); // 10 = static, 7 = npc, 4 = dynamic int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int id = pvSrc.ReadInt16(); int z = pvSrc.ReadSByte(); int hue = pvSrc.ReadUInt16(); Console.WriteLine( "God Client: {0}: Edit {6} ({1}, {2}, {3}) 0x{4:X} (0x{5:X})", state, x, y, z, id, hue, type ); } } public static void DeleteStatic( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int z = pvSrc.ReadInt16(); int id = pvSrc.ReadUInt16(); Console.WriteLine( "God Client: {0}: Delete Static ({1}, {2}, {3}) 0x{4:X}", state, x, y, z, id ); } } public static void NewAnimData( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { Console.WriteLine( "God Client: {0}: New tile animation", state ); pvSrc.Trace( state ); } } public static void NewTerrain( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int id = pvSrc.ReadUInt16(); int width = pvSrc.ReadInt16(); int height = pvSrc.ReadInt16(); Console.WriteLine( "God Client: {0}: New Terrain ({1}, {2})+({3}, {4}) 0x{5:X4}", state, x, y, width, height, id ); } } public static void NewRegion( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { string name = pvSrc.ReadString( 40 ); int unk = pvSrc.ReadInt32(); int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int width = pvSrc.ReadInt16(); int height = pvSrc.ReadInt16(); int zStart = pvSrc.ReadInt16(); int zEnd = pvSrc.ReadInt16(); string desc = pvSrc.ReadString( 40 ); int soundFX = pvSrc.ReadInt16(); int music = pvSrc.ReadInt16(); int nightFX = pvSrc.ReadInt16(); int dungeon = pvSrc.ReadByte(); int light = pvSrc.ReadInt16(); Console.WriteLine( "God Client: {0}: New Region '{1}' ('{2}')", state, name, desc ); } } public static void AccountID( NetState state, PacketReader pvSrc ) { } public static bool VerifyGC( NetState state ) { if ( state.Mobile == null || state.Mobile.AccessLevel <= AccessLevel.Counselor ) { if ( state.Running ) Console.WriteLine( "Warning: {0}: Player using godclient, disconnecting", state ); state.Dispose(); return false; } else { return true; } } public static void TextCommand( NetState state, PacketReader pvSrc ) { int type = pvSrc.ReadByte(); string command = pvSrc.ReadString(); Mobile m = state.Mobile; switch ( type ) { case 0x00: // Go { if ( VerifyGC( state ) ) { try { string[] split = command.Split( ' ' ); int x = Utility.ToInt32( split[0] ); int y = Utility.ToInt32( split[1] ); int z; if ( split.Length >= 3 ) z = Utility.ToInt32( split[2] ); else if ( m.Map != null ) z = m.Map.GetAverageZ( x, y ); else z = 0; m.Location = new Point3D( x, y, z ); } catch { } } break; } case 0xC7: // Animate { EventSink.InvokeAnimateRequest( new AnimateRequestEventArgs( m, command ) ); break; } case 0x24: // Use skill { int skillIndex; if ( !int.TryParse( command.Split( ' ' )[0], out skillIndex ) ) break; Skills.UseSkill( m, skillIndex ); break; } case 0x43: // Open spellbook { int booktype; if ( !int.TryParse( command, out booktype ) ) booktype = 1; EventSink.InvokeOpenSpellbookRequest( new OpenSpellbookRequestEventArgs( m, booktype ) ); break; } case 0x27: // Cast spell from book { string[] split = command.Split( ' ' ); if ( split.Length > 0 ) { int spellID = Utility.ToInt32( split[0] ) - 1; int serial = split.Length > 1 ? Utility.ToInt32( split[1] ) : -1; EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( m, spellID, World.FindItem( serial ) ) ); } break; } case 0x58: // Open door { EventSink.InvokeOpenDoorMacroUsed( new OpenDoorMacroEventArgs( m ) ); break; } case 0x56: // Cast spell from macro { int spellID = Utility.ToInt32( command ) - 1; EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( m, spellID, null ) ); break; } default: { Console.WriteLine( "Client: {0}: Unknown text-command type 0x{1:X2}: {2}", state, type, command ); break; } } } public static void GodModeRequest( NetState state, PacketReader pvSrc ) { if ( VerifyGC( state ) ) { state.Send( new GodModeReply( pvSrc.ReadBoolean() ) ); } } public static void AsciiPromptResponse( NetState state, PacketReader pvSrc ) { int serial = pvSrc.ReadInt32(); int prompt = pvSrc.ReadInt32(); int type = pvSrc.ReadInt32(); string text = pvSrc.ReadStringSafe(); if ( text.Length > 128 ) return; Mobile from = state.Mobile; Prompt p = from.Prompt; if ( p != null && p.Serial == serial && p.Serial == prompt ) { from.Prompt = null; if ( type == 0 ) p.OnCancel( from ); else p.OnResponse( from, text ); } } public static void UnicodePromptResponse( NetState state, PacketReader pvSrc ) { int serial = pvSrc.ReadInt32(); int prompt = pvSrc.ReadInt32(); int type = pvSrc.ReadInt32(); string lang = pvSrc.ReadString( 4 ); string text = pvSrc.ReadUnicodeStringLESafe(); if ( text.Length > 128 ) return; Mobile from = state.Mobile; Prompt p = from.Prompt; if ( p != null && p.Serial == serial && p.Serial == prompt ) { from.Prompt = null; if ( type == 0 ) p.OnCancel( from ); else p.OnResponse( from, text ); } } public static void MenuResponse( NetState state, PacketReader pvSrc ) { int serial = pvSrc.ReadInt32(); int menuID = pvSrc.ReadInt16(); // unused in our implementation int index = pvSrc.ReadInt16(); int itemID = pvSrc.ReadInt16(); int hue = pvSrc.ReadInt16(); index -= 1; // convert from 1-based to 0-based foreach ( IMenu menu in state.Menus ) { if ( menu.Serial == serial ) { state.RemoveMenu( menu ); if ( index >= 0 && index < menu.EntryLength ) { menu.OnResponse( state, index ); } else { menu.OnCancel( state ); } break; } } } public static void ProfileReq( NetState state, PacketReader pvSrc ) { int type = pvSrc.ReadByte(); Serial serial = pvSrc.ReadInt32(); Mobile beholder = state.Mobile; Mobile beheld = World.FindMobile( serial ); if ( beheld == null ) return; switch ( type ) { case 0x00: // display request { EventSink.InvokeProfileRequest( new ProfileRequestEventArgs( beholder, beheld ) ); break; } case 0x01: // edit request { pvSrc.ReadInt16(); // Skip int length = pvSrc.ReadUInt16(); if ( length > 511 ) return; string text = pvSrc.ReadUnicodeString( length ); EventSink.InvokeChangeProfileRequest( new ChangeProfileRequestEventArgs( beholder, beheld, text ) ); break; } } } public static void Disconnect( NetState state, PacketReader pvSrc ) { int minusOne = pvSrc.ReadInt32(); } public static void LiftReq( NetState state, PacketReader pvSrc ) { Serial serial = pvSrc.ReadInt32(); int amount = pvSrc.ReadUInt16(); Item item = World.FindItem( serial ); bool rejected; LRReason reject; state.Mobile.Lift( item, amount, out rejected, out reject ); } public static void EquipReq( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; Item item = from.Holding; bool valid = ( item != null && item.HeldBy == from && item.Map == Map.Internal ); from.Holding = null; if ( !valid ) { return; } pvSrc.Seek( 5, SeekOrigin.Current ); Mobile to = World.FindMobile( pvSrc.ReadInt32() ); if ( to == null ) to = from; if ( !to.AllowEquipFrom( from ) || !to.EquipItem( item ) ) item.Bounce( from ); item.ClearBounce(); } public static void DropReq( NetState state, PacketReader pvSrc ) { pvSrc.ReadInt32(); // serial, ignored int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int z = pvSrc.ReadSByte(); Serial dest = pvSrc.ReadInt32(); Point3D loc = new Point3D( x, y, z ); Mobile from = state.Mobile; if ( dest.IsMobile ) from.Drop( World.FindMobile( dest ), loc ); else if ( dest.IsItem ) from.Drop( World.FindItem( dest ), loc ); else from.Drop( loc ); } public static void DropReq6017( NetState state, PacketReader pvSrc ) { pvSrc.ReadInt32(); // serial, ignored int x = pvSrc.ReadInt16(); int y = pvSrc.ReadInt16(); int z = pvSrc.ReadSByte(); pvSrc.ReadByte(); // Grid Location? Serial dest = pvSrc.ReadInt32(); Point3D loc = new Point3D( x, y, z ); Mobile from = state.Mobile; if ( dest.IsMobile ) from.Drop( World.FindMobile( dest ), loc ); else if ( dest.IsItem ) from.Drop( World.FindItem( dest ), loc ); else from.Drop( loc ); } public static void ConfigurationFile( NetState state, PacketReader pvSrc ) { } public static void LogoutReq( NetState state, PacketReader pvSrc ) { state.Send( new LogoutAck() ); } public static void ChangeSkillLock( NetState state, PacketReader pvSrc ) { Skill s = state.Mobile.Skills[pvSrc.ReadInt16()]; if ( s != null ) s.SetLockNoRelay( (SkillLock)pvSrc.ReadByte() ); } public static void HelpRequest( NetState state, PacketReader pvSrc ) { EventSink.InvokeHelpRequest( new HelpRequestEventArgs( state.Mobile ) ); } public static void TargetResponse( NetState state, PacketReader pvSrc ) { int type = pvSrc.ReadByte(); int targetID = pvSrc.ReadInt32(); int flags = pvSrc.ReadByte(); Serial serial = pvSrc.ReadInt32(); int x = pvSrc.ReadInt16(), y = pvSrc.ReadInt16(), z = pvSrc.ReadInt16(); int graphic = pvSrc.ReadUInt16(); if ( targetID == unchecked( (int) 0xDEADBEEF ) ) return; Mobile from = state.Mobile; Target t = from.Target; if ( t != null ) { TargetProfile prof = TargetProfile.Acquire( t.GetType() ); if ( prof != null ) { prof.Start(); } try { if ( x == -1 && y == -1 && !serial.IsValid ) { // User pressed escape t.Cancel( from, TargetCancelType.Canceled ); } else { object toTarget; if ( type == 1 ) { if ( graphic == 0 ) { toTarget = new LandTarget( new Point3D( x, y, z ), from.Map ); } else { Map map = from.Map; if ( map == null || map == Map.Internal ) { t.Cancel( from, TargetCancelType.Canceled ); return; } else { StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y, !t.DisallowMultis ); bool valid = false; if ( state.HighSeas ) { ItemData id = TileData.ItemTable[graphic&TileData.MaxItemValue]; if ( id.Surface ) { z -= id.Height; } } for ( int i = 0; !valid && i < tiles.Length; ++i ) { if ( tiles[i].Z == z && tiles[i].ID == graphic ) valid = true; } if ( !valid ) { t.Cancel( from, TargetCancelType.Canceled ); return; } else { toTarget = new StaticTarget( new Point3D( x, y, z ), graphic ); } } } } else if ( serial.IsMobile ) { toTarget = World.FindMobile( serial ); } else if ( serial.IsItem ) { toTarget = World.FindItem( serial ); } else { t.Cancel( from, TargetCancelType.Canceled ); return; } t.Invoke( from, toTarget ); } } finally { if ( prof != null ) { prof.Finish(); } } } } public static void DisplayGumpResponse( NetState state, PacketReader pvSrc ) { int serial = pvSrc.ReadInt32(); int typeID = pvSrc.ReadInt32(); int buttonID = pvSrc.ReadInt32(); foreach ( Gump gump in state.Gumps ) { if ( gump.Serial == serial && gump.TypeID == typeID ) { int switchCount = pvSrc.ReadInt32(); if ( switchCount < 0 || switchCount > gump.m_Switches ) { state.WriteConsole( "Invalid gump response, disconnecting..." ); state.Dispose(); return; } int[] switches = new int[switchCount]; for ( int j = 0; j < switches.Length; ++j ) switches[j] = pvSrc.ReadInt32(); int textCount = pvSrc.ReadInt32(); if ( textCount < 0 || textCount > gump.m_TextEntries ) { state.WriteConsole( "Invalid gump response, disconnecting..." ); state.Dispose(); return; } TextRelay[] textEntries = new TextRelay[textCount]; for ( int j = 0; j < textEntries.Length; ++j ) { int entryID = pvSrc.ReadUInt16(); int textLength = pvSrc.ReadUInt16(); if ( textLength > 239 ) { state.WriteConsole( "Invalid gump response, disconnecting..." ); state.Dispose(); return; } string text = pvSrc.ReadUnicodeStringSafe( textLength ); textEntries[j] = new TextRelay( entryID, text ); } state.RemoveGump( gump ); GumpProfile prof = GumpProfile.Acquire( gump.GetType() ); if ( prof != null ) { prof.Start(); } gump.OnResponse( state, new RelayInfo( buttonID, switches, textEntries ) ); if ( prof != null ) { prof.Finish(); } return; } } } public static void SetWarMode( NetState state, PacketReader pvSrc ) { state.Mobile.DelayChangeWarmode( pvSrc.ReadBoolean() ); } public static void Resynchronize( NetState state, PacketReader pvSrc ) { Mobile m = state.Mobile; if ( state.StygianAbyss ) { state.Send( new MobileUpdate( m ) ); state.Send( new MobileIncoming( m, m ) ); } else { state.Send( new MobileUpdateOld( m ) ); state.Send( new MobileIncomingOld( m, m ) ); } m.SendEverything(); state.Sequence = 0; m.ClearFastwalkStack(); } private static int[] m_EmptyInts = new int[0]; public static void AsciiSpeech( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; MessageType type = (MessageType)pvSrc.ReadByte(); int hue = pvSrc.ReadInt16(); pvSrc.ReadInt16(); // font string text = pvSrc.ReadStringSafe().Trim(); if ( text.Length <= 0 || text.Length > 128 ) return; if ( !Enum.IsDefined( typeof( MessageType ), type ) ) type = MessageType.Regular; from.DoSpeech( text, m_EmptyInts, type, Utility.ClipDyedHue( hue ) ); } private static KeywordList m_KeywordList = new KeywordList(); public static void UnicodeSpeech( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; MessageType type = (MessageType)pvSrc.ReadByte(); int hue = pvSrc.ReadInt16(); pvSrc.ReadInt16(); // font string lang = pvSrc.ReadString( 4 ); string text; bool isEncoded = (type & MessageType.Encoded) != 0; int[] keywords; if ( isEncoded ) { int value = pvSrc.ReadInt16(); int count = (value & 0xFFF0) >> 4; int hold = value & 0xF; if ( count < 0 || count > 50 ) return; KeywordList keyList = m_KeywordList; for ( int i = 0; i < count; ++i ) { int speechID; if ( (i & 1) == 0 ) { hold <<= 8; hold |= pvSrc.ReadByte(); speechID = hold; hold = 0; } else { value = pvSrc.ReadInt16(); speechID = (value & 0xFFF0) >> 4; hold = value & 0xF; } if ( !keyList.Contains( speechID ) ) keyList.Add( speechID ); } text = pvSrc.ReadUTF8StringSafe(); keywords = keyList.ToArray(); } else { text = pvSrc.ReadUnicodeStringSafe(); keywords = m_EmptyInts; } text = text.Trim(); if ( text.Length <= 0 || text.Length > 128 ) return; type &= ~MessageType.Encoded; if ( !Enum.IsDefined( typeof( MessageType ), type ) ) type = MessageType.Regular; from.Language = lang; from.DoSpeech( text, keywords, type, Utility.ClipDyedHue( hue ) ); } public static void UseReq( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; if ( from.AccessLevel >= AccessLevel.Counselor || DateTime.Now >= from.NextActionTime ) { int value = pvSrc.ReadInt32(); if ( (value & ~0x7FFFFFFF) != 0 ) { from.OnPaperdollRequest(); } else { Serial s = value; if ( s.IsMobile ) { Mobile m = World.FindMobile( s ); if ( m != null && !m.Deleted ) from.Use( m ); } else if ( s.IsItem ) { Item item = World.FindItem( s ); if ( item != null && !item.Deleted ) from.Use( item ); } } from.NextActionTime = DateTime.Now + TimeSpan.FromSeconds( 0.5 ); } else { from.SendActionMessage(); } } private static bool m_SingleClickProps; public static bool SingleClickProps { get{ return m_SingleClickProps; } set{ m_SingleClickProps = value; } } public static void LookReq( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; Serial s = pvSrc.ReadInt32(); if ( s.IsMobile ) { Mobile m = World.FindMobile( s ); if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) { if ( m_SingleClickProps ) { m.OnAosSingleClick( from ); } else { if ( from.Region.OnSingleClick( from, m ) ) m.OnSingleClick( from ); } } } else if ( s.IsItem ) { Item item = World.FindItem( s ); if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) { if ( m_SingleClickProps ) { item.OnAosSingleClick( from ); } else if ( from.Region.OnSingleClick( from, item ) ) { if ( item.Parent is Item ) ((Item)item.Parent).OnSingleClickContained( from, item ); item.OnSingleClick( from ); } } } } public static void PingReq( NetState state, PacketReader pvSrc ) { state.Send( PingAck.Instantiate( pvSrc.ReadByte() ) ); } public static void SetUpdateRange( NetState state, PacketReader pvSrc ) { state.Send( ChangeUpdateRange.Instantiate( 18 ) ); } private const int BadFood = unchecked( (int)0xBAADF00D ); private const int BadUOTD = unchecked( (int)0xFFCEFFCE ); public static void MovementReq( NetState state, PacketReader pvSrc ) { Direction dir = (Direction)pvSrc.ReadByte(); int seq = pvSrc.ReadByte(); int key = pvSrc.ReadInt32(); Mobile m = state.Mobile; if ( (state.Sequence == 0 && seq != 0) || !m.Move( dir ) ) { state.Send( new MovementRej( seq, m ) ); state.Sequence = 0; m.ClearFastwalkStack(); } else { ++seq; if ( seq == 256 ) seq = 1; state.Sequence = seq; } } public static int[] m_ValidAnimations = new int[] { 6, 21, 32, 33, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 127, 128 }; public static int[] ValidAnimations{ get{ return m_ValidAnimations; } set{ m_ValidAnimations = value; } } public static void Animate( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; int action = pvSrc.ReadInt32(); bool ok = false; for ( int i = 0; !ok && i < m_ValidAnimations.Length; ++i ) ok = ( action == m_ValidAnimations[i] ); if ( from != null && ok && from.Alive && from.Body.IsHuman && !from.Mounted ) from.Animate( action, 7, 1, true, false, 0 ); } public static void QuestArrow( NetState state, PacketReader pvSrc ) { bool rightClick = pvSrc.ReadBoolean(); Mobile from = state.Mobile; if ( from != null && from.QuestArrow != null ) from.QuestArrow.OnClick( rightClick ); } public static void ExtendedCommand( NetState state, PacketReader pvSrc ) { int packetID = pvSrc.ReadUInt16(); PacketHandler ph = GetExtendedHandler( packetID ); if ( ph != null ) { if ( ph.Ingame && state.Mobile == null ) { Console.WriteLine( "Client: {0}: Sent ingame packet (0xBFx{1:X2}) before having been attached to a mobile", state, packetID ); state.Dispose(); } else if ( ph.Ingame && state.Mobile.Deleted ) { state.Dispose(); } else { ph.OnReceive( state, pvSrc ); } } else { pvSrc.Trace( state ); } } public static void CastSpell( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; if ( from == null ) return; Item spellbook = null; if ( pvSrc.ReadInt16() == 1 ) spellbook = World.FindItem( pvSrc.ReadInt32() ); int spellID = pvSrc.ReadInt16() - 1; EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( from, spellID, spellbook ) ); } public static void BatchQueryProperties( NetState state, PacketReader pvSrc ) { if ( !ObjectPropertyList.Enabled ) return; Mobile from = state.Mobile; int length = pvSrc.Size-3; if ( length < 0 || (length%4) != 0 ) return; int count = length/4; for ( int i = 0; i < count; ++i ) { Serial s = pvSrc.ReadInt32(); if ( s.IsMobile ) { Mobile m = World.FindMobile( s ); if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) m.SendPropertiesTo( from ); } else if ( s.IsItem ) { Item item = World.FindItem( s ); if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) item.SendPropertiesTo( from ); } } } public static void QueryProperties( NetState state, PacketReader pvSrc ) { if ( !ObjectPropertyList.Enabled ) return; Mobile from = state.Mobile; Serial s = pvSrc.ReadInt32(); if ( s.IsMobile ) { Mobile m = World.FindMobile( s ); if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) m.SendPropertiesTo( from ); } else if ( s.IsItem ) { Item item = World.FindItem( s ); if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) item.SendPropertiesTo( from ); } } public static void PartyMessage( NetState state, PacketReader pvSrc ) { if ( state.Mobile == null ) return; switch ( pvSrc.ReadByte() ) { case 0x01: PartyMessage_AddMember( state, pvSrc ); break; case 0x02: PartyMessage_RemoveMember( state, pvSrc ); break; case 0x03: PartyMessage_PrivateMessage( state, pvSrc ); break; case 0x04: PartyMessage_PublicMessage( state, pvSrc ); break; case 0x06: PartyMessage_SetCanLoot( state, pvSrc ); break; case 0x08: PartyMessage_Accept( state, pvSrc ); break; case 0x09: PartyMessage_Decline( state, pvSrc ); break; default: pvSrc.Trace( state ); break; } } public static void PartyMessage_AddMember( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnAdd( state.Mobile ); } public static void PartyMessage_RemoveMember( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnRemove( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); } public static void PartyMessage_PrivateMessage( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnPrivateMessage( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ), pvSrc.ReadUnicodeStringSafe() ); } public static void PartyMessage_PublicMessage( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnPublicMessage( state.Mobile, pvSrc.ReadUnicodeStringSafe() ); } public static void PartyMessage_SetCanLoot( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnSetCanLoot( state.Mobile, pvSrc.ReadBoolean() ); } public static void PartyMessage_Accept( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnAccept( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); } public static void PartyMessage_Decline( NetState state, PacketReader pvSrc ) { if ( PartyCommands.Handler != null ) PartyCommands.Handler.OnDecline( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); } public static void StunRequest( NetState state, PacketReader pvSrc ) { EventSink.InvokeStunRequest( new StunRequestEventArgs( state.Mobile ) ); } public static void DisarmRequest( NetState state, PacketReader pvSrc ) { EventSink.InvokeDisarmRequest( new DisarmRequestEventArgs( state.Mobile ) ); } public static void StatLockChange( NetState state, PacketReader pvSrc ) { int stat = pvSrc.ReadByte(); int lockValue = pvSrc.ReadByte(); if ( lockValue > 2 ) lockValue = 0; Mobile m = state.Mobile; if ( m != null ) { switch ( stat ) { case 0: m.StrLock = (StatLockType)lockValue; break; case 1: m.DexLock = (StatLockType)lockValue; break; case 2: m.IntLock = (StatLockType)lockValue; break; } } } public static void ScreenSize( NetState state, PacketReader pvSrc ) { int width = pvSrc.ReadInt32(); int unk = pvSrc.ReadInt32(); } public static void ContextMenuResponse( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; if ( from != null ) { ContextMenu menu = from.ContextMenu; from.ContextMenu = null; if ( menu != null && from != null && from == menu.From ) { IEntity entity = World.FindEntity( pvSrc.ReadInt32() ); if ( entity != null && entity == menu.Target && from.CanSee( entity ) ) { Point3D p; if ( entity is Mobile ) p = entity.Location; else if ( entity is Item ) p = ((Item)entity).GetWorldLocation(); else return; int index = pvSrc.ReadUInt16(); if ( index >= 0 && index < menu.Entries.Length ) { ContextMenuEntry e = menu.Entries[index]; int range = e.Range; if ( range == -1 ) range = 18; if ( e.Enabled && from.InRange( p, range ) ) e.OnClick(); } } } } } public static void ContextMenuRequest( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; IEntity target = World.FindEntity( pvSrc.ReadInt32() ); if ( from != null && target != null && from.Map == target.Map && from.CanSee( target ) ) { if ( target is Mobile && !Utility.InUpdateRange( from.Location, target.Location ) ) return; else if ( target is Item && !Utility.InUpdateRange( from.Location, ((Item)target).GetWorldLocation() ) ) return; if ( !from.CheckContextMenuDisplay( target ) ) return; ContextMenu c = new ContextMenu( from, target ); if ( c.Entries.Length > 0 ) { if ( target is Item ) { object root = ((Item)target).RootParent; if ( root is Mobile && root != from && ((Mobile)root).AccessLevel >= from.AccessLevel ) { for ( int i = 0; i < c.Entries.Length; ++i ) { if ( !c.Entries[i].NonLocalUse ) c.Entries[i].Enabled = false; } } } from.ContextMenu = c; } } } public static void CloseStatus( NetState state, PacketReader pvSrc ) { Serial serial = pvSrc.ReadInt32(); } public static void Language( NetState state, PacketReader pvSrc ) { string lang = pvSrc.ReadString( 4 ); if ( state.Mobile != null ) state.Mobile.Language = lang; } public static void AssistVersion( NetState state, PacketReader pvSrc ) { int unk = pvSrc.ReadInt32(); string av = pvSrc.ReadString(); } public static void ClientVersion( NetState state, PacketReader pvSrc ) { CV version = state.Version = new CV( pvSrc.ReadString() ); EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) ); } public static void ClientType( NetState state, PacketReader pvSrc ) { pvSrc.ReadUInt16(); int type = pvSrc.ReadUInt16(); CV version = state.Version = new CV( pvSrc.ReadString() ); //EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) );//todo } public static void MobileQuery( NetState state, PacketReader pvSrc ) { Mobile from = state.Mobile; pvSrc.ReadInt32(); // 0xEDEDEDED int type = pvSrc.ReadByte(); Mobile m = World.FindMobile( pvSrc.ReadInt32() ); if ( m != null ) { switch ( type ) { case 0x00: // Unknown, sent by godclient { if ( VerifyGC( state ) ) Console.WriteLine( "God Client: {0}: Query 0x{1:X2} on {2} '{3}'", state, type, m.Serial, m.Name ); break; } case 0x04: // Stats { m.OnStatsQuery( from ); break; } case 0x05: { m.OnSkillsQuery( from ); break; } default: { pvSrc.Trace( state ); break; } } } } private class LoginTimer : Timer { private NetState m_State; private Mobile m_Mobile; public LoginTimer( NetState state, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) { m_State = state; m_Mobile = m; } protected override void OnTick() { if ( m_State == null ) Stop(); if ( m_State.Version != null ) { m_State.BlockAllPackets = false; DoLogin( m_State, m_Mobile ); Stop(); } } } public static void PlayCharacter( NetState state, PacketReader pvSrc ) { pvSrc.ReadInt32(); // 0xEDEDEDED string name = pvSrc.ReadString( 30 ); pvSrc.Seek( 2, SeekOrigin.Current ); int flags = pvSrc.ReadInt32(); pvSrc.Seek( 24, SeekOrigin.Current ); int charSlot = pvSrc.ReadInt32(); int clientIP = pvSrc.ReadInt32(); IAccount a = state.Account; if ( a == null || charSlot < 0 || charSlot >= a.Length ) { state.Dispose(); } else { Mobile m = a[charSlot]; // Check if anyone is using this account for ( int i = 0; i < a.Length; ++i ) { Mobile check = a[i]; if ( check != null && check.Map != Map.Internal && check != m ) { Console.WriteLine( "Login: {0}: Account in use", state ); state.Send( new PopupMessage( PMMessage.CharInWorld ) ); return; } } if ( m == null ) { state.Dispose(); } else { if ( m.NetState != null ) m.NetState.Dispose(); NetState.ProcessDisposedQueue(); state.Send( new ClientVersionReq() ); state.BlockAllPackets = true; state.Flags = (ClientFlags)flags; state.Mobile = m; m.NetState = state; new LoginTimer( state, m ).Start(); } } } public static void DoLogin( NetState state, Mobile m ) { state.Send( new LoginConfirm( m ) ); if ( m.Map != null ) state.Send( new MapChange( m ) ); state.Send( new MapPatches() ); state.Send( SeasonChange.Instantiate( m.GetSeason(), true ) ); state.Send( SupportedFeatures.Instantiate( state ) ); state.Sequence = 0; if ( state.StygianAbyss ) { state.Send( new MobileUpdate( m ) ); state.Send( new MobileUpdate( m ) ); m.CheckLightLevels( true ); state.Send( new MobileUpdate( m ) ); state.Send( new MobileIncoming( m, m ) ); //state.Send( new MobileAttributes( m ) ); state.Send( new MobileStatus( m, m ) ); state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); m.SendEverything(); state.Send( SupportedFeatures.Instantiate( state ) ); state.Send( new MobileUpdate( m ) ); //state.Send( new MobileAttributes( m ) ); state.Send( new MobileStatus( m, m ) ); state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); state.Send( new MobileIncoming( m, m ) ); } else { state.Send( new MobileUpdateOld( m ) ); state.Send( new MobileUpdateOld( m ) ); m.CheckLightLevels( true ); state.Send( new MobileUpdateOld( m ) ); state.Send( new MobileIncomingOld( m, m ) ); //state.Send( new MobileAttributes( m ) ); state.Send( new MobileStatus( m, m ) ); state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); m.SendEverything(); state.Send( SupportedFeatures.Instantiate( state ) ); state.Send( new MobileUpdateOld( m ) ); //state.Send( new MobileAttributes( m ) ); state.Send( new MobileStatus( m, m ) ); state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); state.Send( new MobileIncomingOld( m, m ) ); } state.Send( LoginComplete.Instance ); state.Send( new CurrentTime() ); state.Send( SeasonChange.Instantiate( m.GetSeason(), true ) ); state.Send( new MapChange( m ) ); EventSink.InvokeLogin( new LoginEventArgs( m ) ); m.ClearFastwalkStack(); } public static void CreateCharacter( NetState state, PacketReader pvSrc ) { int unk1 = pvSrc.ReadInt32(); int unk2 = pvSrc.ReadInt32(); int unk3 = pvSrc.ReadByte(); string name = pvSrc.ReadString( 30 ); pvSrc.Seek( 2, SeekOrigin.Current ); int flags = pvSrc.ReadInt32(); pvSrc.Seek( 8, SeekOrigin.Current ); int prof = pvSrc.ReadByte(); pvSrc.Seek( 15, SeekOrigin.Current ); //bool female = pvSrc.ReadBoolean(); int genderRace = pvSrc.ReadByte(); int str = pvSrc.ReadByte(); int dex = pvSrc.ReadByte(); int intl= pvSrc.ReadByte(); int is1 = pvSrc.ReadByte(); int vs1 = pvSrc.ReadByte(); int is2 = pvSrc.ReadByte(); int vs2 = pvSrc.ReadByte(); int is3 = pvSrc.ReadByte(); int vs3 = pvSrc.ReadByte(); int hue = pvSrc.ReadUInt16(); int hairVal = pvSrc.ReadInt16(); int hairHue = pvSrc.ReadInt16(); int hairValf= pvSrc.ReadInt16(); int hairHuef= pvSrc.ReadInt16(); pvSrc.ReadByte(); int cityIndex = pvSrc.ReadByte(); int charSlot = pvSrc.ReadInt32(); int clientIP = pvSrc.ReadInt32(); int shirtHue = pvSrc.ReadInt16(); int pantsHue = pvSrc.ReadInt16(); /* Pre-7.0.0.0: 0x00, 0x01 -> Human Male, Human Female 0x02, 0x03 -> Orc Male, Orc Female Post-7.0.0.0: 0x00, 0x01 0x02, 0x03 -> Human Male, Human Female 0x04, 0x05 -> Orc Male, Orc Female */ bool female = ((genderRace % 2) != 0); Race race = null; if ( state.StygianAbyss ) { byte raceID = (byte)(genderRace < 4 ? 0 : ((genderRace / 2) - 1)); race = Race.Races[raceID]; } else { race = Race.Races[(byte)(genderRace / 2)]; } if( race == null ) race = Race.DefaultRace; CityInfo[] info = state.CityInfo; IAccount a = state.Account; if ( info == null || a == null || cityIndex < 0 || cityIndex >= info.Length ) { state.Dispose(); } else { // Check if anyone is using this account for ( int i = 0; i < a.Length; ++i ) { Mobile check = a[i]; if ( check != null && check.Map != Map.Internal ) { Console.WriteLine( "Login: {0}: Account in use", state ); state.Send( new PopupMessage( PMMessage.CharInWorld ) ); return; } } state.Flags = (ClientFlags)flags; CharacterCreatedEventArgs args = new CharacterCreatedEventArgs( state, a, name, female, hue, str, dex, intl, info[cityIndex], new SkillNameValue[3] { new SkillNameValue( (SkillName)is1, vs1 ), new SkillNameValue( (SkillName)is2, vs2 ), new SkillNameValue( (SkillName)is3, vs3 ), }, shirtHue, pantsHue, hairVal, hairHue, hairValf, hairHuef, prof, race ); state.Send( new ClientVersionReq() ); state.BlockAllPackets = true; EventSink.InvokeCharacterCreated( args ); Mobile m = args.Mobile; if ( m != null ) { state.Mobile = m; m.NetState = state; new LoginTimer( state, m ).Start(); } else { state.BlockAllPackets = false; state.Dispose(); } } } public static void CreateCharacter70160( NetState state, PacketReader pvSrc ) { int unk1 = pvSrc.ReadInt32(); int unk2 = pvSrc.ReadInt32(); int unk3 = pvSrc.ReadByte(); string name = pvSrc.ReadString( 30 ); pvSrc.Seek( 2, SeekOrigin.Current ); int flags = pvSrc.ReadInt32(); pvSrc.Seek( 8, SeekOrigin.Current ); int prof = pvSrc.ReadByte(); pvSrc.Seek( 15, SeekOrigin.Current ); int genderRace = pvSrc.ReadByte(); int str = pvSrc.ReadByte(); int dex = pvSrc.ReadByte(); int intl= pvSrc.ReadByte(); int is1 = pvSrc.ReadByte(); int vs1 = pvSrc.ReadByte(); int is2 = pvSrc.ReadByte(); int vs2 = pvSrc.ReadByte(); int is3 = pvSrc.ReadByte(); int vs3 = pvSrc.ReadByte(); int is4 = pvSrc.ReadByte(); int vs4 = pvSrc.ReadByte(); int hue = pvSrc.ReadUInt16(); int hairVal = pvSrc.ReadInt16(); int hairHue = pvSrc.ReadInt16(); int hairValf= pvSrc.ReadInt16(); int hairHuef= pvSrc.ReadInt16(); pvSrc.ReadByte(); int cityIndex = pvSrc.ReadByte(); int charSlot = pvSrc.ReadInt32(); int clientIP = pvSrc.ReadInt32(); int shirtHue = pvSrc.ReadInt16(); int pantsHue = pvSrc.ReadInt16(); /* 0x00, 0x01 0x02, 0x03 -> Human Male, Human Female 0x04, 0x05 -> Orc Male, Orc Female */ bool female = ((genderRace % 2) != 0); Race race = null; byte raceID = (byte)(genderRace < 4 ? 0 : ((genderRace / 2) - 1)); race = Race.Races[raceID]; if( race == null ) race = Race.DefaultRace; CityInfo[] info = state.CityInfo; IAccount a = state.Account; if ( info == null || a == null || cityIndex < 0 || cityIndex >= info.Length ) { state.Dispose(); } else { // Check if anyone is using this account for ( int i = 0; i < a.Length; ++i ) { Mobile check = a[i]; if ( check != null && check.Map != Map.Internal ) { Console.WriteLine( "Login: {0}: Account in use", state ); state.Send( new PopupMessage( PMMessage.CharInWorld ) ); return; } } state.Flags = (ClientFlags)flags; CharacterCreatedEventArgs args = new CharacterCreatedEventArgs( state, a, name, female, hue, str, dex, intl, info[cityIndex], new SkillNameValue[4] { new SkillNameValue( (SkillName)is1, vs1 ), new SkillNameValue( (SkillName)is2, vs2 ), new SkillNameValue( (SkillName)is3, vs3 ), new SkillNameValue( (SkillName)is4, vs4 ), }, shirtHue, pantsHue, hairVal, hairHue, hairValf, hairHuef, prof, race ); state.Send( new ClientVersionReq() ); state.BlockAllPackets = true; EventSink.InvokeCharacterCreated( args ); Mobile m = args.Mobile; if ( m != null ) { state.Mobile = m; m.NetState = state; new LoginTimer( state, m ).Start(); } else { state.BlockAllPackets = false; state.Dispose(); } } } private static bool m_ClientVerification = true; public static bool ClientVerification { get{ return m_ClientVerification; } set{ m_ClientVerification = value; } } internal struct AuthIDPersistence { public DateTime Age; public ClientVersion Version; public AuthIDPersistence( ClientVersion v ) { Age = DateTime.Now; Version = v; } } private const int m_AuthIDWindowSize = 128; private static Dictionary m_AuthIDWindow = new Dictionary( m_AuthIDWindowSize ); private static int GenerateAuthID( NetState state ) { if ( m_AuthIDWindow.Count == m_AuthIDWindowSize ) { int oldestID = 0; DateTime oldest = DateTime.MaxValue; foreach ( KeyValuePair kvp in m_AuthIDWindow ) { if ( kvp.Value.Age < oldest ) { oldestID = kvp.Key; oldest = kvp.Value.Age; } } m_AuthIDWindow.Remove( oldestID ); } int authID; do { authID = Utility.Random( 1, int.MaxValue - 1 ); if ( Utility.RandomBool() ) authID |= 1<<31; } while ( m_AuthIDWindow.ContainsKey( authID ) ); m_AuthIDWindow[authID] = new AuthIDPersistence( state.Version ); return authID; } public static void GameLogin( NetState state, PacketReader pvSrc ) { if ( state.SentFirstPacket ) { state.Dispose(); return; } state.SentFirstPacket = true; int authID = pvSrc.ReadInt32(); if ( m_AuthIDWindow.ContainsKey( authID ) ) { AuthIDPersistence ap = m_AuthIDWindow[authID]; m_AuthIDWindow.Remove( authID ); state.Version = ap.Version; } else if ( m_ClientVerification ) { Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); state.Dispose(); return; } if ( state.m_AuthID != 0 && authID != state.m_AuthID ) { Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); state.Dispose(); return; } else if ( state.m_AuthID == 0 && authID != state.m_Seed ) { Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); state.Dispose(); return; } string username = pvSrc.ReadString( 30 ); string password = pvSrc.ReadString( 30 ); GameLoginEventArgs e = new GameLoginEventArgs( state, username, password ); EventSink.InvokeGameLogin( e ); if ( e.Accepted ) { state.CityInfo = e.CityInfo; state.CompressionEnabled = true; state.Send( SupportedFeatures.Instantiate( state ) ); if ( state.NewCharacterList ) { state.Send( new CharacterList( state.Account, state.CityInfo ) ); } else { state.Send( new CharacterListOld( state.Account, state.CityInfo ) ); } } else { state.Dispose(); } } public static void PlayServer( NetState state, PacketReader pvSrc ) { int index = pvSrc.ReadInt16(); ServerInfo[] info = state.ServerInfo; IAccount a = state.Account; if ( info == null || a == null || index < 0 || index >= info.Length ) { state.Dispose(); } else { ServerInfo si = info[index]; state.m_AuthID = PlayServerAck.m_AuthID = GenerateAuthID( state ); state.SentFirstPacket = false; state.Send( new PlayServerAck( si ) ); } } public static void LoginServerSeed( NetState state, PacketReader pvSrc ) { state.m_Seed = pvSrc.ReadInt32(); state.Seeded = true; if ( state.m_Seed == 0 ) { Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", state); state.Dispose(); return; } int clientMaj = pvSrc.ReadInt32(); int clientMin = pvSrc.ReadInt32(); int clientRev = pvSrc.ReadInt32(); int clientPat = pvSrc.ReadInt32(); state.Version = new ClientVersion( clientMaj, clientMin, clientRev, clientPat ); } public static void AccountLogin( NetState state, PacketReader pvSrc ) { if ( state.SentFirstPacket ) { state.Dispose(); return; } state.SentFirstPacket = true; string username = pvSrc.ReadString( 30 ); string password = pvSrc.ReadString( 30 ); AccountLoginEventArgs e = new AccountLoginEventArgs( state, username, password ); EventSink.InvokeAccountLogin( e ); if ( e.Accepted ) AccountLogin_ReplyAck( state ); else AccountLogin_ReplyRej( state, e.RejectReason ); } public static void AccountLogin_ReplyAck( NetState state ) { ServerListEventArgs e = new ServerListEventArgs( state, state.Account ); EventSink.InvokeServerList( e ); if ( e.Rejected ) { state.Account = null; state.Send( new AccountLoginRej( ALRReason.BadComm ) ); state.Dispose(); } else { ServerInfo[] info = e.Servers.ToArray(); state.ServerInfo = info; state.Send( new AccountLoginAck( info ) ); } } public static void AccountLogin_ReplyRej( NetState state, ALRReason reason ) { state.Send( new AccountLoginRej( reason ) ); state.Dispose(); } } }