Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AccountExtUtility
|
||||
{
|
||||
public static bool IsOnline(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).Any();
|
||||
}
|
||||
|
||||
public static Mobile GetOnlineMobile(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static TMob GetOnlineMobile<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc)
|
||||
{
|
||||
return GetMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] != null && (predicate == null || predicate(acc[i])))
|
||||
{
|
||||
yield return acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return GetMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] is TMob && (predicate == null || predicate((TMob)acc[i])))
|
||||
{
|
||||
yield return (TMob)acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return GetSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this Account acc)
|
||||
{
|
||||
return FindSharedAccounts(acc).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return FindSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this Account acc)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var a in Accounts.GetAccounts().AsParallel().OfType<Account>().Where(a => IsSharedWith(acc, a)))
|
||||
{
|
||||
yield return a;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this IAccount acc, IAccount a)
|
||||
{
|
||||
return IsSharedWith(acc as Account, a as Account);
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this Account acc, Account a)
|
||||
{
|
||||
return acc != null && a != null && (acc == a || acc.LoginIPs.Any(a.LoginIPs.Contains));
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && (a == b || a.Account == b.Account);
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, IAccount b)
|
||||
{
|
||||
return a != null && b != null && a.Account == b;
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this IAccount a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && a == b.Account;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AddonExtUtility
|
||||
{
|
||||
static AddonExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
}
|
||||
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static int ComputeHash(IAddon addon)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = -1;
|
||||
|
||||
hash = (hash * 397) ^ addon.GetTypeHashCode();
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
hash = (hash * 397) ^ comp.Count;
|
||||
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.GetTypeHashCode());
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.ItemID);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this IAddon addon)
|
||||
{
|
||||
if (addon == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = ComputeHash(addon);
|
||||
|
||||
var mcl = ComponentsCache.GetValue(hash);
|
||||
|
||||
if (mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
mcl = new MultiComponentList(MultiComponentList.Empty);
|
||||
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
|
||||
foreach (var c in comp)
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
x1 = Math.Min(off.X, x1);
|
||||
y1 = Math.Min(off.Y, y1);
|
||||
|
||||
x2 = Math.Max(off.X, x2);
|
||||
y2 = Math.Max(off.Y, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mcl.Resize(1 + (x2 - x1), 1 + (y2 - y1));
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
|
||||
foreach (var c in comp.OfType<Item>())
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
off = off.Clone3D(Math.Abs(x1), Math.Abs(y1));
|
||||
|
||||
mcl.Add(c.ItemID, off.X, off.Y, off.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addon is Item)
|
||||
{
|
||||
((Item)addon).Delete();
|
||||
}
|
||||
|
||||
return ComponentsCache[hash] = mcl;
|
||||
}
|
||||
}
|
||||
}
|
||||
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class BodyExtUtility
|
||||
{
|
||||
public static Dictionary<int, string> Names { get; private set; }
|
||||
|
||||
static BodyExtUtility()
|
||||
{
|
||||
Names = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
public static string GetName(this Body body)
|
||||
{
|
||||
if (body.IsEmpty)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
|
||||
if (Names.TryGetValue(body.BodyID, out var name) && !String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
var itemID = ShrinkTable.Lookup(body.BodyID) & TileData.MaxItemValue;
|
||||
|
||||
if (itemID == ShrinkTable.DefaultItemID)
|
||||
{
|
||||
name = String.Empty;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = ClilocLNG.NULL.GetRawString(itemID + (itemID < 0x4000 ? 1020000 : 1078872));
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = TileData.ItemTable[itemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = name.SpaceWords().ToUpperWords();
|
||||
|
||||
name = String.Concat(" ", name, " ");
|
||||
|
||||
if (body.IsHuman || body.IsGhost)
|
||||
{
|
||||
if (body >= 400 && body <= 403)
|
||||
{
|
||||
name = "Human";
|
||||
}
|
||||
else if (body >= 605 && body <= 608)
|
||||
{
|
||||
name = "Elf";
|
||||
}
|
||||
else if ((body >= 666 && body <= 667) || (body >= 694 && body <= 695))
|
||||
{
|
||||
name = "Gargoyle";
|
||||
}
|
||||
|
||||
if (body.IsMale && !Insensitive.Contains(name, "Male"))
|
||||
{
|
||||
name += " Male";
|
||||
}
|
||||
else if (body.IsFemale && !Insensitive.Contains(name, "Female"))
|
||||
{
|
||||
name += " Female";
|
||||
}
|
||||
|
||||
if (body.IsGhost && !Insensitive.Contains(name, "Ghost"))
|
||||
{
|
||||
name += " Ghost";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (itemID)
|
||||
{
|
||||
case 9611:
|
||||
name = "Evil Mage";
|
||||
break;
|
||||
case 9776:
|
||||
name = "Wanderer Of The Void";
|
||||
break;
|
||||
case 11676:
|
||||
name = "Charger";
|
||||
break;
|
||||
case 38990:
|
||||
name = "Baby Dragon Turtle";
|
||||
break;
|
||||
case 40369:
|
||||
name = "Aztec Golem";
|
||||
break;
|
||||
case 40374:
|
||||
name = "Myrmadex Queen";
|
||||
break;
|
||||
case 40420:
|
||||
name = "Spector";
|
||||
break;
|
||||
case 40429:
|
||||
name = "T-Rex";
|
||||
break;
|
||||
case 40501:
|
||||
name = "Rainbow Unicorn";
|
||||
break;
|
||||
case 40661:
|
||||
name = "Windrunner";
|
||||
break;
|
||||
case 40704:
|
||||
name = "Sabertooth Tiger";
|
||||
break;
|
||||
case 40705:
|
||||
name = "Small Platinum Dragon";
|
||||
break;
|
||||
case 40706:
|
||||
name = "Platinum Dragon";
|
||||
break;
|
||||
case 40710:
|
||||
name = "Small Crimson Dragon";
|
||||
break;
|
||||
case 40711:
|
||||
name = "Crimson Dragon";
|
||||
break;
|
||||
case 40713:
|
||||
name = "Small Fox";
|
||||
break;
|
||||
case 40714:
|
||||
name = "Small Stygian Dragon";
|
||||
break;
|
||||
case 40718:
|
||||
name = "Stygian Dragon";
|
||||
break;
|
||||
case 40976:
|
||||
name = "Eastern Dragon";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
name = name.Replace(" Fr ", " Frame ");
|
||||
|
||||
name = name.Replace("Frame", String.Empty);
|
||||
name = name.Replace("Statuette", String.Empty);
|
||||
name = name.Replace("Statue", String.Empty);
|
||||
|
||||
name = name.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
Names[body.BodyID] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static int GetPaperdoll(this Body body)
|
||||
{
|
||||
return ArtworkSupport.LookupGump(body);
|
||||
}
|
||||
|
||||
public static bool HasPaperdoll(this Body body)
|
||||
{
|
||||
return GetPaperdoll(body) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class ContainerExtUtility
|
||||
{
|
||||
public static bool HasItem<TItem>(
|
||||
this Container container,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<TItem, bool> predicate = null)
|
||||
where TItem : Item
|
||||
{
|
||||
return predicate == null
|
||||
? HasItem(container, typeof(TItem), amount, children)
|
||||
: HasItem(container, typeof(TItem), amount, children, i => predicate(i as TItem));
|
||||
}
|
||||
|
||||
public static bool HasItem(
|
||||
this Container container,
|
||||
Type type,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || type == null || amount < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long total = 0;
|
||||
|
||||
total = container.FindItemsByType(type, true)
|
||||
.Where(i => i != null && !i.Deleted && i.TypeEquals(type, children) && (predicate == null || predicate(i)))
|
||||
.Aggregate(total, (c, i) => c + i.Amount);
|
||||
|
||||
return total >= amount;
|
||||
}
|
||||
|
||||
public static bool HasItems(
|
||||
this Container container,
|
||||
Type[] types,
|
||||
int[] amounts = null,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || types == null || types.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amounts == null)
|
||||
{
|
||||
amounts = new int[0];
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < types.Length; i++)
|
||||
{
|
||||
var t = types[i];
|
||||
var amount = amounts.InBounds(i) ? amounts[i] : 1;
|
||||
|
||||
if (HasItem(container, t, amount, children, predicate))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count >= types.Length;
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return DropItemStack(c, c.RootParent as Mobile, item);
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Mobile m, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
c.DropItem(item);
|
||||
|
||||
if (item.Stackable)
|
||||
{
|
||||
MergeStacks(c, item.GetType(), m);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void MergeStacks<T>(this Container c, Mobile m)
|
||||
where T : Item
|
||||
{
|
||||
MergeStacks(c, typeof(T), m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Mobile m)
|
||||
{
|
||||
MergeStacks(c, null, m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Type t, Mobile m)
|
||||
{
|
||||
if (c == null || c.Deleted || (t != null && t.TypeEquals<Container>(true)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var i = c.Items.Count;
|
||||
|
||||
while (--i >= 1)
|
||||
{
|
||||
var o = c.Items[i];
|
||||
|
||||
if (!o.Stackable || (t != null && !o.TypeEquals(t, false)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var s in c.Items.Take(i).NotType<Item, Container>().Where(s => t == null || s.TypeEquals(t, false)))
|
||||
{
|
||||
if (s.StackWith(m, o))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class CreatureExtUtility
|
||||
{
|
||||
public static TMobile GetMaster<TMobile>(this BaseCreature creature)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
return creature != null ? creature.GetMaster() as TMobile : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class EntityExtUtility
|
||||
{
|
||||
public static ObjectPropertyList GetOPL(this IEntity e)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, headerOnly);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer, headerOnly);
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader();
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(lng);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(viewer);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList();
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(lng);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(viewer);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, lng));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, viewer));
|
||||
}
|
||||
|
||||
public static string ResolveName(this IEntity e, Mobile viewer = null)
|
||||
{
|
||||
if (e is Item)
|
||||
{
|
||||
return ((Item)e).ResolveName(viewer);
|
||||
}
|
||||
|
||||
if (e is Mobile)
|
||||
{
|
||||
return ((Mobile)e).GetFullName(viewer);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(e.Name))
|
||||
{
|
||||
return e.GetTypeName(false);
|
||||
}
|
||||
|
||||
return e.Name;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IEntity e)
|
||||
{
|
||||
if (e != null && e.Map != null && e.Map != Map.Internal)
|
||||
{
|
||||
return e.IsInside(e.Map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IEntity e)
|
||||
{
|
||||
return !IsInside(e);
|
||||
}
|
||||
|
||||
public static bool Intersects(this IEntity e, IPoint3D o)
|
||||
{
|
||||
return Block3D.Intersects(e, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
@@ -0,0 +1,765 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class GeoExtUtility
|
||||
{
|
||||
public static Point3D ToPoint3D(this IPoint3D p)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this IPoint2D p, int z = 0)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, z);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this IPoint3D p)
|
||||
{
|
||||
return new Point2D(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this StaticTile t)
|
||||
{
|
||||
return new Point2D(t.X, t.Y);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this StaticTile t)
|
||||
{
|
||||
return new Point3D(t.X, t.Y, t.Z);
|
||||
}
|
||||
|
||||
public static string ToCoordsString(this IPoint2D p, Map map)
|
||||
{
|
||||
return ToCoords(p, map).ToString();
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IPoint2D p, Map m)
|
||||
{
|
||||
return new Coords(m, p);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IEntity e)
|
||||
{
|
||||
return e == null ? Coords.Zero : new Coords(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Coords.Zero;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
return new Coords(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this StaticTile t, Map m)
|
||||
{
|
||||
return new Coords(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint2D p, Map m, int z = 0)
|
||||
{
|
||||
return new MapPoint(m, p, z);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint3D p, Map m)
|
||||
{
|
||||
return new MapPoint(m, p);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IEntity e)
|
||||
{
|
||||
return e == null ? MapPoint.Empty : new MapPoint(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return MapPoint.Empty;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
|
||||
return new MapPoint(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this StaticTile t, Map m)
|
||||
{
|
||||
return new MapPoint(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static IEnumerable<Block3D> Flatten(this IEnumerable<Block3D> blocks)
|
||||
{
|
||||
foreach (var o in blocks.GroupBy(o => o.ToPoint2D()))
|
||||
{
|
||||
var v = new Block3D(o.Key.X, o.Key.Y, o.Min(b => b.Z), 0);
|
||||
|
||||
v.H = o.Max(b => b.Z + b.H) - v.Z;
|
||||
|
||||
yield return v;
|
||||
}
|
||||
}
|
||||
|
||||
public static Direction GetDirection(this IPoint2D from, IPoint2D to)
|
||||
{
|
||||
int dx = to.X - from.X, dy = to.Y - from.Y, adx = Math.Abs(dx), ady = Math.Abs(dy);
|
||||
|
||||
if (adx >= ady * 3)
|
||||
{
|
||||
if (dx > 0)
|
||||
{
|
||||
return Direction.East;
|
||||
}
|
||||
|
||||
return Direction.West;
|
||||
}
|
||||
|
||||
if (ady >= adx * 3)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.South;
|
||||
}
|
||||
|
||||
return Direction.North;
|
||||
}
|
||||
|
||||
if (dx > 0)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Down;
|
||||
}
|
||||
|
||||
return Direction.Right;
|
||||
}
|
||||
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Left;
|
||||
}
|
||||
|
||||
return Direction.Up;
|
||||
}
|
||||
|
||||
public static Direction4 GetDirection4(this Direction dir, bool clockwise = true)
|
||||
{
|
||||
dir = dir & Direction.Mask;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case Direction.Up:
|
||||
return clockwise ? Direction4.North : Direction4.West;
|
||||
case Direction.Right:
|
||||
return clockwise ? Direction4.East : Direction4.North;
|
||||
case Direction.Down:
|
||||
return clockwise ? Direction4.South : Direction4.East;
|
||||
case Direction.Left:
|
||||
return clockwise ? Direction4.West : Direction4.South;
|
||||
}
|
||||
|
||||
return (Direction4)dir;
|
||||
}
|
||||
|
||||
public static Point2D[] GetLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return PlotLine2D(start, end).ToArray();
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return GetLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
return PlotLine3D(start, end, map, avgZ).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> PlotLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Line2D.Plot(start, end);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return PlotLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
var dist = GetDistance(start, end);
|
||||
var dZ = end.Z - start.Z;
|
||||
|
||||
return Line2D.Plot(start, end)
|
||||
.Select(
|
||||
(p, i) =>
|
||||
{
|
||||
var z = start.Z;
|
||||
|
||||
if (avgZ && map != null)
|
||||
{
|
||||
z = map.GetAverageZ(p.X, p.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
z += (int)(dZ * (i / dist));
|
||||
}
|
||||
|
||||
return new Point3D(p, z);
|
||||
});
|
||||
}
|
||||
|
||||
public static Point2D Rotate2D(this IPoint2D from, IPoint2D to, int count)
|
||||
{
|
||||
var rx = from.X - to.X;
|
||||
var ry = from.Y - to.Y;
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var temp = rx;
|
||||
rx = -ry;
|
||||
ry = temp;
|
||||
}
|
||||
|
||||
return new Point2D(to.X + rx, to.Y + ry);
|
||||
}
|
||||
|
||||
public static Point3D Rotate3D(this IPoint3D from, IPoint3D to, int count)
|
||||
{
|
||||
return new Point3D(Rotate2D(from, to, count), from.Z);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, IPoint2D t)
|
||||
{
|
||||
return new Point2D(p.X + t.X, p.Y + t.Y);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, int xOffset = 0, int yOffset = 0)
|
||||
{
|
||||
return new Point2D(p.X + xOffset, p.Y + yOffset);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, IPoint3D t)
|
||||
{
|
||||
return new Point3D(p.X + t.X, p.Y + t.Y, p.Z + t.Z);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, int xOffset = 0, int yOffset = 0, int zOffset = 0)
|
||||
{
|
||||
return new Point3D(p.X + xOffset, p.Y + yOffset, p.Z + zOffset);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, IPoint2D end, double percent)
|
||||
{
|
||||
return Lerp2D(start, end.X, end.Y, percent);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, int x, int y, double percent)
|
||||
{
|
||||
return Clone2D(start, (int)((x - start.X) * percent), (int)((y - start.Y) * percent));
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, IPoint3D end, double percent)
|
||||
{
|
||||
return Lerp3D(start, end.X, end.Y, end.Z, percent);
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, int x, int y, int z, double percent)
|
||||
{
|
||||
return Clone3D(
|
||||
start,
|
||||
(int)((x - start.X) * percent),
|
||||
(int)((y - start.Y) * percent),
|
||||
(int)((z - start.Z) * percent));
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return new Point2D(start.X - end.X, start.Y - end.Y);
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, int endX, int endY)
|
||||
{
|
||||
return new Point2D(start.X - endX, start.Y - endY);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return new Point3D(start.X - end.X, start.Y - end.Y, start.Z - end.Z);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, int endX, int endY, int endZ)
|
||||
{
|
||||
return new Point3D(start.X - endX, start.Y - endY, start.Z - endZ);
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Math.Abs(Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2)));
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return Math.Abs(
|
||||
Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2) + (Math.Pow(end.Z - start.Z, 2) / 44.0)));
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint2D start, IPoint2D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint3D start, IPoint3D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
var z1 = (double)start.Z;
|
||||
var z2 = (double)end.Z;
|
||||
|
||||
var zDiff = Math.Abs(z2 - z1);
|
||||
|
||||
if (zDiff >= 5)
|
||||
{
|
||||
span -= (zDiff / 5.0) * 0.1;
|
||||
}
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static object GetTopSurface(this Map map, Point3D p, bool multis)
|
||||
{
|
||||
if (map == Map.Internal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
object surface = null;
|
||||
var surfaceZ = Int32.MinValue;
|
||||
|
||||
var lt = map.Tiles.GetLandTile(p.X, p.Y);
|
||||
|
||||
if (!lt.Ignored)
|
||||
{
|
||||
var avgZ = map.GetAverageZ(p.X, p.Y);
|
||||
|
||||
if (avgZ <= p.Z)
|
||||
{
|
||||
surface = lt;
|
||||
surfaceZ = avgZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var staticTiles = map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
|
||||
ItemData id;
|
||||
int tileZ;
|
||||
|
||||
foreach (var tile in staticTiles)
|
||||
{
|
||||
id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tileZ = tile.Z + id.CalcHeight;
|
||||
|
||||
if (tileZ <= surfaceZ || tileZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = tile;
|
||||
surfaceZ = tileZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
var sector = map.GetSector(p.X, p.Y);
|
||||
|
||||
int itemZ;
|
||||
|
||||
var items = sector.Items.Where(
|
||||
o => o.ItemID <= TileData.MaxItemValue && !o.Movable && !(o is BaseMulti) && o.AtWorldPoint(p.X, p.Y));
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
id = item.ItemData;
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemZ = item.Z + id.CalcHeight;
|
||||
|
||||
if (itemZ <= surfaceZ || itemZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = item;
|
||||
surfaceZ = itemZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint2D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
return GetSurfaceTop(ToPoint3D(p, Region.MaxZ), map, items, multis);
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint3D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
var o = GetTopSurface(map, ToPoint3D(p, Region.MaxZ), multis);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
if (o is LandTile)
|
||||
{
|
||||
var t = (LandTile)o;
|
||||
return ToPoint3D(p, t.Z + t.Height);
|
||||
}
|
||||
|
||||
if (o is StaticTile)
|
||||
{
|
||||
var t = (StaticTile)o;
|
||||
return ToPoint3D(p, t.Z + TileData.ItemTable[t.ID].CalcHeight);
|
||||
}
|
||||
|
||||
if (o is Item && items)
|
||||
{
|
||||
var t = (Item)o;
|
||||
return ToPoint3D(p, t.Z + t.ItemData.CalcHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint2D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint3D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetTopZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetTopZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return points.Max(p => GetTopZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetAverageZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetAverageZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (int)points.Average(p => GetAverageZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (( ,A,_,A,
|
||||
/// )) ,{=^;^=}
|
||||
/// (( {,,}#{,,}
|
||||
/// `{,,}{,,}
|
||||
/// </summary>
|
||||
public static int GetAverageZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void GetAverageZ(this IPoint2D p, Map map, out int cur, out int avg, out int top)
|
||||
{
|
||||
var land = new
|
||||
{
|
||||
T = map.Tiles.GetLandTile(p.X, p.Y),
|
||||
L = map.Tiles.GetLandTile(p.X, p.Y + 1),
|
||||
R = map.Tiles.GetLandTile(p.X + 1, p.Y),
|
||||
B = map.Tiles.GetLandTile(p.X + 1, p.Y + 1)
|
||||
};
|
||||
|
||||
var surf = new
|
||||
{
|
||||
T = GetSurfaceTop(p, map, false, false),
|
||||
L = GetSurfaceTop(Clone2D(p, 0, 1), map, false, false),
|
||||
R = GetSurfaceTop(Clone2D(p, 1), map, false, false),
|
||||
B = GetSurfaceTop(Clone2D(p, 1, 1), map, false, false)
|
||||
};
|
||||
|
||||
var zT = (land.T.Ignored || surf.T.Z > Region.MinZ) ? surf.T.Z : land.T.Z;
|
||||
var zL = (land.L.Ignored || surf.L.Z > Region.MinZ) ? surf.L.Z : land.L.Z;
|
||||
var zR = (land.R.Ignored || surf.R.Z > Region.MinZ) ? surf.R.Z : land.R.Z;
|
||||
var zB = (land.B.Ignored || surf.B.Z > Region.MinZ) ? surf.B.Z : land.B.Z;
|
||||
|
||||
cur = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL < cur)
|
||||
{
|
||||
cur = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR < cur)
|
||||
{
|
||||
cur = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB < cur)
|
||||
{
|
||||
cur = zB;
|
||||
}
|
||||
|
||||
top = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL > top)
|
||||
{
|
||||
top = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR > top)
|
||||
{
|
||||
top = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB > top)
|
||||
{
|
||||
top = zB;
|
||||
}
|
||||
|
||||
if (cur <= Region.MinZ)
|
||||
{
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
if (top <= Region.MinZ)
|
||||
{
|
||||
top = 0;
|
||||
}
|
||||
|
||||
if (zT <= Region.MinZ)
|
||||
{
|
||||
zT = 0;
|
||||
}
|
||||
|
||||
if (zL <= Region.MinZ)
|
||||
{
|
||||
zL = 0;
|
||||
}
|
||||
|
||||
if (zR <= Region.MinZ)
|
||||
{
|
||||
zR = 0;
|
||||
}
|
||||
|
||||
if (zB <= Region.MinZ)
|
||||
{
|
||||
zB = 0;
|
||||
}
|
||||
|
||||
var vL = zL + zR;
|
||||
|
||||
if (vL < 0)
|
||||
{
|
||||
--vL;
|
||||
}
|
||||
|
||||
var vR = zT + zB;
|
||||
|
||||
if (vR < 0)
|
||||
{
|
||||
--vR;
|
||||
}
|
||||
|
||||
avg = Math.Abs(zT - zB) > Math.Abs(zL - zR) ? vL / 2 : vR / 2;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint3D p, Map map)
|
||||
{
|
||||
if (p != null && map != null && map != Map.Internal)
|
||||
{
|
||||
return IsInside(p, p.Z, map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint3D p, Map map)
|
||||
{
|
||||
return !IsInside(p, map);
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
if (p == null || map == null || map == Map.Internal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p is Item)
|
||||
{
|
||||
z += Math.Max(0, ((Item)p).ItemData.Height) + 1;
|
||||
}
|
||||
|
||||
z = Math.Max(Region.MinZ, Math.Min(Region.MaxZ, z));
|
||||
|
||||
return !map.CanFit(p.X, p.Y, z, Region.MaxZ - z, true, false, false);
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
return !IsInside(p, z, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
#endregion
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public static class GumpExtUtility
|
||||
{
|
||||
public static bool TryGetX(this GumpEntry e, out int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x);
|
||||
}
|
||||
|
||||
public static bool TrySetX(this GumpEntry e, int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x);
|
||||
}
|
||||
|
||||
public static bool TryOffsetX(this GumpEntry e, int x)
|
||||
{
|
||||
|
||||
if (TryGetX(e, out var ox))
|
||||
{
|
||||
return TrySetX(e, ox + x);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetY(this GumpEntry e, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetY(this GumpEntry e, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetY(this GumpEntry e, int y)
|
||||
{
|
||||
|
||||
if (TryGetY(e, out var oy))
|
||||
{
|
||||
return TrySetY(e, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetWidth(this GumpEntry e, out int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width);
|
||||
}
|
||||
|
||||
public static bool TrySetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width);
|
||||
}
|
||||
|
||||
public static bool TryOffsetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
|
||||
if (TryGetWidth(e, out var ow))
|
||||
{
|
||||
return TrySetWidth(e, ow + width);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetHeight(this GumpEntry e, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
|
||||
if (TryGetHeight(e, out var oh))
|
||||
{
|
||||
return TrySetHeight(e, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetPosition(this GumpEntry e, out int x, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
|
||||
if (TryGetPosition(e, out var ox, out var oy))
|
||||
{
|
||||
return TrySetPosition(e, ox + x, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetSize(this GumpEntry e, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetSize(e, out var ow, out var oh))
|
||||
{
|
||||
return TrySetSize(e, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetBounds(this GumpEntry e, out int x, out int y, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
x = ((IGumpEntryVector)e).X;
|
||||
y = ((IGumpEntryVector)e).Y;
|
||||
width = ((IGumpEntryVector)e).Width;
|
||||
height = ((IGumpEntryVector)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y) & //
|
||||
e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
((IGumpEntryVector)e).X = x;
|
||||
((IGumpEntryVector)e).Y = y;
|
||||
((IGumpEntryVector)e).Width = width;
|
||||
((IGumpEntryVector)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y) & //
|
||||
e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetBounds(e, out var ox, out var oy, out var ow, out var oh))
|
||||
{
|
||||
return TrySetBounds(e, ox + x, oy + y, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds(this Gump g)
|
||||
{
|
||||
int x = g.X, y = g.Y, w = 0, h = 0;
|
||||
|
||||
if (g is SuperGump)
|
||||
{
|
||||
var sg = (SuperGump)g;
|
||||
|
||||
x += sg.XOffset;
|
||||
y += sg.YOffset;
|
||||
|
||||
if (sg.Modal)
|
||||
{
|
||||
x += sg.ModalXOffset;
|
||||
y += sg.ModalYOffset;
|
||||
}
|
||||
|
||||
w = sg.OuterWidth;
|
||||
h = sg.OuterHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var e in g.Entries)
|
||||
{
|
||||
e.TryGetPosition(out var ex, out var ey);
|
||||
|
||||
e.TryGetSize(out var ew, out var eh);
|
||||
|
||||
w = Math.Max(ex + ew, w);
|
||||
h = Math.Max(ey + eh, h);
|
||||
}
|
||||
}
|
||||
|
||||
return new Rectangle2D(x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
@@ -0,0 +1,926 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[Flags]
|
||||
public enum GiveFlags
|
||||
{
|
||||
None = 0x0,
|
||||
Pack = 0x1,
|
||||
Bank = 0x2,
|
||||
Corpse = 0x4,
|
||||
Feet = 0x8,
|
||||
|
||||
Delete = 0x40000000,
|
||||
|
||||
PackBank = Pack | Bank,
|
||||
PackCorpse = Pack | Corpse,
|
||||
PackFeet = Pack | Feet,
|
||||
PackDelete = Pack | Delete,
|
||||
|
||||
PackBankCorpse = PackBank | Corpse,
|
||||
PackBankFeet = PackBank | Feet,
|
||||
PackBankDelete = PackBank | Delete,
|
||||
|
||||
PackBankCorpseFeet = PackBankCorpse | Feet,
|
||||
PackBankCorpseDelete = PackBankCorpse | Delete,
|
||||
PackBankFeetDelete = PackBankFeet | Delete,
|
||||
|
||||
PackBankCorpseFeetDelete = PackBankCorpseFeet | Delete,
|
||||
|
||||
PackCorpseFeet = PackCorpse | Feet,
|
||||
PackCorpseDelete = PackCorpse | Delete,
|
||||
PackCorpseFeetDelete = PackCorpseFeet | Delete,
|
||||
|
||||
PackFeetDelete = PackFeet | Delete,
|
||||
|
||||
BankCorpse = Bank | Corpse,
|
||||
BankFeet = Bank | Feet,
|
||||
BankDelete = Bank | Delete,
|
||||
|
||||
BankCorpseFeet = BankCorpse | Feet,
|
||||
BankCorpseDelete = BankCorpse | Delete,
|
||||
BankFeetDelete = BankFeet | Delete,
|
||||
|
||||
BankCorpseFeetDelete = BankCorpseFeet | Delete,
|
||||
|
||||
CorpseFeet = Corpse | Feet,
|
||||
CorpseDelete = Corpse | Delete,
|
||||
|
||||
CorpseFeetDelete = CorpseFeet | Delete,
|
||||
|
||||
FeetDelete = Feet | Delete,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
|
||||
public static class ItemExtUtility
|
||||
{
|
||||
public static T BinaryClone<T>(this T item)
|
||||
where T : Item
|
||||
{
|
||||
var t = item.GetType();
|
||||
|
||||
var o = t.CreateInstanceSafe<T>(Serial.NewItem);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var w = ms.GetBinaryWriter();
|
||||
|
||||
item.Serialize(w);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var r = ms.GetBinaryReader();
|
||||
|
||||
o.Deserialize(r);
|
||||
|
||||
w.Close();
|
||||
r.Close();
|
||||
}
|
||||
|
||||
var m = o.Parent as Mobile;
|
||||
|
||||
o.Amount = 1;
|
||||
|
||||
if (o.Items != null)
|
||||
{
|
||||
o.Items.Clear();
|
||||
}
|
||||
|
||||
o.Internalize();
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
o.OnRemoved(m);
|
||||
|
||||
m.OnItemRemoved(o);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
o.Delete();
|
||||
o = null;
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public static void InvalidateProperties<T>(this Item item)
|
||||
{
|
||||
if (item is T)
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties<T>(item.Items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvalidateProperties(this Item item, Type type)
|
||||
{
|
||||
if (item.TypeEquals(type))
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties(item.Items[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetAnimID(this Item item)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupAnimation(item.ItemID) : 0;
|
||||
}
|
||||
|
||||
public static int GetGumpID(this Item item, bool female)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupGump(item.ItemID, female) : 0;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetGumpBounds(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return PaperdollBounds.Empty;
|
||||
}
|
||||
|
||||
if (item.Layer == Layer.TwoHanded)
|
||||
{
|
||||
if (item is BaseRanged)
|
||||
{
|
||||
return PaperdollBounds.MainHand;
|
||||
}
|
||||
|
||||
if (item is BaseEquipableLight || item is BaseShield)
|
||||
{
|
||||
return PaperdollBounds.OffHand;
|
||||
}
|
||||
}
|
||||
|
||||
return PaperdollBounds.Find(item.Layer);
|
||||
}
|
||||
|
||||
public static Mobile FindOwner(this Item item)
|
||||
{
|
||||
return FindOwner<Mobile>(item);
|
||||
}
|
||||
|
||||
public static TMobile FindOwner<TMobile>(this Item item)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var owner = item.RootParent as TMobile;
|
||||
|
||||
if (owner == null)
|
||||
{
|
||||
var h = BaseHouse.FindHouseAt(item);
|
||||
|
||||
if (h != null)
|
||||
{
|
||||
owner = h.Owner as TMobile;
|
||||
}
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
public static GiveFlags GiveTo(this Item item, Mobile m, GiveFlags flags = GiveFlags.All, bool message = true)
|
||||
{
|
||||
if (item == null || item.Deleted || m == null || m.Deleted || flags == GiveFlags.None)
|
||||
{
|
||||
return GiveFlags.None;
|
||||
}
|
||||
|
||||
var pack = flags.HasFlag(GiveFlags.Pack);
|
||||
var bank = flags.HasFlag(GiveFlags.Bank);
|
||||
var feet = flags.HasFlag(GiveFlags.Feet);
|
||||
var corpse = flags.HasFlag(GiveFlags.Corpse);
|
||||
var delete = flags.HasFlag(GiveFlags.Delete);
|
||||
|
||||
if (pack && (m.Backpack == null || m.Backpack.Deleted || !m.Backpack.CheckHold(m, item, false)))
|
||||
{
|
||||
pack = false;
|
||||
flags &= ~GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && (!m.Player || !m.BankBox.CheckHold(m, item, false)))
|
||||
{
|
||||
bank = false;
|
||||
flags &= ~GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && (m.Alive || m.Corpse == null || m.Corpse.Deleted))
|
||||
{
|
||||
corpse = false;
|
||||
flags &= ~GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet && (m.Map == null || m.Map == Map.Internal) && (m.LogoutMap == null || m.LogoutMap == Map.Internal))
|
||||
{
|
||||
feet = false;
|
||||
flags &= ~GiveFlags.Feet;
|
||||
}
|
||||
|
||||
var result = VitaNexCore.TryCatchGet(
|
||||
f =>
|
||||
{
|
||||
if (pack && m.Backpack.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && m.BankBox.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && m.Corpse.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet)
|
||||
{
|
||||
if (m.Map != null && m.Map != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.Location, m.Map);
|
||||
|
||||
if (m.Player)
|
||||
{
|
||||
item.SendInfoTo(m.NetState);
|
||||
}
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
|
||||
if (m.LogoutMap != null && m.LogoutMap != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.LogoutLocation, m.LogoutMap);
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete)
|
||||
{
|
||||
item.Delete();
|
||||
|
||||
return GiveFlags.Delete;
|
||||
}
|
||||
|
||||
return GiveFlags.None;
|
||||
},
|
||||
flags);
|
||||
|
||||
if (!message || result == GiveFlags.None || result == GiveFlags.Delete)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var amount = String.Empty;
|
||||
var name = ResolveName(item, m);
|
||||
|
||||
var p = item.Stackable && item.Amount > 1;
|
||||
|
||||
if (p)
|
||||
{
|
||||
amount = item.Amount.ToString("#,0") + " ";
|
||||
|
||||
if (!Insensitive.EndsWith(name, "s") && !Insensitive.EndsWith(name, "z"))
|
||||
{
|
||||
name += "s";
|
||||
}
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case GiveFlags.Pack:
|
||||
m.SendMessage("{0}{1} {2} been placed in your pack.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Bank:
|
||||
m.SendMessage("{0}{1} {2} been placed in your bank.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Corpse:
|
||||
m.SendMessage("{0}{1} {2} been placed in your corpse.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Feet:
|
||||
m.SendMessage("{0}{1} {2} been placed at your feet.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool WasReceived(this GiveFlags flags)
|
||||
{
|
||||
return flags != GiveFlags.None && flags != GiveFlags.Delete;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Item, List<object>> _Actions = new Dictionary<Item, List<object>>();
|
||||
|
||||
public static bool BeginAction(this Item item, object toLock)
|
||||
{
|
||||
|
||||
if (!_Actions.TryGetValue(item, out var actions) || actions == null)
|
||||
{
|
||||
ObjectPool.Acquire(out actions);
|
||||
|
||||
_Actions[item] = actions;
|
||||
}
|
||||
|
||||
if (!actions.Contains(toLock))
|
||||
{
|
||||
actions.Add(toLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanBeginAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
return actions == null || !actions.Contains(toLock);
|
||||
}
|
||||
|
||||
public static void EndAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
if (actions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actions.Remove(toLock);
|
||||
|
||||
if (actions.Count == 0)
|
||||
{
|
||||
_Actions.Remove(item);
|
||||
|
||||
ObjectPool.Free(ref actions);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item, T> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item, T>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item)
|
||||
{
|
||||
return ResolveName(item, Clilocs.DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, Mobile viewer)
|
||||
{
|
||||
return ResolveName(item, viewer.GetLanguage());
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, ClilocLNG lng)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
var label = item.GetOPLHeader(lng);
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.Replace("\t", " ").Replace("\u0009", " ").Replace("<br>", "\n").Replace("<BR>", "\n").Trim();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripHtml(false);
|
||||
label = label.Trim();
|
||||
|
||||
int idx;
|
||||
|
||||
if ((idx = label.IndexOf('\n')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
label = label.Substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart('\n');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
|
||||
if ((idx = label.IndexOf(' ')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
|
||||
if (Int32.TryParse(label.Substring(0, idx), NumberStyles.Number, CultureInfo.InvariantCulture, out var amount))
|
||||
{
|
||||
label = label.Substring(idx + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart(' ');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.Name != null)
|
||||
{
|
||||
label = item.Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.DefaultName != null)
|
||||
{
|
||||
label = item.DefaultName;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.LabelNumber > 0)
|
||||
{
|
||||
label = lng.GetString(item.LabelNumber);
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && TileData.ItemTable.InBounds(item.ItemID))
|
||||
{
|
||||
label = TileData.ItemTable[item.ItemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label))
|
||||
{
|
||||
label = item.GetType().Name.SpaceWords();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item)
|
||||
{
|
||||
|
||||
return CheckUsesRemaining(item, false, out var uses);
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, false, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, bool deplete, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, deplete ? 1 : 0, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, int deplete, out int uses)
|
||||
{
|
||||
uses = -1;
|
||||
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(item is IUsesRemaining))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var u = (IUsesRemaining)item;
|
||||
|
||||
if (u.UsesRemaining <= 0)
|
||||
{
|
||||
uses = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deplete > 0)
|
||||
{
|
||||
if (u.UsesRemaining < deplete)
|
||||
{
|
||||
uses = u.UsesRemaining;
|
||||
return false;
|
||||
}
|
||||
|
||||
u.UsesRemaining = Math.Max(0, u.UsesRemaining - deplete);
|
||||
}
|
||||
|
||||
uses = u.UsesRemaining;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckUse(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
return CheckDoubleClick(item, from, handle, allowDead, range, packOnly, inTrade, inDisplay, access);
|
||||
}
|
||||
|
||||
public static bool CheckDoubleClick(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
if (item == null || item.Deleted || from == null || from.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.AccessLevel < access)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("You do not have sufficient access to use this item.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.CanSee(item) && !(item is IAddon))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can't be seen.");
|
||||
item.OnDoubleClickCantSee(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item.IsAccessibleTo(from))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickNotAccessible(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.InSecureTrade && !inTrade)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((item.Parent == null && !item.Movable && !item.IsLockedDown && !item.IsSecure && !item.InSecureTrade) ||
|
||||
IsShopItem(item)) && !inDisplay)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can not be accessed because it is part of a display.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.Alive && !allowDead)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickDead(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (range >= 0 && !packOnly && !from.InRange(item, range))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
if (range > 0)
|
||||
{
|
||||
from.SendMessage("You must be within {0:#,0} paces to use this item.", range);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You must be standing on this item to use it.");
|
||||
}
|
||||
|
||||
item.OnDoubleClickOutOfRange(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packOnly && item.RootParent != from)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
// This item must be in your backpack.
|
||||
from.SendLocalizedMessage(1054107);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsShopItem(this Item item)
|
||||
{
|
||||
return HasParent(item, "Server.Mobiles.GenericBuyInfo+DisplayCache");
|
||||
}
|
||||
|
||||
public static bool IsParentOf(this Item item, Item child)
|
||||
{
|
||||
if (item == null || child == null || item == child)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = child.Parent as Item;
|
||||
|
||||
while (p != null && p != item)
|
||||
{
|
||||
p = p.Parent as Item;
|
||||
}
|
||||
|
||||
return item == p;
|
||||
}
|
||||
|
||||
public static bool HasParent<TEntity>(this Item item)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return HasParent(item, typeof(TEntity));
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, string typeName)
|
||||
{
|
||||
if (item == null || String.IsNullOrWhiteSpace(typeName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = Type.GetType(typeName, false, false) ?? ScriptCompiler.FindTypeByFullName(typeName, false) ??
|
||||
ScriptCompiler.FindTypeByName(typeName, false);
|
||||
|
||||
return HasParent(item, t);
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, Type t)
|
||||
{
|
||||
if (item == null || t == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = item.Parent;
|
||||
|
||||
while (p is Item)
|
||||
{
|
||||
if (p.GetType().IsEqualOrChildOf(t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var i = (Item)p;
|
||||
|
||||
if (i.Parent == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p = i.Parent;
|
||||
}
|
||||
|
||||
return p is Mobile && p.GetType().IsEqualOrChildOf(t);
|
||||
}
|
||||
|
||||
public static bool IsEquipped(this Item item)
|
||||
{
|
||||
return item != null && item.Parent is Mobile && ((Mobile)item.Parent).FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
public static bool IsEquippedBy(this Item item, Mobile m)
|
||||
{
|
||||
return item != null && item.Parent == m && m.FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
#region *OverheadMessage
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text, NetState state)
|
||||
{
|
||||
if (state == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
state.Send(new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, NetState state)
|
||||
{
|
||||
PrivateOverheadMessage(item, type, hue, number, "", state);
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, string args, NetState state)
|
||||
{
|
||||
if (state != null)
|
||||
{
|
||||
state.Send(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
}
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number)
|
||||
{
|
||||
NonlocalOverheadMessage(item, type, hue, number, "");
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number, string args)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var p = Packet.Acquire(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Packet p;
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
p = new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text);
|
||||
}
|
||||
|
||||
p.Acquire();
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class LayerExtUtility
|
||||
{
|
||||
private const Layer _Face = (Layer)15;
|
||||
private const Layer _ShopMax = (Layer)30;
|
||||
|
||||
private const Layer _PlateArms = (Layer)255;
|
||||
private const Layer _ChainTunic = (Layer)254;
|
||||
private const Layer _LeatherShorts = (Layer)253;
|
||||
|
||||
public static Layer[] LayerOrder =
|
||||
{
|
||||
Layer.Cloak, Layer.Bracelet, Layer.Ring, Layer.Shirt, Layer.Pants, Layer.InnerLegs, Layer.Shoes, _LeatherShorts,
|
||||
Layer.Arms, Layer.InnerTorso, _LeatherShorts, _PlateArms, Layer.MiddleTorso, Layer.OuterLegs, Layer.Neck,
|
||||
Layer.Gloves, Layer.OuterTorso, Layer.Waist, Layer.OneHanded, Layer.TwoHanded, _Face, Layer.FacialHair, Layer.Hair,
|
||||
Layer.Helm, Layer.Talisman
|
||||
};
|
||||
|
||||
public static Layer[] EquipLayers =
|
||||
{
|
||||
Layer.Arms, Layer.Bracelet, Layer.Cloak, Layer.Earrings, Layer.Gloves, Layer.Helm, Layer.InnerLegs, Layer.InnerTorso,
|
||||
Layer.MiddleTorso, Layer.Neck, Layer.OneHanded, Layer.OuterLegs, Layer.OuterTorso, Layer.Pants, Layer.Ring,
|
||||
Layer.Shirt, Layer.Shoes, Layer.Talisman, Layer.TwoHanded, Layer.Waist, Layer.Mount
|
||||
};
|
||||
|
||||
public static int[] LayerTable { get; private set; }
|
||||
|
||||
static LayerExtUtility()
|
||||
{
|
||||
LayerTable = new int[256];
|
||||
|
||||
for (var i = 0; i < LayerOrder.Length; ++i)
|
||||
{
|
||||
LayerTable[(int)LayerOrder[i]] = LayerOrder.Length - i;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetOrderIndex(this Layer layer)
|
||||
{
|
||||
return LayerOrder.IndexOf(layer);
|
||||
}
|
||||
|
||||
public static bool IsEquip(this Layer layer)
|
||||
{
|
||||
return EquipLayers.Contains(layer);
|
||||
}
|
||||
|
||||
public static bool IsMount(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Mount;
|
||||
}
|
||||
|
||||
public static bool IsPack(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Backpack;
|
||||
}
|
||||
|
||||
public static bool IsBank(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Bank;
|
||||
}
|
||||
|
||||
public static bool IsPackOrBank(this Layer layer)
|
||||
{
|
||||
return IsPack(layer) || IsBank(layer);
|
||||
}
|
||||
|
||||
public static bool IsFace(this Layer layer)
|
||||
{
|
||||
return layer == _Face;
|
||||
}
|
||||
|
||||
public static bool IsHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Hair;
|
||||
}
|
||||
|
||||
public static bool IsFacialHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.FacialHair;
|
||||
}
|
||||
|
||||
public static bool IsHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsShop(this Layer layer)
|
||||
{
|
||||
return layer == Layer.ShopBuy || layer == Layer.ShopResale || layer == Layer.ShopSell || layer == _ShopMax;
|
||||
}
|
||||
|
||||
public static bool IsInvalid(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Invalid;
|
||||
}
|
||||
|
||||
public static bool IsValid(this Layer layer)
|
||||
{
|
||||
return IsEquip(layer) || IsPackOrBank(layer) || IsFaceOrHair(layer);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayer(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderBy(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayerDescending(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderByDescending(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayer(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderBy(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayerDescending(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderByDescending(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Item> items)
|
||||
{
|
||||
if (items != null && items.Count > 1)
|
||||
{
|
||||
items.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Layer> layers)
|
||||
{
|
||||
if (layers != null && layers.Count > 1)
|
||||
{
|
||||
layers.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Item item, Item other)
|
||||
{
|
||||
var res = 0;
|
||||
|
||||
if (item.CompareNull(other, ref res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
return CompareLayer(Fix(item.Layer, item.ItemID), Fix(other.Layer, other.ItemID));
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Layer layer, Layer other)
|
||||
{
|
||||
return LayerTable[(int)other] - LayerTable[(int)layer];
|
||||
}
|
||||
|
||||
public static bool IsOrdered(this Layer layer)
|
||||
{
|
||||
return LayerTable[(int)layer] > 0;
|
||||
}
|
||||
|
||||
public static Layer Fix(this Layer layer, int itemID)
|
||||
{
|
||||
if (itemID == 0x1410 || itemID == 0x1417) // platemail arms
|
||||
{
|
||||
return _PlateArms;
|
||||
}
|
||||
|
||||
if (itemID == 0x13BF || itemID == 0x13C4) // chainmail tunic
|
||||
{
|
||||
return _ChainTunic;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C08 || itemID == 0x1C09) // leather skirt
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C00 || itemID == 0x1C01) // leather shorts
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetPaperdollBounds(this Layer layer)
|
||||
{
|
||||
return PaperdollBounds.Find(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MapExtUtility
|
||||
{
|
||||
#region StaticWaterTiles
|
||||
public static List<int> StaticWaterTiles = new List<int>
|
||||
{
|
||||
5465,
|
||||
6038,
|
||||
6039,
|
||||
6040,
|
||||
6041,
|
||||
6042,
|
||||
6043,
|
||||
6044,
|
||||
13422,
|
||||
13423,
|
||||
13424,
|
||||
13425,
|
||||
13426,
|
||||
13427,
|
||||
13428,
|
||||
13429,
|
||||
13430,
|
||||
13431,
|
||||
13432,
|
||||
13433,
|
||||
13434,
|
||||
13435,
|
||||
13436,
|
||||
13437,
|
||||
13438,
|
||||
13439,
|
||||
13440,
|
||||
13441,
|
||||
13442,
|
||||
13443,
|
||||
13445,
|
||||
13456,
|
||||
13457,
|
||||
13458,
|
||||
13459,
|
||||
13460,
|
||||
13461,
|
||||
13462,
|
||||
13463,
|
||||
13464,
|
||||
13465,
|
||||
13466,
|
||||
13467,
|
||||
13468,
|
||||
13469,
|
||||
13470,
|
||||
13471,
|
||||
13472,
|
||||
13473,
|
||||
13474,
|
||||
13475,
|
||||
13476,
|
||||
13477,
|
||||
13478,
|
||||
13479,
|
||||
13480,
|
||||
13481,
|
||||
13482,
|
||||
13483,
|
||||
13494,
|
||||
13495,
|
||||
13496,
|
||||
13497,
|
||||
13498,
|
||||
13499,
|
||||
13500,
|
||||
13501,
|
||||
13502,
|
||||
13503,
|
||||
13504,
|
||||
13505,
|
||||
13506,
|
||||
13507,
|
||||
13508,
|
||||
13509,
|
||||
13510,
|
||||
13511,
|
||||
13512,
|
||||
13513,
|
||||
13514,
|
||||
13515,
|
||||
13516,
|
||||
13517,
|
||||
13518,
|
||||
13519,
|
||||
13520,
|
||||
13521,
|
||||
13522,
|
||||
13523,
|
||||
13524,
|
||||
13525,
|
||||
13597,
|
||||
13598,
|
||||
13599,
|
||||
13600,
|
||||
13601,
|
||||
13602,
|
||||
13603,
|
||||
13604,
|
||||
13605,
|
||||
13606,
|
||||
13607,
|
||||
13608,
|
||||
13609,
|
||||
13610,
|
||||
13611,
|
||||
13612,
|
||||
13613,
|
||||
13614,
|
||||
13615,
|
||||
13616
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandWaterTiles
|
||||
public static List<int> LandWaterTiles = new List<int>
|
||||
{
|
||||
168,
|
||||
169,
|
||||
170,
|
||||
171,
|
||||
310,
|
||||
311,
|
||||
|
||||
#region Coastlines
|
||||
76,
|
||||
77,
|
||||
78,
|
||||
79,
|
||||
80,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
92,
|
||||
93,
|
||||
94,
|
||||
95,
|
||||
96,
|
||||
97,
|
||||
98,
|
||||
99,
|
||||
100,
|
||||
101,
|
||||
102,
|
||||
103,
|
||||
104,
|
||||
105,
|
||||
106,
|
||||
107,
|
||||
108,
|
||||
109,
|
||||
110,
|
||||
111
|
||||
#endregion
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandCoastlineTiles
|
||||
public static List<int> LandCoastlineTiles = new List<int>
|
||||
{
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
50
|
||||
};
|
||||
#endregion
|
||||
|
||||
public static bool IsWater(this Item item)
|
||||
{
|
||||
return StaticWaterTiles.Contains(item.ItemID) || item.ItemData.Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(item.Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTarget targ)
|
||||
{
|
||||
return LandWaterTiles.Contains(targ.TileID) || TileData.LandTable[targ.TileID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[targ.TileID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTarget targ)
|
||||
{
|
||||
return StaticWaterTiles.Contains(targ.ItemID) || TileData.ItemTable[targ.ItemID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[targ.ItemID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTile tile)
|
||||
{
|
||||
return LandWaterTiles.Contains(tile.ID) || TileData.LandTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTile tile)
|
||||
{
|
||||
return StaticWaterTiles.Contains(tile.ID) || TileData.ItemTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsCoastline(this LandTile tile)
|
||||
{
|
||||
return LandCoastlineTiles.Contains(tile.ID) || (TileData.LandTable[tile.ID].Flags == TileFlag.Impassable &&
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "sand"));
|
||||
}
|
||||
|
||||
public static bool HasWater(this Map map, IPoint2D p)
|
||||
{
|
||||
return IsWater(GetLandTile(map, p)) || GetStaticTiles(map, p).Any(IsWater);
|
||||
}
|
||||
|
||||
public static bool HasLand(this Map map, IPoint2D p)
|
||||
{
|
||||
return !GetLandTile(map, p).Ignored;
|
||||
}
|
||||
|
||||
public static LandTile GetLandTile(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetLandTile(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p, bool multis)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetInnerBounds2D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle2D(0, 0, Math.Min(5120, map.Width), map.Height);
|
||||
case 3:
|
||||
return new Rectangle2D(512, 0, map.Width - 512, map.Height);
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetInnerBounds3D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle3D(0, 0, Region.MinZ, Math.Min(5120, map.Width), map.Height, Region.MaxZ - Region.MinZ);
|
||||
case 3:
|
||||
return new Rectangle3D(512, 0, Region.MinZ, map.Width - 512, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds2D(this Map map)
|
||||
{
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds3D(this Map map)
|
||||
{
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MultiExtUtility
|
||||
{
|
||||
static MultiExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
WireframeCache = new Dictionary<int, Wireframe>();
|
||||
BoundsCache = new Dictionary<int, Rectangle3D>();
|
||||
}
|
||||
|
||||
#region Components
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi)
|
||||
{
|
||||
return GetComponents(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetComponents(multiID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (ComponentsCache.TryGetValue(multiID, out var mcl) && mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
ComponentsCache[multiID] = mcl = MultiData.GetComponents(multiID);
|
||||
|
||||
// Minax Fortress
|
||||
if (multiID == 0x1388)
|
||||
{
|
||||
// That tree...
|
||||
mcl.Remove(3405, 17, -13, 15);
|
||||
mcl.Remove(3406, 18, -14, 15);
|
||||
mcl.Remove(3393, 18, -14, 17);
|
||||
}
|
||||
|
||||
if (mcl.List.Length == 0)
|
||||
{
|
||||
mcl.Resize(1, 1);
|
||||
mcl.Add(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
return mcl;
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, int x, int y, int w, int h, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, new Rectangle2D(x, y, w, h), z, d);
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle2D bounds, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, bounds.ToRectangle3D(z, d));
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle3D bounds)
|
||||
{
|
||||
for (var z = bounds.Start.Z; z < bounds.End.Z; z++)
|
||||
{
|
||||
for (var x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
for (var y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
mcl.Add(itemID, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Wireframes
|
||||
public static Dictionary<int, Wireframe> WireframeCache { get; private set; }
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset, int hOffset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset, hOffset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, 0);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, offset.H);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset, int hOffset)
|
||||
{
|
||||
var o = GetWireframe(multi, multiID);
|
||||
|
||||
return new Wireframe(o.Select(b => b.Offset(offset.X, offset.Y, offset.Z, hOffset)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID < 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetWireframe(multiID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (WireframeCache.TryGetValue(multiID, out var frame))
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
frame = GetWireframe(GetComponents(multiID));
|
||||
|
||||
WireframeCache[multiID] = frame;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IPoint3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Select(b => b.Offset(offset.X, offset.Y, offset.Z)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IBlock3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Offset(offset.X, offset.Y, offset.Z, offset.H));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Wireframe.Empty;
|
||||
}
|
||||
|
||||
var frame = new Block3D[mcl.List.Length];
|
||||
|
||||
frame.SetAll(
|
||||
i =>
|
||||
{
|
||||
var o = mcl.List[i];
|
||||
var h = Math.Max(5, TileData.ItemTable[o.m_ItemID].Height);
|
||||
|
||||
return new Block3D(o.m_OffsetX, o.m_OffsetY, o.m_OffsetZ, h);
|
||||
});
|
||||
|
||||
return new Wireframe(frame);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Bounds
|
||||
public static Dictionary<int, Rectangle3D> BoundsCache { get; private set; }
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi)
|
||||
{
|
||||
return GetBoundsOffset(multi, multi.Location);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi, Point3D offset)
|
||||
{
|
||||
return GetBounds(multi).Resize(offset.X, offset.Y, offset.Z);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi)
|
||||
{
|
||||
return GetBounds(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetBounds(multiID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (BoundsCache.TryGetValue(multiID, out var bounds))
|
||||
{
|
||||
return bounds;
|
||||
}
|
||||
|
||||
var mcl = GetComponents(multiID);
|
||||
|
||||
int minZ = mcl.List.Min(t => t.m_OffsetZ);
|
||||
var maxZ = mcl.List.Max(t => t.m_OffsetZ + Math.Max(1, TileData.ItemTable[t.m_ItemID].Height));
|
||||
|
||||
if (multiID >= 24 && multiID <= 71)
|
||||
{
|
||||
if (multiID >= 24 && multiID <= 35)
|
||||
{
|
||||
maxZ = Math.Max(80, maxZ);
|
||||
}
|
||||
else if (multiID >= 36 && multiID <= 47)
|
||||
{
|
||||
maxZ = Math.Max(100, maxZ);
|
||||
}
|
||||
else if (multiID >= 48 && multiID <= 59)
|
||||
{
|
||||
maxZ = Math.Max(90, maxZ);
|
||||
}
|
||||
else if (multiID >= 60 && multiID <= 63)
|
||||
{
|
||||
maxZ = Math.Max(20, maxZ);
|
||||
}
|
||||
else if (multiID >= 64 && multiID <= 71)
|
||||
{
|
||||
maxZ = Math.Max(110, maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
bounds = new Rectangle3D(mcl.Min.X, mcl.Min.Y, minZ, mcl.Width + 1, mcl.Height + 1, maxZ - minZ);
|
||||
|
||||
BoundsCache[multiID] = bounds;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public static bool Contains(Point2D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(Point3D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(IPoint3D p)
|
||||
{
|
||||
return Contains(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(int x, int y)
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
|
||||
x -= X + mcl.Min.m_X;
|
||||
y -= Y + mcl.Min.m_Y;
|
||||
|
||||
return x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height && mcl.Tiles[x][y].Length > 0;
|
||||
}
|
||||
*/
|
||||
|
||||
public static bool IsEmpty(this MultiComponentList mcl, int x, int y)
|
||||
{
|
||||
return x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height || mcl.Tiles[x][y].Length == 0;
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.Z == z);
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int itemID, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.ID == itemID && t.Z == z);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetAbsoluteBounds(this MultiComponentList mcl)
|
||||
{
|
||||
return new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
#if !ServUOX
|
||||
using System;
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class NetStateExtUtility
|
||||
{
|
||||
private static readonly ClientVersion _70500 = new ClientVersion(7, 0, 50, 0);
|
||||
private static readonly ClientVersion _70610 = new ClientVersion(7, 0, 61, 0);
|
||||
|
||||
public static bool IsEnhanced(this NetState state)
|
||||
{
|
||||
#if ServUOX
|
||||
return state?.IsEnhancedClient == true;
|
||||
#else
|
||||
var v = state.Version;
|
||||
|
||||
if (v == null || (v.Major == 0 && v.Minor == 0 && v.Revision == 0 && v.Patch == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.GetPropertyValue("IsEnhancedClient", out bool ec))
|
||||
{
|
||||
ec = v.Major >= 67 || v.Type == ClientType.UOTD;
|
||||
}
|
||||
|
||||
return ec;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool SupportsUltimaStore(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70500;
|
||||
}
|
||||
|
||||
public static bool SupportsEndlessJourney(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70610;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum NotorietyType
|
||||
{
|
||||
None = 0,
|
||||
Innocent = Notoriety.Innocent,
|
||||
Ally = Notoriety.Ally,
|
||||
CanBeAttacked = Notoriety.CanBeAttacked,
|
||||
Criminal = Notoriety.Criminal,
|
||||
Enemy = Notoriety.Enemy,
|
||||
Murderer = Notoriety.Murderer,
|
||||
Invulnerable = Notoriety.Invulnerable
|
||||
}
|
||||
|
||||
public static class NotorietyExtUtility
|
||||
{
|
||||
public static int GetHue(this NotorietyType noto)
|
||||
{
|
||||
return Notoriety.GetHue((int)noto);
|
||||
}
|
||||
|
||||
public static Color GetColor(this NotorietyType noto)
|
||||
{
|
||||
switch ((int)noto)
|
||||
{
|
||||
case Notoriety.Innocent:
|
||||
return Color.SkyBlue;
|
||||
case Notoriety.Ally:
|
||||
return Color.LawnGreen;
|
||||
case Notoriety.CanBeAttacked:
|
||||
case Notoriety.Criminal:
|
||||
return Color.Silver;
|
||||
case Notoriety.Enemy:
|
||||
return Color.Orange;
|
||||
case Notoriety.Murderer:
|
||||
return Color.IndianRed;
|
||||
case Notoriety.Invulnerable:
|
||||
return Color.Yellow;
|
||||
}
|
||||
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Network;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Network
|
||||
{
|
||||
public static class PacketExtUtility
|
||||
{
|
||||
#if ServUOX
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset;
|
||||
|
||||
if (p.PacketID == 0x1A)
|
||||
{
|
||||
offset = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 8;
|
||||
}
|
||||
|
||||
return Rewrite(p, offset, (ushort)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#else
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemHS p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingOld p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingOld p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingSA p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, bool value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, sbyte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, byte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, short value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, ushort value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, int value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, uint value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
private static bool Rewrite<T>(PacketWriter writer, int offset, bool reset, Action<T> write, T value)
|
||||
{
|
||||
var pos = -1L;
|
||||
|
||||
try
|
||||
{
|
||||
pos = writer.Position;
|
||||
|
||||
writer.Position = offset;
|
||||
|
||||
write(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reset && pos >= 0)
|
||||
{
|
||||
writer.Position = pos;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] GetBuffer(this Packet packet)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
if (writer != null)
|
||||
{
|
||||
return writer.ToArray();
|
||||
}
|
||||
|
||||
if (GetCompiledBuffer(packet, out var buffer))
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public static bool GetCompiledBuffer(this Packet packet, out byte[] buffer)
|
||||
{
|
||||
return packet.GetFieldValue("m_CompiledBuffer", out buffer);
|
||||
}
|
||||
|
||||
public static bool SetCompiledBuffer(this Packet packet, byte[] buffer)
|
||||
{
|
||||
return packet.SetFieldValue("m_CompiledBuffer", buffer);
|
||||
}
|
||||
|
||||
public static PacketWriter GetWriter(this Packet packet)
|
||||
{
|
||||
#if ServUOX
|
||||
return packet?.Stream;
|
||||
#else
|
||||
return packet?.UnderlyingStream;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public static class PlayerMobileExtUtility
|
||||
{
|
||||
public static ClientVersion GetClientVersion(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version : new ClientVersion(null);
|
||||
}
|
||||
|
||||
public static ClientType GetClientType(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version.Type : ClientType.Regular;
|
||||
}
|
||||
|
||||
public static bool HasClient(this PlayerMobile player, ClientType type)
|
||||
{
|
||||
return player.IsOnline() && player.NetState.Version.Type == type;
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, MapPoint mp)
|
||||
{
|
||||
FixMap(m, mp.Map, mp.Location);
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, Map def, Point3D loc)
|
||||
{
|
||||
if (m == null || m.Deleted || def == null || def == Map.Internal || loc == Point3D.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.LogoutMap == null || m.LogoutMap == Map.Internal)
|
||||
{
|
||||
m.LogoutLocation = loc.ToPoint3D();
|
||||
m.LogoutMap = def;
|
||||
}
|
||||
|
||||
if (m.Map != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.IsOnline())
|
||||
{
|
||||
BaseCreature.TeleportPets(m, loc, def);
|
||||
m.MoveToWorld(loc, def);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.Location = loc;
|
||||
m.Internalize();
|
||||
m.AutoStablePets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,247 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle2DExtUtility
|
||||
{
|
||||
public static Point2D GetRandomPoint(this Rectangle2D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine(this IEnumerable<Rectangle2D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D ToRectangle3D(this Rectangle2D r, int floor = 0, int roof = 0)
|
||||
{
|
||||
return new Rectangle3D(r.X, r.Y, floor, r.Width, r.Height, roof);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle2D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle2D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
public static Point2D GetCenter(this Rectangle2D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle2D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize(this Rectangle2D r, int xOff = 0, int yOff = 0, int wOff = 0, int hOff = 0)
|
||||
{
|
||||
return new Rectangle2D(r.X + xOff, r.Y + yOff, r.Width + wOff, r.Height + hOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice(this Rectangle2D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
int ow, oh;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle2D(x, y, ow, oh);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle2D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints(this Rectangle2D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle2D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle2D r, Rectangle2D or)
|
||||
{
|
||||
return GetBorder(r).Union(GetBorder(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle3DExtUtility
|
||||
{
|
||||
public static Point3D GetRandomPoint(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point3D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y),
|
||||
Utility.RandomMinMax(bounds.Start.Z, bounds.End.Z));
|
||||
}
|
||||
|
||||
public static Point2D GetRandomPoint2D(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine2D(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D Combine(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0,
|
||||
minX = Int32.MaxValue,
|
||||
minY = Int32.MaxValue,
|
||||
maxX = Int32.MinValue,
|
||||
maxY = Int32.MinValue,
|
||||
minZ = Region.MaxZ,
|
||||
maxZ = Region.MinZ;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
minZ = Math.Min(minZ, Math.Min(r.Start.Z, r.End.Z));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
maxZ = Math.Max(maxZ, Math.Max(r.Start.Z, r.End.Z));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle3D(new Point3D(minX, minY, minZ), new Point3D(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects)
|
||||
{
|
||||
return ZFix(rects, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects, int zMin, int zMax)
|
||||
{
|
||||
if (rects == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var r in rects.Select(r => r.ZFix(zMin, zMax)))
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect)
|
||||
{
|
||||
return ZFix(rect, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect, int zMin, int zMax)
|
||||
{
|
||||
return new Rectangle3D(rect.Start.ToPoint3D(Math.Min(zMin, zMax)), rect.End.ToPoint3D(Math.Max(zMin, zMax)));
|
||||
}
|
||||
|
||||
public static Rectangle2D ToRectangle2D(this Rectangle3D r)
|
||||
{
|
||||
return new Rectangle2D(r.Start, r.End);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle3D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height * r.Depth;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle3D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this RegionRect[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this List<RegionRect> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<RegionRect> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint2D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint3D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y)
|
||||
{
|
||||
return x >= rect.Start.X && y >= rect.Start.Y && x < rect.End.X && y < rect.End.Y;
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y, int z)
|
||||
{
|
||||
return Contains(rect, x, y) && z >= rect.Start.Z && z < rect.End.Z;
|
||||
}
|
||||
|
||||
public static Point2D GetCenter2D(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static Point3D GetCenter(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone3D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static int GetVolume(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height * r.Depth;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize2D(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
return ToRectangle2D(r).Resize(xOff, yOff, wOff, hOff);
|
||||
}
|
||||
|
||||
public static Rectangle3D Resize(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
var s = r.Start;
|
||||
|
||||
return new Rectangle3D(s.X + xOff, s.Y + yOff, s.Z + zOff, r.Width + wOff, r.Height + hOff, r.Depth + dOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice2D(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
return ToRectangle2D(rect).Slice(w, h);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> Slice(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y, z = Math.Min(rect.Start.Z, rect.End.Z);
|
||||
int ow, oh, od = rect.Depth;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle3D(x, y, z, ow, oh, od);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle3D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints2D(this Rectangle3D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> EnumeratePoints(this Rectangle3D r)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach2D(this Rectangle3D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints2D(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle3D r, Action<Point3D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder2D(r, 1);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r, int size)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size, z1 = r.Start.Z + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size, z2 = r.End.Z - size;
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
if (z >= z1 || z <= z2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects2D(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
return GetBorder2D(r).Any(GetBorder2D(or).Contains);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
var minZL = Math.Min(r.Start.Z, r.End.Z);
|
||||
var maxZL = Math.Max(r.Start.Z, r.End.Z);
|
||||
|
||||
var minZR = Math.Min(or.Start.Z, or.End.Z);
|
||||
var maxZR = Math.Max(or.Start.Z, or.End.Z);
|
||||
|
||||
if (minZL > maxZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxZL < minZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetBorder2D(r).Union(GetBorder2D(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
@@ -0,0 +1,618 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Crypto;
|
||||
using VitaNex.FX;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class RegionExtUtility
|
||||
{
|
||||
public class RegionSerial : CryptoHashCode
|
||||
{
|
||||
public override string Value => base.Value.Replace("-", String.Empty);
|
||||
|
||||
public RegionSerial(Region r)
|
||||
: base(
|
||||
CryptoHashType.MD5,
|
||||
r.GetType().FullName + r.Map.Name + r.Name + r.Area.GetBoundsHashCode() + TimeStamp.UtcNow.Stamp +
|
||||
Utility.RandomDouble())
|
||||
{ }
|
||||
|
||||
public RegionSerial(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PreviewRegion : Region, IEquatable<Region>
|
||||
{
|
||||
private static ulong _UID;
|
||||
|
||||
public RegionSerial Serial { get; private set; }
|
||||
|
||||
public PollTimer Timer { get; private set; }
|
||||
public EffectInfo[] Effects { get; private set; }
|
||||
|
||||
public DateTime Expire { get; set; }
|
||||
public int EffectID { get; set; }
|
||||
public int EffectHue { get; set; }
|
||||
public EffectRender EffectRender { get; set; }
|
||||
|
||||
public PreviewRegion(Region r)
|
||||
: this(r.Name, r.Map, r.Area)
|
||||
{
|
||||
Serial = GetSerial(r);
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle2D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle3D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
EffectID = 1801;
|
||||
EffectHue = 85;
|
||||
EffectRender = EffectRender.ShadowOutline;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public override void OnRegister()
|
||||
{
|
||||
base.OnRegister();
|
||||
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
if (Effects == null)
|
||||
{
|
||||
var effects = new EffectInfo[Area.Length][,];
|
||||
|
||||
effects.SetAll(i => new EffectInfo[Area[i].Width, Area[i].Height]);
|
||||
|
||||
for (var index = 0; index < Area.Length; index++)
|
||||
{
|
||||
var b = Area[index];
|
||||
|
||||
var xSpacing = Math.Max(1, Math.Min(16, b.Width / 8));
|
||||
var ySpacing = Math.Max(1, Math.Min(16, b.Height / 8));
|
||||
|
||||
var minX = Math.Min(b.Start.X, b.End.X);
|
||||
var maxX = Math.Max(b.Start.X, b.End.X);
|
||||
|
||||
var minY = Math.Min(b.Start.Y, b.End.Y);
|
||||
var maxY = Math.Max(b.Start.Y, b.End.Y);
|
||||
|
||||
Parallel.For(
|
||||
minX,
|
||||
maxX,
|
||||
x => Parallel.For(
|
||||
minY,
|
||||
maxY,
|
||||
y =>
|
||||
{
|
||||
if (x != b.Start.X && x != b.End.X - 1 && x % xSpacing != 0 //
|
||||
&& y != b.Start.Y && y != b.End.Y - 1 && y % ySpacing != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var idxX = x - minX;
|
||||
var idxY = y - minY;
|
||||
|
||||
effects[index][idxX, idxY] = new EffectInfo(
|
||||
new Point3D(x, y, 0),
|
||||
Map,
|
||||
EffectID,
|
||||
EffectHue,
|
||||
1,
|
||||
25,
|
||||
EffectRender);
|
||||
}));
|
||||
}
|
||||
|
||||
Effects = effects.SelectMany(list => list.OfType<EffectInfo>()).ToArray();
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.SetSource(e.Source.ToPoint3D(e.Source.GetAverageZ(e.Map)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Timer == null)
|
||||
{
|
||||
Timer = PollTimer.FromSeconds(
|
||||
1.0,
|
||||
() =>
|
||||
{
|
||||
if (DateTime.UtcNow > Expire)
|
||||
{
|
||||
Unregister();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Send();
|
||||
}
|
||||
},
|
||||
() => Registered);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer.Running = true;
|
||||
}
|
||||
|
||||
_Previews.Update(Serial, this);
|
||||
}
|
||||
|
||||
public override void OnUnregister()
|
||||
{
|
||||
base.OnUnregister();
|
||||
|
||||
if (Timer != null)
|
||||
{
|
||||
Timer.Running = false;
|
||||
Timer = null;
|
||||
}
|
||||
|
||||
if (Effects != null)
|
||||
{
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
|
||||
Effects.SetAll(i => null);
|
||||
Effects = null;
|
||||
}
|
||||
|
||||
Expire = DateTime.UtcNow;
|
||||
|
||||
_Previews.Remove(Serial);
|
||||
}
|
||||
|
||||
public bool Equals(Region other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && Serial.Equals(GetSerial(other));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<RegionSerial, Region> _Regions;
|
||||
private static readonly Dictionary<RegionSerial, PreviewRegion> _Previews;
|
||||
|
||||
static RegionExtUtility()
|
||||
{
|
||||
_Regions = new Dictionary<RegionSerial, Region>();
|
||||
_Previews = new Dictionary<RegionSerial, PreviewRegion>();
|
||||
}
|
||||
|
||||
public static RegionSerial GetSerial(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
return ((PreviewRegion)r).Serial;
|
||||
}
|
||||
|
||||
lock (_Regions)
|
||||
{
|
||||
if (_Regions.ContainsValue(r))
|
||||
{
|
||||
return _Regions.GetKey(r);
|
||||
}
|
||||
|
||||
var s = new RegionSerial(r);
|
||||
|
||||
_Regions.Update(s, r);
|
||||
|
||||
//Console.WriteLine("Region Serial: ('{0}', '{1}', '{2}') = {3}", r.GetType().Name, r.Map, r.Name, s.ValueHash);
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle2D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle3D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
this Region r,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent)
|
||||
{
|
||||
if (r == null || r.Area == null || r.Area.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hue < 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
|
||||
if (effect <= 0)
|
||||
{
|
||||
effect = 1801;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.EffectID = effect;
|
||||
pr.EffectHue = hue;
|
||||
pr.EffectRender = render;
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null && pr.Area.GetBoundsHashCode() != r.Area.GetBoundsHashCode())
|
||||
{
|
||||
pr.Unregister();
|
||||
pr = null;
|
||||
}
|
||||
|
||||
if (pr == null)
|
||||
{
|
||||
pr = new PreviewRegion(r)
|
||||
{
|
||||
EffectHue = hue,
|
||||
EffectID = effect,
|
||||
EffectRender = render
|
||||
};
|
||||
}
|
||||
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
public static void ClearPreview(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.Unregister();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null)
|
||||
{
|
||||
pr.Unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p, Map m)
|
||||
{
|
||||
return s.Owner == m && s.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Region r, Point3D p, Map m)
|
||||
{
|
||||
return r.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects.Values.SelectMany(o => o))
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
public static bool Contains(this RegionRect r, Point3D p, Map m)
|
||||
{
|
||||
return r.Region.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects)
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect r, Point3D p)
|
||||
{
|
||||
return r.Rect.Contains(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion Create<TRegion>(params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
return Create(typeof(TRegion), args) as TRegion;
|
||||
}
|
||||
|
||||
public static Region Create(Type type, params object[] args)
|
||||
{
|
||||
return type.CreateInstanceSafe<Region>(args);
|
||||
}
|
||||
|
||||
public static TRegion Clone<TRegion>(this TRegion region, params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (region == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fields = region.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var remove = new[]
|
||||
{
|
||||
"Serial",
|
||||
"Name",
|
||||
"Map",
|
||||
"Parent",
|
||||
"Area",
|
||||
"Sectors",
|
||||
"ChildLevel",
|
||||
"Registered"
|
||||
};
|
||||
|
||||
foreach (var entry in remove)
|
||||
{
|
||||
if (!fields.Remove("m_" + entry))
|
||||
{
|
||||
fields.Remove("_" + entry);
|
||||
}
|
||||
}
|
||||
|
||||
region.Unregister();
|
||||
|
||||
var reg = Create(region.GetType(), args) as TRegion;
|
||||
|
||||
if (reg != null)
|
||||
{
|
||||
fields.Serialize(reg);
|
||||
reg.Register();
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool IsPartOf<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf<TRegion>();
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion<TRegion>() : null;
|
||||
}
|
||||
#else
|
||||
public static bool IsPartOf<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf(typeof(TRegion));
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion(typeof(TRegion)) as TRegion : null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null ? GetRegion<TRegion>(m.Region) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null && GetRegion<TRegion>(m.Region) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && GetRegion(m, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && GetRegion(m, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Region r)
|
||||
{
|
||||
return m != null && m.Region != null && m.Region.IsPartOf(r);
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Region.Find(i.GetWorldLocation(), i.Map);
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? GetRegion<TRegion>(reg) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, string name)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, Type type)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && GetRegion<TRegion>(reg) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Type type)
|
||||
{
|
||||
return i != null && GetRegion(i, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, string name)
|
||||
{
|
||||
return i != null && GetRegion(i, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Region r)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && reg.IsPartOf(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum SkillCategory
|
||||
{
|
||||
None = 0,
|
||||
Combat,
|
||||
Healing,
|
||||
Magic,
|
||||
Bardic,
|
||||
Rogue,
|
||||
Knowledge,
|
||||
Craft,
|
||||
Harvest
|
||||
}
|
||||
|
||||
public enum SkillIcon
|
||||
{
|
||||
None = 1033,
|
||||
Combat = 1008,
|
||||
Healing = 1037,
|
||||
Magic = 1006,
|
||||
Bardic = 1031,
|
||||
Rogue = 1002,
|
||||
Knowledge = 1034,
|
||||
Craft = 1030,
|
||||
Harvest = 1036
|
||||
}
|
||||
|
||||
public static class SkillExtUtility
|
||||
{
|
||||
public static readonly SkillName[] EmptySkills = new SkillName[0];
|
||||
|
||||
public static readonly SkillName[] AllSkills = default(SkillName).GetValues<SkillName>();
|
||||
|
||||
public static readonly SkillName[] CombatSkills =
|
||||
{
|
||||
SkillName.Archery, SkillName.Fencing, SkillName.Focus, SkillName.Macing, SkillName.Parry, SkillName.Swords,
|
||||
SkillName.Tactics, SkillName.Wrestling, SkillName.Bushido
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HealingSkills =
|
||||
{
|
||||
SkillName.Healing, SkillName.Veterinary
|
||||
};
|
||||
|
||||
public static readonly SkillName[] MagicSkills =
|
||||
{
|
||||
SkillName.EvalInt, SkillName.Inscribe, SkillName.Magery, SkillName.Meditation, SkillName.Chivalry,
|
||||
SkillName.Necromancy, SkillName.MagicResist, SkillName.Spellweaving, SkillName.SpiritSpeak
|
||||
};
|
||||
|
||||
public static readonly SkillName[] BardicSkills =
|
||||
{SkillName.Discordance, SkillName.Musicianship, SkillName.Peacemaking, SkillName.Provocation};
|
||||
|
||||
public static readonly SkillName[] RogueSkills =
|
||||
{
|
||||
SkillName.Begging, SkillName.DetectHidden, SkillName.Hiding, SkillName.Lockpicking, SkillName.Poisoning,
|
||||
SkillName.RemoveTrap, SkillName.Snooping, SkillName.Stealing, SkillName.Stealth, SkillName.Ninjitsu
|
||||
};
|
||||
|
||||
public static readonly SkillName[] KnowledgeSkills =
|
||||
{
|
||||
SkillName.Anatomy, SkillName.AnimalLore, SkillName.AnimalTaming, SkillName.ArmsLore, SkillName.Camping,
|
||||
SkillName.Forensics, SkillName.Herding, SkillName.ItemID, SkillName.TasteID, SkillName.Tracking
|
||||
};
|
||||
|
||||
public static readonly SkillName[] CraftSkills =
|
||||
{
|
||||
SkillName.Alchemy, SkillName.Blacksmith, SkillName.Fletching, SkillName.Carpentry, SkillName.Cooking,
|
||||
SkillName.Cartography, SkillName.Tailoring, SkillName.Tinkering, SkillName.Imbuing
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HarvestSkills =
|
||||
{
|
||||
SkillName.Fishing, SkillName.Mining, SkillName.Lumberjacking
|
||||
};
|
||||
|
||||
public static readonly SkillCategory[] Categories =
|
||||
{
|
||||
SkillCategory.Combat, SkillCategory.Healing, SkillCategory.Magic, SkillCategory.Bardic, SkillCategory.Rogue,
|
||||
SkillCategory.Knowledge, SkillCategory.Craft, SkillCategory.Harvest
|
||||
};
|
||||
|
||||
public static readonly SkillIcon[] Icons =
|
||||
{
|
||||
SkillIcon.None, SkillIcon.Combat, SkillIcon.Healing, SkillIcon.Magic, SkillIcon.Bardic, SkillIcon.Rogue,
|
||||
SkillIcon.Knowledge, SkillIcon.Craft, SkillIcon.Harvest
|
||||
};
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName)).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills, Expansion ex)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName), ex).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills)
|
||||
{
|
||||
return OfExpansion(skills, Core.Expansion);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills, Expansion ex)
|
||||
{
|
||||
foreach (var sk in skills)
|
||||
{
|
||||
switch (sk)
|
||||
{
|
||||
case SkillName.Chivalry:
|
||||
case SkillName.Focus:
|
||||
case SkillName.Necromancy:
|
||||
case SkillName.SpiritSpeak:
|
||||
{
|
||||
if (ex >= Expansion.AOS)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Bushido:
|
||||
case SkillName.Ninjitsu:
|
||||
{
|
||||
if (ex >= Expansion.SE)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Spellweaving:
|
||||
{
|
||||
if (ex >= Expansion.ML)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Imbuing:
|
||||
case SkillName.Throwing:
|
||||
case SkillName.Mysticism:
|
||||
{
|
||||
if (ex >= Expansion.SA)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
yield return sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SkillName[] GetSkills(this SkillCategory cat)
|
||||
{
|
||||
switch (cat)
|
||||
{
|
||||
case SkillCategory.Combat:
|
||||
return CombatSkills;
|
||||
case SkillCategory.Healing:
|
||||
return HealingSkills;
|
||||
case SkillCategory.Magic:
|
||||
return MagicSkills;
|
||||
case SkillCategory.Bardic:
|
||||
return BardicSkills;
|
||||
case SkillCategory.Rogue:
|
||||
return RogueSkills;
|
||||
case SkillCategory.Knowledge:
|
||||
return KnowledgeSkills;
|
||||
case SkillCategory.Craft:
|
||||
return CraftSkills;
|
||||
case SkillCategory.Harvest:
|
||||
return HarvestSkills;
|
||||
}
|
||||
|
||||
return EmptySkills;
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillCategory cat)
|
||||
{
|
||||
return Icons[(int)cat];
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillInfo info)
|
||||
{
|
||||
return GetIcon((SkillName)info.SkillID);
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillName skill)
|
||||
{
|
||||
return GetIcon(GetCategory(skill));
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillInfo info)
|
||||
{
|
||||
return (int)GetIcon(info);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillCategory cat)
|
||||
{
|
||||
return (int)GetIcon(cat);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillName skill)
|
||||
{
|
||||
return (int)GetIcon(skill);
|
||||
}
|
||||
|
||||
public static bool IsLocked(this Skill skill, SkillLock locked)
|
||||
{
|
||||
return skill.Lock == locked;
|
||||
}
|
||||
|
||||
public static bool IsCapped(this Skill skill)
|
||||
{
|
||||
return skill.Base >= skill.Cap;
|
||||
}
|
||||
|
||||
public static bool IsZero(this Skill skill)
|
||||
{
|
||||
return skill.Base <= 0;
|
||||
}
|
||||
|
||||
public static bool IsZeroOrCapped(this Skill skill)
|
||||
{
|
||||
return IsZero(skill) || IsCapped(skill);
|
||||
}
|
||||
|
||||
public static bool WillCap(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base + value >= skill.Cap) : (skill.Base + value > skill.Cap);
|
||||
}
|
||||
|
||||
public static bool WillZero(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base - value <= 0) : (skill.Base - value < 0);
|
||||
}
|
||||
|
||||
public static bool DecreaseBase(this Skill skill, double value, bool ignoreZero = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreZero || (!IsZero(skill) && !WillZero(skill, value, false)))
|
||||
{
|
||||
skill.Base -= value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IncreaseBase(this Skill skill, double value, bool ignoreCap = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Cap - skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreCap || (!IsCapped(skill) && !WillCap(skill, value, false)))
|
||||
{
|
||||
skill.Base += value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetBase(this Skill skill, double value, bool ignoreLimits = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Max(0, Math.Min(skill.Cap, value));
|
||||
}
|
||||
|
||||
if (ignoreLimits || (value < skill.Base && !IsZero(skill) && !WillZero(skill, skill.Base - value, false)) ||
|
||||
(value > skill.Base && !IsCapped(skill) && !WillCap(skill, value - skill.Base, false)))
|
||||
{
|
||||
skill.Base = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void DecreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap - value);
|
||||
}
|
||||
|
||||
public static void IncreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap + value);
|
||||
}
|
||||
|
||||
public static void SetCap(this Skill skill, double value)
|
||||
{
|
||||
skill.Cap = Math.Max(0, value);
|
||||
Normalize(skill);
|
||||
}
|
||||
|
||||
public static void Normalize(this Skill skill)
|
||||
{
|
||||
if (IsCapped(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = skill.CapFixedPoint;
|
||||
}
|
||||
|
||||
if (IsZero(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetName(this SkillName skill)
|
||||
{
|
||||
return SkillInfo.Table[(int)skill].Name;
|
||||
}
|
||||
|
||||
public static bool CheckCategory(this SkillName skill, SkillCategory category)
|
||||
{
|
||||
return GetCategory(skill) == category;
|
||||
}
|
||||
|
||||
public static SkillCategory GetCategory(this SkillName skill)
|
||||
{
|
||||
if (IsCombat(skill))
|
||||
{
|
||||
return SkillCategory.Combat;
|
||||
}
|
||||
|
||||
if (IsHealing(skill))
|
||||
{
|
||||
return SkillCategory.Healing;
|
||||
}
|
||||
|
||||
if (IsMagic(skill))
|
||||
{
|
||||
return SkillCategory.Magic;
|
||||
}
|
||||
|
||||
if (IsBardic(skill))
|
||||
{
|
||||
return SkillCategory.Bardic;
|
||||
}
|
||||
|
||||
if (IsRogue(skill))
|
||||
{
|
||||
return SkillCategory.Rogue;
|
||||
}
|
||||
|
||||
if (IsKnowledge(skill))
|
||||
{
|
||||
return SkillCategory.Knowledge;
|
||||
}
|
||||
|
||||
if (IsCraft(skill))
|
||||
{
|
||||
return SkillCategory.Craft;
|
||||
}
|
||||
|
||||
if (IsHarvest(skill))
|
||||
{
|
||||
return SkillCategory.Harvest;
|
||||
}
|
||||
|
||||
return SkillCategory.None;
|
||||
}
|
||||
|
||||
public static bool IsCombat(this SkillName skill)
|
||||
{
|
||||
return CombatSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHealing(this SkillName skill)
|
||||
{
|
||||
return HealingSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsMagic(this SkillName skill)
|
||||
{
|
||||
return MagicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsBardic(this SkillName skill)
|
||||
{
|
||||
return BardicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsRogue(this SkillName skill)
|
||||
{
|
||||
return RogueSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsKnowledge(this SkillName skill)
|
||||
{
|
||||
return KnowledgeSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsCraft(this SkillName skill)
|
||||
{
|
||||
return CraftSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHarvest(this SkillName skill)
|
||||
{
|
||||
return HarvestSkills.Contains(skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Spells;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class SpellExtUtility
|
||||
{
|
||||
public static SpellInfo GetSpellInfo(this ISpell s)
|
||||
{
|
||||
return SpellUtility.GetSpellInfo(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
457
Scripts/SubSystem/VitaNex/Core/Extensions/System/ChronExt.cs
Normal file
457
Scripts/SubSystem/VitaNex/Core/Extensions/System/ChronExt.cs
Normal file
@@ -0,0 +1,457 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Text;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
[Flags]
|
||||
public enum Months
|
||||
{
|
||||
None = 0x000,
|
||||
January = 0x001,
|
||||
Febuary = 0x002,
|
||||
March = 0x004,
|
||||
April = 0x008,
|
||||
May = 0x010,
|
||||
June = 0x020,
|
||||
July = 0x040,
|
||||
August = 0x080,
|
||||
September = 0x100,
|
||||
October = 0x200,
|
||||
November = 0x400,
|
||||
December = 0x800,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
|
||||
public enum TimeUnit
|
||||
{
|
||||
Years,
|
||||
Months,
|
||||
Weeks,
|
||||
Days,
|
||||
Hours,
|
||||
Minutes,
|
||||
Seconds,
|
||||
Milliseconds
|
||||
}
|
||||
|
||||
public static class ChronExtUtility
|
||||
{
|
||||
public static bool InRange(this TimeSpan now, TimeSpan start, TimeSpan end)
|
||||
{
|
||||
if (start <= end)
|
||||
{
|
||||
return now >= start && now <= end;
|
||||
}
|
||||
|
||||
return now >= start || now <= end;
|
||||
}
|
||||
|
||||
public static bool InRange(this DateTime now, DateTime start, DateTime end)
|
||||
{
|
||||
if (now.Year < end.Year)
|
||||
{
|
||||
return now >= start;
|
||||
}
|
||||
|
||||
if (now.Year > start.Year)
|
||||
{
|
||||
return now <= end;
|
||||
}
|
||||
|
||||
return now >= start && now <= end;
|
||||
}
|
||||
|
||||
public static double GetTotal(this TimeSpan time, TimeUnit unit)
|
||||
{
|
||||
var total = (double)time.Ticks;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case TimeUnit.Years:
|
||||
total = time.TotalDays / 365.2422;
|
||||
break;
|
||||
case TimeUnit.Months:
|
||||
total = time.TotalDays / 30.43685;
|
||||
break;
|
||||
case TimeUnit.Weeks:
|
||||
total = time.TotalDays / 7.0;
|
||||
break;
|
||||
case TimeUnit.Days:
|
||||
total = time.TotalDays;
|
||||
break;
|
||||
case TimeUnit.Hours:
|
||||
total = time.TotalHours;
|
||||
break;
|
||||
case TimeUnit.Minutes:
|
||||
total = time.TotalMinutes;
|
||||
break;
|
||||
case TimeUnit.Seconds:
|
||||
total = time.TotalSeconds;
|
||||
break;
|
||||
case TimeUnit.Milliseconds:
|
||||
total = time.TotalMilliseconds;
|
||||
break;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public static DateTime Interpolate(this DateTime start, DateTime end, double percent)
|
||||
{
|
||||
return new DateTime((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeSpan Interpolate(this TimeSpan start, TimeSpan end, double percent)
|
||||
{
|
||||
return new TimeSpan((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeStamp Interpolate(this TimeStamp start, TimeStamp end, double percent)
|
||||
{
|
||||
return new TimeStamp((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeStamp ToTimeStamp(this DateTime date)
|
||||
{
|
||||
return new TimeStamp(date);
|
||||
}
|
||||
|
||||
public static Months GetMonth(this DateTime date)
|
||||
{
|
||||
switch (date.Month)
|
||||
{
|
||||
case 1:
|
||||
return Months.January;
|
||||
case 2:
|
||||
return Months.Febuary;
|
||||
case 3:
|
||||
return Months.March;
|
||||
case 4:
|
||||
return Months.April;
|
||||
case 5:
|
||||
return Months.May;
|
||||
case 6:
|
||||
return Months.June;
|
||||
case 7:
|
||||
return Months.July;
|
||||
case 8:
|
||||
return Months.August;
|
||||
case 9:
|
||||
return Months.September;
|
||||
case 10:
|
||||
return Months.October;
|
||||
case 11:
|
||||
return Months.November;
|
||||
case 12:
|
||||
return Months.December;
|
||||
default:
|
||||
return Months.None;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this TimeZoneInfo tzo, bool dst)
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
if (tzo.Id == "UTC")
|
||||
{
|
||||
return tzo.Id;
|
||||
}
|
||||
|
||||
string value;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
value = tzo.DaylightName.Replace("Daylight Time", String.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = tzo.StandardName.Replace("Standard Time", String.Empty);
|
||||
}
|
||||
|
||||
foreach (var c in value)
|
||||
{
|
||||
if (!Char.IsWhiteSpace(c) && Char.IsLetter(c) && Char.IsUpper(c))
|
||||
{
|
||||
build.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
build.Append(dst ? "-DT" : "-ST");
|
||||
|
||||
value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this DateTime date, string format = "t D d M y")
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
build.EnsureCapacity(format.Length * 2);
|
||||
|
||||
var noformat = false;
|
||||
|
||||
for (var i = 0; i < format.Length; i++)
|
||||
{
|
||||
if (format[i] == '#')
|
||||
{
|
||||
noformat = !noformat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (noformat)
|
||||
{
|
||||
build.Append(format[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '\\':
|
||||
build.Append((i + 1 < format.Length) ? Convert.ToString(format[++i]) : String.Empty);
|
||||
break;
|
||||
case 'x':
|
||||
case 'z':
|
||||
{
|
||||
var utc = date.Kind == DateTimeKind.Utc;
|
||||
var tzo = utc ? TimeZoneInfo.Utc : TimeZoneInfo.Local;
|
||||
|
||||
build.Append(ToSimpleString(tzo, false));
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
case 'Z':
|
||||
{
|
||||
var utc = date.Kind == DateTimeKind.Utc;
|
||||
var tzo = utc ? TimeZoneInfo.Utc : TimeZoneInfo.Local;
|
||||
|
||||
build.Append(ToSimpleString(tzo, date.IsDaylightSavingTime()));
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
build.Append(date.DayOfWeek);
|
||||
break;
|
||||
case 'd':
|
||||
build.Append(date.Day);
|
||||
break;
|
||||
case 'M':
|
||||
build.Append(GetMonth(date));
|
||||
break;
|
||||
case 'm':
|
||||
build.Append(date.Month);
|
||||
break;
|
||||
case 'y':
|
||||
build.Append(date.Year);
|
||||
break;
|
||||
case 't':
|
||||
{
|
||||
var tf = String.Empty;
|
||||
|
||||
if (i + 1 < format.Length)
|
||||
{
|
||||
if (format[i + 1] == '@')
|
||||
{
|
||||
++i;
|
||||
|
||||
while (++i < format.Length && format[i] != '@')
|
||||
{
|
||||
tf += format[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build.Append(ToSimpleString(date.TimeOfDay, !String.IsNullOrWhiteSpace(tf) ? tf : "h-m-s"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
build.Append(format[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this TimeSpan time, string format = "h-m-s")
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
build.EnsureCapacity(format.Length * 2);
|
||||
|
||||
var noformat = false;
|
||||
var nopadding = false;
|
||||
var zeroValue = false;
|
||||
var zeroEmpty = 0;
|
||||
|
||||
string fFormat, dFormat;
|
||||
object append;
|
||||
|
||||
for (var i = 0; i < format.Length; i++)
|
||||
{
|
||||
if (format[i] == '#')
|
||||
{
|
||||
noformat = !noformat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (noformat)
|
||||
{
|
||||
build.Append(format[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '!':
|
||||
nopadding = !nopadding;
|
||||
continue;
|
||||
}
|
||||
|
||||
fFormat = zeroEmpty > 0 ? (nopadding ? "{0:#.#}" : "{0:#.##}") : (nopadding ? "{0:0.#}" : "{0:0.##}");
|
||||
dFormat = zeroEmpty > 0 ? (nopadding ? "{0:#}" : "{0:##}") : (nopadding ? "{0:0}" : "{0:00}");
|
||||
|
||||
append = null;
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '<':
|
||||
++zeroEmpty;
|
||||
break;
|
||||
case '>':
|
||||
{
|
||||
if (zeroEmpty == 0 || (zeroEmpty > 0 && --zeroEmpty == 0))
|
||||
{
|
||||
zeroValue = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
{
|
||||
if (i + 1 < format.Length)
|
||||
{
|
||||
append = format[++i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
append = ToSimpleString(TimeZoneInfo.Utc, false);
|
||||
break;
|
||||
case 'X':
|
||||
append = ToSimpleString(TimeZoneInfo.Utc, DateTime.UtcNow.IsDaylightSavingTime());
|
||||
break;
|
||||
case 'z':
|
||||
append = ToSimpleString(TimeZoneInfo.Local, false);
|
||||
break;
|
||||
case 'Z':
|
||||
append = ToSimpleString(TimeZoneInfo.Local, DateTime.Now.IsDaylightSavingTime());
|
||||
break;
|
||||
case 'D':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalDays);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalHours);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalMinutes);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalSeconds);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
append = String.Format(dFormat, time.Days);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
{
|
||||
append = String.Format(dFormat, time.Hours);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
{
|
||||
append = String.Format(dFormat, time.Minutes);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
append = String.Format(dFormat, time.Seconds);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
append = format[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (append != null && (!zeroValue || zeroEmpty <= 0))
|
||||
{
|
||||
build.Append(append);
|
||||
}
|
||||
}
|
||||
|
||||
var value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToDirectoryName(this DateTime date, string format = "D d M y")
|
||||
{
|
||||
return ToSimpleString(date, format);
|
||||
}
|
||||
|
||||
public static string ToFileName(this DateTime date, string format = "D d M y")
|
||||
{
|
||||
return ToSimpleString(date, format);
|
||||
}
|
||||
|
||||
public static string ToDirectoryName(this TimeSpan time, string format = "h-m")
|
||||
{
|
||||
return ToSimpleString(time, format);
|
||||
}
|
||||
|
||||
public static string ToFileName(this TimeSpan time, string format = "h-m")
|
||||
{
|
||||
return ToSimpleString(time, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Scripts/SubSystem/VitaNex/Core/Extensions/System/ColorExt.cs
Normal file
105
Scripts/SubSystem/VitaNex/Core/Extensions/System/ColorExt.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ColorExtUtility
|
||||
{
|
||||
public static Color ToColor(this KnownColor color)
|
||||
{
|
||||
return Color.FromKnownColor(color);
|
||||
}
|
||||
|
||||
public static Color555 ToColor555(this Color value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ushort ToArgb555(this Color value)
|
||||
{
|
||||
return ToColor555(value);
|
||||
}
|
||||
|
||||
public static int ToRgb(this Color value)
|
||||
{
|
||||
return value.ToArgb() & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
public static Color Interpolate(this Color source, Color target, double percent)
|
||||
{
|
||||
if (percent <= 0.0)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
if (percent >= 1.0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
var r = (int)(source.R + (target.R - source.R) * percent);
|
||||
var g = (int)(source.G + (target.G - source.G) * percent);
|
||||
var b = (int)(source.B + (target.B - source.B) * percent);
|
||||
|
||||
return Color.FromArgb(255, r, g, b);
|
||||
}
|
||||
|
||||
public static Color FixBlackTransparency(this Color source)
|
||||
{
|
||||
if (source.IsEmpty || source.A <= 0 || source.R >= 0x08 || source.G >= 0x08 || source.B >= 0x08)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
var r = source.R;
|
||||
var g = source.G;
|
||||
var b = source.B;
|
||||
|
||||
if (r != g || r != b)
|
||||
{
|
||||
var rd = 0x08 - r;
|
||||
var gd = 0x08 - g;
|
||||
var bd = 0x08 - b;
|
||||
|
||||
if (rd < gd && rd < bd)
|
||||
{
|
||||
r = 0x08;
|
||||
}
|
||||
else if (gd < rd && gd < bd)
|
||||
{
|
||||
g = 0x08;
|
||||
}
|
||||
else if (bd < rd && bd < gd)
|
||||
{
|
||||
b = 0x08;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 0x08;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 0x08;
|
||||
}
|
||||
|
||||
source = Color.FromArgb(source.A, r, g, b);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
||||
396
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumExt.cs
Normal file
396
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumExt.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class EnumExtUtility
|
||||
{
|
||||
public static string ToString(this Enum e, bool friendly)
|
||||
{
|
||||
return friendly ? GetFriendlyName(e) : GetName(e);
|
||||
}
|
||||
|
||||
public static string GetName(this Enum e)
|
||||
{
|
||||
return EnumCache.GetName(e);
|
||||
}
|
||||
|
||||
public static string GetFriendlyName(this Enum e)
|
||||
{
|
||||
return EnumCache.GetFriendlyName(e);
|
||||
}
|
||||
|
||||
public static string GetDescription(this Enum e)
|
||||
{
|
||||
return EnumCache.GetDescription(e);
|
||||
}
|
||||
|
||||
public static T GetAttribute<T>(this Enum e) where T : Attribute
|
||||
{
|
||||
return GetAttributes<T>(e).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetAttributes<T>(this Enum e) where T : Attribute
|
||||
{
|
||||
var type = e.GetType();
|
||||
var info = type.GetMember(e.ToString());
|
||||
|
||||
if (info.IsNullOrEmpty() || info[0] == null)
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
var attributes = info[0].GetCustomAttributes(typeof(T), false);
|
||||
|
||||
if (attributes.IsNullOrEmpty())
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
return attributes.OfType<T>();
|
||||
}
|
||||
|
||||
public static TEnum Normalize<TEnum>(this Enum e)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
var type = typeof(TEnum);
|
||||
var flag = default(TEnum);
|
||||
|
||||
if (!type.IsEnum)
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse(e.ToString(), out flag) || (!type.HasCustomAttribute<FlagsAttribute>(true) && !Enum.IsDefined(type, flag)))
|
||||
{
|
||||
flag = default(TEnum);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static bool IsValid(this Enum e)
|
||||
{
|
||||
return Enum.IsDefined(e.GetType(), e);
|
||||
}
|
||||
|
||||
public static TCast[] Split<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetValues<TCast>(e, true);
|
||||
}
|
||||
|
||||
public static TCast[] GetValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static TCast[] GetValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, local).ToArray();
|
||||
}
|
||||
|
||||
public static TCast[] GetAbsoluteValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetAbsoluteValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static TCast[] GetAbsoluteValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateAbsoluteValues<TCast>(e, local).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateAbsoluteValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateAbsoluteValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateAbsoluteValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, local).Where(o => !Equals(o, 0) && !Equals(o, String.Empty)).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
var eType = e.GetType();
|
||||
var vType = typeof(TCast);
|
||||
var vals = EnumCache.EnumerateValues(eType);
|
||||
|
||||
if (local)
|
||||
{
|
||||
vals = vals.Where(e.HasFlag);
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(char)))
|
||||
{
|
||||
return vals.Select(Convert.ToChar).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(sbyte)))
|
||||
{
|
||||
return vals.Select(Convert.ToSByte).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(byte)))
|
||||
{
|
||||
return vals.Select(Convert.ToByte).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(short)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt16).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(ushort)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt16).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(int)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt32).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(uint)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt32).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(long)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt64).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(ulong)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt64).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(string)))
|
||||
{
|
||||
return vals.Select(Convert.ToString).Cast<TCast>();
|
||||
}
|
||||
|
||||
return vals.Cast<TCast>();
|
||||
}
|
||||
|
||||
public static bool AnyFlags<TEnum>(this Enum e, IEnumerable<TEnum> flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.Any(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().Any(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AnyFlags<TEnum>(this Enum e, params TEnum[] flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.Any(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().Any(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AllFlags<TEnum>(this Enum e, IEnumerable<TEnum> flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.All(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().All(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AllFlags<TEnum>(this Enum e, params TEnum[] flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.All(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().All(e.HasFlag);
|
||||
}
|
||||
|
||||
private static class EnumCache
|
||||
{
|
||||
public class Entry
|
||||
{
|
||||
public readonly Enum[] Values;
|
||||
public readonly string[] Names, FriendlyNames, Descriptions;
|
||||
|
||||
public Entry(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
Values = new Enum[0];
|
||||
Names = new string[0];
|
||||
FriendlyNames = new string[0];
|
||||
Descriptions = new string[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Values = Enum.GetValues(type).CastToArray<Enum>();
|
||||
Names = Enum.GetNames(type);
|
||||
|
||||
FriendlyNames = new string[Names.Length];
|
||||
Descriptions = new string[Names.Length];
|
||||
|
||||
for (var i = 0; i < Values.Length; i++)
|
||||
{
|
||||
FriendlyNames[i] = Names[i].SpaceWords();
|
||||
Descriptions[i] = String.Join("\n", GetAttributes<DescriptionAttribute>(Values[i]).Where(o => !String.IsNullOrWhiteSpace(o.Description)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Entry _Empty = new Entry(null);
|
||||
|
||||
private static readonly Dictionary<Type, Entry> _Cache = new Dictionary<Type, Entry>();
|
||||
|
||||
public static Entry Lookup(Type type)
|
||||
{
|
||||
if (type == null || !type.IsEnum)
|
||||
{
|
||||
return _Empty;
|
||||
}
|
||||
|
||||
if (!_Cache.TryGetValue(type, out var result))
|
||||
{
|
||||
_Cache[type] = result = new Entry(type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string[] GetNames(Type type)
|
||||
{
|
||||
return Lookup(type).Names;
|
||||
}
|
||||
|
||||
public static Enum[] GetValues(Type type)
|
||||
{
|
||||
return Lookup(type).Values;
|
||||
}
|
||||
|
||||
public static string[] GetDescriptions(Type type)
|
||||
{
|
||||
return Lookup(type).Descriptions;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateNames(Type type)
|
||||
{
|
||||
return GetNames(type);
|
||||
}
|
||||
|
||||
public static IEnumerable<Enum> EnumerateValues(Type type)
|
||||
{
|
||||
return GetValues(type);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateDescriptions(Type type)
|
||||
{
|
||||
return GetDescriptions(type);
|
||||
}
|
||||
|
||||
public static string GetName(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.Names[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static string GetFriendlyName(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.FriendlyNames[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static string GetDescription(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.Descriptions[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static int GetIndex(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
return Array.IndexOf(entry.Values, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2607
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumerableExt.cs
Normal file
2607
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumerableExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.IO;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ExceptionExtUtility
|
||||
{
|
||||
public static void ToConsole(this Exception e, bool simple = false, bool log = false)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (VitaNexCore.ConsoleLock)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine(simple ? e.Message : e.ToString());
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Log(this Exception e, FileInfo file = null)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
file = file ?? VitaNexCore.LogFile;
|
||||
|
||||
var now = String.Format("***ERROR LOG [{0}]***", DateTime.Now);
|
||||
|
||||
lock (VitaNexCore.IOLock)
|
||||
{
|
||||
file.AppendText(false, String.Empty, now, e.Message, e.ToString(), e.HelpLink, String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
508
Scripts/SubSystem/VitaNex/Core/Extensions/System/IOExt.cs
Normal file
508
Scripts/SubSystem/VitaNex/Core/Extensions/System/IOExt.cs
Normal file
@@ -0,0 +1,508 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace System.IO
|
||||
{
|
||||
public static class IOExtUtility
|
||||
{
|
||||
public static FileMime GetMimeType(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return FileMime.Lookup(file);
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllBytes(file.FullName);
|
||||
}
|
||||
|
||||
public static string[] ReadAllLines(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllLines(file.FullName);
|
||||
}
|
||||
|
||||
public static string ReadAllText(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllText(file.FullName);
|
||||
}
|
||||
|
||||
public static void WriteAllBytes(this FileInfo file, byte[] bytes)
|
||||
{
|
||||
File.WriteAllBytes(file.FullName, bytes);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, string[] contents)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, string[] contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, IEnumerable<string> contents)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, IEnumerable<string> contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllText(this FileInfo file, string contents)
|
||||
{
|
||||
File.WriteAllText(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllText(this FileInfo file, string contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllText(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static bool GetAttribute(this FileInfo file, FileAttributes attr)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
return file.Attributes.HasFlag(attr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void SetAttribute(this FileInfo file, FileAttributes attr, bool value)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
file.Attributes |= attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Attributes &= ~attr;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHidden(this FileInfo file, bool value)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
SetAttribute(file, FileAttributes.Hidden, value);
|
||||
}
|
||||
|
||||
public static FileStream OpenRead(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
}
|
||||
|
||||
public static FileStream OpenWrite(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.Write, FileShare.Write);
|
||||
}
|
||||
|
||||
public static FileStream OpenAppend(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Append, FileAccess.Write, FileShare.Write);
|
||||
}
|
||||
|
||||
public static FileStream Open(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
|
||||
public static void AppendText(this FileInfo file, bool truncate, params string[] lines)
|
||||
{
|
||||
if (lines == null || lines.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
file = EnsureFile(file, false);
|
||||
}
|
||||
else if (truncate)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
|
||||
using (var fs = OpenAppend(file))
|
||||
{
|
||||
var data = String.Join(Environment.NewLine, lines) + Environment.NewLine;
|
||||
var buffer = Encoding.UTF8.GetBytes(data);
|
||||
|
||||
fs.Write(buffer, 0, buffer.Length);
|
||||
fs.Flush();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a files' existence
|
||||
/// </summary>
|
||||
/// <returns>FileInfo representing the file ensured for 'info'</returns>
|
||||
public static FileInfo EnsureFile(this FileInfo file)
|
||||
{
|
||||
return EnsureFile(file, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a files' existence
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="replace">True: replace the file if it exists</param>
|
||||
/// <returns>FileInfo representing the file ensured for 'info'</returns>
|
||||
public static FileInfo EnsureFile(this FileInfo file, bool replace)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
EnsureDirectory(file.Directory, false);
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
using (var fs = file.Create())
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
else if (replace)
|
||||
{
|
||||
VitaNexCore.TryCatch(file.Delete);
|
||||
|
||||
using (var fs = file.Create())
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a directories' existence
|
||||
/// </summary>
|
||||
/// <returns>DirectoryInfo representing the directory ensured for 'info'</returns>
|
||||
public static DirectoryInfo EnsureDirectory(this DirectoryInfo dir)
|
||||
{
|
||||
return EnsureDirectory(dir, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a directories' existence
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <param name="replace">True: replace the directory if it exists</param>
|
||||
/// <returns>DirectoryInfo representing the directory ensured for 'info'</returns>
|
||||
public static DirectoryInfo EnsureDirectory(this DirectoryInfo dir, bool replace)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
}
|
||||
else if (replace)
|
||||
{
|
||||
EmptyDirectory(dir, true);
|
||||
|
||||
VitaNexCore.TryCatch(dir.Delete, true);
|
||||
|
||||
dir.Create();
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory with the option to include sub directories
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="incDirs">True: includes sub directories</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, bool incDirs)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var f in dir.EnumerateFiles())
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
if (incDirs)
|
||||
{
|
||||
foreach (var d in dir.EnumerateDirectories())
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, including all sub-directories and files that are older than the
|
||||
/// given age.
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="age">Age at which a directory or file is considered old enough to be deleted</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, TimeSpan age)
|
||||
{
|
||||
EmptyDirectory(dir, age, "*", SearchOption.AllDirectories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, only deleting files that meet the mask criteria and are older than
|
||||
/// the given age.
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="age">Age at which a directory or file is considered old enough to be deleted</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, TimeSpan age, string mask, SearchOption option)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var expire = DateTime.UtcNow.Subtract(age);
|
||||
|
||||
foreach (var d in AllDirectories(dir, mask, option).Where(d => d.CreationTimeUtc < expire))
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
|
||||
foreach (var f in AllFiles(dir, mask, option).Where(f => f.CreationTimeUtc < expire))
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, only deleting files that meet the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var d in AllDirectories(dir, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
|
||||
foreach (var f in AllFiles(dir, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the specified directory to the specified target directory, only including files that meet
|
||||
/// the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to copy</param>
|
||||
/// <param name="dest">Directory to copy to</param>
|
||||
public static void CopyDirectory(this DirectoryInfo source, DirectoryInfo dest)
|
||||
{
|
||||
CopyDirectory(source, dest, "*", SearchOption.AllDirectories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the specified directory to the specified target directory, only including files that meet
|
||||
/// the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to copy</param>
|
||||
/// <param name="dest">Directory to copy to</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void CopyDirectory(this DirectoryInfo source, DirectoryInfo dest, string mask, SearchOption option)
|
||||
{
|
||||
source.Refresh();
|
||||
|
||||
if (!source.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDirectory(dest, false);
|
||||
|
||||
foreach (var f in AllFiles(source, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(
|
||||
() =>
|
||||
{
|
||||
var t = new FileInfo(f.FullName.Replace(source.FullName, dest.FullName));
|
||||
|
||||
EnsureDirectory(t.Directory);
|
||||
|
||||
f.CopyTo(t.FullName, true);
|
||||
});
|
||||
}
|
||||
|
||||
source.Refresh();
|
||||
dest.Refresh();
|
||||
}
|
||||
|
||||
public static IEnumerable<DirectoryInfo> AllDirectories(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
foreach (var d in dir.EnumerateDirectories(mask).Where(d => d != dir))
|
||||
{
|
||||
if (option == SearchOption.AllDirectories)
|
||||
{
|
||||
foreach (var s in AllDirectories(d, mask, SearchOption.AllDirectories).Where(s => s != d))
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
|
||||
yield return d;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<FileInfo> AllFiles(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
if (option == SearchOption.AllDirectories)
|
||||
{
|
||||
foreach (var f in dir.EnumerateDirectories()
|
||||
.Where(d => d != dir)
|
||||
.SelectMany(d => AllFiles(d, mask, SearchOption.AllDirectories)))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var f in dir.EnumerateFiles(mask))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
Scripts/SubSystem/VitaNex/Core/Extensions/System/IPAddressExt.cs
Normal file
115
Scripts/SubSystem/VitaNex/Core/Extensions/System/IPAddressExt.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class IPAddressExtUtility
|
||||
{
|
||||
private static readonly Regex _AddressPattern = new Regex(@"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})");
|
||||
|
||||
private static IPAddress _Public;
|
||||
|
||||
public static IPAddress FindPublic()
|
||||
{
|
||||
if (_Public != null)
|
||||
{
|
||||
return _Public;
|
||||
}
|
||||
|
||||
var data = String.Empty;
|
||||
|
||||
var request = WebRequest.Create("https://api.ipify.org");
|
||||
|
||||
using (var response = request.GetResponse())
|
||||
{
|
||||
var r = response.GetResponseStream();
|
||||
|
||||
if (r != null)
|
||||
{
|
||||
using (var stream = new StreamReader(r))
|
||||
{
|
||||
data = stream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var m = _AddressPattern.Match(data);
|
||||
|
||||
return (_Public = m.Success ? IPAddress.Parse(m.Value) : null);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPAddress> FindInternal(this IPAddress address)
|
||||
{
|
||||
if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Select(a => a.GetIPProperties())
|
||||
.SelectMany(p => p.UnicastAddresses.Where(u => address.AddressFamily == u.Address.AddressFamily))
|
||||
.Select(uni => uni.Address);
|
||||
}
|
||||
|
||||
return address.ToEnumerable();
|
||||
}
|
||||
|
||||
public static bool IsPrivateNetwork(this IPAddress address)
|
||||
{
|
||||
// 10.0.0.0/8
|
||||
// 172.16.0.0/12
|
||||
// 192.168.0.0/16
|
||||
// 169.254.0.0/16
|
||||
// 100.64.0.0/10 RFC 6598
|
||||
|
||||
if (address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("192.168.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("10.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("172.16-31.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("169.254.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("100.64-127.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
423
Scripts/SubSystem/VitaNex/Core/Extensions/System/NumericExt.cs
Normal file
423
Scripts/SubSystem/VitaNex/Core/Extensions/System/NumericExt.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class NumericExtUtility
|
||||
{
|
||||
private static string GetOrdinalSuffix(double value)
|
||||
{
|
||||
var ones = (int)(value % 10);
|
||||
var tens = (int)Math.Floor(value / 10.0) % 10;
|
||||
|
||||
string suff;
|
||||
|
||||
if (tens == 1)
|
||||
{
|
||||
suff = "th";
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ones)
|
||||
{
|
||||
case 1:
|
||||
suff = "st";
|
||||
break;
|
||||
case 2:
|
||||
suff = "nd";
|
||||
break;
|
||||
case 3:
|
||||
suff = "rd";
|
||||
break;
|
||||
default:
|
||||
suff = "th";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return suff;
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this decimal value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix((double)value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this double value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this float value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this sbyte value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this byte value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this short value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this ushort value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this int value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this uint value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this long value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this ulong value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static decimal Overflow(this decimal value, decimal min, decimal max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static double Overflow(this double value, double min, double max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float Overflow(this float value, float min, float max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static sbyte Overflow(this sbyte value, sbyte min, sbyte max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (sbyte)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (sbyte)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static byte Overflow(this byte value, byte min, byte max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (byte)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (byte)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static short Overflow(this short value, short min, short max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (short)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (short)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ushort Overflow(this ushort value, ushort min, ushort max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (ushort)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (ushort)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int Overflow(this int value, int min, int max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static uint Overflow(this uint value, uint min, uint max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static long Overflow(this long value, long min, long max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ulong Overflow(this ulong value, ulong min, ulong max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
401
Scripts/SubSystem/VitaNex/Core/Extensions/System/ObjectExt.cs
Normal file
401
Scripts/SubSystem/VitaNex/Core/Extensions/System/ObjectExt.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Reflection;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ObjectExtUtility
|
||||
{
|
||||
private const BindingFlags _CommonFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
||||
|
||||
private static readonly Delegate[] _EmptyDelegates = new Delegate[0];
|
||||
|
||||
public static Delegate[] GetEventDelegates(this object obj, string eventName)
|
||||
{
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var ei = t.GetEvent(eventName, f);
|
||||
|
||||
if (ei == null)
|
||||
{
|
||||
return _EmptyDelegates;
|
||||
}
|
||||
|
||||
var efi = t.GetField(ei.Name, f | BindingFlags.GetField);
|
||||
|
||||
if (efi == null)
|
||||
{
|
||||
efi = t.GetField("EVENT_" + ei.Name.ToUpper(), f | BindingFlags.GetField);
|
||||
}
|
||||
|
||||
if (efi == null)
|
||||
{
|
||||
return _EmptyDelegates;
|
||||
}
|
||||
|
||||
var efv = (Delegate)efi.GetValue(obj is Type ? null : obj);
|
||||
|
||||
return efv.GetInvocationList();
|
||||
}
|
||||
|
||||
public static MethodInfo[] GetEventMethods(this object obj, string eventName)
|
||||
{
|
||||
return GetEventDelegates(obj, eventName).Select(e => e.Method).ToArray();
|
||||
}
|
||||
|
||||
public static bool GetFieldValue(this object obj, string name, out object value)
|
||||
{
|
||||
return GetFieldValue<object>(obj, name, out value);
|
||||
}
|
||||
|
||||
public static bool GetFieldValue<T>(this object obj, string name, out T value)
|
||||
{
|
||||
value = default(T);
|
||||
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetField(name, f);
|
||||
|
||||
try
|
||||
{
|
||||
value = (T)o.GetValue(obj is Type ? null : obj);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SetFieldValue(this object obj, string name, object value)
|
||||
{
|
||||
return SetFieldValue<object>(obj, name, value);
|
||||
}
|
||||
|
||||
public static bool SetFieldValue<T>(this object obj, string name, T value)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetField(name, f);
|
||||
|
||||
try
|
||||
{
|
||||
o.SetValue(obj is Type ? null : obj, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetPropertyValue(this object obj, string name, out object value)
|
||||
{
|
||||
return GetPropertyValue<object>(obj, name, out value);
|
||||
}
|
||||
|
||||
public static bool GetPropertyValue<T>(this object obj, string name, out T value)
|
||||
{
|
||||
value = default(T);
|
||||
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetProperty(name, f, null, typeof(T), Type.EmptyTypes, null);
|
||||
|
||||
try
|
||||
{
|
||||
value = (T)o.GetValue(obj is Type ? null : obj, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SetPropertyValue(this object obj, string name, object value)
|
||||
{
|
||||
return SetPropertyValue<object>(obj, name, value);
|
||||
}
|
||||
|
||||
public static bool SetPropertyValue<T>(this object obj, string name, T value)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetProperty(name, f, null, typeof(T), Type.EmptyTypes, null);
|
||||
|
||||
try
|
||||
{
|
||||
o.SetValue(obj is Type ? null : obj, value, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static object InvokeMethod(this object obj, string name, params object[] args)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var a = args != null ? Type.GetTypeArray(args) : Type.EmptyTypes;
|
||||
|
||||
var o = t.GetMethod(name, f, null, a, null);
|
||||
|
||||
try
|
||||
{
|
||||
if (o.ReturnType == typeof(void))
|
||||
{
|
||||
return o.Invoke(obj is Type ? null : obj, args) ?? true;
|
||||
}
|
||||
|
||||
return o.Invoke(obj is Type ? null : obj, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
public static T InvokeMethod<T>(this object obj, string name, params object[] args)
|
||||
{
|
||||
if (InvokeMethod(obj, name, args) is T o)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
|
||||
#if NET48_OR_GREATER
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int GetTypeHashCode(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var type = obj.GetType();
|
||||
|
||||
return type.GetValueHashCode();
|
||||
}
|
||||
|
||||
public static string GetTypeName(this object obj, bool raw)
|
||||
{
|
||||
Type type;
|
||||
|
||||
if (obj is Type t)
|
||||
{
|
||||
type = t;
|
||||
}
|
||||
else if (obj is ITypeSelectProperty ts)
|
||||
{
|
||||
type = ts.ExpectedType;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = obj.GetType();
|
||||
}
|
||||
|
||||
if (raw)
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
return type.ResolveName();
|
||||
}
|
||||
|
||||
public static bool TypeEquals<T>(this object obj)
|
||||
{
|
||||
return TypeEquals<T>(obj, true);
|
||||
}
|
||||
|
||||
public static bool TypeEquals<T>(this object obj, bool child)
|
||||
{
|
||||
return TypeEquals(obj, typeof(T), child);
|
||||
}
|
||||
|
||||
public static bool TypeEquals(this object obj, object other)
|
||||
{
|
||||
return TypeEquals(obj, other, true);
|
||||
}
|
||||
|
||||
public static bool TypeEquals(this object obj, object other, bool child)
|
||||
{
|
||||
if (obj == null || other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(obj, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Type l, r;
|
||||
|
||||
if (obj is Type tl)
|
||||
{
|
||||
l = tl;
|
||||
}
|
||||
else if (obj is ITypeSelectProperty tsl)
|
||||
{
|
||||
l = tsl.InternalType;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = obj.GetType();
|
||||
}
|
||||
|
||||
if (other is Type tr)
|
||||
{
|
||||
r = tr;
|
||||
}
|
||||
else if (other is ITypeSelectProperty tsr)
|
||||
{
|
||||
r = tsr.InternalType;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = other as Type ?? other.GetType();
|
||||
}
|
||||
|
||||
if (child)
|
||||
{
|
||||
return l.IsEqualOrChildOf(r);
|
||||
}
|
||||
|
||||
return l.IsEqual(r);
|
||||
}
|
||||
|
||||
public static int CompareNull<T>(this T obj, T other)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
CompareNull(obj, other, ref result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool CompareNull<T>(this T obj, T other, ref int result)
|
||||
{
|
||||
if (obj == null && other == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
++result;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (other == null)
|
||||
{
|
||||
--result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static FieldList<T> GetFields<T>(this T obj, BindingFlags flags = BindingFlags.Default, Func<FieldInfo, bool> filter = null)
|
||||
{
|
||||
return new FieldList<T>(obj, flags, filter);
|
||||
}
|
||||
|
||||
public static PropertyList<T> GetProperties<T>(this T obj, BindingFlags flags = BindingFlags.Default, Func<PropertyInfo, bool> filter = null)
|
||||
{
|
||||
return new PropertyList<T>(obj, flags, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
1252
Scripts/SubSystem/VitaNex/Core/Extensions/System/StringExt.cs
Normal file
1252
Scripts/SubSystem/VitaNex/Core/Extensions/System/StringExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
448
Scripts/SubSystem/VitaNex/Core/Extensions/System/TypeExt.cs
Normal file
448
Scripts/SubSystem/VitaNex/Core/Extensions/System/TypeExt.cs
Normal file
@@ -0,0 +1,448 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.Crypto;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class TypeExtUtility
|
||||
{
|
||||
private static readonly Dictionary<Type, List<Type>> _ChildrenCache;
|
||||
private static readonly Dictionary<Type, List<Type>> _ConstructableChildrenCache;
|
||||
|
||||
private static readonly Dictionary<Type, int> _ValueHashCache;
|
||||
|
||||
static TypeExtUtility()
|
||||
{
|
||||
_ChildrenCache = new Dictionary<Type, List<Type>>(0x100);
|
||||
_ConstructableChildrenCache = new Dictionary<Type, List<Type>>(0x100);
|
||||
|
||||
_ValueHashCache = new Dictionary<Type, int>(0x400);
|
||||
}
|
||||
|
||||
private static string FormatName(string value)
|
||||
{
|
||||
var i = value.IndexOf('`');
|
||||
|
||||
return (i > 0 ? value.Substring(0, i) : value).SpaceWords();
|
||||
}
|
||||
|
||||
public static string ResolveName(this Type t)
|
||||
{
|
||||
return FormatName(t.Name);
|
||||
}
|
||||
|
||||
public static int GetValueHashCode(this Type t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_ValueHashCache.TryGetValue(t, out var hash) || hash == 0)
|
||||
{
|
||||
using (var c = new CryptoHashCode(CryptoHashType.MD5, t.FullName))
|
||||
{
|
||||
_ValueHashCache[t] = hash = c.ValueHash;
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static Type[] GetTypeCache(this Assembly asm)
|
||||
{
|
||||
return ScriptCompiler.GetTypeCache(asm).Types;
|
||||
}
|
||||
|
||||
public static Type[] GetHierarchy(this Type t)
|
||||
{
|
||||
return GetHierarchy(t, false);
|
||||
}
|
||||
|
||||
public static Type[] GetHierarchy(this Type t, bool self)
|
||||
{
|
||||
return EnumerateHierarchy(t, self).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> EnumerateHierarchy(this Type t)
|
||||
{
|
||||
return EnumerateHierarchy(t, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> EnumerateHierarchy(this Type t, bool self)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
yield return t;
|
||||
}
|
||||
|
||||
while (t.BaseType != null)
|
||||
{
|
||||
yield return t = t.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type FindParent<T>(this Type type)
|
||||
{
|
||||
var ot = typeof(T);
|
||||
|
||||
return EnumerateHierarchy(type, false).FirstOrDefault(pt => pt == ot);
|
||||
}
|
||||
|
||||
public static bool TryFindParent<T>(this Type type, out Type parent)
|
||||
{
|
||||
return (parent = FindParent<T>(type)) != null;
|
||||
}
|
||||
|
||||
public static Type FindParent<T>(this Type type, Func<Type, bool> predicate)
|
||||
{
|
||||
var ot = typeof(T);
|
||||
|
||||
return EnumerateHierarchy(type, false).Where(t => t == ot).FirstOrDefault(predicate);
|
||||
}
|
||||
|
||||
public static bool TryFindParent<T>(this Type type, Func<Type, bool> predicate, out Type parent)
|
||||
{
|
||||
return (parent = FindParent<T>(type, predicate)) != null;
|
||||
}
|
||||
|
||||
public static Type FindParent(this Type type, Func<Type, bool> predicate)
|
||||
{
|
||||
return EnumerateHierarchy(type, false).FirstOrDefault(predicate);
|
||||
}
|
||||
|
||||
public static bool TryFindParent(this Type type, Func<Type, bool> predicate, out Type parent)
|
||||
{
|
||||
return (parent = FindParent(type, predicate)) != null;
|
||||
}
|
||||
|
||||
public static bool GetCustomAttributes<TAttribute>(this Type t, bool inherit, out TAttribute[] attrs)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
attrs = GetCustomAttributes<TAttribute>(t, inherit);
|
||||
return attrs != null && attrs.Length > 0;
|
||||
}
|
||||
|
||||
public static TAttribute[] GetCustomAttributes<TAttribute>(this Type t, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return t != null
|
||||
? t.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().ToArray()
|
||||
: new TAttribute[0];
|
||||
}
|
||||
|
||||
public static bool HasCustomAttribute<TAttribute>(this Type t, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
var attrs = GetCustomAttributes<TAttribute>(t, inherit);
|
||||
|
||||
return attrs != null && attrs.Length > 0;
|
||||
}
|
||||
|
||||
public static int CompareTo(this Type t, Type other)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
if (t.CompareNull(other, ref result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var lp = t.BaseType;
|
||||
|
||||
while (lp != null)
|
||||
{
|
||||
if (lp == other)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lp = lp.BaseType;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName)
|
||||
{
|
||||
return IsEqual(a, bName, true);
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName, bool ignoreCase)
|
||||
{
|
||||
return IsEqual(a, bName, ignoreCase, bName.ContainsAny('.', '+'));
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName, bool ignoreCase, bool fullName)
|
||||
{
|
||||
var b = Type.GetType(bName) ??
|
||||
(fullName ? ScriptCompiler.FindTypeByFullName(bName) : ScriptCompiler.FindTypeByName(bName));
|
||||
|
||||
return IsEqual(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, Type b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public static bool IsEqual<TObj>(this Type t)
|
||||
{
|
||||
return IsEqual(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName)
|
||||
{
|
||||
return IsEqualOrChildOf(a, bName, true);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName, bool ignoreCase)
|
||||
{
|
||||
return IsEqualOrChildOf(a, bName, ignoreCase, bName.ContainsAny('.', '+'));
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName, bool ignoreCase, bool fullName)
|
||||
{
|
||||
var b = Type.GetType(bName) ??
|
||||
(fullName ? ScriptCompiler.FindTypeByFullName(bName) : ScriptCompiler.FindTypeByName(bName));
|
||||
|
||||
return IsEqualOrChildOf(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, Type b)
|
||||
{
|
||||
return IsEqual(a, b) || IsChildOf(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf<TObj>(this Type t)
|
||||
{
|
||||
return IsEqualOrChildOf(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsChildOf(this Type a, Type b)
|
||||
{
|
||||
return a != null && b != null && a != b && !a.IsInterface && !a.IsEnum &&
|
||||
(b.IsInterface ? HasInterface(a, b) : b.IsAssignableFrom(a));
|
||||
}
|
||||
|
||||
public static bool IsChildOf<TObj>(this Type t)
|
||||
{
|
||||
return IsChildOf(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool HasInterface(this Type t, string i)
|
||||
{
|
||||
var iType = Type.GetType(i, false) ??
|
||||
(i.IndexOf('.') < 0 ? ScriptCompiler.FindTypeByName(i) : ScriptCompiler.FindTypeByFullName(i));
|
||||
|
||||
return iType != null && iType.IsInterface && HasInterface(t, iType);
|
||||
}
|
||||
|
||||
public static bool HasInterface<TObj>(this Type t)
|
||||
{
|
||||
return HasInterface(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool HasInterface(this Type t, Type i)
|
||||
{
|
||||
return t != null && i != null && i.IsInterface && t.GetInterface(i.FullName) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructable(this Type a)
|
||||
{
|
||||
return IsConstructable(a, Type.EmptyTypes);
|
||||
}
|
||||
|
||||
public static bool IsConstructable(this Type a, Type[] argTypes)
|
||||
{
|
||||
if (a == null || a.IsAbstract || a.IsInterface || a.IsEnum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructor(argTypes) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom(this Type a, Type b)
|
||||
{
|
||||
if (a == null || b == null || a.IsAbstract || !IsChildOf(a, b))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Length > 0;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom<TObj>(this Type t)
|
||||
{
|
||||
return IsConstructableFrom(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom(this Type a, Type b, Type[] argTypes)
|
||||
{
|
||||
if (a == null || b == null || a.IsAbstract || !IsChildOf(a, b))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructor(argTypes) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom<TObj>(this Type t, Type[] argTypes)
|
||||
{
|
||||
return IsConstructableFrom(t, typeof(TObj), argTypes);
|
||||
}
|
||||
|
||||
public static Type[] GetChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
return FindChildren(type, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
|
||||
var types = _ChildrenCache.GetValue(type);
|
||||
|
||||
if (types == null)
|
||||
{
|
||||
var asm = ScriptCompiler.Assemblies.With(Core.Assembly, Assembly.GetCallingAssembly()).ToList();
|
||||
|
||||
asm.Prune();
|
||||
|
||||
types = asm.Select(GetTypeCache).SelectMany(o => o.Where(t => !IsEqual(t, type) && IsChildOf(t, type))).ToList();
|
||||
|
||||
asm.Free(true);
|
||||
|
||||
if (types.Count > 0 && types.Count <= 0x100)
|
||||
{
|
||||
_ChildrenCache[type] = types;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ChildrenCache.Count >= 0x100)
|
||||
{
|
||||
_ChildrenCache.Pop().Value.Free(true);
|
||||
}
|
||||
|
||||
return predicate != null ? types.Where(predicate) : types.AsEnumerable();
|
||||
}
|
||||
|
||||
public static Type[] GetConstructableChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
return FindConstructableChildren(type, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindConstructableChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
|
||||
var types = _ConstructableChildrenCache.GetValue(type);
|
||||
|
||||
if (types == null)
|
||||
{
|
||||
types = FindChildren(type).Where(t => IsConstructableFrom(t, type)).ToList();
|
||||
|
||||
if (types.Count > 0 && types.Count <= 0x100)
|
||||
{
|
||||
_ConstructableChildrenCache[type] = types;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ConstructableChildrenCache.Count >= 0x100)
|
||||
{
|
||||
_ConstructableChildrenCache.Pop().Value.Free(true);
|
||||
}
|
||||
|
||||
return predicate != null ? types.Where(predicate) : types.AsEnumerable();
|
||||
}
|
||||
|
||||
public static TObj CreateInstance<TObj>(this Type t, params object[] args)
|
||||
{
|
||||
if (t == null || t.IsAbstract || t.IsInterface || t.IsEnum)
|
||||
{
|
||||
return default(TObj);
|
||||
}
|
||||
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
return (TObj)Activator.CreateInstance(t, true);
|
||||
}
|
||||
|
||||
return (TObj)Activator.CreateInstance(t, args);
|
||||
}
|
||||
|
||||
public static TObj CreateInstanceSafe<TObj>(this Type t, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CreateInstance<TObj>(t, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e = new TypeConstructException(t, new StackTrace(1, true), e);
|
||||
|
||||
e.ToConsole(true, true);
|
||||
|
||||
return default(TObj);
|
||||
}
|
||||
}
|
||||
|
||||
public static object CreateInstanceUnsafe(this Type t, params object[] args)
|
||||
{
|
||||
return CreateInstance<object>(t, args);
|
||||
}
|
||||
|
||||
public static object CreateInstance(this Type t, params object[] args)
|
||||
{
|
||||
return CreateInstanceSafe<object>(t, args);
|
||||
}
|
||||
}
|
||||
|
||||
public class TypeConstructException : Exception
|
||||
{
|
||||
private readonly string _Trace;
|
||||
|
||||
public override string StackTrace => _Trace;
|
||||
|
||||
public TypeConstructException(Type type, StackTrace trace, Exception inner)
|
||||
: base("Type Construction Failed: " + type.FullName, inner)
|
||||
{
|
||||
_Trace = trace.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "\n\n" + _Trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/SubSystem/VitaNex/Core/Extensions/System/UriExt.cs
Normal file
32
Scripts/SubSystem/VitaNex/Core/Extensions/System/UriExt.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VitaNex.Web;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class UriExtUtility
|
||||
{
|
||||
public static IEnumerable<KeyValuePair<string, string>> DecodeQueryString(this Uri uri)
|
||||
{
|
||||
return WebAPI.DecodeQuery(uri.Query);
|
||||
}
|
||||
|
||||
public static Uri EncodeQueryString(this Uri uri, IEnumerable<KeyValuePair<string, string>> queries)
|
||||
{
|
||||
return new Uri(uri.GetLeftPart(UriPartial.Path) + WebAPI.EncodeQuery(queries));
|
||||
}
|
||||
}
|
||||
}
|
||||
479
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/ArtExt.cs
Normal file
479
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/ArtExt.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class ArtExtUtility
|
||||
{
|
||||
public const int TileWxH = 44, TileHalfWxH = TileWxH / 2;
|
||||
|
||||
public static readonly Size TileSize = new Size(TileWxH, TileWxH);
|
||||
|
||||
#if ServUOX
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return ArtData.GetStatic(index);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, int hue, bool onlyHueGrayPixels)
|
||||
{
|
||||
return ArtData.GetStatic(index, hue, onlyHueGrayPixels);
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
ArtData.Measure(img, out xMin, out yMin, out xMax, out yMax);
|
||||
}
|
||||
|
||||
#region Ultima SDK Signatures
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
patched = false;
|
||||
|
||||
if (checkMaxID)
|
||||
index &= TileData.MaxItemValue;
|
||||
|
||||
return GetStatic(index);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#elif ServUO
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return GetStatic(index, out _, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
return Art.GetStatic(index, out patched, checkMaxID);
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
Art.Measure(img, out xMin, out yMin, out xMax, out yMax);
|
||||
}
|
||||
#else
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return GetStatic(index, out _, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
var param = new object[] { index, false, checkMaxID };
|
||||
|
||||
var img = Bootstrap.Invoke<Bitmap>("Art", "GetStatic", param);
|
||||
|
||||
patched = (bool)param[1];
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
var param = new object[] { img, 0, 0, 0, 0 };
|
||||
|
||||
Bootstrap.Invoke("Art", "Measure", param);
|
||||
|
||||
xMin = (int)param[1];
|
||||
yMin = (int)param[2];
|
||||
xMax = (int)param[3];
|
||||
yMax = (int)param[4];
|
||||
}
|
||||
#endif
|
||||
public static Rectangle2D GetStaticBounds(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return new Rectangle2D(0, 0, TileWxH, TileWxH);
|
||||
}
|
||||
|
||||
Measure(img, out var xMin, out var yMin, out var xMax, out var yMax);
|
||||
|
||||
return new Rectangle2D(new Point2D(xMin, yMin), new Point2D(xMax, yMax));
|
||||
}
|
||||
|
||||
public static Rectangle2D GetStaticBounds(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return new Rectangle2D(0, 0, TileWxH, TileWxH);
|
||||
}
|
||||
|
||||
return GetStaticBounds(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
return GetImageOffset(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(int id)
|
||||
{
|
||||
var p = Point.Empty;
|
||||
var b = GetImageSize(id);
|
||||
|
||||
if (b.Width > TileWxH)
|
||||
{
|
||||
p.X -= (b.Width - TileWxH) / 2;
|
||||
}
|
||||
else if (b.Width < TileWxH)
|
||||
{
|
||||
p.X += (TileWxH - b.Width) / 2;
|
||||
}
|
||||
|
||||
if (b.Height > TileWxH)
|
||||
{
|
||||
p.Y -= b.Height - TileWxH;
|
||||
}
|
||||
else if (b.Height < TileWxH)
|
||||
{
|
||||
p.Y += TileWxH - b.Height;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
return img.Width;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageWidth(m);
|
||||
}
|
||||
|
||||
return GetImageWidth(item.ItemID);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
return img.Height;
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageHeight(m);
|
||||
}
|
||||
|
||||
return GetImageHeight(item.ItemID);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileSize;
|
||||
}
|
||||
|
||||
return new Size(img.Width, img.Height);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileSize;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageSize(m);
|
||||
}
|
||||
|
||||
return GetImageSize(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
return GetImageOffset(m.Components);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
Point o, p = Point.Empty;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
p.X = Math.Min(p.X, o.X);
|
||||
p.Y = Math.Min(p.Y, o.Y);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetImageWidth(m.Components);
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point o;
|
||||
int x1 = 0, x2 = 0, w;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
w = GetImageWidth(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
|
||||
x1 = Math.Min(x1, o.X);
|
||||
x2 = Math.Max(x2, o.X + w);
|
||||
}
|
||||
|
||||
return Math.Max(0, x2 - x1);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetImageHeight(m.Components);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point o;
|
||||
int y1 = 0, y2 = 0, h;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
h = GetImageHeight(t.m_ItemID);
|
||||
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
y1 = Math.Min(y1, o.Y);
|
||||
y2 = Math.Max(y2, o.Y + h);
|
||||
}
|
||||
|
||||
return Math.Max(0, y2 - y1);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
return GetImageSize(m.Components);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
Point o;
|
||||
Size s;
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
s = GetImageSize(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
x1 = Math.Min(x1, o.X);
|
||||
y1 = Math.Min(y1, o.Y);
|
||||
|
||||
x2 = Math.Max(x2, o.X + s.Width);
|
||||
y2 = Math.Max(y2, o.Y + s.Height);
|
||||
}
|
||||
|
||||
return new Size(Math.Max(0, x2 - x1), Math.Max(0, y2 - y1));
|
||||
}
|
||||
|
||||
public static IEnumerable<MultiTileEntry> OrderByRender(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Enumerable.Empty<MultiTileEntry>();
|
||||
}
|
||||
|
||||
return OrderByRender(m.Components);
|
||||
}
|
||||
|
||||
public static IEnumerable<MultiTileEntry> OrderByRender(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var e in mcl.List //
|
||||
.OrderBy(o => ((o.m_OffsetX * mcl.Height) + o.m_OffsetY) * 2)
|
||||
.ThenBy(zt => zt.m_OffsetZ)
|
||||
.ThenByDescending(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Surface)) != 0)
|
||||
.ThenByDescending(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Wall)) != 0)
|
||||
.ThenBy(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Roof)) != 0)
|
||||
.ThenBy(zt => Server.TileData.ItemTable[zt.m_ItemID].CalcHeight))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnumerateByRender(this BaseMulti m, Action<Point, MultiTileEntry> action)
|
||||
{
|
||||
if (m != null && action != null)
|
||||
{
|
||||
EnumerateByRender(m.Components, action);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnumerateByRender(this Server.MultiComponentList mcl, Action<Point, MultiTileEntry> action)
|
||||
{
|
||||
if (mcl == null || action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Point o;
|
||||
|
||||
foreach (var t in mcl.OrderByRender())
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
action(o, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/Bootstrap.cs
Normal file
153
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/Bootstrap.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class Bootstrap
|
||||
{
|
||||
#if ServUO && !ServUOX
|
||||
[CallPriority(1)]
|
||||
public static void Configure()
|
||||
{
|
||||
foreach (var path in Core.DataDirectories)
|
||||
{
|
||||
Files.SetMulPath(path);
|
||||
}
|
||||
}
|
||||
#else
|
||||
private static readonly Dictionary<string, Type> _Modules = new Dictionary<string, Type>();
|
||||
|
||||
public static Assembly UltimaSDK { get; private set; }
|
||||
|
||||
public static bool Loaded { get; private set; }
|
||||
public static bool Warned { get; private set; }
|
||||
|
||||
static Bootstrap()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
private static void Load()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UltimaSDK = Assembly.LoadFrom("Ultima.dll");
|
||||
|
||||
Loaded = true;
|
||||
Warned = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UltimaSDK = null;
|
||||
|
||||
VitaNexCore.ToConsole("Could not load Ultima.dll");
|
||||
|
||||
if (!Warned)
|
||||
{
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
Warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Loaded)
|
||||
{
|
||||
foreach (var path in Core.DataDirectories)
|
||||
{
|
||||
Invoke("Files", "SetMulPath", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Type GetModule(string name)
|
||||
{
|
||||
Load();
|
||||
|
||||
if (!Loaded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!_Modules.TryGetValue(name, out var type))
|
||||
{
|
||||
_Modules[name] = type = UltimaSDK.GetType($"Ultima.{name}");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole($"Could not find Ultima.{name}:");
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static T Invoke<T>(string module, string method, params object[] args)
|
||||
{
|
||||
if (Invoke(module, method, args) is T o)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
|
||||
#if NET48_OR_GREATER
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static object Invoke(string module, string method, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = GetModule(module).InvokeMethod(method, args);
|
||||
|
||||
if (result is Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole($"Could not invoke Ultima.{module}.{method}:");
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
109
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/GumpsExt.cs
Normal file
109
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/GumpsExt.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class GumpsExtUtility
|
||||
{
|
||||
#if ServUOX
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return Server.GumpData.GetGump(index);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, int hue, bool onlyHueGrayPixels)
|
||||
{
|
||||
return Server.GumpData.GetGump(index, hue, onlyHueGrayPixels);
|
||||
}
|
||||
|
||||
#region Ultima SDK Signatures
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
patched = false;
|
||||
|
||||
return GetGump(index);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#elif ServUO
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return GetGump(index, out _);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
return Gumps.GetGump(index, out patched);
|
||||
}
|
||||
#else
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return GetGump(index, out _);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
var param = new object[] { index, false };
|
||||
|
||||
var img = Bootstrap.Invoke<Bitmap>("Gumps", "GetGump", param);
|
||||
|
||||
patched = (bool)param[1];
|
||||
|
||||
return img;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Size GetImageSize(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return new Size(0, 0);
|
||||
}
|
||||
|
||||
return new Size(img.Width, img.Height);
|
||||
}
|
||||
|
||||
public static int GetImageWidth(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return img.Width;
|
||||
}
|
||||
|
||||
public static int GetImageHeight(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return img.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user