Adds assemblies config, fixes crash bugs. (#134)

This commit is contained in:
Kamron Batman 2020-05-09 12:55:56 -07:00 • committed by GitHub
parent 0140eb73b4
commit 8ec166bcd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3223 changed files with 191 additions and 191 deletions

View file

@ -0,0 +1,131 @@
using System.Collections.Generic;
namespace Server.Commands.Generic
{
public enum ObjectTypes
{
Both,
Items,
Mobiles,
All
}
public abstract class BaseCommand
{
private readonly List<MessageEntry> m_Responses = new List<MessageEntry>();
private readonly List<MessageEntry> m_Failures = new List<MessageEntry>();
public bool ListOptimized { get; set; }
public string[] Commands { get; set; }
public string Usage { get; set; }
public string Description { get; set; }
public AccessLevel AccessLevel { get; set; }
public ObjectTypes ObjectTypes { get; set; }
public CommandSupport Supports { get; set; }
public static bool IsAccessible(Mobile from, object obj)
{
if (from.AccessLevel >= AccessLevel.Administrator || obj == null)
return true;
Mobile mob = null;
if (obj is Mobile m)
mob = m;
else if (obj is Item item)
mob = item.RootParent as Mobile;
return mob == null || mob == from || from.AccessLevel > mob.AccessLevel;
}
public virtual void ExecuteList(CommandEventArgs e, List<object> list)
{
for (int i = 0; i < list.Count; ++i)
Execute(e, list[i]);
}
public virtual void Execute(CommandEventArgs e, object obj)
{
}
public virtual bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) => true;
public void AddResponse(string message)
{
for (int i = 0; i < m_Responses.Count; ++i)
{
MessageEntry entry = m_Responses[i];
if (entry.m_Message == message)
{
++entry.m_Count;
return;
}
}
if (m_Responses.Count == 10)
return;
m_Responses.Add(new MessageEntry(message));
}
public void LogFailure(string message)
{
for (int i = 0; i < m_Failures.Count; ++i)
{
MessageEntry entry = m_Failures[i];
if (entry.m_Message == message)
{
++entry.m_Count;
return;
}
}
if (m_Failures.Count == 10)
return;
m_Failures.Add(new MessageEntry(message));
}
public void Flush(Mobile from, bool flushToLog)
{
if (m_Responses.Count > 0)
for (int i = 0; i < m_Responses.Count; ++i)
{
MessageEntry entry = m_Responses[i];
from.SendMessage(entry.ToString());
if (flushToLog)
CommandLogging.WriteLine(from, entry.ToString());
}
else
for (int i = 0; i < m_Failures.Count; ++i)
from.SendMessage(m_Failures[i].ToString());
m_Responses.Clear();
m_Failures.Clear();
}
private class MessageEntry
{
public int m_Count;
public readonly string m_Message;
public MessageEntry(string message)
{
m_Message = message;
m_Count = 1;
}
public override string ToString() => m_Count > 1 ? $"{m_Message} ({m_Count})" : m_Message;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,195 @@
using System.Collections.Generic;
using Server.Gumps;
using Server.Items;
using Server.Multis;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class DesignInsertCommand : BaseCommand
{
public enum DesignInsertResult
{
Valid,
InvalidItem,
NotInHouse,
OutsideHouseBounds
}
public DesignInsertCommand()
{
AccessLevel = AccessLevel.GameMaster;
Supports = CommandSupport.Single | CommandSupport.Area;
Commands = new[] { "DesignInsert" };
ObjectTypes = ObjectTypes.Items;
Usage = "DesignInsert [allItems=false]";
Description = "Inserts multiple targeted items into a customizable house's design.";
}
public static void Initialize()
{
TargetCommands.Register(new DesignInsertCommand());
}
public static DesignInsertResult ProcessInsert(Item item, bool staticsOnly, out HouseFoundation house)
{
house = null;
if (item == null || item is BaseMulti || item is HouseSign || (staticsOnly && !(item is Static)))
return DesignInsertResult.InvalidItem;
house = BaseHouse.FindHouseAt(item) as HouseFoundation;
if (house == null)
return DesignInsertResult.NotInHouse;
int x = item.X - house.X;
int y = item.Y - house.Y;
int z = item.Z - house.Z;
if (!TryInsertIntoState(house.CurrentState, item.ItemID, x, y, z))
return DesignInsertResult.OutsideHouseBounds;
TryInsertIntoState(house.DesignState, item.ItemID, x, y, z);
item.Delete();
return DesignInsertResult.Valid;
}
private static bool TryInsertIntoState(DesignState state, int itemID, int x, int y, int z)
{
MultiComponentList mcl = state.Components;
if (x < mcl.Min.X || y < mcl.Min.Y || x > mcl.Max.X || y > mcl.Max.Y)
return false;
mcl.Add(itemID, x, y, z);
state.OnRevised();
return true;
}
public override void Execute(CommandEventArgs e, object obj)
{
Target t = new DesignInsertTarget(new List<HouseFoundation>(), e.Length < 1 || !e.GetBoolean(0));
t.Invoke(e.Mobile, obj);
}
private class DesignInsertTarget : Target
{
private readonly List<HouseFoundation> m_Foundations;
private readonly bool m_StaticsOnly;
public DesignInsertTarget(List<HouseFoundation> foundations, bool staticsOnly)
: base(-1, false, TargetFlags.None)
{
m_Foundations = foundations;
m_StaticsOnly = staticsOnly;
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
if (m_Foundations.Count != 0)
{
from.SendMessage("Your changes have been committed. Updating...");
foreach (HouseFoundation house in m_Foundations)
house.Delta(ItemDelta.Update);
}
}
protected override void OnTarget(Mobile from, object obj)
{
DesignInsertResult result = ProcessInsert(obj as Item, m_StaticsOnly, out HouseFoundation house);
switch (result)
{
case DesignInsertResult.Valid:
{
if (m_Foundations.Count == 0)
from.SendMessage(
"The item has been inserted into the house design. Press ESC when you are finished.");
else
from.SendMessage("The item has been inserted into the house design.");
if (!m_Foundations.Contains(house))
m_Foundations.Add(house);
break;
}
case DesignInsertResult.InvalidItem:
{
from.SendMessage("That cannot be inserted. Try again.");
break;
}
case DesignInsertResult.NotInHouse:
case DesignInsertResult.OutsideHouseBounds:
{
from.SendMessage("That item is not inside a customizable house. Try again.");
break;
}
}
from.Target = new DesignInsertTarget(m_Foundations, m_StaticsOnly);
}
}
public override void ExecuteList(CommandEventArgs e, List<object> list)
{
Mobile from = e.Mobile;
from.SendGump(new WarningGump(1060637, 30720,
$"You are about to insert {list.Count} objects. This cannot be undone without a full server revert.<br><br>Continue?",
0xFFC000, 420, 280, okay => OnConfirmCallback(from, okay, list, e.Length < 1 || !e.GetBoolean(0))));
AddResponse("Awaiting confirmation...");
}
private void OnConfirmCallback(Mobile from, bool okay, List<object> list, bool staticsOnly)
{
bool flushToLog = false;
if (okay)
{
List<HouseFoundation> foundations = new List<HouseFoundation>();
flushToLog = list.Count > 20;
for (int i = 0; i < list.Count; ++i)
{
DesignInsertResult result = ProcessInsert(list[i] as Item, staticsOnly, out HouseFoundation house);
switch (result)
{
case DesignInsertResult.Valid:
{
AddResponse("The item has been inserted into the house design.");
if (!foundations.Contains(house))
foundations.Add(house);
break;
}
case DesignInsertResult.InvalidItem:
{
LogFailure("That cannot be inserted.");
break;
}
case DesignInsertResult.NotInHouse:
case DesignInsertResult.OutsideHouseBounds:
{
LogFailure("That item is not inside a customizable house.");
break;
}
}
}
foreach (HouseFoundation house in foundations)
house.Delta(ItemDelta.Update);
}
else
{
AddResponse("Command aborted.");
}
Flush(from, flushToLog);
}
}
}

View file

@ -0,0 +1,567 @@
using System.Collections.Generic;
using System.Reflection;
using Server.Gumps;
using Server.Network;
using Server.Targets;
namespace Server.Commands.Generic
{
public class InterfaceCommand : BaseCommand
{
public InterfaceCommand()
{
AccessLevel = AccessLevel.GameMaster;
Supports = CommandSupport.Complex | CommandSupport.Simple;
Commands = new[] { "Interface" };
ObjectTypes = ObjectTypes.Both;
Usage = "Interface [view <properties ...>]";
Description = "Opens an interface to interact with matched objects. Generally used with condition arguments.";
ListOptimized = true;
}
public override void ExecuteList(CommandEventArgs e, List<object> list)
{
if (list.Count > 0)
{
List<string> columns = new List<string> { "Object" };
if (e.Length > 0)
{
int offset = 0;
if (Insensitive.Equals(e.GetString(0), "view"))
++offset;
while (offset < e.Length)
columns.Add(e.GetString(offset++));
}
e.Mobile.SendGump(new InterfaceGump(e.Mobile, columns.ToArray(), list, 0, null));
}
else
{
AddResponse("No matching objects found.");
}
}
}
public class InterfaceGump : BaseGridGump
{
private const int EntriesPerPage = 15;
private readonly string[] m_Columns;
private readonly Mobile m_From;
private readonly List<object> m_List;
private readonly int m_Page;
private readonly object m_Select;
public InterfaceGump(Mobile from, string[] columns, List<object> list, int page, object select) : base(30, 30)
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Select = select;
Render();
}
public void Render()
{
AddNewPage();
if (m_Page > 0)
AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
else
AddEntryHeader(20);
AddEntryHtml(40 + m_Columns.Length * 130 - 20 + (m_Columns.Length - 2) * OffsetSize, Center(
$"Page {m_Page + 1} of {(m_List.Count + EntriesPerPage - 1) / EntriesPerPage}"));
if ((m_Page + 1) * EntriesPerPage < m_List.Count)
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
else
AddEntryHeader(20);
if (m_Columns.Length > 1)
{
AddNewLine();
for (int i = 0; i < m_Columns.Length; ++i)
{
if (i > 0 && m_List.Count > 0)
{
object obj = m_List[0];
if (obj != null)
{
string failReason = null;
PropertyInfo[] chain = Properties.GetPropertyInfoChain(m_From, obj.GetType(), m_Columns[i],
PropertyAccess.Read, ref failReason);
if (chain?.Length > 0)
{
m_Columns[i] = "";
for (int j = 0; j < chain.Length; ++j)
{
if (j > 0)
m_Columns[i] += '.';
m_Columns[i] += chain[j].Name;
}
}
}
}
AddEntryHtml(130 + (i == 0 ? 40 : 0), m_Columns[i]);
}
AddEntryHeader(20);
}
for (int i = m_Page * EntriesPerPage, line = 0; line < EntriesPerPage && i < m_List.Count; ++i, ++line)
{
AddNewLine();
object obj = m_List[i];
bool isDeleted = false;
if (obj is Item item)
{
if (!(isDeleted = item.Deleted))
AddEntryHtml(40 + 130, item.GetType().Name);
}
else if (obj is Mobile mob)
{
if (!(isDeleted = mob.Deleted))
AddEntryHtml(40 + 130, mob.Name);
}
if (isDeleted)
{
AddEntryHtml(40 + 130, "(deleted)");
for (int j = 1; j < m_Columns.Length; ++j)
AddEntryHtml(130, "---");
AddEntryHeader(20);
}
else
{
for (int j = 1; j < m_Columns.Length; ++j)
{
object src = obj;
string value;
string failReason = "";
PropertyInfo[] chain = Properties.GetPropertyInfoChain(m_From, src.GetType(), m_Columns[j],
PropertyAccess.Read, ref failReason);
if (chain == null || chain.Length == 0)
{
value = "---";
}
else
{
PropertyInfo p = Properties.GetPropertyInfo(ref src, chain, ref failReason);
if (p == null)
value = "---";
else
value = PropertiesGump.ValueToString(src, p);
}
AddEntryHtml(130, value);
}
bool isSelected = m_Select != null && obj == m_Select;
AddEntryButton(20, isSelected ? 9762 : ArrowRightID1, isSelected ? 9763 : ArrowRightID2, 3 + i,
ArrowRightWidth, ArrowRightHeight);
}
}
FinishPage();
}
public override void OnResponse(NetState sender, RelayInfo info)
{
switch (info.ButtonID)
{
case 1:
{
if (m_Page > 0)
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page - 1, m_Select));
break;
}
case 2:
{
if ((m_Page + 1) * EntriesPerPage < m_List.Count)
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page + 1, m_Select));
break;
}
default:
{
int v = info.ButtonID - 3;
if (v >= 0 && v < m_List.Count)
{
object obj = m_List[v];
if (!BaseCommand.IsAccessible(m_From, obj))
{
m_From.SendLocalizedMessage(500447); // That is not accessible.
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Select));
break;
}
if (obj is Item item && !item.Deleted)
m_From.SendGump(new InterfaceItemGump(m_From, m_Columns, m_List, m_Page, item));
else if (obj is Mobile mobile && !mobile.Deleted)
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, mobile));
else
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Select));
}
break;
}
}
}
}
public class InterfaceItemGump : BaseGridGump
{
private readonly string[] m_Columns;
private readonly Mobile m_From;
private readonly Item m_Item;
private readonly List<object> m_List;
private readonly int m_Page;
public InterfaceItemGump(Mobile from, string[] columns, List<object> list, int page, Item item) : base(30, 30)
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Item = item;
Render();
}
public void Render()
{
AddNewPage();
AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
AddEntryHtml(160, m_Item.GetType().Name);
AddEntryHeader(20);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Properties");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Delete");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Go there");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Move to target");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Bring to pack");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight);
FinishPage();
}
private void InvokeCommand(string ip)
{
CommandSystem.Handle(m_From, $"{CommandSystem.Prefix}{ip}");
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (m_Item.Deleted)
{
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Item));
return;
}
if (!BaseCommand.IsAccessible(m_From, m_Item))
{
m_From.SendMessage("That is no longer accessible.");
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Item));
return;
}
switch (info.ButtonID)
{
case 0:
case 1:
{
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Item));
break;
}
case 2: // Properties
{
m_From.SendGump(new InterfaceItemGump(m_From, m_Columns, m_List, m_Page, m_Item));
m_From.SendGump(new PropertiesGump(m_From, m_Item));
break;
}
case 3: // Delete
{
CommandLogging.WriteLine(m_From, "{0} {1} deleting {2}", m_From.AccessLevel,
CommandLogging.Format(m_From), CommandLogging.Format(m_Item));
m_Item.Delete();
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Item));
break;
}
case 4: // Go there
{
m_From.SendGump(new InterfaceItemGump(m_From, m_Columns, m_List, m_Page, m_Item));
InvokeCommand($"Go {m_Item.Serial.Value}");
break;
}
case 5: // Move to target
{
m_From.SendGump(new InterfaceItemGump(m_From, m_Columns, m_List, m_Page, m_Item));
m_From.Target = new MoveTarget(m_Item);
break;
}
case 6: // Bring to pack
{
Mobile owner = m_Item.RootParent as Mobile;
if (owner?.Map != null && owner.Map != Map.Internal &&
!BaseCommand.IsAccessible(m_From, owner) /* !m_From.CanSee( owner )*/)
{
m_From.SendMessage("You can not get what you can not see.");
}
else if (owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden &&
owner.AccessLevel >= m_From.AccessLevel)
{
m_From.SendMessage("You can not get what you can not see.");
}
else
{
m_From.SendGump(new InterfaceItemGump(m_From, m_Columns, m_List, m_Page, m_Item));
m_From.AddToBackpack(m_Item);
}
break;
}
}
}
}
public class InterfaceMobileGump : BaseGridGump
{
private readonly string[] m_Columns;
private readonly Mobile m_From;
private readonly List<object> m_List;
private readonly Mobile m_Mobile;
private readonly int m_Page;
public InterfaceMobileGump(Mobile from, string[] columns, List<object> list, int page, Mobile mob)
: base(30, 30)
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Mobile = mob;
Render();
}
public void Render()
{
AddNewPage();
AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
AddEntryHtml(160, m_Mobile.Name);
AddEntryHeader(20);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Properties");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
if (!m_Mobile.Player)
{
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Delete");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight);
}
if (m_Mobile != m_From)
{
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Go to there");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight);
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Bring them here");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight);
}
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Move to target");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight);
if (m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel)
{
AddNewLine();
if (m_Mobile.Alive)
{
AddEntryHtml(20 + OffsetSize + 160, "Kill");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 7, ArrowRightWidth, ArrowRightHeight);
}
else
{
AddEntryHtml(20 + OffsetSize + 160, "Resurrect");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 8, ArrowRightWidth, ArrowRightHeight);
}
}
if (m_Mobile.NetState != null)
{
AddNewLine();
AddEntryHtml(20 + OffsetSize + 160, "Client");
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 9, ArrowRightWidth, ArrowRightHeight);
}
FinishPage();
}
private void InvokeCommand(string ip)
{
CommandSystem.Handle(m_From, $"{CommandSystem.Prefix}{ip}");
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (m_Mobile.Deleted)
{
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
return;
}
if (!BaseCommand.IsAccessible(m_From, m_Mobile))
{
m_From.SendMessage("That is no longer accessible.");
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
return;
}
switch (info.ButtonID)
{
case 0:
case 1:
{
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
break;
}
case 2: // Properties
{
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
m_From.SendGump(new PropertiesGump(m_From, m_Mobile));
break;
}
case 3: // Delete
{
if (!m_Mobile.Player)
{
CommandLogging.WriteLine(m_From, "{0} {1} deleting {2}", m_From.AccessLevel,
CommandLogging.Format(m_From), CommandLogging.Format(m_Mobile));
m_Mobile.Delete();
m_From.SendGump(new InterfaceGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
}
break;
}
case 4: // Go there
{
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
InvokeCommand($"Go {m_Mobile.Serial.Value}");
break;
}
case 5: // Bring them here
{
if (m_From.Map == null || m_From.Map == Map.Internal)
{
m_From.SendMessage("You cannot bring that person here.");
}
else
{
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
m_Mobile.MoveToWorld(m_From.Location, m_From.Map);
}
break;
}
case 6: // Move to target
{
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
m_From.Target = new MoveTarget(m_Mobile);
break;
}
case 7: // Kill
{
if (m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel)
m_Mobile.Kill();
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
break;
}
case 8: // Res
{
if (m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel)
{
m_Mobile.PlaySound(0x214);
m_Mobile.FixedEffect(0x376A, 10, 16);
m_Mobile.Resurrect();
}
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
break;
}
case 9: // Client
{
m_From.SendGump(new InterfaceMobileGump(m_From, m_Columns, m_List, m_Page, m_Mobile));
if (m_Mobile.NetState != null)
m_From.SendGump(new ClientGump(m_From, m_Mobile.NetState));
break;
}
}
}
}
}