2464 lines
No EOL
66 KiB
C#
2464 lines
No EOL
66 KiB
C#
/***************************************************************************
|
|
* 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<int, PacketHandler> m_ExtendedHandlersHigh;
|
|
|
|
private static EncodedPacketHandler[] m_EncodedHandlersLow;
|
|
private static Dictionary<int, EncodedPacketHandler> 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<int, PacketHandler>();
|
|
|
|
m_EncodedHandlersLow = new EncodedPacketHandler[0x100];
|
|
m_EncodedHandlersHigh = new Dictionary<int, EncodedPacketHandler>();
|
|
|
|
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<BuyItemResponse> buyList = new List<BuyItemResponse>( 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<SellItemResponse> sellList = new List<SellItemResponse>( count );
|
|
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
Item item = World.FindItem( pvSrc.ReadInt32() );
|
|
int Amount = pvSrc.ReadInt16();
|
|
|
|
if ( item != null && Amount > 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<int, AuthIDPersistence> m_AuthIDWindow = new Dictionary<int, AuthIDPersistence>( m_AuthIDWindowSize );
|
|
|
|
private static int GenerateAuthID( NetState state )
|
|
{
|
|
if ( m_AuthIDWindow.Count == m_AuthIDWindowSize ) {
|
|
int oldestID = 0;
|
|
DateTime oldest = DateTime.MaxValue;
|
|
|
|
foreach ( KeyValuePair<int, AuthIDPersistence> 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();
|
|
}
|
|
}
|
|
} |