Adds BufferReader and BufferWriter. Updates UOP handling. (#101)

This commit is contained in:
Kamron Batman 2020-04-12 21:33:24 -07:00 committed by GitHub
parent 2c0d97cd36
commit 038c3be258
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 2458 additions and 2185 deletions

View file

@ -427,9 +427,9 @@ namespace Server.Accounting
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Connected( ConnectedEventArgs e ) private static void EventSink_Connected(Mobile m)
{ {
if ( !(e.Mobile.Account is Account acc) ) if ( !(m.Account is Account acc) )
return; return;
if ( acc.Young && acc.m_YoungTimer == null ) if ( acc.Young && acc.m_YoungTimer == null )
@ -439,9 +439,9 @@ namespace Server.Accounting
} }
} }
private static void EventSink_Disconnected( DisconnectedEventArgs e ) private static void EventSink_Disconnected(Mobile m)
{ {
if ( !(e.Mobile.Account is Account acc) ) if ( !(m.Account is Account acc) )
return; return;
if ( acc.m_YoungTimer != null ) if ( acc.m_YoungTimer != null )
@ -450,21 +450,21 @@ namespace Server.Accounting
acc.m_YoungTimer = null; acc.m_YoungTimer = null;
} }
if ( !(e.Mobile is PlayerMobile m) ) if ( !(m is PlayerMobile pm) )
return; return;
acc.m_TotalGameTime += DateTime.UtcNow - m.SessionStart; acc.m_TotalGameTime += DateTime.UtcNow - pm.SessionStart;
} }
private static void EventSink_Login( LoginEventArgs e ) private static void EventSink_Login(Mobile m)
{ {
if ( !(e.Mobile is PlayerMobile m) ) if ( !(m is PlayerMobile pm) )
return; return;
if ( !(m.Account is Account acc) ) if ( !(m.Account is Account acc) )
return; return;
if ( m.Young && acc.Young ) if ( pm.Young && acc.Young )
{ {
TimeSpan ts = YoungDuration - acc.TotalGameTime; TimeSpan ts = YoungDuration - acc.TotalGameTime;
int hours = Math.Max( (int) ts.TotalHours, 0 ); int hours = Math.Max( (int) ts.TotalHours, 0 );

View file

@ -191,11 +191,8 @@ namespace Server.Misc
} }
} }
private static void EventSink_DeleteRequest(DeleteRequestEventArgs e) private static void EventSink_DeleteRequest(NetState state, int index)
{ {
NetState state = e.State;
int index = e.Index;
if (!(state.Account is Account acct)) if (!(state.Account is Account acct))
{ {
state.Dispose(); state.Dispose();

View file

@ -65,7 +65,7 @@ namespace Server.Accounting
} }
} }
public static void Save(WorldSaveEventArgs e) public static void Save(bool message)
{ {
if (!Directory.Exists("Saves/Accounts")) if (!Directory.Exists("Saves/Accounts"))
Directory.CreateDirectory("Saves/Accounts"); Directory.CreateDirectory("Saves/Accounts");

View file

@ -96,7 +96,7 @@ namespace Server.Commands
{ {
var paramList = c.GetParameters(); var paramList = c.GetParameters();
object[] args = paramList.Length == 0 ? null : new object[paramList.Length]; object[] args = paramList.Length == 0 ? null : new object[paramList.Length];
Array.Fill(args, Type.Missing); if (args != null) Array.Fill(args, Type.Missing);
try try
{ {
from.SendMessage("Duping {0}...", m_Amount); from.SendMessage("Duping {0}...", m_Amount);

View file

@ -5,7 +5,7 @@ using Server.Targeting;
namespace Server.Commands namespace Server.Commands
{ {
public class VisibilityList public static class VisibilityList
{ {
public static void Initialize() public static void Initialize()
{ {
@ -16,9 +16,9 @@ namespace Server.Commands
CommandSystem.Register("VisClear", AccessLevel.Counselor, VisClear_OnCommand); CommandSystem.Register("VisClear", AccessLevel.Counselor, VisClear_OnCommand);
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
if (e.Mobile is PlayerMobile pm) pm.VisibilityList.Clear(); (m as PlayerMobile)?.VisibilityList.Clear();
} }
[Usage("Vis")] [Usage("Vis")]
@ -138,4 +138,4 @@ namespace Server.Commands
} }
} }
} }
} }

View file

@ -1,15 +1,15 @@
namespace Server.Chat namespace Server.Chat
{ {
public class ChatSystem public static class ChatSystem
{ {
public static void Initialize() public static void Initialize()
{ {
EventSink.ChatRequest += EventSink_ChatRequest; EventSink.ChatRequest += EventSink_ChatRequest;
} }
private static void EventSink_ChatRequest(ChatRequestEventArgs e) private static void EventSink_ChatRequest(Mobile m)
{ {
e.Mobile.SendMessage("Chat is not currently supported."); m.SendMessage("Chat is not currently supported.");
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Server.Engines.PartySystem; using Server.Engines.PartySystem;
using Server.Factions; using Server.Factions;
using Server.Gumps; using Server.Gumps;
@ -160,7 +161,7 @@ namespace Server.Engines.ConPVP
if (spell is RecallSpell) if (spell is RecallSpell)
from.SendMessage("You may not cast this spell."); from.SendMessage("You may not cast this spell.");
string title = null; string title;
string option; string option;
switch (spell) switch (spell)
@ -498,7 +499,7 @@ namespace Server.Engines.ConPVP
DuelPlayer pl = Find(mob); DuelPlayer pl = Find(mob);
if (pl?.Eliminated == true || m_EventGame?.OnDeath(mob, corpse) == false) if (pl?.Eliminated != false || m_EventGame?.OnDeath(mob, corpse) == false)
return; return;
pl.Eliminated = true; pl.Eliminated = true;
@ -1075,30 +1076,13 @@ namespace Server.Engines.ConPVP
} }
} }
public static bool CheckCombat(Mobile m) public static bool CheckCombat(Mobile m) =>
m.Aggressed.Any(info => info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay) ||
m.Aggressors.Any(info => info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay);
private static void EventSink_Login(Mobile m)
{ {
for (int i = 0; i < m.Aggressed.Count; ++i) if (!(m is PlayerMobile pm))
{
AggressorInfo info = m.Aggressed[i];
if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay)
return true;
}
for (int i = 0; i < m.Aggressors.Count; ++i)
{
AggressorInfo info = m.Aggressors[i];
if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay)
return true;
}
return false;
}
private static void EventSink_Login(LoginEventArgs e)
{
if (!(e.Mobile is PlayerMobile pm))
return; return;
DuelContext dc = pm.DuelContext; DuelContext dc = pm.DuelContext;

View file

@ -19,9 +19,8 @@ namespace Server.Engines.Doom
EventSink.Login += OnLogin; EventSink.Login += OnLogin;
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
Mobile m = e.Mobile;
Rectangle2D rect = LeverPuzzleController.lr_Rect; Rectangle2D rect = LeverPuzzleController.lr_Rect;
if (m.X >= rect.X && m.X <= rect.X + 10 && m.Y >= rect.Y && m.Y <= rect.Y + 10 && m.Map == Map.Internal) if (m.X >= rect.X && m.X <= rect.X + 10 && m.Y >= rect.Y && m.Y <= rect.Y + 10 && m.Map == Map.Internal)
{ {

View file

@ -940,7 +940,7 @@ namespace Server.Factions
int silver = killerState.Faction.AwardSilver(killer, bc.FactionSilverWorth); int silver = killerState.Faction.AwardSilver(killer, bc.FactionSilverWorth);
if (silver > 0) if (silver > 0)
killer.SendLocalizedMessage(1042748, killer?.SendLocalizedMessage(1042748,
silver.ToString("N0")); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature. silver.ToString("N0")); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature.
} }
@ -981,7 +981,7 @@ namespace Server.Factions
{ {
if (victimState.KillPoints <= -6) if (victimState.KillPoints <= -6)
{ {
killer.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. killer?.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from.
#region Ethics #region Ethics
@ -1029,7 +1029,7 @@ namespace Server.Factions
int silver = killerState.Faction.AwardSilver(killer, award * 40); int silver = killerState.Faction.AwardSilver(killer, award * 40);
if (silver > 0) if (silver > 0)
killer.SendLocalizedMessage(1042736, killer?.SendLocalizedMessage(1042736,
$"{silver:N0} silver\t{victim.Name}"); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! $"{silver:N0} silver\t{victim.Name}"); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~!
} }
@ -1038,9 +1038,9 @@ namespace Server.Factions
int offset = award != 1 ? 0 : 2; // for pluralization int offset = award != 1 ? 0 : 2; // for pluralization
string args = $"{award}\t{victim.Name}\t{killer.Name}"; string args = $"{award}\t{victim.Name}\t{killer?.Name}";
killer.SendLocalizedMessage(1042737 + offset, killer?.SendLocalizedMessage(1042737 + offset,
args); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~! args); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~!
victim.SendLocalizedMessage(1042738 + offset, victim.SendLocalizedMessage(1042738 + offset,
args); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished! args); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished!
@ -1072,24 +1072,19 @@ namespace Server.Factions
} }
else else
{ {
killer.SendLocalizedMessage( killer?.SendLocalizedMessage(
1042231); // You have recently defeated this enemy and thus their death brings you no honor. 1042231); // You have recently defeated this enemy and thus their death brings you no honor.
} }
} }
} }
} }
private static void EventSink_Logout(LogoutEventArgs e) private static void EventSink_Logout(Mobile m)
{ {
e.Mobile.Backpack?.FindItemsByType<Sigil>().ForEach(sigil => sigil.ReturnHome()); m.Backpack?.FindItemsByType<Sigil>().ForEach(sigil => sigil.ReturnHome());
} }
private static void EventSink_Login(LoginEventArgs e) private static void EventSink_Login(Mobile m) => CheckLeaveTimer(m);
{
Mobile mob = e.Mobile;
CheckLeaveTimer(mob);
}
public static void WriteReference(IGenericWriter writer, Faction fact) public static void WriteReference(IGenericWriter writer, Faction fact)
{ {
@ -1102,10 +1097,7 @@ namespace Server.Factions
{ {
int idx = reader.ReadEncodedInt() - 1; int idx = reader.ReadEncodedInt() - 1;
if (idx >= 0 && idx < Factions.Count) return idx >= 0 && idx < Factions.Count ? Factions[idx] : null;
return Factions[idx];
return null;
} }
public static Faction Find(Mobile mob, bool inherit = false, bool creatureAllegiances = false) public static Faction Find(Mobile mob, bool inherit = false, bool creatureAllegiances = false)

View file

@ -4,7 +4,7 @@ using Server.Network;
namespace Server.Factions namespace Server.Factions
{ {
public class Keywords public static class Keywords
{ {
public static void Initialize() public static void Initialize()
{ {

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Server.Engines.ConPVP; using Server.Engines.ConPVP;
using Server.Factions; using Server.Factions;
using Server.Gumps; using Server.Gumps;
@ -194,19 +195,17 @@ namespace Server.Engines.Help
EventSink.HelpRequest += EventSink_HelpRequest; EventSink.HelpRequest += EventSink_HelpRequest;
} }
private static void EventSink_HelpRequest(HelpRequestEventArgs e) private static void EventSink_HelpRequest(Mobile m)
{ {
foreach (Gump g in e.Mobile.NetState.Gumps) if (m.NetState.Gumps.OfType<HelpGump>().Any()) return;
if (g is HelpGump)
return;
if (!PageQueue.CheckAllowedToPage(e.Mobile)) if (!PageQueue.CheckAllowedToPage(m))
return; return;
if (PageQueue.Contains(e.Mobile)) if (PageQueue.Contains(m))
e.Mobile.SendMenu(new ContainedMenu(e.Mobile)); m.SendMenu(new ContainedMenu(m));
else else
e.Mobile.SendGump(new HelpGump(e.Mobile)); m.SendGump(new HelpGump(m));
} }
private static bool IsYoung(Mobile m) => m is PlayerMobile mobile && mobile.Young; private static bool IsYoung(Mobile m) => m is PlayerMobile mobile && mobile.Young;

View file

@ -535,9 +535,9 @@ namespace Server.Engines.MLQuests
} }
} }
public static void EventSink_QuestGumpRequest(QuestGumpRequestArgs args) public static void EventSink_QuestGumpRequest(Mobile m)
{ {
if (!Enabled || !(args.Mobile is PlayerMobile pm)) if (!Enabled || !(m is PlayerMobile pm))
return; return;
pm.SendGump(new QuestLogGump(pm)); pm.SendGump(new QuestLogGump(pm));

View file

@ -134,9 +134,8 @@ namespace Server.Engines.PartySystem
} }
} }
public static void EventSink_PlayerDeath(PlayerDeathEventArgs e) public static void EventSink_PlayerDeath(Mobile from)
{ {
Mobile from = e.Mobile;
Party p = Get(from); Party p = Get(from);
if (p != null) if (p != null)
@ -152,9 +151,8 @@ namespace Server.Engines.PartySystem
} }
} }
public static void EventSink_Login(LoginEventArgs e) public static void EventSink_Login(Mobile from)
{ {
Mobile from = e.Mobile;
Party p = Get(from); Party p = Get(from);
if (p != null) if (p != null)
@ -163,9 +161,8 @@ namespace Server.Engines.PartySystem
from.Party = null; from.Party = null;
} }
public static void EventSink_Logout(LogoutEventArgs e) public static void EventSink_Logout(Mobile from)
{ {
Mobile from = e.Mobile;
Party p = Get(from); Party p = Get(from);
p?.Remove(from); p?.Remove(from);

View file

@ -407,10 +407,8 @@ namespace Server.Engines.Plants
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs args) private static void EventSink_Login(Mobile from)
{ {
Mobile from = args.Mobile;
from.Backpack?.FindItemsByType<PlantItem>().ForEach(plant => from.Backpack?.FindItemsByType<PlantItem>().ForEach(plant =>
{ {
if (plant.IsGrowable) if (plant.IsGrowable)
@ -443,7 +441,7 @@ namespace Server.Engines.Plants
GrowAll(); GrowAll();
} }
private static void EventSink_WorldSave(WorldSaveEventArgs args) private static void EventSink_WorldSave(bool message)
{ {
GrowAll(); GrowAll();
} }

View file

@ -252,7 +252,7 @@ namespace Server.Engines.VeteranRewards
if (args == null && entries[j].Args.Length == 0) if (args == null && entries[j].Args.Length == 0)
return i + 1; return i + 1;
if (args.Length == entries[j].Args.Length) if (args?.Length == entries[j].Args.Length)
{ {
bool match = true; bool match = true;
@ -467,15 +467,15 @@ namespace Server.Engines.VeteranRewards
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs e) private static void EventSink_Login(Mobile m)
{ {
if (!e.Mobile.Alive) if (!m.Alive)
return; return;
ComputeRewardInfo(e.Mobile, out int cur, out int max, out int level); ComputeRewardInfo(m, out int cur, out int max, out int level);
if (e.Mobile.SkillsCap == 7000 || e.Mobile.SkillsCap == 7050 || e.Mobile.SkillsCap == 7100 || if (m.SkillsCap == 7000 || m.SkillsCap == 7050 || m.SkillsCap == 7100 ||
e.Mobile.SkillsCap == 7150 || e.Mobile.SkillsCap == 7200) m.SkillsCap == 7150 || m.SkillsCap == 7200)
{ {
if (level > 4) if (level > 4)
level = 4; level = 4;
@ -483,19 +483,19 @@ namespace Server.Engines.VeteranRewards
level = 0; level = 0;
if (SkillCapRewards) if (SkillCapRewards)
e.Mobile.SkillsCap = 7000 + level * 50; m.SkillsCap = 7000 + level * 50;
else else
e.Mobile.SkillsCap = 7000; m.SkillsCap = 7000;
} }
if (Core.ML && e.Mobile is PlayerMobile mobile && !mobile.HasStatReward && HasHalfLevel(mobile)) if (Core.ML && m is PlayerMobile pm && !pm.HasStatReward && HasHalfLevel(pm))
{ {
mobile.HasStatReward = true; pm.HasStatReward = true;
mobile.StatCap += 5; pm.StatCap += 5;
} }
if (cur < max) if (cur < max)
e.Mobile.SendGump(new RewardNoticeGump(e.Mobile)); m.SendGump(new RewardNoticeGump(m));
} }
} }

View file

@ -64,47 +64,41 @@ namespace Server
m_Callbacks[gumpID] = callback; m_Callbacks[gumpID] = callback;
} }
private static void EventSink_VirtueItemRequest(VirtueItemRequestEventArgs e) private static void EventSink_VirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID)
{ {
if (e.Beholder != e.Beheld) if (beholder != beheld)
return; return;
e.Beholder.CloseGump<VirtueGump>(); beholder.CloseGump<VirtueGump>();
if (e.Beholder.Kills >= 5) if (beholder.Kills >= 5)
{ {
e.Beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue. beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.
return; return;
} }
if (m_Callbacks.TryGetValue(e.GumpID, out OnVirtueUsed callback)) if (m_Callbacks.TryGetValue(gumpID, out OnVirtueUsed callback))
callback(e.Beholder); callback(beholder);
else else
e.Beholder.SendLocalizedMessage(1052066); // That virtue is not active yet. beholder.SendLocalizedMessage(1052066); // That virtue is not active yet.
} }
private static void EventSink_VirtueMacroRequest(VirtueMacroRequestEventArgs e) private static void EventSink_VirtueMacroRequest(Mobile beholder, int virtue)
{ {
var virtueID = e.VirtueID switch var virtueID = virtue switch
{ {
0 => // Honor 0 => 107, // Honor
107, 1 => 110, // Sacrifice
1 => // Sacrifice 2 => 112, // Valor;
110,
2 => // Valor;
112,
_ => 0 _ => 0
}; };
EventSink_VirtueItemRequest(new VirtueItemRequestEventArgs(e.Mobile, e.Mobile, virtueID)); EventSink_VirtueItemRequest(beholder, beholder, virtueID);
} }
private static void EventSink_VirtueGumpRequest(VirtueGumpRequestEventArgs e) private static void EventSink_VirtueGumpRequest(Mobile beholder, Mobile beheld)
{ {
Mobile beholder = e.Beholder;
Mobile beheld = e.Beheld;
if (beholder == beheld && beholder.Kills >= 5) if (beholder == beheld && beholder.Kills >= 5)
{ {
beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue. beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.

View file

@ -17,10 +17,8 @@ namespace Server.Gumps
EventSink.PlayerDeath += EventSink_PlayerDeath; EventSink.PlayerDeath += EventSink_PlayerDeath;
} }
public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) public static void EventSink_PlayerDeath(Mobile m)
{ {
Mobile m = e.Mobile;
List<Mobile> killers = new List<Mobile>(); List<Mobile> killers = new List<Mobile>();
List<Mobile> toGive = new List<Mobile>(); List<Mobile> toGive = new List<Mobile>();
@ -46,7 +44,7 @@ namespace Server.Gumps
{ {
int n = Notoriety.Compute( g, m ); int n = Notoriety.Compute( g, m );
int theirKarma = m.Karma, ourKarma = g.Karma; int ourKarma = g.Karma;
bool innocent = n == Notoriety.Innocent; bool innocent = n == Notoriety.Innocent;
bool criminal = n == Notoriety.Criminal || n == Notoriety.Murderer; bool criminal = n == Notoriety.Criminal || n == Notoriety.Murderer;

View file

@ -7,7 +7,7 @@ using Server.Targeting;
namespace Server.Engines.Events namespace Server.Engines.Events
{ {
public class TrickOrTreat public static class TrickOrTreat
{ {
public static TimeSpan OneSecond = TimeSpan.FromSeconds(1); public static TimeSpan OneSecond = TimeSpan.FromSeconds(1);

View file

@ -64,10 +64,10 @@ namespace Server.Engines.Events
} }
} }
public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) public static void EventSink_PlayerDeath(Mobile m)
{ {
if ( e.Mobile is PlayerMobile player && !player.Deleted && m_Timer.Running && !m_DeathQueue.Contains( player ) && m_DeathQueue.Count < m_DeathQueueLimit ) if (m is PlayerMobile pm && !pm.Deleted && m_Timer.Running && !m_DeathQueue.Contains(pm) && m_DeathQueue.Count < m_DeathQueueLimit)
m_DeathQueue.Add( player ); m_DeathQueue.Add(pm);
} }
private static void Clear_Callback() private static void Clear_Callback()

View file

@ -215,61 +215,58 @@ namespace Server.Items
} }
} }
private static void EventSink_OpenDoorMacroUsed(OpenDoorMacroEventArgs args) private static void EventSink_OpenDoorMacroUsed(Mobile m)
{ {
Mobile m = args.Mobile; if (m.Map == null) return;
if (m.Map != null) int x = m.X, y = m.Y;
switch (m.Direction & Direction.Mask)
{ {
int x = m.X, y = m.Y; case Direction.North:
--y;
switch (m.Direction & Direction.Mask) break;
{ case Direction.Right:
case Direction.North: ++x;
--y; --y;
break; break;
case Direction.Right: case Direction.East:
++x; ++x;
--y; break;
break; case Direction.Down:
case Direction.East: ++x;
++x; ++y;
break; break;
case Direction.Down: case Direction.South:
++x; ++y;
++y; break;
break; case Direction.Left:
case Direction.South: --x;
++y; ++y;
break; break;
case Direction.Left: case Direction.West:
--x; --x;
++y; break;
break; case Direction.Up:
case Direction.West: --x;
--x; --y;
break; break;
case Direction.Up:
--x;
--y;
break;
}
Sector sector = m.Map.GetSector(x, y);
foreach (Item item in sector.Items)
if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z &&
m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item))
{
if (m.CheckAlive())
{
m.SendLocalizedMessage(500024); // Opening door...
item.OnDoubleClick(m);
}
break;
}
} }
Sector sector = m.Map.GetSector(x, y);
foreach (Item item in sector.Items)
if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z &&
m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item))
{
if (m.CheckAlive())
{
m.SendLocalizedMessage(500024); // Opening door...
item.OnDoubleClick(m);
}
break;
}
} }
public static Point3D GetOffset(DoorFacing facing) => m_Offsets[(int)facing]; public static Point3D GetOffset(DoorFacing facing) => m_Offsets[(int)facing];

View file

@ -1048,9 +1048,9 @@ namespace Server.Items
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs e) private static void EventSink_Login(Mobile m)
{ {
CheckHeaveTimer(e.Mobile); CheckHeaveTimer(m);
} }
public static void CheckHeaveTimer(Mobile from) public static void CheckHeaveTimer(Mobile from)

View file

@ -193,16 +193,7 @@ namespace Server.Items
} }
[CommandProperty(AccessLevel.GameMaster)] [CommandProperty(AccessLevel.GameMaster)]
public virtual bool InstancedCorpse public virtual bool InstancedCorpse => Core.SE && DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime;
{
get
{
if (!Core.SE)
return false;
return DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime;
}
}
public override bool IsDecoContainer => false; public override bool IsDecoContainer => false;

View file

@ -630,10 +630,8 @@ namespace Server.Items
EventSink.Logout += EventSink_Logout; EventSink.Logout += EventSink_Logout;
} }
public static void EventSink_Logout(LogoutEventArgs e) public static void EventSink_Logout(Mobile from)
{ {
Mobile from = e.Mobile;
if (from == null || !m_Table.TryGetValue(from, out TeleportingInfo info)) if (from == null || !m_Table.TryGetValue(from, out TeleportingInfo info))
return; return;

View file

@ -245,6 +245,7 @@ namespace Server.Items
{ {
EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest;
EventSink.CastSpellRequest += EventSink_CastSpellRequest; EventSink.CastSpellRequest += EventSink_CastSpellRequest;
EventSink.TargetedSpell += EventSink_TargetedSpell;
CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand);
} }
@ -278,14 +279,12 @@ namespace Server.Items
} }
} }
private static void EventSink_OpenSpellbookRequest(OpenSpellbookRequestEventArgs e) private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID)
{ {
Mobile from = e.Mobile;
if (!DesignContext.Check(from)) if (!DesignContext.Check(from))
return; // They are customizing return; // They are customizing
var type = e.Type switch var type = typeID switch
{ {
1 => SpellbookType.Regular, 1 => SpellbookType.Regular,
2 => SpellbookType.Necromancer, 2 => SpellbookType.Necromancer,
@ -302,15 +301,32 @@ namespace Server.Items
book?.DisplayTo(from); book?.DisplayTo(from);
} }
private static void EventSink_CastSpellRequest(CastSpellRequestEventArgs e) private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId)
{ {
Mobile from = e.Mobile; if (!DesignContext.Check(from)) return; // They are customizing
Spellbook book = Find(from, spellId);
if (book?.HasSpell(spellId) != true)
{
from.SendLocalizedMessage(500015); // You do not have that spell!
return;
}
SpecialMove move = SpellRegistry.GetSpecialMove(spellId);
if (move != null)
SpecialMove.SetCurrentMove(from, move);
else
SpellRegistry.NewSpell(spellId, @from, null)?.Cast();
}
private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item)
{
if (!DesignContext.Check(from)) if (!DesignContext.Check(from))
return; // They are customizing return; // They are customizing
Spellbook book = e.Spellbook as Spellbook; Spellbook book = item as Spellbook;
int spellID = e.SpellID;
if (book?.HasSpell(spellID) != true) if (book?.HasSpell(spellID) != true)
book = Find(from, spellID); book = Find(from, spellID);
@ -688,7 +704,7 @@ namespace Server.Items
if ((prop = Attributes.RegenMana) != 0) if ((prop = Attributes.RegenMana) != 0)
list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~
if ((prop = Attributes.NightSight) != 0) if ((Attributes.NightSight) != 0)
list.Add(1060441); // night sight list.Add(1060441); // night sight
if ((prop = Attributes.ReflectPhysical) != 0) if ((prop = Attributes.ReflectPhysical) != 0)
@ -700,7 +716,7 @@ namespace Server.Items
if ((prop = Attributes.RegenHits) != 0) if ((prop = Attributes.RegenHits) != 0)
list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~
if ((prop = Attributes.SpellChanneling) != 0) if ((Attributes.SpellChanneling) != 0)
list.Add(1060482); // spell channeling list.Add(1060482); // spell channeling
if ((prop = Attributes.SpellDamage) != 0) if ((prop = Attributes.SpellDamage) != 0)

View file

@ -70,30 +70,27 @@ namespace Server.Items
} }
} }
private static void EventSink_BandageTargetRequest(BandageTargetRequestEventArgs e) private static void EventSink_BandageTargetRequest(Mobile from, Item item, Mobile target)
{ {
if (!(e.Bandage is Bandage b) || b.Deleted) if (!(item is Bandage b) || b.Deleted)
return; return;
Mobile from = e.Mobile; if (!from.InRange(b.GetWorldLocation(), Range))
if (from.InRange(b.GetWorldLocation(), Range))
{
if (from.Target != null)
{
Target.Cancel(from);
from.Target = null;
}
from.RevealingAction();
from.SendLocalizedMessage(500948); // Who will you use the bandages on?
new InternalTarget(b).Invoke(from, e.Target);
}
else
{ {
from.SendLocalizedMessage(500295); // You are too far away to do that. from.SendLocalizedMessage(500295); // You are too far away to do that.
return;
} }
if (from.Target != null)
{
Target.Cancel(from);
from.Target = null;
}
from.RevealingAction();
from.SendLocalizedMessage(500948); // Who will you use the bandages on?
new InternalTarget(b).Invoke(from, target);
} }
private class InternalTarget : Target private class InternalTarget : Target
@ -203,7 +200,7 @@ namespace Server.Items
{ {
StopHeal(); StopHeal();
int healerNumber = -1, patientNumber = -1; int healerNumber, patientNumber;
bool playSound = true; bool playSound = true;
bool checkSkills = false; bool checkSkills = false;

View file

@ -389,14 +389,12 @@ namespace Server.Items
EventSink.SetAbility += EventSink_SetAbility; EventSink.SetAbility += EventSink_SetAbility;
} }
private static void EventSink_SetAbility(SetAbilityEventArgs e) private static void EventSink_SetAbility(Mobile m, int index)
{ {
int index = e.Index;
if (index == 0) if (index == 0)
ClearCurrentAbility(e.Mobile); ClearCurrentAbility(m);
else if (index >= 1 && index < Abilities.Length) else if (index >= 1 && index < Abilities.Length)
SetCurrentAbility(e.Mobile, Abilities[index]); SetCurrentAbility(m, Abilities[index]);
} }
private static void AddContext(Mobile m, WeaponAbilityContext context) private static void AddContext(Mobile m, WeaponAbilityContext context)

View file

@ -216,13 +216,11 @@ namespace Server.Items
return (item == null || item is Spellbook) && m.FindItemOnLayer(Layer.TwoHanded) == null; return (item == null || item is Spellbook) && m.FindItemOnLayer(Layer.TwoHanded) == null;
} }
private static void EventSink_DisarmRequest(DisarmRequestEventArgs e) private static void EventSink_DisarmRequest(Mobile m)
{ {
if (Core.AOS) if (Core.AOS)
return; return;
Mobile m = e.Mobile;
#region Dueling #region Dueling
if (!DuelContext.AllowSpecialAbility(m, "Disarm", true)) if (!DuelContext.AllowSpecialAbility(m, "Disarm", true))
@ -251,13 +249,11 @@ namespace Server.Items
} }
} }
private static void EventSink_StunRequest(StunRequestEventArgs e) private static void EventSink_StunRequest(Mobile m)
{ {
if (Core.AOS) if (Core.AOS)
return; return;
Mobile m = e.Mobile;
#region Dueling #region Dueling
if (!DuelContext.AllowSpecialAbility(m, "Stun", true)) if (!DuelContext.AllowSpecialAbility(m, "Stun", true))

View file

@ -1,31 +1,23 @@
namespace Server.Misc namespace Server.Misc
{ {
public class Animations public static class Animations
{ {
public static void Initialize() public static void Initialize()
{ {
EventSink.AnimateRequest += EventSink_AnimateRequest; EventSink.AnimateRequest += EventSink_AnimateRequest;
} }
private static void EventSink_AnimateRequest(AnimateRequestEventArgs e) private static void EventSink_AnimateRequest(Mobile from, string actionName)
{ {
Mobile from = e.Mobile; int action = actionName switch
int action;
switch (e.Action)
{ {
case "bow": "bow" => 32,
action = 32; "salute" => 33,
break; _ => 0,
case "salute": };
action = 33;
break;
default: return;
}
if (from.Alive && !from.Mounted && from.Body.IsHuman) if (action > 0 && from.Alive && !from.Mounted && from.Body.IsHuman)
from.Animate(action, 5, 1, true, false, 0); from.Animate(action, 5, 1, true, false, 0);
} }
} }
} }

View file

@ -59,4 +59,4 @@ namespace Server.Misc
return false; return false;
} }
} }
} }

View file

@ -1,14 +1,14 @@
namespace Server.Misc namespace Server.Misc
{ {
public class Broadcasts public static class Broadcasts
{ {
public static void Initialize() public static void Initialize()
{ {
EventSink.Crashed += EventSink_Crashed; EventSink.ServerCrashed += EventSink_Crashed;
EventSink.Shutdown += EventSink_Shutdown; EventSink.Shutdown += EventSink_Shutdown;
} }
public static void EventSink_Crashed(CrashedEventArgs e) public static void EventSink_Crashed(ServerCrashedEventArgs e)
{ {
try try
{ {
@ -20,16 +20,16 @@ namespace Server.Misc
} }
} }
public static void EventSink_Shutdown(ShutdownEventArgs e) public static void EventSink_Shutdown()
{ {
/* try /* try
{ {
World.Broadcast(0x35, true, "The server has shut down."); World.Broadcast(0x35, true, "The server has shut down.");
} }
catch catch
{ {
// ignored // ignored
}*/ }*/
} }
} }
} }

View file

@ -11,11 +11,13 @@ namespace Server
public static void Initialize() public static void Initialize()
{ {
if (Enabled) if (Enabled)
EventSink.ClientVersionReceived += delegate(ClientVersionReceivedArgs args) EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived;
{ }
if (args.State.Mobile is PlayerMobile pm)
Timer.DelayCall(TimeSpan.Zero, pm.ResendBuffs); public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv)
}; {
if (ns.Mobile is PlayerMobile pm)
Timer.DelayCall(TimeSpan.Zero, pm.ResendBuffs);
} }
#region Properties #region Properties
@ -284,4 +286,4 @@ namespace Server
m_Stream.Fill(4); m_Stream.Fill(4);
} }
} }
} }

View file

@ -1164,7 +1164,7 @@ namespace Server.Misc
if (m_Mobile?.EquipItem(item) == true) if (m_Mobile?.EquipItem(item) == true)
return; return;
Container pack = m_Mobile.Backpack; Container pack = m_Mobile?.Backpack;
if (!mustEquip && pack != null) if (!mustEquip && pack != null)
pack.DropItem(item); pack.DropItem(item);

View file

@ -56,13 +56,11 @@ namespace Server.Misc
} }
} }
private static void EventSink_ClientVersionReceived(ClientVersionReceivedArgs e) private static void EventSink_ClientVersionReceived(NetState state, ClientVersion version)
{ {
string kickMessage = null; string kickMessage = null;
NetState state = e.State;
ClientVersion version = e.Version;
if (state.Mobile == null || state.Mobile.AccessLevel > AccessLevel.Player) if (state.Mobile?.AccessLevel != AccessLevel.Player)
return; return;
if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick || if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick ||

View file

@ -7,20 +7,20 @@ using Server.Network;
namespace Server.Misc namespace Server.Misc
{ {
public class CrashGuard public static class CrashGuard
{ {
private static bool Enabled = true; private static readonly bool Enabled = true;
private static bool SaveBackup = true; private static readonly bool SaveBackup = true;
private static bool RestartServer = true; private static readonly bool RestartServer = true;
private static bool GenerateReport = true; private static readonly bool GenerateReport = true;
public static void Initialize() public static void Initialize()
{ {
if (Enabled) // If enabled, register our crash event handler if (Enabled) // If enabled, register our crash event handler
EventSink.Crashed += CrashGuard_OnCrash; EventSink.ServerCrashed += CrashGuard_OnCrash;
} }
public static void CrashGuard_OnCrash(CrashedEventArgs e) public static void CrashGuard_OnCrash(ServerCrashedEventArgs e)
{ {
if (GenerateReport) if (GenerateReport)
GenerateCrashReport(e); GenerateCrashReport(e);
@ -61,7 +61,7 @@ namespace Server.Misc
private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2); private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2);
private static void Restart(CrashedEventArgs e) private static void Restart(ServerCrashedEventArgs e)
{ {
string root = GetRoot(); string root = GetRoot();
@ -152,7 +152,7 @@ namespace Server.Misc
} }
} }
private static void GenerateCrashReport(CrashedEventArgs e) private static void GenerateCrashReport(ServerCrashedEventArgs e)
{ {
Console.Write("Crash: Generating report..."); Console.Write("Crash: Generating report...");

View file

@ -4,7 +4,7 @@ namespace Server.Misc
{ {
// This fastwalk detection is no longer required // This fastwalk detection is no longer required
// As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds
public class Fastwalk public static class Fastwalk
{ {
private static int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected private static int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected
private static bool Enabled = false; // Is fastwalk detection enabled? private static bool Enabled = false; // Is fastwalk detection enabled?
@ -30,4 +30,4 @@ namespace Server.Misc
Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name); Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name);
} }
} }
} }

View file

@ -484,9 +484,7 @@ namespace Server.Guilds
public class WarTimer : Timer public class WarTimer : Timer
{ {
private static TimeSpan InternalDelay = TimeSpan.FromMinutes(1.0); public WarTimer() : base(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0)) => Priority = TimerPriority.FiveSeconds;
public WarTimer() : base(InternalDelay, InternalDelay) => Priority = TimerPriority.FiveSeconds;
public static void Initialize() public static void Initialize()
{ {
@ -718,7 +716,7 @@ namespace Server.Guilds
if (o is Guildstone stone) if (o is Guildstone stone)
{ {
if (stone?.Guild.Disbanded != false) if (stone.Guild.Disbanded)
{ {
from.SendMessage("The guild associated with that Guildstone no longer exists"); from.SendMessage("The guild associated with that Guildstone no longer exists");
return; return;
@ -748,9 +746,9 @@ namespace Server.Guilds
#region EventSinks #region EventSinks
public static void EventSink_GuildGumpRequest(GuildGumpRequestArgs args) public static void EventSink_GuildGumpRequest(Mobile m)
{ {
if (!NewGuildSystem || !(args.Mobile is PlayerMobile pm)) if (!NewGuildSystem || !(m is PlayerMobile pm))
return; return;
if (pm.Guild == null) if (pm.Guild == null)

View file

@ -4,7 +4,7 @@ using Server.Mobiles;
namespace Server.Misc namespace Server.Misc
{ {
public class Keywords public static class Keywords
{ {
public static void Initialize() public static void Initialize()
{ {
@ -51,4 +51,4 @@ namespace Server.Misc
} }
} }
} }
} }

View file

@ -54,10 +54,8 @@ namespace Server
} }
} }
public static void OnLogin(LoginEventArgs args) public static void OnLogin(Mobile m)
{ {
Mobile m = args.Mobile;
m.CheckLightLevels(true); m.CheckLightLevels(true);
} }

View file

@ -10,17 +10,15 @@ namespace Server.Misc
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs args) private static void EventSink_Login(Mobile m)
{ {
int userCount = TcpServer.Instances.Count; int userCount = TcpServer.Instances.Count;
int itemCount = World.Items.Count; int itemCount = World.Items.Count;
int mobileCount = World.Mobiles.Count; int mobileCount = World.Mobiles.Count;
Mobile m = args.Mobile;
m.SendMessage( m.SendMessage(
"Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.", "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.",
args.Mobile.Name, m.Name,
userCount == 1 ? "is" : "are", userCount == 1 ? "is" : "are",
userCount, userCount == 1 ? "" : "s", userCount, userCount == 1 ? "" : "s",
itemCount, itemCount == 1 ? "" : "s", itemCount, itemCount == 1 ? "" : "s",

View file

@ -3,18 +3,15 @@ using Server.Network;
namespace Server.Misc namespace Server.Misc
{ {
public class Paperdoll public static class Paperdoll
{ {
public static void Initialize() public static void Initialize()
{ {
EventSink.PaperdollRequest += EventSink_PaperdollRequest; EventSink.PaperdollRequest += EventSink_PaperdollRequest;
} }
public static void EventSink_PaperdollRequest(PaperdollRequestEventArgs e) public static void EventSink_PaperdollRequest(Mobile beholder, Mobile beheld)
{ {
Mobile beholder = e.Beholder;
Mobile beheld = e.Beheld;
beholder.Send(new DisplayPaperdoll(beheld, Titles.ComputeTitle(beholder, beheld), beholder.Send(new DisplayPaperdoll(beheld, Titles.ComputeTitle(beholder, beheld),
beheld.AllowEquipFrom(beholder))); beheld.AllowEquipFrom(beholder)));
@ -30,4 +27,4 @@ namespace Server.Misc
} }
} }
} }
} }

View file

@ -10,7 +10,7 @@ namespace Server.Misc
Other // some other implementation Other // some other implementation
} }
public class ProfanityProtection public static class ProfanityProtection
{ {
private static bool Enabled = false; private static bool Enabled = false;
@ -118,4 +118,4 @@ namespace Server.Misc
e.Blocked = !OnProfanityDetected(from, e.Speech); e.Blocked = !OnProfanityDetected(from, e.Speech);
} }
} }
} }

View file

@ -4,7 +4,7 @@ using Server.Network;
namespace Server.Misc namespace Server.Misc
{ {
public class Profile public static class Profile
{ {
public static void Initialize() public static void Initialize()
{ {
@ -12,21 +12,16 @@ namespace Server.Misc
EventSink.ChangeProfileRequest += EventSink_ChangeProfileRequest; EventSink.ChangeProfileRequest += EventSink_ChangeProfileRequest;
} }
public static void EventSink_ChangeProfileRequest(ChangeProfileRequestEventArgs e) public static void EventSink_ChangeProfileRequest(Mobile beholder, Mobile beheld, string text)
{ {
Mobile from = e.Beholder; if (beholder.ProfileLocked)
beholder.SendMessage("Your profile is locked. You may not change it.");
if (from.ProfileLocked)
from.SendMessage("Your profile is locked. You may not change it.");
else else
from.Profile = e.Text; beholder.Profile = text;
} }
public static void EventSink_ProfileRequest(ProfileRequestEventArgs e) public static void EventSink_ProfileRequest(Mobile beholder, Mobile beheld)
{ {
Mobile beholder = e.Beholder;
Mobile beheld = e.Beheld;
if (!beheld.Player) if (!beheld.Player)
return; return;
@ -48,10 +43,7 @@ namespace Server.Misc
if (footer.Length == 0 && beholder == beheld) if (footer.Length == 0 && beholder == beheld)
footer = GetAccountDuration(beheld); footer = GetAccountDuration(beheld);
string body = beheld.Profile; string body = beheld.Profile ?? "";
if (body == null || body.Length <= 0)
body = "";
beholder.Send(new DisplayProfile(beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer)); beholder.Send(new DisplayProfile(beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer));
} }
@ -90,4 +82,4 @@ namespace Server.Misc
return false; return false;
} }
} }
} }

View file

@ -1,18 +1,14 @@
namespace Server.Misc namespace Server.Misc
{ {
public class RenameRequests public static class RenameRequests
{ {
public static void Initialize() public static void Initialize()
{ {
EventSink.RenameRequest += EventSink_RenameRequest; EventSink.RenameRequest += EventSink_RenameRequest;
} }
private static void EventSink_RenameRequest(RenameRequestEventArgs e) private static void EventSink_RenameRequest(Mobile from, Mobile targ, string name)
{ {
Mobile from = e.From;
Mobile targ = e.Target;
string name = e.Name;
if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from)) if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from))
{ {
name = name.Trim(); name = name.Trim();
@ -44,4 +40,4 @@ namespace Server.Misc
} }
} }
} }
} }

View file

@ -142,12 +142,12 @@ namespace Server.Misc
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs e) private static void EventSink_Login(Mobile m)
{ {
if (m_ActivePollers.Count == 0) if (m_ActivePollers.Count == 0)
return; return;
Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, e.Mobile); Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, m);
} }
private static void EventSink_Login_Callback(Mobile from) private static void EventSink_Login_Callback(Mobile from)

View file

@ -10,7 +10,7 @@ namespace Server.Misc
PainSpike PainSpike
} }
public class WeightOverloading public static class WeightOverloading
{ {
public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued
@ -117,4 +117,4 @@ namespace Server.Misc
return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance; return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance;
} }
} }
} }

View file

@ -632,7 +632,7 @@ namespace Server.Mobiles
if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills.Wrestling.Value >= 80.0 &&
m_Mobile.Skills.Anatomy.Value >= 80.0) m_Mobile.Skills.Anatomy.Value >= 80.0)
EventSink.InvokeStunRequest(new StunRequestEventArgs(m_Mobile)); EventSink.InvokeStunRequest(m_Mobile);
if (!m_Mobile.InRange(c, m_Mobile.RangePerception)) if (!m_Mobile.InRange(c, m_Mobile.RangePerception))
{ {

View file

@ -56,7 +56,7 @@ namespace Server.Mobiles
if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills.Wrestling.Value >= 80.0 &&
m_Mobile.Skills.ArmsLore.Value >= 80.0 && m_toDisarm != null) m_Mobile.Skills.ArmsLore.Value >= 80.0 && m_toDisarm != null)
EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(m_Mobile)); EventSink.InvokeDisarmRequest(m_Mobile);
if (m_toDisarm?.IsChildOf(combatant.Backpack) == true && if (m_toDisarm?.IsChildOf(combatant.Backpack) == true &&
Core.TickCount - m_Mobile.NextSkillTime >= 0 && m_toDisarm.LootType != LootType.Blessed && Core.TickCount - m_Mobile.NextSkillTime >= 0 && m_toDisarm.LootType != LootType.Blessed &&

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Server.Items; using Server.Items;
namespace Server.Mobiles namespace Server.Mobiles
@ -71,21 +72,16 @@ namespace Server.Mobiles
EventSink.PlayerDeath += EventSink_PlayerDeath; EventSink.PlayerDeath += EventSink_PlayerDeath;
} }
public static void EventSink_PlayerDeath(PlayerDeathEventArgs e) public static void EventSink_PlayerDeath(Mobile m)
{ {
Mobile m = e.Mobile;
Mobile lastKiller = m.LastKiller; Mobile lastKiller = m.LastKiller;
if (lastKiller is BaseCreature creature) if (lastKiller is BaseCreature creature)
lastKiller = creature.GetMaster(); lastKiller = creature.GetMaster();
if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller)) if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller) &&
foreach (AggressorInfo ai in m.Aggressors) m.Aggressors.Any(ai => ai.Attacker == lastKiller && ai.CanReportMurder))
if (ai.Attacker == lastKiller && ai.CanReportMurder) SummonRevenant(m, lastKiller);
{
SummonRevenant(m, lastKiller);
break;
}
} }
public static void SummonRevenant(Mobile victim, Mobile killer) public static void SummonRevenant(Mobile victim, Mobile killer)

View file

@ -543,9 +543,76 @@ namespace Server.Mobiles
EventSink.Connected += EventSink_Connected; EventSink.Connected += EventSink_Connected;
EventSink.Disconnected += EventSink_Disconnected; EventSink.Disconnected += EventSink_Disconnected;
EventSink.TargetedSkillUse += TargetedSkillUse;
EventSink.EquipMacro += EquipMacro;
EventSink.UnequipMacro += UnequipMacro;
if (Core.SE) Timer.DelayCall(TimeSpan.Zero, CheckPets); if (Core.SE) Timer.DelayCall(TimeSpan.Zero, CheckPets);
} }
private static void TargetedSkillUse(Mobile from, IEntity target, int skillId)
{
if (from == null || target == null)
return;
from.TargetLocked = true;
if (skillId == 35)
AnimalTaming.DisableMessage = true;
// AnimalTaming.DeferredTarget = false;
if (from.UseSkill(skillId))
from.Target?.Invoke(from, target);
if (skillId == 35)
// AnimalTaming.DeferredTarget = true;
AnimalTaming.DisableMessage = false;
from.TargetLocked = false;
}
public static void EquipMacro(Mobile m, List<Serial> list)
{
if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive)
{
Container pack = pm.Backpack;
foreach (var serial in list)
{
Item item = pack.Items.FirstOrDefault(i => i.Serial == serial);
if (item == null) continue;
Item toMove = pm.FindItemOnLayer(item.Layer);
if (toMove != null)
{
//pack.DropItem(toMove);
toMove.Internalize();
if (!pm.EquipItem(item))
pm.EquipItem(toMove);
else
pack.DropItem(toMove);
}
else
pm.EquipItem(item);
}
}
}
public static void UnequipMacro(Mobile m, List<Layer> layers)
{
if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive)
{
Container pack = pm.Backpack;
List<Item> eq = m.Items;
foreach (var item in eq)
if (layers.Contains(item.Layer))
pack.TryDropItem(pm, item, false);
}
}
private static void CheckPets() private static void CheckPets()
{ {
foreach (Mobile m in World.Mobiles.Values) foreach (Mobile m in World.Mobiles.Values)
@ -666,10 +733,8 @@ namespace Server.Mobiles
SpecialMove.ClearCurrentMove(this); SpecialMove.ClearCurrentMove(this);
} }
private static void OnLogin(LoginEventArgs e) private static void OnLogin(Mobile from)
{ {
Mobile from = e.Mobile;
CheckAtrophies(from); CheckAtrophies(from);
if (AccountHandler.LockdownLevel > AccessLevel.Player) if (AccountHandler.LockdownLevel > AccessLevel.Player)
@ -925,15 +990,14 @@ namespace Server.Mobiles
ValidateEquipment(); ValidateEquipment();
} }
private static void OnLogout(LogoutEventArgs e) private static void OnLogout(Mobile m)
{ {
if (e.Mobile is PlayerMobile mobile) (m as PlayerMobile)?.AutoStablePets();
mobile.AutoStablePets();
} }
private static void EventSink_Connected(ConnectedEventArgs e) private static void EventSink_Connected(Mobile m)
{ {
if (e.Mobile is PlayerMobile pm) if (m is PlayerMobile pm)
{ {
pm.SessionStart = DateTime.UtcNow; pm.SessionStart = DateTime.UtcNow;
@ -943,14 +1007,13 @@ namespace Server.Mobiles
pm.LastOnline = DateTime.UtcNow; pm.LastOnline = DateTime.UtcNow;
} }
DisguiseTimers.StartTimer(e.Mobile); DisguiseTimers.StartTimer(m);
Timer.DelayCall(TimeSpan.Zero, SpecialMove.ClearAllMoves, e.Mobile); Timer.DelayCall(TimeSpan.Zero, SpecialMove.ClearAllMoves, m);
} }
private static void EventSink_Disconnected(DisconnectedEventArgs e) private static void EventSink_Disconnected(Mobile from)
{ {
Mobile from = e.Mobile;
DesignContext context = DesignContext.Find(from); DesignContext context = DesignContext.Find(from);
if (context != null) if (context != null)
@ -977,7 +1040,7 @@ namespace Server.Mobiles
context.Foundation.RestoreRelocatedEntities(); context.Foundation.RestoreRelocatedEntities();
} }
if (e.Mobile is PlayerMobile pm) if (from is PlayerMobile pm)
{ {
pm.m_GameTime += DateTime.UtcNow - pm.SessionStart; pm.m_GameTime += DateTime.UtcNow - pm.SessionStart;

View file

@ -1650,7 +1650,7 @@ namespace Server.Multis
EventSink.WorldSave += EventSink_WorldSave; EventSink.WorldSave += EventSink_WorldSave;
} }
private static void EventSink_WorldSave(WorldSaveEventArgs e) private static void EventSink_WorldSave(bool message)
{ {
new UpdateAllTimer().Start(); new UpdateAllTimer().Start();
} }

View file

@ -115,10 +115,8 @@ namespace Server.Misc
return false; return false;
} }
public static void EventSink_Login(LoginEventArgs e) public static void EventSink_Login(Mobile from)
{ {
Mobile from = e.Mobile;
if (!IsStranded(from)) if (!IsStranded(from))
return; return;
@ -153,7 +151,7 @@ namespace Server.Misc
int x = p.X, y = p.Y; int x = p.X, y = p.Y;
int z; int z;
bool canFit = false; bool canFit;
z = map.GetAverageZ(x, y); z = map.GetAverageZ(x, y);
canFit = map.CanSpawnMobile(x, y, z); canFit = map.CanSpawnMobile(x, y, z);
@ -175,4 +173,4 @@ namespace Server.Misc
from.Location = new Point3D(x, y, z); from.Location = new Point3D(x, y, z);
} }
} }
} }

View file

@ -1745,7 +1745,7 @@ namespace Server.Multis
Fixtures[i].m_OffsetX = reader.ReadShort(); Fixtures[i].m_OffsetX = reader.ReadShort();
Fixtures[i].m_OffsetY = reader.ReadShort(); Fixtures[i].m_OffsetY = reader.ReadShort();
Fixtures[i].m_OffsetZ = reader.ReadShort(); Fixtures[i].m_OffsetZ = reader.ReadShort();
Fixtures[i].m_Flags = reader.ReadInt(); Fixtures[i].m_Flags = (TileFlag)reader.ReadInt();
} }
Revision = reader.ReadInt(); Revision = reader.ReadInt();
@ -1793,7 +1793,7 @@ namespace Server.Multis
writer.Write(ent.m_OffsetX); writer.Write(ent.m_OffsetX);
writer.Write(ent.m_OffsetY); writer.Write(ent.m_OffsetY);
writer.Write(ent.m_OffsetZ); writer.Write(ent.m_OffsetZ);
writer.Write(ent.m_Flags); writer.Write((int)ent.m_Flags);
} }
writer.Write(Revision); writer.Write(Revision);

View file

@ -30,12 +30,12 @@ namespace Server.Regions
EventSink.Login += OnLogin; EventSink.Login += OnLogin;
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
BaseHouse house = BaseHouse.FindHouseAt(e.Mobile); BaseHouse house = BaseHouse.FindHouseAt(m);
if (house?.Public == false && !house.IsFriend(e.Mobile)) if (house?.Public == false && !house.IsFriend(m))
e.Mobile.Location = house.BanLocation; m.Location = house.BanLocation;
} }
public override bool AllowHousing(Mobile from, Point3D p) => false; public override bool AllowHousing(Mobile from, Point3D p) => false;

View file

@ -35,7 +35,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MailKit" Version="2.4.1" /> <PackageReference Include="MailKit" Version="2.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />

View file

@ -24,9 +24,9 @@ namespace Server.Misc
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
} }
private static void EventSink_Login(LoginEventArgs e) private static void EventSink_Login(Mobile m)
{ {
if (!(e.Mobile.Account is Account acct)) if (!(m.Account is Account acct))
return; return;
DateTime now = DateTime.UtcNow; DateTime now = DateTime.UtcNow;
@ -44,7 +44,7 @@ namespace Server.Misc
if (acct.LastLogin >= giver.Start) if (acct.LastLogin >= giver.Start)
continue; // already got one continue; // already got one
giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), e.Mobile); giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), m);
} }
acct.LastLogin = now; acct.LastLogin = now;

View file

@ -37,10 +37,8 @@ namespace Server.Misc
EventSink.Login += OnLogin; EventSink.Login += OnLogin;
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile from)
{ {
Mobile from = e.Mobile;
if (from == null || from.AccessLevel < AccessLevel.Counselor) if (from == null || from.AccessLevel < AccessLevel.Counselor)
return; return;

View file

@ -93,9 +93,9 @@ namespace Server.Spells.Mysticism
context.OnDamage(); context.OnDamage();
} }
private static void OnPlayerDeath(PlayerDeathEventArgs e) private static void OnPlayerDeath(Mobile m)
{ {
RemoveEffect(e.Mobile); RemoveEffect(m);
} }
protected void VisualEffect(Mobile to) protected void VisualEffect(Mobile to)

View file

@ -146,9 +146,9 @@ namespace Server.Spells.Mysticism
BuffInfo.RemoveBuff(m, BuffIcon.StoneForm); BuffInfo.RemoveBuff(m, BuffIcon.StoneForm);
} }
private static void OnPlayerDeath(PlayerDeathEventArgs e) private static void OnPlayerDeath(Mobile m)
{ {
RemoveEffects(e.Mobile); RemoveEffects(m);
} }
} }
} }

View file

@ -67,10 +67,10 @@ namespace Server.Spells.Ninjitsu
EventSink.Login += OnLogin; EventSink.Login += OnLogin;
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
if (GetContext(e.Mobile)?.SpeedBoost == true) if (GetContext(m)?.SpeedBoost == true)
e.Mobile.Send(SpeedControl.MountSpeed); m.Send(SpeedControl.MountSpeed);
} }
public override bool CheckCast() public override bool CheckCast()

View file

@ -24,11 +24,13 @@ namespace Server.Spells.Spellweaving
public static void Initialize() public static void Initialize()
{ {
EventSink.AggressiveAction += delegate(AggressiveActionEventArgs e) EventSink.AggressiveAction += RemoveTransformationOnAggressiveAction;
{ }
if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell)))
TransformationSpellHelper.RemoveContext(e.Aggressor, true); public static void RemoveTransformationOnAggressiveAction(AggressiveActionEventArgs e)
}; {
if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell)))
TransformationSpellHelper.RemoveContext(e.Aggressor, true);
} }
public override bool CheckCast() public override bool CheckCast()

View file

@ -29,7 +29,7 @@ namespace Server.Spells.Spellweaving
public static void Initialize() public static void Initialize()
{ {
EventSink.PlayerDeath += delegate(PlayerDeathEventArgs e) { HandleDeath(e.Mobile); }; EventSink.PlayerDeath += HandleDeath;
} }
public override void OnCast() public override void OnCast()
@ -132,10 +132,8 @@ namespace Server.Spells.Spellweaving
timer.DoExpire(); timer.DoExpire();
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
Mobile m = e.Mobile;
if (m?.Alive != false || m_Table[m] == null) if (m?.Alive != false || m_Table[m] == null)
return; return;

View file

@ -32,12 +32,12 @@ namespace Server.Spells.Spellweaving
EventSink.Login += OnLogin; EventSink.Login += OnLogin;
} }
public static void OnLogin(LoginEventArgs e) public static void OnLogin(Mobile m)
{ {
TransformContext context = TransformationSpellHelper.GetContext(e.Mobile); TransformContext context = TransformationSpellHelper.GetContext(m);
if (context?.Type == typeof(ReaperFormSpell)) if (context?.Type == typeof(ReaperFormSpell))
e.Mobile.Send(SpeedControl.WalkSpeed); m.Send(SpeedControl.WalkSpeed);
} }
public override void DoEffect(Mobile m) public override void DoEffect(Mobile m)

View file

@ -68,6 +68,7 @@ namespace Server
var types = FindTypesByName(name, ignoreCase).ToList(); var types = FindTypesByName(name, ignoreCase).ToList();
if (types.Count == 0) if (types.Count == 0)
return null; return null;
if (predicate != null) if (predicate != null)
return types.FirstOrDefault(predicate); return types.FirstOrDefault(predicate);
if (types.Count == 1) if (types.Count == 1)
@ -76,10 +77,13 @@ namespace Server
// Check for exact match of the FullName or Name // Check for exact match of the FullName or Name
// Then check for case-insensitive match of FullName or Name // Then check for case-insensitive match of FullName or Name
// Otherwise just return the first entry // Otherwise just return the first entry
return (!ignoreCase ? types.FirstOrDefault(x => x.FullName == name || x.Name == name) : null) var stringComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
?? types.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.FullName, name) || StringComparer.OrdinalIgnoreCase.Equals(x.Name, name))
?? types[0]; return types.FirstOrDefault(x =>
stringComparer.Equals(x.FullName, name) || stringComparer.Equals(x.Name, name)) ??
types[0];
} }
public static IEnumerable<Type> FindTypesByName(string name, bool ignoreCase = false) public static IEnumerable<Type> FindTypesByName(string name, bool ignoreCase = false)
{ {
List<Type> types = new List<Type>(); List<Type> types = new List<Type>();
@ -122,31 +126,30 @@ namespace Server
refs.Add(index); refs.Add(index);
else else
{ {
refs = new HashSet<int>(); refs = new HashSet<int> {index};
refs.Add(index);
nameMap.Add(key, refs); nameMap.Add(key, refs);
} }
}; };
Type current; Type current;
Type aliasType = typeof(TypeAliasAttribute); Type aliasType = typeof(TypeAliasAttribute);
TypeAliasAttribute alias; TypeAliasAttribute alias;
for (int i = 0, j = 0; i < m_Types.Length; i++) for (int i = 0; i < m_Types.Length; i++)
{ {
current = m_Types[i]; current = m_Types[i];
addToRefs(i, current.Name); addToRefs(i, current.Name);
addToRefs(i, current.Name.ToLower()); addToRefs(i, current.Name.ToLower());
addToRefs(i, current.FullName); addToRefs(i, current.FullName);
addToRefs(i, current.FullName.ToLower()); addToRefs(i, current.FullName?.ToLower());
alias = current.GetCustomAttribute(aliasType, false) as TypeAliasAttribute; alias = current.GetCustomAttribute(aliasType, false) as TypeAliasAttribute;
if (alias != null) if (alias != null)
for (j = 0; j < alias.Aliases.Length; j++) for (int j = 0; j < alias.Aliases.Length; j++)
{ {
addToRefs(i, alias.Aliases[j]); addToRefs(i, alias.Aliases[j]);
addToRefs(i, alias.Aliases[j].ToLower()); addToRefs(i, alias.Aliases[j].ToLower());
} }
} }
foreach (var entry in nameMap) foreach (var (key, value) in nameMap)
m_NameMap[entry.Key] = entry.Value.ToArray(); m_NameMap[key] = value.ToArray();
} }
} }
} }

View file

@ -0,0 +1,314 @@
// Copyright (c) Harry Pierson. All rights reserved.
// Licensed under the MIT license.
// See LICENSE file in the project root for full license information.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Buffers
{
public ref struct BufferReader<T>
{
private readonly bool usingSequence;
private readonly ReadOnlySequence<T> sequence;
private SequencePosition currentPosition;
private SequencePosition nextPosition;
private bool moreData;
private readonly long length;
public BufferReader(ReadOnlySpan<T> span)
{
usingSequence = false;
CurrentSpanIndex = 0;
Consumed = 0;
sequence = default;
currentPosition = default;
length = span.Length;
CurrentSpan = span;
nextPosition = default;
moreData = span.Length > 0;
}
public BufferReader(in ReadOnlySequence<T> sequence)
{
usingSequence = true;
CurrentSpanIndex = 0;
Consumed = 0;
this.sequence = sequence;
currentPosition = sequence.Start;
length = -1;
var first = sequence.First.Span;
CurrentSpan = first;
nextPosition = sequence.GetPosition(first.Length);
moreData = first.Length > 0;
if (!moreData && !sequence.IsSingleSegment)
{
moreData = true;
GetNextSpan();
}
}
public readonly bool End => !moreData;
public ReadOnlySpan<T> CurrentSpan { get; private set; }
public int CurrentSpanIndex { get; private set; }
public readonly ReadOnlySpan<T> UnreadSpan
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => CurrentSpan.Slice(CurrentSpanIndex);
}
public long Consumed { get; private set; }
public readonly long Remaining => Length - Consumed;
public readonly long Length
{
get
{
if (length < 0)
{
Debug.Assert(usingSequence, "usingSequence");
// Cast-away readonly to initialize lazy field
Volatile.Write(ref Unsafe.AsRef(length), sequence.Length);
}
return length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool TryPeek([MaybeNullWhen(false)] out T value)
{
if (moreData)
{
value = CurrentSpan[CurrentSpanIndex];
return true;
}
value = default!;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryRead([MaybeNullWhen(false)] out T value)
{
if (End)
{
value = default!;
return false;
}
value = CurrentSpan[CurrentSpanIndex];
CurrentSpanIndex++;
Consumed++;
if (CurrentSpanIndex >= CurrentSpan.Length)
{
if (usingSequence)
GetNextSpan();
else
moreData = false;
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Rewind(long count)
{
if ((ulong)count > (ulong)Consumed) throw new ArgumentOutOfRangeException(nameof(count));
Consumed -= count;
if (CurrentSpanIndex >= count)
{
CurrentSpanIndex -= (int)count;
moreData = true;
}
else if (usingSequence)
{
// Current segment doesn't have enough data, scan backward through segments
RetreatToPreviousSpan(Consumed);
}
else
{
throw new ArgumentOutOfRangeException($"Rewind went past the start of the memory by {count}.", nameof(count));
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void RetreatToPreviousSpan(long consumed)
{
Debug.Assert(usingSequence, "usingSequence");
ResetReader();
Advance(consumed);
}
private void ResetReader()
{
Debug.Assert(usingSequence, "usingSequence");
CurrentSpanIndex = 0;
Consumed = 0;
currentPosition = sequence.Start;
nextPosition = currentPosition;
if (sequence.TryGet(ref nextPosition, out ReadOnlyMemory<T> memory))
{
moreData = true;
if (memory.Length == 0)
{
CurrentSpan = default;
// No data in the first span, move to one with data
GetNextSpan();
}
else
{
CurrentSpan = memory.Span;
}
}
else
{
// No data in any spans and at end of sequence
moreData = false;
CurrentSpan = default;
}
}
private void GetNextSpan()
{
Debug.Assert(usingSequence, "usingSequence");
if (!sequence.IsSingleSegment)
{
SequencePosition previousNextPosition = nextPosition;
while (sequence.TryGet(ref nextPosition, out ReadOnlyMemory<T> memory))
{
currentPosition = previousNextPosition;
if (memory.Length > 0)
{
CurrentSpan = memory.Span;
CurrentSpanIndex = 0;
return;
}
CurrentSpan = default;
CurrentSpanIndex = 0;
previousNextPosition = nextPosition;
}
}
moreData = false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(long count)
{
const long TooBigOrNegative = unchecked((long)0xFFFFFFFF80000000);
if ((count & TooBigOrNegative) == 0 && CurrentSpan.Length - CurrentSpanIndex > (int)count)
{
CurrentSpanIndex += (int)count;
Consumed += count;
}
else if (usingSequence)
{
// Can't satisfy from the current span
AdvanceToNextSpan(count);
}
else if (CurrentSpan.Length - CurrentSpanIndex == (int)count)
{
CurrentSpanIndex += (int)count;
Consumed += count;
moreData = false;
}
else
{
throw new ArgumentOutOfRangeException(nameof(count));
}
}
private void AdvanceToNextSpan(long count)
{
Debug.Assert(usingSequence, "usingSequence");
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
Consumed += count;
while (moreData)
{
int remaining = CurrentSpan.Length - CurrentSpanIndex;
if (remaining > count)
{
CurrentSpanIndex += (int)count;
count = 0;
break;
}
// As there may not be any further segments we need to
// push the current index to the end of the span.
CurrentSpanIndex += remaining;
count -= remaining;
Debug.Assert(count >= 0);
GetNextSpan();
if (count == 0) break;
}
if (count != 0)
{
// Not enough data left- adjust for where we actually ended and throw
Consumed -= count;
throw new ArgumentOutOfRangeException(nameof(count));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool TryCopyTo(Span<T> destination)
{
// This API doesn't advance to facilitate conditional advancement based on the data returned.
// We don't provide an advance option to allow easier utilizing of stack allocated destination spans.
// (Because we can make this method readonly we can guarantee that we won't capture the span.)
ReadOnlySpan<T> firstSpan = UnreadSpan;
if (firstSpan.Length >= destination.Length)
{
firstSpan.Slice(0, destination.Length).CopyTo(destination);
return true;
}
// Not enough in the current span to satisfy the request, fall through to the slow path
return TryCopyMultisegment(destination);
}
internal readonly bool TryCopyMultisegment(Span<T> destination)
{
// If we don't have enough to fill the requested buffer, return false
if (Remaining < destination.Length)
return false;
ReadOnlySpan<T> firstSpan = UnreadSpan;
Debug.Assert(firstSpan.Length < destination.Length);
firstSpan.CopyTo(destination);
int copied = firstSpan.Length;
SequencePosition next = nextPosition;
while (sequence.TryGet(ref next, out ReadOnlyMemory<T> nextSegment))
if (nextSegment.Length > 0)
{
ReadOnlySpan<T> nextSpan = nextSegment.Span;
int toCopy = Math.Min(nextSpan.Length, destination.Length - copied);
nextSpan.Slice(0, toCopy).CopyTo(destination.Slice(copied));
copied += toCopy;
if (copied >= destination.Length) break;
}
return true;
}
}
}

View file

@ -0,0 +1,181 @@
// Copyright (c) Harry Pierson. All rights reserved.
// Licensed under the MIT license.
// See LICENSE file in the project root for full license information.
using System.Buffers.Binary;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers
{
public static class BufferReaderExtensions
{
private static unsafe bool TryRead<T>(ref this BufferReader<byte> reader, out T value)
where T : unmanaged
{
ReadOnlySpan<byte> span = reader.UnreadSpan;
if (span.Length < sizeof(T)) return TryReadMultisegment(ref reader, out value);
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(span));
reader.Advance(sizeof(T));
return true;
}
private static unsafe bool TryReadMultisegment<T>(ref BufferReader<byte> reader, out T value)
where T : unmanaged
{
Debug.Assert(reader.UnreadSpan.Length < sizeof(T), "reader.UnreadSpan.Length < sizeof(T)");
// Not enough data in the current segment, try to peek for the data we need.
T buffer = default;
Span<byte> tempSpan = new Span<byte>(&buffer, sizeof(T));
if (!reader.TryCopyTo(tempSpan))
{
value = default;
return false;
}
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(tempSpan));
reader.Advance(sizeof(T));
return true;
}
public static bool TryRead(ref this BufferReader<byte> reader, out sbyte value)
{
if (TryRead(ref reader, out byte byteValue))
{
value = unchecked((sbyte)byteValue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out short value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out short value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out short value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out ushort value)
{
if (TryReadLittleEndian(ref reader, out short signedvalue))
{
value = unchecked((ushort)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out ushort value)
{
if (TryReadBigEndian(ref reader, out short signedvalue))
{
value = unchecked((ushort)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out int value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out int value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out int value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out uint value)
{
if (TryReadLittleEndian(ref reader, out int signedvalue))
{
value = unchecked((uint)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out uint value)
{
if (TryReadBigEndian(ref reader, out int signedvalue))
{
value = unchecked((uint)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out long value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out long value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out long value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out ulong value)
{
if (TryReadLittleEndian(ref reader, out long signedvalue))
{
value = unchecked((ulong)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out ulong value)
{
if (TryReadBigEndian(ref reader, out long signedvalue))
{
value = unchecked((ulong)signedvalue);
return true;
}
value = default;
return false;
}
}
}

View file

@ -0,0 +1,143 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
namespace System.Buffers
{
/// <summary>
/// A fast access struct that wraps <see cref="IBufferWriter{T}"/>.
/// </summary>
/// <typeparam name="T">The type of element to be written.</typeparam>
internal ref struct BufferWriter<T> where T : IBufferWriter<byte>
{
/// <summary>
/// The underlying <see cref="IBufferWriter{T}"/>.
/// </summary>
private T _output;
/// <summary>
/// The result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>.
/// Backing field for the <see cref="Span"/> property.
/// </summary>
private Span<byte> _span;
/// <summary>
/// The number of uncommitted bytes (all the calls to <see cref="Advance(int)"/> since the last call to <see cref="Commit"/>).
/// </summary>
private int _buffered;
/// <summary>
/// The total number of bytes written with this writer.
/// Backing field for the <see cref="BytesCommitted"/> property.
/// </summary>
private long _bytesCommitted;
/// <summary>
/// Initializes a new instance of the <see cref="BufferWriter{T}"/> struct.
/// </summary>
/// <param name="output">The <see cref="IBufferWriter{T}"/> to be wrapped.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferWriter(T output)
{
_buffered = 0;
_bytesCommitted = 0;
_output = output;
_span = output.GetSpan();
}
/// <summary>
/// Gets the result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>.
/// </summary>
public Span<byte> Span => _span;
/// <summary>
/// Gets the total number of bytes written with this writer.
/// </summary>
public long BytesCommitted => _bytesCommitted;
/// <summary>
/// Calls <see cref="IBufferWriter{T}.Advance(int)"/> on the underlying writer
/// with the number of uncommitted bytes.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Commit()
{
var buffered = _buffered;
if (buffered > 0)
{
_bytesCommitted += buffered;
_buffered = 0;
_output.Advance(buffered);
}
}
/// <summary>
/// Used to indicate that part of the buffer has been written to.
/// </summary>
/// <param name="count">The number of bytes written to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(int count)
{
_buffered += count;
_span = _span.Slice(count);
}
/// <summary>
/// Copies the caller's buffer into this writer and calls <see cref="Advance(int)"/> with the length of the source buffer.
/// </summary>
/// <param name="source">The buffer to copy in.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write(ReadOnlySpan<byte> source)
{
if (_span.Length >= source.Length)
{
source.CopyTo(_span);
Advance(source.Length);
}
else
{
WriteMultiBuffer(source);
}
}
/// <summary>
/// Acquires a new buffer if necessary to ensure that some given number of bytes can be written to a single buffer.
/// </summary>
/// <param name="count">The number of bytes that must be allocated in a single buffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Ensure(int count = 1)
{
if (_span.Length < count) EnsureMore(count);
}
/// <summary>
/// Gets a fresh span to write to, with an optional minimum size.
/// </summary>
/// <param name="count">The minimum size for the next requested buffer.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
private void EnsureMore(int count = 0)
{
if (_buffered > 0) Commit();
_span = _output.GetSpan(count);
}
/// <summary>
/// Copies the caller's buffer into this writer, potentially across multiple buffers from the underlying writer.
/// </summary>
/// <param name="source">The buffer to copy into this writer.</param>
private void WriteMultiBuffer(ReadOnlySpan<byte> source)
{
while (source.Length > 0)
{
if (_span.Length == 0) EnsureMore();
var writable = Math.Min(source.Length, _span.Length);
source.Slice(0, writable).CopyTo(_span);
source = source.Slice(writable);
Advance(writable);
}
}
}
}

View file

@ -1,132 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace System.Buffers
{
/// <summary>
/// Used to allocate and distribute re-usable blocks of memory.
/// </summary>
public class DiagnosticMemoryPool : MemoryPool<byte>
{
private readonly MemoryPool<byte> _pool;
private readonly bool _allowLateReturn;
private readonly bool _rentTracking;
private readonly object _syncObj;
private readonly HashSet<DiagnosticPoolBlock> _blocks;
private readonly List<Exception> _blockAccessExceptions;
private readonly TaskCompletionSource<object> _allBlocksReturned;
private int _totalBlocks;
/// <summary>
/// This default value passed in to Rent to use the default value for the pool.
/// </summary>
private const int AnySize = -1;
public DiagnosticMemoryPool(MemoryPool<byte> pool, bool allowLateReturn = false, bool rentTracking = false)
{
_pool = pool;
_allowLateReturn = allowLateReturn;
_rentTracking = rentTracking;
_blocks = new HashSet<DiagnosticPoolBlock>();
_syncObj = new object();
_allBlocksReturned = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_blockAccessExceptions = new List<Exception>();
}
public bool IsDisposed { get; private set; }
public override IMemoryOwner<byte> Rent(int size = AnySize)
{
lock (_syncObj)
{
if (IsDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPool);
var diagnosticPoolBlock = new DiagnosticPoolBlock(this, _pool.Rent(size));
if (_rentTracking) diagnosticPoolBlock.Track();
_totalBlocks++;
_blocks.Add(diagnosticPoolBlock);
return diagnosticPoolBlock;
}
}
public override int MaxBufferSize => _pool.MaxBufferSize;
internal void Return(DiagnosticPoolBlock block)
{
bool returnedAllBlocks;
lock (_syncObj)
{
_blocks.Remove(block);
returnedAllBlocks = _blocks.Count == 0;
}
if (IsDisposed)
{
if (!_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockReturnedToDisposedPool(block);
if (returnedAllBlocks) SetAllBlocksReturned();
}
}
internal void ReportException(Exception exception)
{
lock (_syncObj)
{
_blockAccessExceptions.Add(exception);
}
}
protected override void Dispose(bool disposing)
{
if (IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_DoubleDispose();
bool allBlocksReturned = false;
try
{
lock (_syncObj)
{
IsDisposed = true;
allBlocksReturned = _blocks.Count == 0;
if (!allBlocksReturned && !_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray());
if (_blockAccessExceptions.Any()) throw CreateAccessExceptions();
}
}
finally
{
if (allBlocksReturned) SetAllBlocksReturned();
}
}
private void SetAllBlocksReturned()
{
if (_blockAccessExceptions.Any())
_allBlocksReturned.SetException(CreateAccessExceptions());
else
_allBlocksReturned.SetResult(null);
}
private AggregateException CreateAccessExceptions() => new AggregateException("Exceptions occurred while accessing blocks", _blockAccessExceptions.ToArray());
public async Task WhenAllBlocksReturnedAsync(TimeSpan timeout)
{
var task = await Task.WhenAny(_allBlocksReturned.Task, Task.Delay(timeout));
if (task != _allBlocksReturned.Task)
MemoryPoolThrowHelper.ThrowInvalidOperationException_BlocksWereNotReturnedInTime(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray());
await task;
}
}
}

View file

@ -1,188 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Buffers
{
/// <summary>
/// Block tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The
/// individual blocks are then treated as independent array segments.
/// </summary>
public sealed class DiagnosticPoolBlock : MemoryManager<byte>
{
/// <summary>
/// Back-reference to the memory pool which this block was allocated from. It may only be returned to this pool.
/// </summary>
private readonly DiagnosticMemoryPool _pool;
private readonly IMemoryOwner<byte> _memoryOwner;
private MemoryHandle? _memoryHandle;
private readonly Memory<byte> _memory;
private readonly object _syncObj = new object();
private bool _isDisposed;
private int _pinCount;
/// <summary>
/// This object cannot be instantiated outside of the static Create method
/// </summary>
internal DiagnosticPoolBlock(DiagnosticMemoryPool pool, IMemoryOwner<byte> memoryOwner)
{
_pool = pool;
_memoryOwner = memoryOwner;
_memory = memoryOwner.Memory;
}
public override Memory<byte> Memory
{
get
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return CreateMemory(_memory.Length);
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
}
protected override void Dispose(bool disposing)
{
try
{
lock (_syncObj)
{
if (Volatile.Read(ref _pinCount) > 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_ReturningPinnedBlock(this);
if (_isDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockDoubleDispose(this);
_memoryOwner.Dispose();
_pool.Return(this);
_isDisposed = true;
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override Span<byte> GetSpan()
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return _memory.Span;
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override MemoryHandle Pin(int byteOffset = 0)
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
if (byteOffset < 0 || byteOffset > _memory.Length) MemoryPoolThrowHelper.ThrowArgumentOutOfRangeException(_memory.Length, byteOffset);
_pinCount++;
_memoryHandle ??= _memory.Pin();
unsafe
{
return new MemoryHandle(((IntPtr)_memoryHandle.Value.Pointer + byteOffset).ToPointer(), default, this);
}
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
protected override bool TryGetArray(out ArraySegment<byte> segment)
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return MemoryMarshal.TryGetArray(_memory, out segment);
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override void Unpin()
{
try
{
lock (_syncObj)
{
if (_pinCount == 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_PinCountZero(this);
_pinCount--;
if (_pinCount == 0)
{
Debug.Assert(_memoryHandle.HasValue);
_memoryHandle.Value.Dispose();
_memoryHandle = null;
}
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public StackTrace Leaser { get; set; }
public void Track()
{
Leaser = new StackTrace(false);
}
}
}

View file

@ -7,7 +7,7 @@ using System.Text;
namespace System.Buffers namespace System.Buffers
{ {
public class MemoryPoolThrowHelper public static class MemoryPoolThrowHelper
{ {
public static void ThrowArgumentOutOfRangeException(int sourceLength, int offset) public static void ThrowArgumentOutOfRangeException(int sourceLength, int offset)
{ {
@ -17,60 +17,6 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(int sourceLength, int offset) => private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(int sourceLength, int offset) =>
(uint)offset > (uint)sourceLength ? new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.offset)) : new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.length)); (uint)offset > (uint)sourceLength ? new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.offset)) : new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.length));
public static void ThrowInvalidOperationException_PinCountZero(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Can't unpin, pin count is zero", block));
}
public static void ThrowInvalidOperationException_ReturningPinnedBlock(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Disposing pinned block", block));
}
public static void ThrowInvalidOperationException_DoubleDispose()
{
throw new InvalidOperationException("Object is being disposed twice");
}
public static void ThrowInvalidOperationException_BlockDoubleDispose(DiagnosticPoolBlock block)
{
throw new InvalidOperationException("Block is being disposed twice");
}
public static void ThrowInvalidOperationException_BlockReturnedToDisposedPool(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Block is being returned to disposed pool", block));
}
public static void ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Block is backed by disposed slab", block));
}
public static void ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(int returned, int total, DiagnosticPoolBlock[] blocks)
{
throw new InvalidOperationException(GenerateMessage($"Memory pool with active blocks is being disposed, {returned} of {total} returned", blocks));
}
public static void ThrowInvalidOperationException_BlocksWereNotReturnedInTime(int returned, int total, DiagnosticPoolBlock[] blocks)
{
throw new InvalidOperationException(GenerateMessage($"Blocks were not returned in time, {returned} of {total} returned ", blocks));
}
private static string GenerateMessage(string message, params DiagnosticPoolBlock[] blocks)
{
StringBuilder builder = new StringBuilder(message);
foreach (var diagnosticPoolBlock in blocks)
if (diagnosticPoolBlock.Leaser != null)
{
builder.AppendLine();
builder.AppendLine("Block leased from:");
builder.AppendLine(diagnosticPoolBlock.Leaser.ToString());
}
return builder.ToString();
}
public static void ThrowArgumentOutOfRangeException_BufferRequestTooLarge(int maxSize) public static void ThrowArgumentOutOfRangeException_BufferRequestTooLarge(int maxSize)
{ {

View file

@ -95,6 +95,12 @@ namespace Server
} }
} }
public static partial class EventSink
{
public static event Action<CommandEventArgs> Command;
public static void InvokeCommand(CommandEventArgs e) => Command?.Invoke(e);
}
public class CommandEntry : IComparable<CommandEntry> public class CommandEntry : IComparable<CommandEntry>
{ {
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel) public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: AccountLoginEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Network;
namespace Server
{
public class AccountLoginEventArgs : EventArgs
{
public AccountLoginEventArgs(NetState state, string username, string password)
{
State = state;
Username = username;
Password = password;
}
public NetState State{ get; }
public string Username{ get; }
public string Password{ get; }
public bool Accepted{ get; set; }
public ALRReason RejectReason{ get; set; }
}
public static partial class EventSink
{
public static event Action<AccountLoginEventArgs> AccountLogin;
public static void InvokeAccountLogin(AccountLoginEventArgs e) => AccountLogin?.Invoke(e);
}
}

View file

@ -0,0 +1,75 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: AggressiveActionEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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;
namespace Server
{
public class AggressiveActionEventArgs : EventArgs
{
private static Queue<AggressiveActionEventArgs> m_Pool = new Queue<AggressiveActionEventArgs>();
private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal)
{
Aggressed = aggressed;
Aggressor = aggressor;
Criminal = criminal;
}
public Mobile Aggressed{ get; private set; }
public Mobile Aggressor{ get; private set; }
public bool Criminal{ get; private set; }
public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal)
{
AggressiveActionEventArgs args;
if (m_Pool.Count > 0)
{
args = m_Pool.Dequeue();
args.Aggressed = aggressed;
args.Aggressor = aggressor;
args.Criminal = criminal;
}
else
{
args = new AggressiveActionEventArgs(aggressed, aggressor, criminal);
}
return args;
}
public void Free()
{
m_Pool.Enqueue(this);
}
}
public static partial class EventSink
{
public static event Action<AggressiveActionEventArgs> AggressiveAction;
public static void InvokeAggressiveAction(AggressiveActionEventArgs e) => AggressiveAction?.Invoke(e);
}
}

View file

@ -0,0 +1,110 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: CharacterCreatedEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Accounting;
using Server.Network;
namespace Server
{
public class CharacterCreatedEventArgs : EventArgs
{
public CharacterCreatedEventArgs(NetState state, IAccount a, string name, bool female, int hue, int str, int dex,
int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue,
int beardID, int beardHue, int profession, Race race)
{
State = state;
Account = a;
Name = name;
Female = female;
Hue = hue;
Str = str;
Dex = dex;
Int = intel;
City = city;
Skills = skills;
ShirtHue = shirtHue;
PantsHue = pantsHue;
HairID = hairID;
HairHue = hairHue;
BeardID = beardID;
BeardHue = beardHue;
Profession = profession;
Race = race;
}
public NetState State{ get; }
public IAccount Account{ get; }
public Mobile Mobile{ get; set; }
public string Name{ get; }
public bool Female{ get; }
public int Hue{ get; }
public int Str{ get; }
public int Dex{ get; }
public int Int{ get; }
public CityInfo City{ get; }
public SkillNameValue[] Skills{ get; }
public int ShirtHue{ get; }
public int PantsHue{ get; }
public int HairID{ get; }
public int HairHue{ get; }
public int BeardID{ get; }
public int BeardHue{ get; }
public int Profession{ get; set; }
public Race Race{ get; }
}
public struct SkillNameValue
{
public SkillName Name{ get; }
public int Value{ get; }
public SkillNameValue(SkillName name, int value)
{
Name = name;
Value = value;
}
}
public static partial class EventSink {
public static event Action<CharacterCreatedEventArgs> CharacterCreated;
public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) => CharacterCreated?.Invoke(e);
}
}

View file

@ -0,0 +1,41 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: CreateGuildEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Guilds;
namespace Server
{
public class CreateGuildEventArgs : EventArgs
{
public CreateGuildEventArgs(uint id) => Id = id;
public uint Id{ get; set; }
public BaseGuild Guild{ get; set; }
}
public static partial class EventSink
{
public static event Action<CreateGuildEventArgs> CreateGuild;
public static void InvokeCreateGuild(CreateGuildEventArgs e) => CreateGuild?.Invoke(e);
}
}

View file

@ -0,0 +1,150 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: EventSink.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Network;
namespace Server
{
public static partial class EventSink
{
public static event Action<Mobile> OpenDoorMacroUsed;
public static void InvokeOpenDoorMacroUsed(Mobile m) => OpenDoorMacroUsed?.Invoke(m);
public static event Action<Mobile> Login;
public static void InvokeLogin(Mobile m) => Login?.Invoke(m);
public static event Action<Mobile, int> HungerChanged;
public static void InvokeHungerChanged(Mobile mobile, int oldValue) => HungerChanged?.Invoke(mobile, oldValue);
public static event Action Shutdown;
public static void InvokeShutdown() => Shutdown?.Invoke();
public static event Action<Mobile> HelpRequest;
public static void InvokeHelpRequest(Mobile m) => HelpRequest?.Invoke(m);
public static event Action<Mobile> DisarmRequest;
public static void InvokeDisarmRequest(Mobile m) => DisarmRequest?.Invoke(m);
public static event Action<Mobile> StunRequest;
public static void InvokeStunRequest(Mobile m) => StunRequest?.Invoke(m);
public static event Action<Mobile, int> OpenSpellbookRequest;
public static void InvokeOpenSpellbookRequest(Mobile m, int type) => OpenSpellbookRequest?.Invoke(m, type);
public static event Action<Mobile, int, Item> CastSpellRequest;
public static void InvokeCastSpellRequest(Mobile m, int spellID, Item book) => CastSpellRequest?.Invoke(m, spellID, book);
public static event Action<Mobile, Item, Mobile> BandageTargetRequest;
public static void InvokeBandageTargetRequest(Mobile m, Item bandage, Mobile target) => BandageTargetRequest?.Invoke(m, bandage, target);
public static event Action<Mobile, string> AnimateRequest;
public static void InvokeAnimateRequest(Mobile m, string action) => AnimateRequest?.Invoke(m, action);
public static event Action<Mobile> Logout;
public static void InvokeLogout(Mobile m) => Logout?.Invoke(m);
public static event Action<Mobile> Connected;
public static void InvokeConnected(Mobile m) => Connected?.Invoke(m);
public static event Action<Mobile> Disconnected;
public static void InvokeDisconnected(Mobile m) => Disconnected?.Invoke(m);
public static event Action<Mobile, Mobile, string> RenameRequest;
public static void InvokeRenameRequest(Mobile from, Mobile target, string name) => RenameRequest?.Invoke(from, target, name);
public static event Action<Mobile> PlayerDeath;
public static void InvokePlayerDeath(Mobile m) => PlayerDeath?.Invoke(m);
public static event Action<Mobile, Mobile> VirtueGumpRequest;
public static void InvokeVirtueGumpRequest(Mobile beholder, Mobile beheld) => VirtueGumpRequest?.Invoke(beholder, beheld);
public static event Action<Mobile, Mobile, int> VirtueItemRequest;
public static void InvokeVirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) => VirtueItemRequest?.Invoke(beholder, beheld, gumpID);
public static event Action<Mobile, int> VirtueMacroRequest;
public static void InvokeVirtueMacroRequest(Mobile mobile, int virtueID) => VirtueMacroRequest?.Invoke(mobile, virtueID);
public static event Action<Mobile> ChatRequest;
public static void InvokeChatRequest(Mobile m) => ChatRequest?.Invoke(m);
public static event Action<Mobile, Mobile> PaperdollRequest;
public static void InvokePaperdollRequest(Mobile beholder, Mobile beheld) => PaperdollRequest?.Invoke(beholder ,beheld);
public static event Action<Mobile, Mobile> ProfileRequest;
public static void InvokeProfileRequest(Mobile beholder, Mobile beheld) => ProfileRequest?.Invoke(beholder, beheld);
public static event Action<Mobile, Mobile, string> ChangeProfileRequest;
public static void InvokeChangeProfileRequest(Mobile beholder, Mobile beheld, string text) =>
ChangeProfileRequest?.Invoke(beholder, beheld, text);
public static event Action<NetState, int> DeleteRequest;
public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index);
public static event Action WorldLoad;
public static void InvokeWorldLoad() => WorldLoad?.Invoke();
public static event Action<bool> WorldSave;
public static void InvokeWorldSave(bool sendMessage) => WorldSave?.Invoke(sendMessage);
public static event Action<Mobile, int> SetAbility;
public static void InvokeSetAbility(Mobile mobile, int index) => SetAbility?.Invoke(mobile, index);
public static event Action ServerStarted;
public static void InvokeServerStarted() => ServerStarted?.Invoke();
public static event Action<Mobile> GuildGumpRequest;
public static void InvokeGuildGumpRequest(Mobile m) => GuildGumpRequest?.Invoke(m);
public static event Action<Mobile> QuestGumpRequest;
public static void InvokeQuestGumpRequest(Mobile m) => QuestGumpRequest?.Invoke(m);
public static event Action<NetState, ClientVersion> ClientVersionReceived;
public static void InvokeClientVersionReceived(NetState state, ClientVersion cv) => ClientVersionReceived?.Invoke(state, cv);
public static event Action<Mobile, List<Serial>> EquipMacro;
public static void InvokeEquipMacro(Mobile m, List<Serial> list)
{
if (list?.Count > 0)
EquipMacro?.Invoke(m, list);
}
public static event Action<Mobile, List<Layer>> UnequipMacro;
public static void InvokeUnequipMacro(Mobile m, List<Layer> layers)
{
if (layers?.Count > 0)
UnequipMacro?.Invoke(m, layers);
}
public static event Action<Mobile, IEntity, int> TargetedSpell;
public static void InvokeTargetedSpell(Mobile m, IEntity target, int spellId) => TargetedSpell?.Invoke(m, target, spellId);
public static event Action<Mobile, IEntity, int> TargetedSkillUse;
public static void InvokeTargetedSkillUse(Mobile m, IEntity target, int skillId) => TargetedSkillUse?.Invoke(m, target, skillId);
public static event Action<Mobile, Item, short> TargetByResourceMacro;
public static void InvokeTargetByResourceMacro(Mobile m, Item item, short resourceType) => TargetByResourceMacro?.Invoke(m, item, resourceType);
}
}

View file

@ -0,0 +1,45 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: FastWalkEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Network;
namespace Server
{
public class FastWalkEventArgs : EventArgs
{
public FastWalkEventArgs(NetState state)
{
NetState = state;
Blocked = false;
}
public NetState NetState{ get; }
public bool Blocked{ get; set; }
}
public static partial class EventSink
{
public static event Action<FastWalkEventArgs> FastWalk;
public static void InvokeFastWalk(FastWalkEventArgs e) => FastWalk?.Invoke(e);
}
}

View file

@ -0,0 +1,52 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: GameLoginEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Server.Network;
namespace Server
{
public class GameLoginEventArgs : EventArgs
{
public GameLoginEventArgs(NetState state, string un, string pw)
{
State = state;
Username = un;
Password = pw;
}
public NetState State{ get; }
public string Username{ get; }
public string Password{ get; }
public bool Accepted{ get; set; }
public CityInfo[] CityInfo{ get; set; }
}
public static partial class EventSink
{
public static event Action<GameLoginEventArgs> GameLogin;
public static void InvokeGameLogin(GameLoginEventArgs e) => GameLogin?.Invoke(e);
}
}

View file

@ -0,0 +1,74 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MovementEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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;
namespace Server
{
public class MovementEventArgs : EventArgs
{
private static Queue<MovementEventArgs> m_Pool = new Queue<MovementEventArgs>();
public MovementEventArgs(Mobile mobile, Direction dir)
{
Mobile = mobile;
Direction = dir;
}
public Mobile Mobile{ get; private set; }
public Direction Direction{ get; private set; }
public bool Blocked{ get; set; }
public static MovementEventArgs Create(Mobile mobile, Direction dir)
{
MovementEventArgs args;
if (m_Pool.Count > 0)
{
args = m_Pool.Dequeue();
args.Mobile = mobile;
args.Direction = dir;
args.Blocked = false;
}
else
{
args = new MovementEventArgs(mobile, dir);
}
return args;
}
public void Free()
{
m_Pool.Enqueue(this);
}
}
public static partial class EventSink
{
public static event Action<MovementEventArgs> Movement;
public static void InvokeMovement(MovementEventArgs e) => Movement?.Invoke(e);
}
}

View file

@ -0,0 +1,40 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerCrashedEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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;
namespace Server
{
public class ServerCrashedEventArgs : EventArgs
{
public ServerCrashedEventArgs(Exception e) => Exception = e;
public Exception Exception{ get; }
public bool Close{ get; set; }
}
public static partial class EventSink
{
public static event Action<ServerCrashedEventArgs> ServerCrashed;
public static void InvokeServerCrashed(ServerCrashedEventArgs e) => ServerCrashed?.Invoke(e);
}
}

View file

@ -0,0 +1,63 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerListEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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.Net;
using Server.Accounting;
using Server.Network;
namespace Server
{
public class ServerListEventArgs : EventArgs
{
public ServerListEventArgs(NetState state, IAccount account)
{
State = state;
Account = account;
Servers = new List<ServerInfo>();
}
public NetState State{ get; }
public IAccount Account{ get; }
public bool Rejected{ get; set; }
public List<ServerInfo> Servers{ get; }
public void AddServer(string name, IPEndPoint address)
{
AddServer(name, 0, TimeZoneInfo.Local, address);
}
public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address)
{
Servers.Add(new ServerInfo(name, fullPercent, tz, address));
}
}
public static partial class EventSink
{
public static event Action<ServerListEventArgs> ServerList;
public static void InvokeServerList(ServerListEventArgs e) => ServerList?.Invoke(e);
}
}

View file

@ -0,0 +1,45 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: SocketConnectionEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 Microsoft.AspNetCore.Connections;
namespace Server
{
public class SocketConnectEventArgs : EventArgs
{
public SocketConnectEventArgs(ConnectionContext c)
{
Context = c;
AllowConnection = true;
}
public ConnectionContext Context{ get; }
public bool AllowConnection{ get; set; }
}
public static partial class EventSink
{
public static event Action<SocketConnectEventArgs> SocketConnect;
public static void InvokeSocketConnect(SocketConnectEventArgs e) => SocketConnect?.Invoke(e);
}
}

View file

@ -0,0 +1,46 @@
using System;
using Server.Network;
namespace Server
{
public class SpeechEventArgs : EventArgs
{
public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords)
{
Mobile = mobile;
Speech = speech;
Type = type;
Hue = hue;
Keywords = keywords;
}
public Mobile Mobile{ get; }
public string Speech{ get; set; }
public MessageType Type{ get; }
public int Hue{ get; }
public int[] Keywords{ get; }
public bool Handled{ get; set; }
public bool Blocked{ get; set; }
public bool HasKeyword(int keyword)
{
for (int i = 0; i < Keywords.Length; ++i)
if (Keywords[i] == keyword)
return true;
return false;
}
}
public static partial class EventSink
{
public static event Action<SpeechEventArgs> Speech;
public static void InvokeSpeech(SpeechEventArgs e) => Speech?.Invoke(e);
}
}

View file

@ -251,9 +251,9 @@ namespace Server
try try
{ {
CrashedEventArgs args = new CrashedEventArgs(e.ExceptionObject as Exception); ServerCrashedEventArgs args = new ServerCrashedEventArgs(e.ExceptionObject as Exception);
EventSink.InvokeCrashed(args); EventSink.InvokeServerCrashed(args);
close = args.Close; close = args.Close;
} }
@ -318,7 +318,7 @@ namespace Server
World.WaitForWriteCompletion(); World.WaitForWriteCompletion();
if (!m_Crashed) if (!m_Crashed)
EventSink.InvokeShutdown(new ShutdownEventArgs()); EventSink.InvokeShutdown();
Timer.TimerThread.Set(); Timer.TimerThread.Set();

View file

@ -707,7 +707,7 @@ namespace Server
{ {
m_Hunger = value; m_Hunger = value;
EventSink.InvokeHungerChanged(new HungerChangedEventArgs(this, oldValue)); EventSink.InvokeHungerChanged(this, oldValue);
} }
} }
} }
@ -1461,7 +1461,7 @@ namespace Server
if (m_NetState == null) if (m_NetState == null)
{ {
OnDisconnected(); OnDisconnected();
EventSink.InvokeDisconnected(new DisconnectedEventArgs(this)); EventSink.InvokeDisconnected(this);
// Disconnected, start the logout timer // Disconnected, start the logout timer
@ -1476,7 +1476,7 @@ namespace Server
else else
{ {
OnConnected(); OnConnected();
EventSink.InvokeConnected(new ConnectedEventArgs(this)); EventSink.InvokeConnected(this);
// Connected, stop the logout timer and if needed, move to the world // Connected, stop the logout timer and if needed, move to the world
@ -1818,16 +1818,7 @@ namespace Server
public virtual bool KeepsItemsOnDeath => m_AccessLevel > AccessLevel.Player; public virtual bool KeepsItemsOnDeath => m_AccessLevel > AccessLevel.Player;
public bool HasTrade public bool HasTrade => m_NetState?.Trades.Count > 0;
{
get
{
if (m_NetState != null)
return m_NetState.Trades.Count > 0;
return false;
}
}
public bool NoMoveHS{ get; set; } public bool NoMoveHS{ get; set; }
@ -4394,7 +4385,7 @@ namespace Server
Stam = 0; Stam = 0;
Mana = 0; Mana = 0;
EventSink.InvokePlayerDeath(new PlayerDeathEventArgs(this)); EventSink.InvokePlayerDeath(this);
ProcessDeltaQueue(); ProcessDeltaQueue();
@ -6456,10 +6447,10 @@ namespace Server
return false; return false;
return this == m || m.m_Map == m_Map && return this == m || m.m_Map == m_Map &&
(!m.Hidden || m_AccessLevel != AccessLevel.Player && (!m.Hidden || m_AccessLevel != AccessLevel.Player &&
(m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) && (m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) &&
(m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive || (m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive ||
m_AccessLevel > AccessLevel.Player || m.Warmode); m_AccessLevel > AccessLevel.Player || m.Warmode);
} }
public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel;
@ -7069,7 +7060,7 @@ namespace Server
public virtual void DisplayPaperdollTo(Mobile to) public virtual void DisplayPaperdollTo(Mobile to)
{ {
EventSink.InvokePaperdollRequest(new PaperdollRequestEventArgs(to, this)); EventSink.InvokePaperdollRequest(to, this);
} }
/// <summary> /// <summary>
@ -7548,7 +7539,7 @@ namespace Server
{ {
if (m_Mobile.m_Map != Map.Internal) if (m_Mobile.m_Map != Map.Internal)
{ {
EventSink.InvokeLogout(new LogoutEventArgs(m_Mobile)); EventSink.InvokeLogout(m_Mobile);
m_Mobile.LogoutLocation = m_Mobile.m_Location; m_Mobile.LogoutLocation = m_Mobile.m_Location;
m_Mobile.LogoutMap = m_Mobile.m_Map; m_Mobile.LogoutMap = m_Mobile.m_Map;
@ -7725,8 +7716,8 @@ namespace Server
m_Callback(from, ""); m_Callback(from, "");
else else
m_CancelCallback?.Invoke(@from, ""); m_CancelCallback?.Invoke(@from, "");
}
} }
}
public Prompt BeginPrompt(PromptCallback callback, PromptCallback cancelCallback) public Prompt BeginPrompt(PromptCallback callback, PromptCallback cancelCallback)
{ {

View file

@ -19,91 +19,203 @@
***************************************************************************/ ***************************************************************************/
using System; using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO; using System.IO;
using Server.Network;
namespace Server namespace Server
{ {
public static class MultiData public static class MultiData
{ {
private static readonly MultiComponentList[] m_Components; public static Dictionary<int, MultiComponentList> Components { get; } = new Dictionary<int, MultiComponentList>();
private static readonly FileStream m_Index;
private static readonly FileStream m_Stream;
private static readonly BinaryReader m_IndexReader; private static readonly BinaryReader m_IndexReader;
private static readonly BinaryReader m_StreamReader; private static readonly BinaryReader m_StreamReader;
private static readonly bool UsingUOPFormat;
static MultiData() static MultiData()
{ {
string multiUOPPath = Core.FindDataFile("MultiCollection.uop");
if (File.Exists(multiUOPPath))
{
LoadUOP(multiUOPPath);
UsingUOPFormat = true;
return;
}
string idxPath = Core.FindDataFile("multi.idx"); string idxPath = Core.FindDataFile("multi.idx");
string mulPath = Core.FindDataFile("multi.mul"); string mulPath = Core.FindDataFile("multi.mul");
if (File.Exists(idxPath) && File.Exists(mulPath)) if (File.Exists(idxPath) && File.Exists(mulPath))
{ {
m_Index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read); var idx = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_IndexReader = new BinaryReader(m_Index); m_IndexReader = new BinaryReader(idx);
m_Stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read); var stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_StreamReader = new BinaryReader(m_Stream); m_StreamReader = new BinaryReader(stream);
m_Components = new MultiComponentList[(int)(m_Index.Length / 12)];
string vdPath = Core.FindDataFile("verdata.mul"); string vdPath = Core.FindDataFile("verdata.mul");
if (File.Exists(vdPath)) if (!File.Exists(vdPath)) return;
using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader bin = new BinaryReader(fs);
int count = bin.ReadInt32();
for (int i = 0; i < count; ++i)
{ {
using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read); int file = bin.ReadInt32();
BinaryReader bin = new BinaryReader(fs); int index = bin.ReadInt32();
int lookup = bin.ReadInt32();
int length = bin.ReadInt32();
bin.ReadInt32(); // extra
int count = bin.ReadInt32(); if (file == 14 && index >= 0 && lookup >= 0 && length > 0)
for (int i = 0; i < count; ++i)
{ {
int file = bin.ReadInt32(); bin.BaseStream.Seek(lookup, SeekOrigin.Begin);
int index = bin.ReadInt32();
int lookup = bin.ReadInt32();
int length = bin.ReadInt32();
int extra = bin.ReadInt32();
if (file == 14 && index >= 0 && index < m_Components.Length && lookup >= 0 && length > 0) Components[index] = new MultiComponentList(bin, length / 12);
{
bin.BaseStream.Seek(lookup, SeekOrigin.Begin);
m_Components[index] = new MultiComponentList(bin, length / 12); bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin);
bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin);
}
} }
bin.Close();
} }
bin.Close();
} }
else else
{
Console.WriteLine("Warning: Multi data files not found"); Console.WriteLine("Warning: Multi data files not found");
m_Components = new MultiComponentList[0];
}
} }
public static MultiComponentList GetComponents(int multiID) public static MultiComponentList GetComponents(int multiID)
{ {
MultiComponentList mcl; MultiComponentList mcl;
if (multiID >= 0 && multiID < m_Components.Length) multiID &= 0x3FFF;
{
mcl = m_Components[multiID];
if (mcl == null) if (Components.ContainsKey(multiID))
m_Components[multiID] = mcl = Load(multiID); mcl = Components[multiID];
} else if (!UsingUOPFormat)
Components[multiID] = mcl = Load(multiID);
else else
{
mcl = MultiComponentList.Empty; mcl = MultiComponentList.Empty;
}
return mcl; return mcl;
} }
public static void LoadUOP(string path)
{
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader streamReader = new BinaryReader(stream);
// Head Information Start
if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files
return;
if (streamReader.ReadInt32() > 5) // Bad Version
return;
// Multi ID List Array Start
UOPHash.BuildChunkIDs(out var chunkIds);
// Multi ID List Array End
streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43
long startAddress = streamReader.ReadInt64();
streamReader.ReadInt32();
streamReader.ReadInt32();
stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End
long nextBlock;
do
{
int blockFileCount = streamReader.ReadInt32();
nextBlock = streamReader.ReadInt64();
int index = 0;
do
{
long offset = streamReader.ReadInt64();
int headerSize = streamReader.ReadInt32(); // header length
int compressedSize = streamReader.ReadInt32(); // compressed size
int decompressedSize = streamReader.ReadInt32(); // decompressed size
ulong filehash = streamReader.ReadUInt64(); // filename hash (HashLittle2)
streamReader.ReadUInt32();
short compressionMethod = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib)
index++;
if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin
continue;
chunkIds.TryGetValue(filehash, out var chunkID);
long position = stream.Position; // save current position
stream.Seek(offset + headerSize, SeekOrigin.Begin);
Span<byte> sourceData = new byte[compressedSize];
if (stream.Read(sourceData) != compressedSize)
continue;
Span<byte> data;
if (compressionMethod == 1)
{
data = new byte[decompressedSize];
Compression.Unpack(data, ref decompressedSize, sourceData, compressedSize);
}
else
data = sourceData;
var tileList = new List<MultiTileEntry>();
// Skip the first 4 bytes
BufferReader<byte> reader = new BufferReader<byte>(data);
reader.Advance(4); // ???
reader.TryReadLittleEndian(out uint count);
for (uint i = 0; i < count; i++)
{
reader.TryReadLittleEndian(out ushort itemid);
reader.TryReadLittleEndian(out short x);
reader.TryReadLittleEndian(out short y);
reader.TryReadLittleEndian(out short z);
reader.TryReadLittleEndian(out ushort flagValue);
TileFlag tileFlag = flagValue switch
{
1 => TileFlag.None,
257 => TileFlag.Generic,
_ => TileFlag.Background // 0
};
reader.TryReadLittleEndian(out uint clilocsCount);
reader.Advance(clilocsCount * 4); // bypass binary block
tileList.Add(new MultiTileEntry(itemid, x, y, z, tileFlag));
}
Components[chunkID] = new MultiComponentList(tileList);
stream.Seek(position, SeekOrigin.Begin); // back to position
}
while (index < blockFileCount);
}
while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0);
}
// TODO: Change this to read the file all during load time
public static MultiComponentList Load(int multiID) public static MultiComponentList Load(int multiID)
{ {
try try
@ -131,9 +243,9 @@ namespace Server
{ {
public ushort m_ItemID; public ushort m_ItemID;
public short m_OffsetX, m_OffsetY, m_OffsetZ; public short m_OffsetX, m_OffsetY, m_OffsetZ;
public int m_Flags; public TileFlag m_Flags;
public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, int flags) public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, TileFlag flags)
{ {
m_ItemID = itemID; m_ItemID = itemID;
m_OffsetX = xOffset; m_OffsetX = xOffset;
@ -205,7 +317,7 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadShort(); allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort(); allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort(); allTiles[i].m_OffsetZ = reader.ReadShort();
allTiles[i].m_Flags = reader.ReadInt(); allTiles[i].m_Flags = (TileFlag)reader.ReadInt();
} }
else else
for (int i = 0; i < length; ++i) for (int i = 0; i < length; ++i)
@ -214,7 +326,7 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadShort(); allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort(); allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort(); allTiles[i].m_OffsetZ = reader.ReadShort();
allTiles[i].m_Flags = reader.ReadInt(); allTiles[i].m_Flags = (TileFlag)reader.ReadInt();
} }
TileList[][] tiles = new TileList[Width][]; TileList[][] tiles = new TileList[Width][];
@ -253,10 +365,11 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadInt16(); allTiles[i].m_OffsetX = reader.ReadInt16();
allTiles[i].m_OffsetY = reader.ReadInt16(); allTiles[i].m_OffsetY = reader.ReadInt16();
allTiles[i].m_OffsetZ = reader.ReadInt16(); allTiles[i].m_OffsetZ = reader.ReadInt16();
allTiles[i].m_Flags = reader.ReadInt32();
if (PostHSFormat) if (PostHSFormat)
reader.ReadInt32(); // ?? allTiles[i].m_Flags = (TileFlag)reader.ReadUInt64();
else
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt32();
MultiTileEntry e = allTiles[i]; MultiTileEntry e = allTiles[i];
@ -306,6 +419,63 @@ namespace Server
Tiles[x][y] = tiles[x][y].ToArray(); Tiles[x][y] = tiles[x][y].ToArray();
} }
public MultiComponentList(List<MultiTileEntry> list)
{
var allTiles = List = new MultiTileEntry[list.Count];
for (int i = 0; i < list.Count; ++i)
{
allTiles[i].m_ItemID = list[i].m_ItemID;
allTiles[i].m_OffsetX = list[i].m_OffsetX;
allTiles[i].m_OffsetY = list[i].m_OffsetY;
allTiles[i].m_OffsetZ = list[i].m_OffsetZ;
allTiles[i].m_Flags = list[i].m_Flags;
MultiTileEntry e = allTiles[i];
if (i == 0 || e.m_Flags != 0)
{
if (e.m_OffsetX < m_Min.m_X) m_Min.m_X = e.m_OffsetX;
if (e.m_OffsetY < m_Min.m_Y) m_Min.m_Y = e.m_OffsetY;
if (e.m_OffsetX > m_Max.m_X) m_Max.m_X = e.m_OffsetX;
if (e.m_OffsetY > m_Max.m_Y) m_Max.m_Y = e.m_OffsetY;
}
}
Center = new Point2D(-m_Min.m_X, -m_Min.m_Y);
Width = (m_Max.m_X - m_Min.m_X) + 1;
Height = (m_Max.m_Y - m_Min.m_Y) + 1;
var tiles = new TileList[Width][];
Tiles = new StaticTile[Width][][];
for (int x = 0; x < Width; ++x)
{
tiles[x] = new TileList[Height];
Tiles[x] = new StaticTile[Height][];
for (int y = 0; y < Height; ++y) tiles[x][y] = new TileList();
}
for (int i = 0; i < allTiles.Length; ++i)
if (i == 0 || allTiles[i].m_Flags != 0)
{
int xOffset = allTiles[i].m_OffsetX + Center.m_X;
int yOffset = allTiles[i].m_OffsetY + Center.m_Y;
int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000);
tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ);
}
for (int x = 0; x < Width; ++x)
for (int y = 0; y < Height; ++y)
Tiles[x][y] = tiles[x][y].ToArray();
}
private MultiComponentList() private MultiComponentList()
{ {
Tiles = new StaticTile[0][][]; Tiles = new StaticTile[0][][];
@ -368,7 +538,7 @@ namespace Server
for (int i = 0; i < oldList.Length; ++i) for (int i = 0; i < oldList.Length; ++i)
newList[i] = oldList[i]; newList[i] = oldList[i];
newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, 1); newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, TileFlag.Background);
List = newList; List = newList;
@ -552,7 +722,7 @@ namespace Server
if (vy > m_Max.m_Y) if (vy > m_Max.m_Y)
m_Max.m_Y = vy; m_Max.m_Y = vy;
List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, 1); List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, TileFlag.Background);
} }
} }
} }
@ -578,8 +748,86 @@ namespace Server
writer.Write(ent.m_OffsetX); writer.Write(ent.m_OffsetX);
writer.Write(ent.m_OffsetY); writer.Write(ent.m_OffsetY);
writer.Write(ent.m_OffsetZ); writer.Write(ent.m_OffsetZ);
writer.Write(ent.m_Flags); writer.Write((int)ent.m_Flags);
} }
} }
} }
}
public static class UOPHash
{
public static void BuildChunkIDs(out Dictionary<ulong, int> chunkIds)
{
const int maxId = 0x10000;
chunkIds = new Dictionary<ulong, int>();
for (int i = 0; i < maxId; ++i)
chunkIds[HashLittle2($"build/multicollection/{i:000000}.bin")] = i;
}
private static ulong HashLittle2(string s)
{
int length = s.Length;
uint b, c;
uint a = b = c = 0xDEADBEEF + (uint)length;
int k = 0;
while (length > 12)
{
a += s[k];
a += (uint)s[k + 1] << 8;
a += (uint)s[k + 2] << 16;
a += (uint)s[k + 3] << 24;
b += s[k + 4];
b += (uint)s[k + 5] << 8;
b += (uint)s[k + 6] << 16;
b += (uint)s[k + 7] << 24;
c += s[k + 8];
c += (uint)s[k + 9] << 8;
c += (uint)s[k + 10] << 16;
c += (uint)s[k + 11] << 24;
a -= c; a ^= (c << 4) | (c >> 28); c += b;
b -= a; b ^= (a << 6) | (a >> 26); a += c;
c -= b; c ^= (b << 8) | (b >> 24); b += a;
a -= c; a ^= (c << 16) | (c >> 16); c += b;
b -= a; b ^= (a << 19) | (a >> 13); a += c;
c -= b; c ^= (b << 4) | (b >> 28); b += a;
length -= 12;
k += 12;
}
if (length != 0)
{
switch (length)
{
case 12: c += (uint)s[k + 11] << 24; goto case 11;
case 11: c += (uint)s[k + 10] << 16; goto case 10;
case 10: c += (uint)s[k + 9] << 8; goto case 9;
case 9: c += s[k + 8]; goto case 8;
case 8: b += (uint)s[k + 7] << 24; goto case 7;
case 7: b += (uint)s[k + 6] << 16; goto case 6;
case 6: b += (uint)s[k + 5] << 8; goto case 5;
case 5: b += s[k + 4]; goto case 4;
case 4: a += (uint)s[k + 3] << 24; goto case 3;
case 3: a += (uint)s[k + 2] << 16; goto case 2;
case 2: a += (uint)s[k + 1] << 8; goto case 1;
case 1: a += s[k]; break;
}
c ^= b; c -= (b << 14) | (b >> 18);
a ^= c; a -= (c << 11) | (c >> 21);
b ^= a; b -= (a << 25) | (a >> 7);
c ^= b; c -= (b << 16) | (b >> 16);
a ^= c; a -= (c << 4) | (c >> 28);
b ^= a; b -= (a << 14) | (a >> 18);
c ^= b; c -= (b << 24) | (b >> 8);
}
return ((ulong)b << 32) | c;
}
}
}

View file

@ -1,23 +1,23 @@
/*************************************************************************
/*************************************************************************** * ModernUO *
* MessagePump.cs * Copyright (C) 2019 - ModernUO Development Team *
* ------------------- * Email: hi@modernuo.com *
* begin : May 1, 2002 * File: MessagePumpService.cs *
* copyright : (C) The RunUO Software Team * Created: 2020/04/12 - Updated: 2020/04/12 *
* email : info@runuo.com * *
* * This program is free software: you can redistribute it and/or modify *
* $Id$ * 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. *
* *
/*************************************************************************** * This program is distributed in the hope that it will be useful, *
* * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* This program is free software; you can redistribute it and/or modify * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* it under the terms of the GNU General Public License as published by * GNU General Public License for more details. *
* the Free Software Foundation; either version 2 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.Buffers; using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;

View file

@ -285,7 +285,6 @@ namespace Server.Network
public static int MenuCap { get; set; } = 512; public static int MenuCap { get; set; } = 512;
public void WriteConsole(string text) public void WriteConsole(string text)
{ {
Console.WriteLine("Client: {0}: {1}", this, text); Console.WriteLine("Client: {0}: {1}", this, text);
@ -395,8 +394,8 @@ namespace Server.Network
public IAccount Account { get; set; } public IAccount Account { get; set; }
public override string ToString() => m_ToString; public override string ToString() => m_ToString;
public NetState(ConnectionContext connection) public NetState(ConnectionContext connection)
{ {
Connection = connection; Connection = connection;
Seeded = false; Seeded = false;

View file

@ -157,6 +157,8 @@ namespace Server.Network
Register(0xD7, 0, true, EncodedCommand); Register(0xD7, 0, true, EncodedCommand);
Register(0xE1, 0, false, ClientType); Register(0xE1, 0, false, ClientType);
Register(0xEF, 21, false, LoginServerSeed); Register(0xEF, 21, false, LoginServerSeed);
Register(0xEC, 0, false, EquipMacro);
Register(0xED, 0, false, UnequipMacro);
Register(0xF4, 0, false, CrashReport); Register(0xF4, 0, false, CrashReport);
Register(0xF8, 106, false, CreateCharacter70160); Register(0xF8, 106, false, CreateCharacter70160);
Register(0xFB, 2, false, ShowPublicHouseContent); Register(0xFB, 2, false, ShowPublicHouseContent);
@ -179,6 +181,9 @@ namespace Server.Network
RegisterExtended(0x1C, true, CastSpell); RegisterExtended(0x1C, true, CastSpell);
RegisterExtended(0x24, false, UnhandledBF); RegisterExtended(0x24, false, UnhandledBF);
RegisterExtended(0x2C, true, BandageTarget); RegisterExtended(0x2C, true, BandageTarget);
RegisterExtended(0x2D, true, TargetedSpell);
RegisterExtended(0x2E, true, TargetedSkillUse);
RegisterExtended(0x30, true, TargetByResourceMacro);
RegisterExtended(0x32, true, ToggleFlying); RegisterExtended(0x32, true, ToggleFlying);
RegisterEncoded(0x19, true, SetAbility); RegisterEncoded(0x19, true, SetAbility);
@ -289,6 +294,8 @@ namespace Server.Network
return -1; return -1;
} }
Console.WriteLine("Processing Packet... {0:X}", packetId);
if (!ns.Seeded) if (!ns.Seeded)
{ {
if (packetId == 0xEF) if (packetId == 0xEF)
@ -381,17 +388,17 @@ namespace Server.Network
public static void SetAbility(NetState state, IEntity e, EncodedReader reader) public static void SetAbility(NetState state, IEntity e, EncodedReader reader)
{ {
EventSink.InvokeSetAbility(new SetAbilityEventArgs(state.Mobile, reader.ReadInt32())); EventSink.InvokeSetAbility(state.Mobile, reader.ReadInt32());
} }
public static void GuildGumpRequest(NetState state, IEntity e, EncodedReader reader) public static void GuildGumpRequest(NetState state, IEntity e, EncodedReader reader)
{ {
EventSink.InvokeGuildGumpRequest(new GuildGumpRequestArgs(state.Mobile)); EventSink.InvokeGuildGumpRequest(state.Mobile);
} }
public static void QuestGumpRequest(NetState state, IEntity e, EncodedReader reader) public static void QuestGumpRequest(NetState state, IEntity e, EncodedReader reader)
{ {
EventSink.InvokeQuestGumpRequest(new QuestGumpRequestArgs(state.Mobile)); EventSink.InvokeQuestGumpRequest(state.Mobile);
} }
public static void EncodedCommand(NetState state, PacketReader pvSrc) public static void EncodedCommand(NetState state, PacketReader pvSrc)
@ -431,12 +438,12 @@ namespace Server.Network
Mobile targ = World.FindMobile(pvSrc.ReadUInt32()); Mobile targ = World.FindMobile(pvSrc.ReadUInt32());
if (targ != null) if (targ != null)
EventSink.InvokeRenameRequest(new RenameRequestEventArgs(from, targ, pvSrc.ReadStringSafe())); EventSink.InvokeRenameRequest(from, targ, pvSrc.ReadStringSafe());
} }
public static void ChatRequest(NetState state, PacketReader pvSrc) public static void ChatRequest(NetState state, PacketReader pvSrc)
{ {
EventSink.InvokeChatRequest(new ChatRequestEventArgs(state.Mobile)); EventSink.InvokeChatRequest(state.Mobile);
} }
public static void SecureTrade(NetState state, PacketReader pvSrc) public static void SecureTrade(NetState state, PacketReader pvSrc)
@ -591,7 +598,7 @@ namespace Server.Network
pvSrc.Seek(30, SeekOrigin.Current); pvSrc.Seek(30, SeekOrigin.Current);
int index = pvSrc.ReadInt32(); int index = pvSrc.ReadInt32();
EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index)); EventSink.InvokeDeleteRequest(state, index);
} }
public static void DeathStatusResponse(NetState state, PacketReader pvSrc) public static void DeathStatusResponse(NetState state, PacketReader pvSrc)
@ -697,7 +704,7 @@ namespace Server.Network
{ {
case 0xC7: // Animate case 0xC7: // Animate
{ {
EventSink.InvokeAnimateRequest(new AnimateRequestEventArgs(m, command)); EventSink.InvokeAnimateRequest(m, command);
break; break;
} }
@ -715,7 +722,7 @@ namespace Server.Network
if (!int.TryParse(command, out int booktype)) if (!int.TryParse(command, out int booktype))
booktype = 1; booktype = 1;
EventSink.InvokeOpenSpellbookRequest(new OpenSpellbookRequestEventArgs(m, booktype)); EventSink.InvokeOpenSpellbookRequest(m, booktype);
break; break;
} }
@ -728,14 +735,14 @@ namespace Server.Network
int spellID = Utility.ToInt32(split[0]) - 1; int spellID = Utility.ToInt32(split[0]) - 1;
uint serial = split.Length > 1 ? Utility.ToUInt32(split[1]) : (uint)Serial.MinusOne; uint serial = split.Length > 1 ? Utility.ToUInt32(split[1]) : (uint)Serial.MinusOne;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, World.FindItem(serial))); EventSink.InvokeCastSpellRequest(m, spellID, World.FindItem(serial));
} }
break; break;
} }
case 0x58: // Open door case 0x58: // Open door
{ {
EventSink.InvokeOpenDoorMacroUsed(new OpenDoorMacroEventArgs(m)); EventSink.InvokeOpenDoorMacroUsed(m);
break; break;
} }
@ -743,7 +750,7 @@ namespace Server.Network
{ {
int spellID = Utility.ToInt32(command) - 1; int spellID = Utility.ToInt32(command) - 1;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, null)); EventSink.InvokeCastSpellRequest(m, spellID, null);
break; break;
} }
@ -751,7 +758,7 @@ namespace Server.Network
{ {
int virtueID = Utility.ToInt32(command) - 1; int virtueID = Utility.ToInt32(command) - 1;
EventSink.InvokeVirtueMacroRequest(new VirtueMacroRequestEventArgs(m, virtueID)); EventSink.InvokeVirtueMacroRequest(m, virtueID);
break; break;
} }
@ -863,7 +870,7 @@ namespace Server.Network
{ {
case 0x00: // display request case 0x00: // display request
{ {
EventSink.InvokeProfileRequest(new ProfileRequestEventArgs(beholder, beheld)); EventSink.InvokeProfileRequest(beholder, beheld);
break; break;
} }
@ -877,7 +884,7 @@ namespace Server.Network
string text = pvSrc.ReadUnicodeString(length); string text = pvSrc.ReadUnicodeString(length);
EventSink.InvokeChangeProfileRequest(new ChangeProfileRequestEventArgs(beholder, beheld, text)); EventSink.InvokeChangeProfileRequest(beholder, beheld, text);
break; break;
} }
@ -1011,7 +1018,7 @@ namespace Server.Network
public static void HelpRequest(NetState state, PacketReader pvSrc) public static void HelpRequest(NetState state, PacketReader pvSrc)
{ {
EventSink.InvokeHelpRequest(new HelpRequestEventArgs(state.Mobile)); EventSink.InvokeHelpRequest(state.Mobile);
} }
public static void TargetResponse(NetState state, PacketReader pvSrc) public static void TargetResponse(NetState state, PacketReader pvSrc)
@ -1216,14 +1223,14 @@ namespace Server.Network
Mobile beheld = World.FindMobile(pvSrc.ReadUInt32()); Mobile beheld = World.FindMobile(pvSrc.ReadUInt32());
if (beheld != null) if (beheld != null)
EventSink.InvokeVirtueGumpRequest(new VirtueGumpRequestEventArgs(state.Mobile, beheld)); EventSink.InvokeVirtueGumpRequest(state.Mobile, beheld);
} }
else else
{ {
Mobile beheld = World.FindMobile(serial); Mobile beheld = World.FindMobile(serial);
if (beheld != null) if (beheld != null)
EventSink.InvokeVirtueItemRequest(new VirtueItemRequestEventArgs(state.Mobile, beheld, buttonID)); EventSink.InvokeVirtueItemRequest(state.Mobile, beheld, buttonID);
} }
} }
} }
@ -1513,7 +1520,7 @@ namespace Server.Network
int spellID = pvSrc.ReadInt16() - 1; int spellID = pvSrc.ReadInt16() - 1;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(from, spellID, spellbook)); EventSink.InvokeCastSpellRequest(from, spellID, spellbook);
} }
public static void BandageTarget(NetState state, PacketReader pvSrc) public static void BandageTarget(NetState state, PacketReader pvSrc)
@ -1535,7 +1542,7 @@ namespace Server.Network
if (target == null) if (target == null)
return; return;
EventSink.InvokeBandageTargetRequest(new BandageTargetRequestEventArgs(from, bandage, target)); EventSink.InvokeBandageTargetRequest(from, bandage, target);
from.NextActionTime = Core.TickCount + Mobile.ActionDelay; from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
} }
@ -1691,12 +1698,12 @@ namespace Server.Network
public static void StunRequest(NetState state, PacketReader pvSrc) public static void StunRequest(NetState state, PacketReader pvSrc)
{ {
EventSink.InvokeStunRequest(new StunRequestEventArgs(state.Mobile)); EventSink.InvokeStunRequest(state.Mobile);
} }
public static void DisarmRequest(NetState state, PacketReader pvSrc) public static void DisarmRequest(NetState state, PacketReader pvSrc)
{ {
EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(state.Mobile)); EventSink.InvokeDisarmRequest(state.Mobile);
} }
public static void StatLockChange(NetState state, PacketReader pvSrc) public static void StatLockChange(NetState state, PacketReader pvSrc)
@ -1828,7 +1835,7 @@ namespace Server.Network
{ {
CV version = state.Version = new CV(pvSrc.ReadString()); CV version = state.Version = new CV(pvSrc.ReadString());
EventSink.InvokeClientVersionReceived(new ClientVersionReceivedArgs(state, version)); EventSink.InvokeClientVersionReceived(state, version);
} }
public static void ClientType(NetState state, PacketReader pvSrc) public static void ClientType(NetState state, PacketReader pvSrc)
@ -1838,7 +1845,7 @@ namespace Server.Network
int type = pvSrc.ReadUInt16(); int type = pvSrc.ReadUInt16();
CV version = state.Version = new CV(pvSrc.ReadString()); CV version = state.Version = new CV(pvSrc.ReadString());
//EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) );//todo EventSink.InvokeClientVersionReceived(state, version);
} }
public static void MobileQuery(NetState state, PacketReader pvSrc) public static void MobileQuery(NetState state, PacketReader pvSrc)
@ -2025,7 +2032,7 @@ namespace Server.Network
state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
state.Send(new MapChange(m)); state.Send(new MapChange(m));
EventSink.InvokeLogin(new LoginEventArgs(m)); EventSink.InvokeLogin(m);
m.ClearFastwalkStack(); m.ClearFastwalkStack();
} }
@ -2493,6 +2500,47 @@ namespace Server.Network
state.Dispose(); state.Dispose();
} }
public static void EquipMacro(NetState ns, PacketReader pvSrc)
{
int count = pvSrc.ReadByte();
List<Serial> serialList = new List<Serial>(count);
for (int i = 0; i < count; ++i)
serialList.Add(pvSrc.ReadUInt32());
EventSink.InvokeEquipMacro(ns.Mobile, serialList);
}
public static void UnequipMacro(NetState ns, PacketReader pvSrc)
{
int count = pvSrc.ReadByte();
List<Layer> layers = new List<Layer>(count);
for (int i = 0; i < count; ++i)
layers.Add((Layer)pvSrc.ReadUInt16());
EventSink.InvokeUnequipMacro(ns.Mobile, layers);
}
public static void TargetedSpell(NetState ns, PacketReader pvSrc)
{
short spellId = (short)(pvSrc.ReadInt16() - 1); // zero based;
EventSink.InvokeTargetedSpell(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), spellId);
}
public static void TargetedSkillUse(NetState ns, PacketReader pvSrc)
{
short skillId = pvSrc.ReadInt16();
EventSink.InvokeTargetedSkillUse(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), skillId);
}
public static void TargetByResourceMacro(NetState ns, PacketReader pvSrc)
{
Serial serial = pvSrc.ReadUInt32();
if (serial.IsItem) EventSink.InvokeTargetByResourceMacro(ns.Mobile, World.FindItem(serial), pvSrc.ReadInt16());
}
private class LoginTimer : Timer private class LoginTimer : Timer
{ {
private readonly Mobile m_Mobile; private readonly Mobile m_Mobile;

View file

@ -1,3 +1,24 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerConnectionHandler.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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;
using System.Buffers; using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;

View file

@ -1,7 +1,27 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerStartup.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Server.Network;
namespace Server.Network namespace Server.Network
{ {

View file

@ -1,3 +1,24 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: TcpServer.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;

View file

@ -49,11 +49,7 @@ namespace Server
{ {
PermitBackgroundWrite = permitBackgroundWrite; PermitBackgroundWrite = permitBackgroundWrite;
Task.WaitAll(new Task[3] { Task.WaitAll(Task.Factory.StartNew(SaveMobiles), Task.Factory.StartNew(SaveItems), Task.Factory.StartNew(SaveGuilds));
Task.Factory.StartNew(() => SaveMobiles()),
Task.Factory.StartNew(() => SaveItems()),
Task.Factory.StartNew(() => SaveGuilds())
});
if (permitBackgroundWrite && UseSequentialWriters if (permitBackgroundWrite && UseSequentialWriters
) //If we're permitted to write in the background, but we don't anyways, then notify. ) //If we're permitted to write in the background, but we don't anyways, then notify.
@ -155,7 +151,10 @@ namespace Server
foreach (Item item in items.Values) foreach (Item item in items.Values)
{ {
if (item.Decays && item.Parent == null && item.Map != Map.Internal && item.LastMoved + item.DecayTime <= n) if (item.Decays && item.Parent == null && item.Map != Map.Internal && item.LastMoved + item.DecayTime <= n)
{
Console.WriteLine($"Decay Item {item.Name ?? item.DefaultName} ({item.GetType().FullName})");
_decayQueue.Enqueue(item); _decayQueue.Enqueue(item);
}
long start = bin.Position; long start = bin.Position;
@ -217,7 +216,8 @@ namespace Server
{ {
Item item = _decayQueue.Dequeue(); Item item = _decayQueue.Dequeue();
if (item.OnDecay()) item.Delete(); if (item.OnDecay())
item.Delete();
} }
} }
} }

View file

@ -183,116 +183,7 @@ namespace Server
{ {
string filePath = Core.FindDataFile("tiledata.mul"); string filePath = Core.FindDataFile("tiledata.mul");
if (File.Exists(filePath)) if (!File.Exists(filePath))
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BinaryReader bin = new BinaryReader(fs);
if (fs.Length == 3188736)
{
// 7.0.9.0
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
ItemTable = new ItemData[0x10000];
for (int i = 0; i < 0x10000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
if (fs.Length == 1644544)
{
// 7.0.0.0
ItemTable = new ItemData[0x8000];
for (int i = 0; i < 0x8000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
ItemTable = new ItemData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
}
}
MaxLandValue = LandTable.Length - 1;
MaxItemValue = ItemTable.Length - 1;
}
else
{ {
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("tiledata.mul was not found"); Console.WriteLine("tiledata.mul was not found");
@ -302,6 +193,111 @@ namespace Server
throw new Exception($"TileData: {filePath} not found"); throw new Exception($"TileData: {filePath} not found");
} }
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader bin = new BinaryReader(fs);
if (fs.Length == 3188736)
{
// 7.0.9.0
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
ItemTable = new ItemData[0x10000];
for (int i = 0; i < 0x10000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
if (fs.Length == 1644544)
{
// 7.0.0.0
ItemTable = new ItemData[0x8000];
for (int i = 0; i < 0x8000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
ItemTable = new ItemData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
}
MaxLandValue = LandTable.Length - 1;
MaxItemValue = ItemTable.Length - 1;
} }
public static LandData[] LandTable{ get; } public static LandData[] LandTable{ get; }

View file

@ -34,6 +34,14 @@ namespace Server
private readonly int m_FileIndex; private readonly int m_FileIndex;
private readonly List<TileMatrix> m_FileShare = new List<TileMatrix>(); private readonly List<TileMatrix> m_FileShare = new List<TileMatrix>();
private readonly FileStream m_MapStream;
public FileStream IndexStream { get; }
public FileStream DataStream { get; }
private readonly BinaryReader m_IndexReader;
private readonly LandTile[] m_InvalidLandBlock; private readonly LandTile[] m_InvalidLandBlock;
private readonly int[][] m_LandPatches; private readonly int[][] m_LandPatches;
private readonly LandTile[][][] m_LandTiles; private readonly LandTile[][][] m_LandTiles;
@ -53,7 +61,6 @@ namespace Server
private StaticTile[] m_TileBuffer = new StaticTile[128]; private StaticTile[] m_TileBuffer = new StaticTile[128];
private readonly TileList m_TilesList = new TileList(); private readonly TileList m_TilesList = new TileList();
// private int m_Width, m_Height;
public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height) public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height)
{ {
@ -78,8 +85,6 @@ namespace Server
} }
m_FileIndex = fileIndex; m_FileIndex = fileIndex;
// m_Width = width;
// m_Height = height;
BlockWidth = width >> 3; BlockWidth = width >> 3;
BlockHeight = height >> 3; BlockHeight = height >> 3;
@ -87,21 +92,19 @@ namespace Server
if (fileIndex != 0x7F) if (fileIndex != 0x7F)
{ {
string mapPath = Core.FindDataFile("map{0}.mul", fileIndex); string mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex);
if (File.Exists(mapPath)) if (File.Exists(mapPath))
{ {
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_MapIndex = new UOPIndex(m_MapStream);
} }
else else
{ {
mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex); mapPath = Core.FindDataFile("map{0}.mul", fileIndex);
if (File.Exists(mapPath)) if (File.Exists(mapPath))
{ m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_MapIndex = new UOPIndex(MapStream);
}
} }
string indexPath = Core.FindDataFile("staidx{0}.mul", fileIndex); string indexPath = Core.FindDataFile("staidx{0}.mul", fileIndex);
@ -109,7 +112,7 @@ namespace Server
if (File.Exists(indexPath)) if (File.Exists(indexPath))
{ {
IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
IndexReader = new BinaryReader(IndexStream); m_IndexReader = new BinaryReader(IndexStream);
} }
string staticsPath = Core.FindDataFile("statics{0}.mul", fileIndex); string staticsPath = Core.FindDataFile("statics{0}.mul", fileIndex);
@ -138,51 +141,12 @@ namespace Server
Patch = new TileMatrixPatch(this, mapID); Patch = new TileMatrixPatch(this, mapID);
} }
/*public Map Owner
{
get
{
return m_Owner;
}
}*/
public TileMatrixPatch Patch{ get; } public TileMatrixPatch Patch{ get; }
public int BlockWidth{ get; } public int BlockWidth{ get; }
public int BlockHeight{ get; } public int BlockHeight{ get; }
/*public int Width
{
get
{
return m_Width;
}
}
public int Height
{
get
{
return m_Height;
}
}*/
public FileStream MapStream{ get; set; }
/*public bool MapUOPPacked
{
get{ return ( m_MapIndex != null ); }
}*/
public FileStream IndexStream{ get; set; }
public FileStream DataStream{ get; set; }
public BinaryReader IndexReader{ get; set; }
public bool Exists => MapStream != null && IndexStream != null && DataStream != null;
public StaticTile[][][] EmptyStaticBlock{ get; } public StaticTile[][][] EmptyStaticBlock{ get; }
[MethodImpl(MethodImplOptions.Synchronized)] [MethodImpl(MethodImplOptions.Synchronized)]
@ -292,7 +256,7 @@ namespace Server
[MethodImpl(MethodImplOptions.Synchronized)] [MethodImpl(MethodImplOptions.Synchronized)]
public LandTile[] GetLandBlock(int x, int y) public LandTile[] GetLandBlock(int x, int y)
{ {
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || MapStream == null) if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || m_MapStream == null)
return m_InvalidLandBlock; return m_InvalidLandBlock;
m_LandTiles[x] ??= new LandTile[BlockHeight][]; m_LandTiles[x] ??= new LandTile[BlockHeight][];
@ -339,10 +303,10 @@ namespace Server
{ {
try try
{ {
IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin); m_IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin);
int lookup = IndexReader.ReadInt32(); int lookup = m_IndexReader.ReadInt32();
int length = IndexReader.ReadInt32(); int length = m_IndexReader.ReadInt32();
if (lookup < 0 || length <= 0) if (lookup < 0 || length <= 0)
return EmptyStaticBlock; return EmptyStaticBlock;
@ -423,13 +387,13 @@ namespace Server
if (m_MapIndex != null) if (m_MapIndex != null)
offset = m_MapIndex.Lookup(offset); offset = m_MapIndex.Lookup(offset);
MapStream.Seek(offset, SeekOrigin.Begin); m_MapStream.Seek(offset, SeekOrigin.Begin);
LandTile[] tiles = new LandTile[64]; LandTile[] tiles = new LandTile[64];
fixed (LandTile* pTiles = tiles) fixed (LandTile* pTiles = tiles)
{ {
NativeReader.Read(MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192); NativeReader.Read(m_MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192);
} }
return tiles; return tiles;
@ -448,14 +412,10 @@ namespace Server
public void Dispose() public void Dispose()
{ {
if (m_MapIndex != null) m_MapIndex?.Close();
m_MapIndex.Close(); m_MapStream?.Close();
else
MapStream?.Close();
DataStream?.Close(); DataStream?.Close();
m_IndexReader?.Close();
IndexReader?.Close();
} }
} }
@ -670,16 +630,8 @@ namespace Server
{ {
public static readonly IComparer<UOPEntry> Instance = new OffsetComparer(); public static readonly IComparer<UOPEntry> Instance = new OffsetComparer();
public int Compare(UOPEntry x, UOPEntry y) public int Compare(UOPEntry x, UOPEntry y) =>
{ x == null ? y == null ? 0 : 1 : y == null ? -1 : x.m_Offset.CompareTo(y.m_Offset);
if (x == null)
return y == null ? 0 : 1;
if (y == null)
return -1;
return x.m_Offset.CompareTo(y.m_Offset);
}
} }
} }
} }

View file

@ -19,8 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/ *************************************************************************/
#nullable enable
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Cryptography; using System.Security.Cryptography;

View file

@ -645,7 +645,7 @@ namespace Server
try try
{ {
EventSink.InvokeWorldSave(new WorldSaveEventArgs(message)); EventSink.InvokeWorldSave(message);
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -579,3 +579,25 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. Public License instead of this License.
The MIT License (MIT)
Copyright (c) Harry Pierson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.