Adds BufferReader and BufferWriter. Updates UOP handling. (#101)
This commit is contained in:
parent
2c0d97cd36
commit
038c3be258
98 changed files with 2458 additions and 2185 deletions
|
|
@ -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 );
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,4 +59,4 @@ namespace Server.Misc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 ||
|
||||||
|
|
|
||||||
|
|
@ -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...");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 &&
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
314
Projects/Server/Buffers/BufferReader.cs
Normal file
314
Projects/Server/Buffers/BufferReader.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
181
Projects/Server/Buffers/BufferReaderExtensions.cs
Normal file
181
Projects/Server/Buffers/BufferReaderExtensions.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
Projects/Server/Buffers/BufferWriter.cs
Normal file
143
Projects/Server/Buffers/BufferWriter.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
52
Projects/Server/Events/AccountLoginEvent.cs
Normal file
52
Projects/Server/Events/AccountLoginEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
75
Projects/Server/Events/AggressiveActionEvent.cs
Normal file
75
Projects/Server/Events/AggressiveActionEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
110
Projects/Server/Events/CharacterCreatedEvent.cs
Normal file
110
Projects/Server/Events/CharacterCreatedEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Projects/Server/Events/CreateGuildEvent.cs
Normal file
41
Projects/Server/Events/CreateGuildEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
150
Projects/Server/Events/EventSink.cs
Normal file
150
Projects/Server/Events/EventSink.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
Projects/Server/Events/FastwalkEvent.cs
Normal file
45
Projects/Server/Events/FastwalkEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Projects/Server/Events/GameLoginEvent.cs
Normal file
52
Projects/Server/Events/GameLoginEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Projects/Server/Events/MovementEvent.cs
Normal file
74
Projects/Server/Events/MovementEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Projects/Server/Events/ServerCrashedEvent.cs
Normal file
40
Projects/Server/Events/ServerCrashedEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Projects/Server/Events/ServerListEvent.cs
Normal file
63
Projects/Server/Events/ServerListEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
Projects/Server/Events/SocketConnectionEvent.cs
Normal file
45
Projects/Server/Events/SocketConnectionEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Projects/Server/Events/SpeechEvent.cs
Normal file
46
Projects/Server/Events/SpeechEvent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -645,7 +645,7 @@ namespace Server
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
EventSink.InvokeWorldSave(new WorldSaveEventArgs(message));
|
EventSink.InvokeWorldSave(message);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue