fix: Moves accounting, entity, 0xBF, and house packets to UOContent project (#1337)
This commit is contained in:
parent
3cf6db73f0
commit
a8d8db8f59
5 changed files with 24 additions and 22 deletions
|
|
@ -48,7 +48,7 @@ public partial class NetState : IComparable<NetState>
|
|||
private const int MenuCap = 512;
|
||||
private const int PacketPerSecondThreshold = 3000;
|
||||
|
||||
private static GCHandle[] _polledStates = new GCHandle[2048];
|
||||
private static readonly GCHandle[] _polledStates = new GCHandle[2048];
|
||||
private static readonly IPollGroup _pollGroup = PollGroup.Create();
|
||||
private static readonly Queue<NetState> _flushPending = new(2048);
|
||||
private static readonly Queue<NetState> _flushedPartials = new(256);
|
||||
|
|
@ -67,8 +67,6 @@ public partial class NetState : IComparable<NetState>
|
|||
private readonly long[] _packetCounts = new long[0x100];
|
||||
private string _disconnectReason = string.Empty;
|
||||
|
||||
internal int _authId;
|
||||
internal int _seed;
|
||||
internal ParserState _parserState = ParserState.AwaitingNextPacket;
|
||||
internal ProtocolState _protocolState = ProtocolState.AwaitingSeed;
|
||||
internal GCHandle _handle;
|
||||
|
|
@ -166,6 +164,10 @@ public partial class NetState : IComparable<NetState>
|
|||
}
|
||||
}
|
||||
|
||||
public int AuthId { get; set; }
|
||||
|
||||
public int Seed { get; set; }
|
||||
|
||||
public DateTime ConnectedOn { get; }
|
||||
|
||||
public TimeSpan ConnectedFor => Core.Now - ConnectedOn;
|
||||
|
|
@ -611,15 +613,15 @@ public partial class NetState : IComparable<NetState>
|
|||
}
|
||||
else if (length >= 4)
|
||||
{
|
||||
int seed = (packetId << 24) | (packetReader.ReadByte() << 16) | (packetReader.ReadByte() << 8) | packetReader.ReadByte();
|
||||
int newSeed = (packetId << 24) | (packetReader.ReadByte() << 16) | (packetReader.ReadByte() << 8) | packetReader.ReadByte();
|
||||
|
||||
if (seed == 0)
|
||||
if (newSeed == 0)
|
||||
{
|
||||
HandleError(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_seed = seed;
|
||||
Seed = newSeed;
|
||||
packetLength = 4;
|
||||
|
||||
_parserState = ParserState.AwaitingNextPacket;
|
||||
|
|
|
|||
|
|
@ -1,528 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2022 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: IncomingAccountPackets.cs *
|
||||
* *
|
||||
* 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 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using CV = Server.ClientVersion;
|
||||
|
||||
namespace Server.Network;
|
||||
|
||||
public static class IncomingAccountPackets
|
||||
{
|
||||
private const int m_AuthIDWindowSize = 128;
|
||||
private static readonly Dictionary<int, AuthIDPersistence> m_AuthIDWindow =
|
||||
new(m_AuthIDWindowSize);
|
||||
|
||||
internal struct AuthIDPersistence
|
||||
{
|
||||
public DateTime Age;
|
||||
public readonly ClientVersion Version;
|
||||
|
||||
public AuthIDPersistence(ClientVersion v)
|
||||
{
|
||||
Age = Core.Now;
|
||||
Version = v;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void Configure()
|
||||
{
|
||||
IncomingPackets.Register(0x00, 104, false, &CreateCharacter);
|
||||
IncomingPackets.Register(0x5D, 73, false, &PlayCharacter);
|
||||
IncomingPackets.Register(0x80, 62, false, &AccountLogin);
|
||||
IncomingPackets.Register(0x83, 39, false, &DeleteCharacter);
|
||||
IncomingPackets.Register(0x91, 65, false, &GameLogin);
|
||||
IncomingPackets.Register(0xA0, 3, false, &PlayServer);
|
||||
IncomingPackets.Register(0xBB, 9, false, &AccountID);
|
||||
IncomingPackets.Register(0xBD, 0, false, &ClientVersion);
|
||||
IncomingPackets.Register(0xCF, 0, false, &AccountLogin);
|
||||
IncomingPackets.Register(0xE1, 0, false, &ClientType);
|
||||
IncomingPackets.Register(0xEF, 21, false, &LoginServerSeed);
|
||||
IncomingPackets.Register(0xF8, 106, false, &CreateCharacter);
|
||||
}
|
||||
|
||||
public static void CreateCharacter(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
reader.Seek(9, SeekOrigin.Current);
|
||||
/*
|
||||
var unk1 = reader.ReadInt32();
|
||||
var unk2 = reader.ReadInt32();
|
||||
int unk3 = reader.ReadByte();
|
||||
*/
|
||||
var name = reader.ReadAscii(30);
|
||||
|
||||
reader.Seek(2, SeekOrigin.Current);
|
||||
var flags = reader.ReadInt32();
|
||||
reader.Seek(8, SeekOrigin.Current);
|
||||
int prof = reader.ReadByte();
|
||||
reader.Seek(15, SeekOrigin.Current);
|
||||
|
||||
var genderRace = reader.ReadByte();
|
||||
|
||||
var stats = new StatNameValue[]
|
||||
{
|
||||
new(StatType.Str, reader.ReadByte()),
|
||||
new(StatType.Dex, reader.ReadByte()),
|
||||
new(StatType.Int, reader.ReadByte())
|
||||
};
|
||||
|
||||
var skills = new SkillNameValue[state.NewCharacterCreation ? 4 : 3];
|
||||
skills[0] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte());
|
||||
skills[1] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte());
|
||||
skills[2] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte());
|
||||
if (state.NewCharacterCreation)
|
||||
{
|
||||
skills[3] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte());
|
||||
}
|
||||
|
||||
int hue = reader.ReadUInt16();
|
||||
int hairVal = reader.ReadInt16();
|
||||
int hairHue = reader.ReadInt16();
|
||||
int hairValf = reader.ReadInt16();
|
||||
int hairHuef = reader.ReadInt16();
|
||||
reader.ReadByte();
|
||||
int cityIndex = reader.ReadByte();
|
||||
reader.Seek(8, SeekOrigin.Current);
|
||||
/*
|
||||
var charSlot = reader.ReadInt32();
|
||||
var clientIP = reader.ReadInt32();
|
||||
*/
|
||||
int shirtHue = reader.ReadInt16();
|
||||
int pantsHue = reader.ReadInt16();
|
||||
|
||||
/*
|
||||
Pre-7.0.0.0:
|
||||
0x00, 0x01 -> Human Male, Human Female
|
||||
0x02, 0x03 -> Elf Male, Elf Female
|
||||
|
||||
Post-7.0.0.0:
|
||||
0x00, 0x01
|
||||
0x02, 0x03 -> Human Male, Human Female
|
||||
0x04, 0x05 -> Elf Male, Elf Female
|
||||
0x05, 0x06 -> Gargoyle Male, Gargoyle Female
|
||||
*/
|
||||
|
||||
var female = genderRace % 2 != 0;
|
||||
|
||||
var raceID = state.StygianAbyss ? (byte)(genderRace < 4 ? 0 : genderRace / 2 - 1) : (byte)(genderRace / 2);
|
||||
Race race = Race.Races[raceID] ?? Race.DefaultRace;
|
||||
|
||||
var info = state.CityInfo;
|
||||
var a = state.Account;
|
||||
|
||||
if (info == null || a == null || cityIndex >= info.Length)
|
||||
{
|
||||
state.Disconnect("Invalid city selected during character creation.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if anyone is using this account
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
var check = a[i];
|
||||
|
||||
if (check != null && check.Map != Map.Internal)
|
||||
{
|
||||
state.LogInfo("Account in use");
|
||||
state.SendPopupMessage(PMMessage.CharInWorld);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
state.Flags = (ClientFlags)flags;
|
||||
|
||||
var args = new CharacterCreatedEventArgs(
|
||||
state,
|
||||
a,
|
||||
name,
|
||||
female,
|
||||
hue,
|
||||
stats,
|
||||
info[cityIndex],
|
||||
skills,
|
||||
shirtHue,
|
||||
pantsHue,
|
||||
hairVal,
|
||||
hairHue,
|
||||
hairValf,
|
||||
hairHuef,
|
||||
prof,
|
||||
race
|
||||
);
|
||||
|
||||
state.SendClientVersionRequest();
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
EventSink.InvokeCharacterCreated(args);
|
||||
|
||||
var m = args.Mobile;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
state.Mobile = m;
|
||||
m.NetState = state;
|
||||
new LoginTimer(state, m).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.BlockAllPackets = false;
|
||||
state.Disconnect("Character creation blocked.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteCharacter(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
reader.Seek(30, SeekOrigin.Current);
|
||||
var index = reader.ReadInt32();
|
||||
|
||||
EventSink.InvokeDeleteRequest(state, index);
|
||||
}
|
||||
|
||||
public static void AccountID(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
}
|
||||
|
||||
public static void ClientVersion(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var version = state.Version = new CV(reader.ReadAscii());
|
||||
|
||||
EventSink.InvokeClientVersionReceived(state, version);
|
||||
}
|
||||
|
||||
public static void ClientType(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
reader.ReadUInt16();
|
||||
|
||||
int type = reader.ReadUInt16();
|
||||
var version = state.Version = new CV(reader.ReadAscii());
|
||||
|
||||
EventSink.InvokeClientVersionReceived(state, version);
|
||||
}
|
||||
|
||||
public static void PlayCharacter(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
reader.Seek(36, SeekOrigin.Current); // 4 = 0xEDEDEDED, 30 = Name, 2 = unknown
|
||||
var flags = reader.ReadInt32();
|
||||
reader.Seek(24, SeekOrigin.Current);
|
||||
var charSlot = reader.ReadInt32();
|
||||
reader.Seek(4, SeekOrigin.Current); // var clientIP = reader.ReadInt32();
|
||||
|
||||
var a = state.Account;
|
||||
|
||||
if (a == null || charSlot < 0 || charSlot >= a.Length)
|
||||
{
|
||||
state.Disconnect("Invalid character slot selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
var m = a[charSlot];
|
||||
|
||||
// Check if anyone is using this account
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
var check = a[i];
|
||||
|
||||
if (check != null && check.Map != Map.Internal && check != m)
|
||||
{
|
||||
state.LogInfo("Account in use");
|
||||
state.SendPopupMessage(PMMessage.CharInWorld);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
state.Disconnect("Empty character slot selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
m.NetState?.Disconnect("Character selected for a player already logged in.");
|
||||
|
||||
state.SendClientVersionRequest();
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
state.Flags = (ClientFlags)flags;
|
||||
|
||||
state.Mobile = m;
|
||||
m.NetState = state;
|
||||
|
||||
new LoginTimer(state, m).Start();
|
||||
}
|
||||
|
||||
public static void DoLogin(this NetState state, Mobile m)
|
||||
{
|
||||
state.SendLoginConfirmation(m);
|
||||
|
||||
state.SendMapChange(m.Map);
|
||||
|
||||
state.SendMapPatches();
|
||||
|
||||
state.SendSeasonChange((byte)m.GetSeason(), true);
|
||||
|
||||
state.SendSupportedFeature();
|
||||
|
||||
state.Sequence = 0;
|
||||
|
||||
state.SendMobileUpdate(m);
|
||||
state.SendMobileUpdate(m);
|
||||
|
||||
m.CheckLightLevels(true);
|
||||
|
||||
state.SendMobileUpdate(m);
|
||||
|
||||
state.SendMobileIncoming(m, m);
|
||||
|
||||
state.SendMobileStatus(m);
|
||||
state.SendSetWarMode(m.Warmode);
|
||||
|
||||
m.SendEverything();
|
||||
|
||||
state.SendSupportedFeature();
|
||||
state.SendMobileUpdate(m);
|
||||
|
||||
state.SendMobileStatus(m);
|
||||
state.SendSetWarMode(m.Warmode);
|
||||
state.SendMobileIncoming(m, m);
|
||||
|
||||
state.SendLoginComplete();
|
||||
state.SendCurrentTime();
|
||||
state.SendSeasonChange((byte)m.GetSeason(), true);
|
||||
state.SendMapChange(m.Map);
|
||||
|
||||
state.SendPlayMusic(m.Region.Music);
|
||||
|
||||
EventSink.InvokeLogin(m);
|
||||
}
|
||||
|
||||
private static int GenerateAuthID(this NetState state)
|
||||
{
|
||||
if (m_AuthIDWindow.Count == m_AuthIDWindowSize)
|
||||
{
|
||||
var oldestID = 0;
|
||||
var oldest = DateTime.MaxValue;
|
||||
|
||||
foreach (var (key, authId) in m_AuthIDWindow)
|
||||
{
|
||||
if (authId.Age < oldest)
|
||||
{
|
||||
oldestID = key;
|
||||
oldest = authId.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, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
// TODO: Connection throttling
|
||||
|
||||
if (state.SentFirstPacket)
|
||||
{
|
||||
state.Disconnect("Duplicate game login packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
state.SentFirstPacket = true;
|
||||
|
||||
var authID = reader.ReadInt32();
|
||||
|
||||
if (!m_AuthIDWindow.TryGetValue(authID, out var ap))
|
||||
{
|
||||
state.LogInfo("Invalid client detected, disconnecting...");
|
||||
state.Disconnect("Unable to find auth id.");
|
||||
}
|
||||
|
||||
if (state._authId != 0 && authID != state._authId || state._authId == 0 && authID != state._seed)
|
||||
{
|
||||
state.LogInfo("Invalid client detected, disconnecting...");
|
||||
state.Disconnect("Invalid auth id in game login packet.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_AuthIDWindow.Remove(authID);
|
||||
state.Version = ap.Version;
|
||||
|
||||
var username = reader.ReadAscii(30);
|
||||
var password = reader.ReadAscii(30);
|
||||
|
||||
var e = new GameLoginEventArgs(state, username, password);
|
||||
|
||||
EventSink.InvokeGameLogin(e);
|
||||
|
||||
if (e.Accepted)
|
||||
{
|
||||
state.CityInfo = e.CityInfo;
|
||||
|
||||
// Comment out these lines to turn off huffman compression
|
||||
state.CompressionEnabled = true;
|
||||
state.PacketEncoder ??= NetworkCompression.Compress;
|
||||
|
||||
state.SendSupportedFeature();
|
||||
state.SendCharacterList();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Disconnect("Login rejected by GameLogin packet handler.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void PlayServer(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
int index = reader.ReadInt16();
|
||||
var info = state.ServerInfo;
|
||||
var a = state.Account;
|
||||
|
||||
if (info == null || a == null || index < 0 || index >= info.Length)
|
||||
{
|
||||
state.Disconnect("Invalid server selected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = info[index];
|
||||
|
||||
state._authId = GenerateAuthID(state);
|
||||
|
||||
state.SentFirstPacket = false;
|
||||
state.SendPlayServerAck(si, state._authId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoginServerSeed(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
state._seed = reader.ReadInt32();
|
||||
state.Seeded = true;
|
||||
|
||||
if (state._seed == 0)
|
||||
{
|
||||
state.LogInfo("Invalid client detected, disconnecting");
|
||||
state.Disconnect("Duplicate seed sent.");
|
||||
return;
|
||||
}
|
||||
|
||||
var clientMaj = reader.ReadInt32();
|
||||
var clientMin = reader.ReadInt32();
|
||||
var clientRev = reader.ReadInt32();
|
||||
var clientPat = reader.ReadInt32();
|
||||
|
||||
state.Version = new ClientVersion(clientMaj, clientMin, clientRev, clientPat);
|
||||
}
|
||||
|
||||
public static void AccountLogin(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
// TODO: Throttle Connection
|
||||
|
||||
if (state.SentFirstPacket)
|
||||
{
|
||||
state.Disconnect("Duplicate account login packet sent.");
|
||||
return;
|
||||
}
|
||||
|
||||
state.SentFirstPacket = true;
|
||||
|
||||
var username = reader.ReadAscii(30);
|
||||
var password = reader.ReadAscii(30);
|
||||
|
||||
var accountLoginEventArgs = new AccountLoginEventArgs(state, username, password);
|
||||
|
||||
EventSink.InvokeAccountLogin(accountLoginEventArgs);
|
||||
|
||||
if (accountLoginEventArgs.Accepted)
|
||||
{
|
||||
var serverListEventArgs = new ServerListEventArgs(state, state.Account);
|
||||
|
||||
EventSink.InvokeServerList(serverListEventArgs);
|
||||
|
||||
if (serverListEventArgs.Rejected)
|
||||
{
|
||||
state.Account = null;
|
||||
AccountLogin_ReplyRej(state, ALRReason.BadComm);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ServerInfo = serverListEventArgs.Servers.ToArray();
|
||||
state.SendAccountLoginAck();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountLogin_ReplyRej(state, accountLoginEventArgs.RejectReason);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AccountLogin_ReplyRej(this NetState state, ALRReason reason)
|
||||
{
|
||||
state.SendAccountLoginRejected(reason);
|
||||
state.Disconnect($"Account login rejected due to {reason}");
|
||||
}
|
||||
|
||||
private class LoginTimer : Timer
|
||||
{
|
||||
private readonly Mobile _mobile;
|
||||
private readonly NetState _state;
|
||||
|
||||
public LoginTimer(NetState state, Mobile m) : base(TimeSpan.FromMilliseconds(64), TimeSpan.FromMilliseconds(64))
|
||||
{
|
||||
_state = state;
|
||||
_mobile = m;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (_state != null)
|
||||
{
|
||||
if (_state.Account == null)
|
||||
{
|
||||
_state.Disconnect("Account was deleted during the login process.");
|
||||
}
|
||||
else if (_mobile == null)
|
||||
{
|
||||
_state.Disconnect("Player was deleted during the login process.");
|
||||
}
|
||||
else if (_state.Version != null)
|
||||
{
|
||||
_state.BlockAllPackets = false;
|
||||
DoLogin(_state, _mobile);
|
||||
}
|
||||
else // Waiting to receive the client version before we continue the login process
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2022 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: IncomingEntityPackets.cs *
|
||||
* *
|
||||
* 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 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
namespace Server.Network;
|
||||
|
||||
public static class IncomingEntityPackets
|
||||
{
|
||||
public static bool SingleClickProps { get; set; }
|
||||
|
||||
public static unsafe void Configure()
|
||||
{
|
||||
IncomingPackets.Register(0x06, 5, true, &UseReq);
|
||||
IncomingPackets.Register(0x09, 5, true, &LookReq);
|
||||
IncomingPackets.Register(0xB6, 9, true, &ObjectHelpRequest);
|
||||
IncomingPackets.Register(0xD6, 0, true, &BatchQueryProperties);
|
||||
}
|
||||
|
||||
public static void ObjectHelpRequest(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
var serial = (Serial)reader.ReadUInt32();
|
||||
int unk = reader.ReadByte();
|
||||
var lang = reader.ReadAscii(3);
|
||||
|
||||
if (serial.IsItem)
|
||||
{
|
||||
var 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)
|
||||
{
|
||||
var 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 UseReq(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from.AccessLevel >= AccessLevel.Counselor || Core.TickCount - from.NextActionTime >= 0)
|
||||
{
|
||||
var value = reader.ReadUInt32();
|
||||
|
||||
if ((value & ~0x7FFFFFFF) != 0)
|
||||
{
|
||||
from.OnPaperdollRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial s = (Serial)value;
|
||||
|
||||
if (s.IsMobile)
|
||||
{
|
||||
var m = World.FindMobile(s);
|
||||
|
||||
if (m?.Deleted == false)
|
||||
{
|
||||
from.Use(m);
|
||||
}
|
||||
}
|
||||
else if (s.IsItem)
|
||||
{
|
||||
var item = World.FindItem(s);
|
||||
|
||||
if (item?.Deleted == false)
|
||||
{
|
||||
from.Use(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendActionMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static void LookReq(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
Serial s = (Serial)reader.ReadUInt32();
|
||||
|
||||
if (s.IsMobile)
|
||||
{
|
||||
var m = World.FindMobile(s);
|
||||
|
||||
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from.Location, m.Location))
|
||||
{
|
||||
if (SingleClickProps)
|
||||
{
|
||||
m.OnAosSingleClick(from);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.Region.OnSingleClick(from, m))
|
||||
{
|
||||
m.OnSingleClick(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s.IsItem)
|
||||
{
|
||||
var item = World.FindItem(s);
|
||||
|
||||
if (item?.Deleted == false && from.CanSee(item) &&
|
||||
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
|
||||
{
|
||||
if (SingleClickProps)
|
||||
{
|
||||
item.OnAosSingleClick(from);
|
||||
}
|
||||
else if (from.Region.OnSingleClick(from, item))
|
||||
{
|
||||
if (item.Parent is Item parentItem)
|
||||
{
|
||||
parentItem.OnSingleClickContained(from, item);
|
||||
}
|
||||
|
||||
item.OnSingleClick(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void BatchQueryProperties(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
if (!ObjectPropertyList.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var from = state.Mobile;
|
||||
|
||||
var length = reader.Remaining;
|
||||
|
||||
if (length % 4 != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (reader.Remaining > 0)
|
||||
{
|
||||
Serial s = (Serial)reader.ReadUInt32();
|
||||
|
||||
if (s.IsMobile)
|
||||
{
|
||||
var m = World.FindMobile(s);
|
||||
|
||||
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from.Location, m.Location))
|
||||
{
|
||||
m.SendPropertiesTo(state);
|
||||
}
|
||||
}
|
||||
else if (s.IsItem)
|
||||
{
|
||||
var item = World.FindItem(s);
|
||||
|
||||
if (item?.Deleted == false && from.CanSee(item) &&
|
||||
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
|
||||
{
|
||||
item.SendPropertiesTo(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,498 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2022 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: IncomingExtendedCommandPackets.cs *
|
||||
* *
|
||||
* 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 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using Server.ContextMenus;
|
||||
|
||||
namespace Server.Network;
|
||||
|
||||
public static class IncomingExtendedCommandPackets
|
||||
{
|
||||
private static readonly PacketHandler[] _extendedHandlers = new PacketHandler[0x100];
|
||||
|
||||
// TODO: Change to outside configuration
|
||||
public static int[] ValidAnimations { get; set; } =
|
||||
{
|
||||
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 unsafe void Configure()
|
||||
{
|
||||
IncomingPackets.Register(0xBF, 0, true, &ExtendedCommand);
|
||||
|
||||
RegisterExtended(0x05, false, &ScreenSize);
|
||||
RegisterExtended(0x06, true, &PartyMessage);
|
||||
RegisterExtended(0x09, true, &DisarmRequest);
|
||||
RegisterExtended(0x0A, true, &StunRequest);
|
||||
RegisterExtended(0x0B, false, &Language);
|
||||
RegisterExtended(0x0C, true, &CloseStatus);
|
||||
RegisterExtended(0x0E, true, &Animate);
|
||||
RegisterExtended(0x0F, false, &Empty); // What's this?
|
||||
RegisterExtended(0x10, true, &QueryProperties);
|
||||
RegisterExtended(0x13, true, &ContextMenuRequest);
|
||||
RegisterExtended(0x15, true, &ContextMenuResponse);
|
||||
RegisterExtended(0x1A, true, &StatLockChange);
|
||||
RegisterExtended(0x1C, true, &CastSpell);
|
||||
RegisterExtended(0x24, false, &UnhandledBF);
|
||||
RegisterExtended(0x2C, true, &BandageTarget);
|
||||
RegisterExtended(0x2D, true, &TargetedSpell);
|
||||
RegisterExtended(0x2E, true, &TargetedSkillUse);
|
||||
RegisterExtended(0x30, true, &TargetByResourceMacro);
|
||||
RegisterExtended(0x32, true, &ToggleFlying);
|
||||
}
|
||||
|
||||
private static void UnhandledBF(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
}
|
||||
|
||||
public static void Empty(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
}
|
||||
|
||||
public static unsafe void RegisterExtended(int packetID, bool ingame,
|
||||
delegate*<NetState, CircularBufferReader, int, void> onReceive)
|
||||
{
|
||||
if (packetID is >= 0 and < 0x100)
|
||||
{
|
||||
_extendedHandlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive);
|
||||
}
|
||||
}
|
||||
|
||||
public static PacketHandler GetExtendedHandler(int packetID) =>
|
||||
packetID is >= 0 and < 0x100 ? _extendedHandlers[packetID] : null;
|
||||
|
||||
public static void RemoveExtendedHandler(int packetID)
|
||||
{
|
||||
if (packetID is >= 0 and < 0x100)
|
||||
{
|
||||
_extendedHandlers[packetID] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void ExtendedCommand(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
int packetId = reader.ReadUInt16();
|
||||
|
||||
var ph = GetExtendedHandler(packetId);
|
||||
|
||||
if (ph == null)
|
||||
{
|
||||
reader.Trace(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ph.Ingame && state.Mobile?.Deleted != false)
|
||||
{
|
||||
if (state.Mobile == null)
|
||||
{
|
||||
state.LogInfo(
|
||||
$"Sent in-game packet (0xBFx{packetId:X2}) before having been attached to a mobile"
|
||||
);
|
||||
}
|
||||
|
||||
state.Disconnect($"Sent in-game packet(0xBFx{packetId:X2}) but mobile is deleted.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ph.OnReceive(state, reader, packetLength);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ScreenSize(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var width = reader.ReadInt32();
|
||||
var unk = reader.ReadInt32();
|
||||
}
|
||||
|
||||
// TODO: Move out of the core
|
||||
public static void PartyMessage(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
if (state.Mobile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reader.ReadByte())
|
||||
{
|
||||
case 0x01:
|
||||
PartyMessage_AddMember(state, reader, packetLength);
|
||||
break;
|
||||
case 0x02:
|
||||
PartyMessage_RemoveMember(state, reader, packetLength);
|
||||
break;
|
||||
case 0x03:
|
||||
PartyMessage_PrivateMessage(state, reader, packetLength);
|
||||
break;
|
||||
case 0x04:
|
||||
PartyMessage_PublicMessage(state, reader, packetLength);
|
||||
break;
|
||||
case 0x06:
|
||||
PartyMessage_SetCanLoot(state, reader, packetLength);
|
||||
break;
|
||||
case 0x08:
|
||||
PartyMessage_Accept(state, reader, packetLength);
|
||||
break;
|
||||
case 0x09:
|
||||
PartyMessage_Decline(state, reader, packetLength);
|
||||
break;
|
||||
default:
|
||||
reader.Trace(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void PartyMessage_AddMember(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnAdd(state.Mobile);
|
||||
}
|
||||
|
||||
public static void PartyMessage_RemoveMember(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnRemove(state.Mobile, World.FindMobile((Serial)reader.ReadUInt32()));
|
||||
}
|
||||
|
||||
public static void PartyMessage_PrivateMessage(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnPrivateMessage(
|
||||
state.Mobile,
|
||||
World.FindMobile((Serial)reader.ReadUInt32()),
|
||||
reader.ReadBigUniSafe()
|
||||
);
|
||||
}
|
||||
|
||||
public static void PartyMessage_PublicMessage(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnPublicMessage(state.Mobile, reader.ReadBigUniSafe());
|
||||
}
|
||||
|
||||
public static void PartyMessage_SetCanLoot(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnSetCanLoot(state.Mobile, reader.ReadBoolean());
|
||||
}
|
||||
|
||||
public static void PartyMessage_Accept(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnAccept(state.Mobile, World.FindMobile((Serial)reader.ReadUInt32()));
|
||||
}
|
||||
|
||||
public static void PartyMessage_Decline(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
PartyCommands.Handler?.OnDecline(state.Mobile, World.FindMobile((Serial)reader.ReadUInt32()));
|
||||
}
|
||||
|
||||
public static void Animate(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var action = reader.ReadInt32();
|
||||
|
||||
var ok = false;
|
||||
|
||||
for (var i = 0; !ok && i < ValidAnimations.Length; ++i)
|
||||
{
|
||||
ok = action == ValidAnimations[i];
|
||||
}
|
||||
|
||||
if (ok && from.Alive && from.Body.IsHuman && !from.Mounted)
|
||||
{
|
||||
from.Animate(action, 7, 1, true, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CastSpell(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Item spellbook = reader.ReadInt16() == 1 ? World.FindItem((Serial)reader.ReadUInt32()) : null;
|
||||
|
||||
var spellID = reader.ReadInt16() - 1;
|
||||
EventSink.InvokeCastSpellRequest(from, spellID, spellbook);
|
||||
}
|
||||
|
||||
public static void ToggleFlying(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
state.Mobile?.ToggleFlying();
|
||||
}
|
||||
|
||||
public static void StunRequest(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EventSink.InvokeStunRequest(from);
|
||||
}
|
||||
|
||||
public static void DisarmRequest(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EventSink.InvokeDisarmRequest(from);
|
||||
}
|
||||
|
||||
public static void StatLockChange(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int stat = reader.ReadByte();
|
||||
int lockValue = reader.ReadByte();
|
||||
|
||||
if (lockValue > 2)
|
||||
{
|
||||
lockValue = 0;
|
||||
}
|
||||
|
||||
switch (stat)
|
||||
{
|
||||
case 0:
|
||||
from.StrLock = (StatLockType)lockValue;
|
||||
break;
|
||||
case 1:
|
||||
from.DexLock = (StatLockType)lockValue;
|
||||
break;
|
||||
case 2:
|
||||
from.IntLock = (StatLockType)lockValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CloseStatus(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var serial = (Serial)reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public static void Language(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
from.Language = reader.ReadAscii(4);
|
||||
}
|
||||
|
||||
public static void QueryProperties(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
if (!ObjectPropertyList.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var from = state.Mobile;
|
||||
|
||||
Serial s = (Serial)reader.ReadUInt32();
|
||||
|
||||
if (s.IsMobile)
|
||||
{
|
||||
var m = World.FindMobile(s);
|
||||
|
||||
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from.Location, m.Location))
|
||||
{
|
||||
m.SendPropertiesTo(state);
|
||||
}
|
||||
}
|
||||
else if (s.IsItem)
|
||||
{
|
||||
var item = World.FindItem(s);
|
||||
|
||||
if (item?.Deleted == false && from.CanSee(item) &&
|
||||
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
|
||||
{
|
||||
item.SendPropertiesTo(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ContextMenuResponse(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = from.ContextMenu;
|
||||
|
||||
from.ContextMenu = null;
|
||||
|
||||
if (menu != null && from == menu.From)
|
||||
{
|
||||
var entity = World.FindEntity((Serial)reader.ReadUInt32());
|
||||
|
||||
if (entity != null && entity == menu.Target && from.CanSee(entity))
|
||||
{
|
||||
Point3D p;
|
||||
|
||||
if (entity is Mobile)
|
||||
{
|
||||
p = entity.Location;
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
p = item.GetWorldLocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = reader.ReadUInt16();
|
||||
|
||||
if (index >= 0 && index < menu.Entries.Length)
|
||||
{
|
||||
var e = menu.Entries[index];
|
||||
|
||||
var range = e.Range;
|
||||
|
||||
if (range == -1)
|
||||
{
|
||||
range = 18;
|
||||
}
|
||||
|
||||
if (e.Enabled && from.InRange(p, range))
|
||||
{
|
||||
e.OnClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ContextMenuRequest(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
var target = World.FindEntity((Serial)reader.ReadUInt32());
|
||||
|
||||
if (from != null && target != null && from.Map == target.Map && from.CanSee(target))
|
||||
{
|
||||
var item = target as Item;
|
||||
|
||||
var checkLocation = item?.GetWorldLocation() ?? target.Location;
|
||||
if (!(Utility.InUpdateRange(from.Location, checkLocation) && from.CheckContextMenuDisplay(target)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var c = new ContextMenu(from, target);
|
||||
|
||||
if (c.Entries.Length > 0)
|
||||
{
|
||||
if (item?.RootParent is Mobile mobile && mobile != from && mobile.AccessLevel >= from.AccessLevel)
|
||||
{
|
||||
for (var i = 0; i < c.Entries.Length; ++i)
|
||||
{
|
||||
if (!c.Entries[i].NonLocalUse)
|
||||
{
|
||||
c.Entries[i].Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from.ContextMenu = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void BandageTarget(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var from = state.Mobile;
|
||||
|
||||
if (from == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from.AccessLevel >= AccessLevel.Counselor || Core.TickCount - from.NextActionTime >= 0)
|
||||
{
|
||||
var bandage = World.FindItem((Serial)reader.ReadUInt32());
|
||||
|
||||
if (bandage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var target = World.FindMobile((Serial)reader.ReadUInt32());
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EventSink.InvokeBandageTargetRequest(from, bandage, target);
|
||||
|
||||
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendActionMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static void TargetedSpell(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var spellId = (short)(reader.ReadInt16() - 1); // zero based;
|
||||
|
||||
EventSink.InvokeTargetedSpell(state.Mobile, World.FindEntity((Serial)reader.ReadUInt32()), spellId);
|
||||
}
|
||||
|
||||
public static void TargetedSkillUse(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var skillId = reader.ReadInt16();
|
||||
|
||||
EventSink.InvokeTargetedSkillUse(state.Mobile, World.FindEntity((Serial)reader.ReadUInt32()), skillId);
|
||||
}
|
||||
|
||||
public static void TargetByResourceMacro(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var serial = (Serial)reader.ReadUInt32();
|
||||
|
||||
if (serial.IsItem)
|
||||
{
|
||||
EventSink.InvokeTargetByResourceMacro(state.Mobile, World.FindItem(serial), reader.ReadInt16());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2022 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: IncomingHousePackets.cs *
|
||||
* *
|
||||
* 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 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
namespace Server.Network;
|
||||
|
||||
public static class IncomingHousePackets
|
||||
{
|
||||
public static unsafe void Configure()
|
||||
{
|
||||
IncomingPackets.Register(0xFB, 2, false, &ShowPublicHouseContent);
|
||||
}
|
||||
|
||||
public static void ShowPublicHouseContent(NetState state, CircularBufferReader reader, int packetLength)
|
||||
{
|
||||
var showPublicHouseContent = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue