Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,19 @@
# Common Directories
/.vs
/.JustCode
# Wildcard Files
*.rar
*.pdb
*.exe
*.exe.mdb
*.exe.config
*.dll.config
*.sh
*.suo
*.idea
*.log
*.bin
*.csproj.user
*.DotSettings.user

View File

@@ -0,0 +1,361 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CSharp;
using Server;
using VitaNex.IO;
#endregion
#if !MUO
namespace VitaNex.Build
{
public enum CompileStatus
{
Initializing,
Compiling,
Completed,
Aborted
}
public class CSharpCompiler
{
public static readonly string[] DefaultReferences =
{
"System.dll", "System.Core.dll", "System.Data.dll", "System.Drawing.dll", "System.Web.dll",
"System.Windows.Forms.dll", "System.Xml.dll"
};
private static volatile string _DefaultInputPath = IOUtility.GetSafeDirectoryPath(Core.BaseDirectory + "/Scripts");
private static volatile string _DefaultOutputPath =
IOUtility.GetSafeDirectoryPath(Core.BaseDirectory + "/Scripts/Output");
public static string DefaultInputPath
{
get => _DefaultInputPath;
set => _DefaultInputPath = IOUtility.GetSafeDirectoryPath(value);
}
public static string DefaultOutputPath
{
get => _DefaultOutputPath;
set => _DefaultOutputPath = IOUtility.GetSafeDirectoryPath(value);
}
public bool Debug { get; set; }
public List<string> References { get; private set; }
public List<string> FileMasks { get; private set; }
public List<string> Arguments { get; private set; }
public string[] Errors { get; private set; }
public CompileStatus Status { get; private set; }
public string StatusMessage { get; private set; }
public CSharpCodeProvider Provider { get; private set; }
public CompilerParameters Parameters { get; private set; }
public CompilerResults Results { get; private set; }
public DirectoryInfo InputDirectory { get; set; }
public DirectoryInfo OutputDirectory { get; set; }
public string OutputFileName { get; set; }
public Action<CompilerResults> CompiledCallback { get; set; }
public CSharpCompiler(
DirectoryInfo input,
DirectoryInfo output,
string outputFileName,
Action<CompilerResults> onCompiled = null)
{
References = new List<string>();
FileMasks = new List<string>();
Arguments = new List<string>();
Errors = new string[0];
Status = CompileStatus.Initializing;
StatusMessage = String.Empty;
Provider = new CSharpCodeProvider();
InputDirectory = input;
OutputDirectory = output.EnsureDirectory(false);
OutputFileName = outputFileName;
CompiledCallback = onCompiled;
}
public CSharpCompiler(
string inputPath,
string outputPath,
string outputFileName,
Action<CompilerResults> onCompiled = null)
: this(
new DirectoryInfo(IOUtility.GetSafeDirectoryPath(inputPath)),
IOUtility.EnsureDirectory(outputPath, true),
outputFileName,
onCompiled)
{ }
public CSharpCompiler(string outputFileName, Action<CompilerResults> onCompiled = null)
: this(new DirectoryInfo(_DefaultInputPath), new DirectoryInfo(_DefaultOutputPath), outputFileName, onCompiled)
{ }
public void AddReference(string name)
{
if (!References.Contains(name))
{
References.Add(name);
}
}
public void AddFileMask(string mask)
{
if (!FileMasks.Contains(mask))
{
FileMasks.Add(mask);
}
}
public void Compile(bool async = false)
{
if (Status == CompileStatus.Compiling)
{
return;
}
var pct = new Thread(Init)
{
Name = "VNCSharpCompiler"
};
pct.Start();
if (async)
{
return;
}
VitaNexCore.WaitWhile(
() => Status == CompileStatus.Initializing || Status == CompileStatus.Compiling,
TimeSpan.FromMinutes(5.0));
pct.Join();
}
[STAThread]
private void Init()
{
VitaNexCore.TryCatch(
() =>
{
Status = CompileStatus.Initializing;
if (!InputDirectory.Exists)
{
Status = CompileStatus.Aborted;
StatusMessage = "Input directory '" + InputDirectory + "' does not exist.";
return;
}
var infos = new List<FileInfo>();
foreach (var file in FileMasks.SelectMany(
t => InputDirectory.GetFiles(t, SearchOption.AllDirectories).Where(file => !infos.Contains(file))))
{
infos.Add(file);
}
var files = infos.ToArray();
infos.Clear();
if (files.Length == 0)
{
Status = CompileStatus.Aborted;
StatusMessage = "No files to compile.";
return;
}
var refs = new List<string>();
var fileNames = new List<string>();
foreach (var fName in files.Select(t => t.FullName)
.Where(fName => !String.IsNullOrEmpty(fName))
.Where(fName => !fileNames.Contains(fName)))
{
fileNames.Add(fName);
}
foreach (var t in DefaultReferences.Where(t => !String.IsNullOrEmpty(t)).Where(t => !refs.Contains(t)))
{
refs.Add(t);
}
foreach (var t in References.Where(t => !String.IsNullOrEmpty(t)).Where(t => !refs.Contains(t)))
{
refs.Add(t);
}
var configs = GetConfigFiles();
if (configs != null)
{
foreach (var t in configs.Select(GetConfigAssemblies)
.SelectMany(
asm => asm.Where(t => !String.IsNullOrEmpty(t))
.Where(t => File.Exists(IOUtility.GetSafeFilePath(IOUtility.GetBaseDirectory() + "/" + t, true)))
.Where(t => !refs.Contains(t))))
{
refs.Add(t);
}
}
Status = CompileStatus.Compiling;
Parameters = new CompilerParameters(
refs.ToArray(),
IOUtility.GetUnusedFilePath(OutputDirectory.FullName, OutputFileName),
Debug)
{
GenerateExecutable = false,
WarningLevel = 4,
CompilerOptions = String.Empty
};
foreach (var arg in Arguments)
{
Parameters.CompilerOptions += arg + " ";
}
Results = Provider.CompileAssemblyFromFile(Parameters, fileNames.ToArray());
if (Results.Errors.Count > 0)
{
int errorCount = 0, warningCount = 0;
foreach (CompilerError e in Results.Errors)
{
if (e.IsWarning)
{
++warningCount;
}
else
{
++errorCount;
}
}
Errors = new string[Results.Errors.Count];
for (var e = 0; e < Results.Errors.Count; e++)
{
Errors[e] = String.Format(
"[{0}][{1}][{2}]: Line {3}, Column {4}\n{5}",
Results.Errors[e].IsWarning ? "Warning" : "Error",
Results.Errors[e].FileName,
Results.Errors[e].ErrorNumber,
Results.Errors[e].Line,
Results.Errors[e].Column,
Results.Errors[e].ErrorText);
}
StatusMessage = String.Format(
"Finished compiling with {0} error{1} and {2} warning{3}",
errorCount,
errorCount > 1 ? "s" : "",
warningCount,
warningCount > 1 ? "s" : "");
Status = CompileStatus.Completed;
}
else
{
StatusMessage = "Finished compiling with no errors or warnings.";
Status = CompileStatus.Completed;
}
},
ex =>
{
Status = CompileStatus.Aborted;
StatusMessage = ex.Message;
});
if (CompiledCallback != null)
{
CompiledCallback(Results);
}
}
public FileInfo[] GetConfigFiles()
{
var configs = InputDirectory.GetFiles("*.cfg", SearchOption.AllDirectories);
if (configs.Length > 0)
{
return configs;
}
return null;
}
private string[] GetConfigAssemblies(FileInfo file)
{
var list = new List<string>();
if (file.Exists)
{
var lines = File.ReadAllLines(file.FullName, Encoding.Default);
var content = String.Empty;
var inTag = false;
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].StartsWith("[VNC]"))
{
inTag = true;
lines[i] = lines[i].Replace("[VNC]", String.Empty);
}
else if (lines[i].StartsWith("["))
{
inTag = false;
lines[i] = String.Empty;
}
if (inTag)
{
if (!String.IsNullOrEmpty(lines[i]))
{
content += lines[i].Trim();
}
}
}
var split = content.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
list.AddRange(split.Where(assembly => !String.IsNullOrEmpty(assembly) && !assembly.StartsWith("#")));
}
return list.ToArray();
}
}
}
#endif

View File

@@ -0,0 +1,60 @@
#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 VitaNex.Collections
{
public sealed class GenericComparer<T> : Comparer<T>
where T : IComparable<T>
{
private static readonly GenericComparer<T> _Instance = new GenericComparer<T>();
public static IOrderedEnumerable<T> Order(IEnumerable<T> source)
{
return source.Ensure().OrderBy(o => o, _Instance);
}
public static IOrderedEnumerable<T> OrderDescending(IEnumerable<T> source)
{
return source.Ensure().OrderBy(o => o, _Instance);
}
public static int Compute(T x, T y)
{
return _Instance.Compare(x, y);
}
public override int Compare(T x, T y)
{
if (ReferenceEquals(x, y))
{
return 0;
}
if (ReferenceEquals(x, null))
{
return 1;
}
if (ReferenceEquals(y, null))
{
return -1;
}
return x.CompareTo(y);
}
}
}

View File

@@ -0,0 +1,35 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
using System.Collections.Concurrent;
namespace VitaNex.Collections
{
public sealed class ConcurrentBagPool<T> : ObjectPool<ConcurrentBag<T>>
{
public ConcurrentBagPool()
{ }
public ConcurrentBagPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(ConcurrentBag<T> o)
{
while (!o.IsEmpty)
{
o.TryTake(out _);
}
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,32 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
using System.Collections.Concurrent;
namespace VitaNex.Collections
{
public sealed class ConcurrentDictionaryPool<TKey, TVal> : ObjectPool<ConcurrentDictionary<TKey, TVal>>
{
public ConcurrentDictionaryPool()
{ }
public ConcurrentDictionaryPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(ConcurrentDictionary<TKey, TVal> o)
{
o.Clear();
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,35 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
using System.Collections.Concurrent;
namespace VitaNex.Collections
{
public sealed class ConcurrentQueuePool<T> : ObjectPool<ConcurrentQueue<T>>
{
public ConcurrentQueuePool()
{ }
public ConcurrentQueuePool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(ConcurrentQueue<T> o)
{
while (!o.IsEmpty)
{
o.TryDequeue(out _);
}
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,32 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
using System.Collections.Concurrent;
namespace VitaNex.Collections
{
public sealed class ConcurrentStackPool<T> : ObjectPool<ConcurrentStack<T>>
{
public ConcurrentStackPool()
{ }
public ConcurrentStackPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(ConcurrentStack<T> o)
{
o.Clear();
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,34 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
#endregion
namespace VitaNex.Collections
{
public sealed class DictionaryPool<TKey, TVal> : ObjectPool<Dictionary<TKey, TVal>>
{
public DictionaryPool()
{ }
public DictionaryPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(Dictionary<TKey, TVal> o)
{
o.Clear();
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,33 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
#endregion
namespace VitaNex.Collections
{
public sealed class GridPool<T> : ObjectPool<Grid<T>>
{
public GridPool()
{ }
public GridPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(Grid<T> o)
{
o.Resize(0, 0);
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,39 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
#endregion
namespace VitaNex.Collections
{
public sealed class ListPool<T> : ObjectPool<List<T>>
{
public ListPool()
{ }
public ListPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(List<T> o)
{
o.Clear();
if (o.Capacity > 0x1000)
{
o.Capacity = 0x1000;
}
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,209 @@
#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.Concurrent;
#endregion
namespace VitaNex.Collections
{
public static class ObjectPool
{
public static T Acquire<T>() where T : class, new()
{
return ObjectPool<T>.AcquireObject();
}
public static void Acquire<T>(out T o) where T : class, new()
{
ObjectPool<T>.AcquireObject(out o);
}
public static void Free<T>(T o) where T : class, new()
{
ObjectPool<T>.FreeObject(o);
}
public static void Free<T>(ref T o) where T : class, new()
{
ObjectPool<T>.FreeObject(ref o);
}
}
public class ObjectPool<T> where T : class, new()
{
private static readonly ObjectPool<T> _Instance;
static ObjectPool()
{
_Instance = new ObjectPool<T>();
}
public static T AcquireObject()
{
return _Instance.Acquire();
}
public static void AcquireObject(out T o)
{
o = _Instance.Acquire();
}
public static void FreeObject(T o)
{
_Instance.Free(o);
}
public static void FreeObject(ref T o)
{
_Instance.Free(ref o);
}
protected readonly ConcurrentQueue<T> _Pool;
private volatile int _Capacity;
public int Capacity
{
get => _Capacity;
set
{
if (value < 0)
{
value = DefaultCapacity;
}
_Capacity = value;
}
}
public int Count => _Pool.Count;
public bool IsEmpty => _Pool.IsEmpty;
public bool IsOverflow => _Pool.Count > _Capacity;
public bool IsFull => _Capacity > 0 && _Pool.Count >= _Capacity;
public virtual int DefaultCapacity => 64;
public ObjectPool()
{
_Capacity = DefaultCapacity;
_Pool = new ConcurrentQueue<T>();
}
public ObjectPool(int capacity)
{
_Capacity = capacity;
_Pool = new ConcurrentQueue<T>();
}
public virtual T Acquire()
{
if (!_Pool.TryDequeue(out var o) || o == null)
{
o = new T();
}
return o;
}
public virtual void Free(T o)
{
if (o == null)
{
return;
}
try
{
if (!Sanitize(o))
{
return;
}
}
catch
{
return;
}
if (!IsFull)
{
_Pool.Enqueue(o);
}
}
public void Free(ref T o)
{
Free(o);
o = default(T);
}
protected virtual bool Sanitize(T o)
{
if (o is IList l)
{
l.Clear();
return l.Count == 0;
}
o.InvokeMethod("Clear");
return true;
}
public void Clear()
{
while (!IsEmpty)
{
_Pool.TryDequeue(out _);
}
}
public virtual int Trim()
{
var c = 0;
while (IsOverflow)
{
_Pool.TryDequeue(out _);
++c;
}
return c;
}
public virtual int Fill()
{
var c = 0;
while (!IsFull)
{
_Pool.Enqueue(new T());
++c;
}
return c;
}
public virtual void Free()
{
Clear();
}
}
}

View File

@@ -0,0 +1,34 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
#endregion
namespace VitaNex.Collections
{
public sealed class QueuePool<T> : ObjectPool<Queue<T>>
{
public QueuePool()
{ }
public QueuePool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(Queue<T> o)
{
o.Clear();
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,34 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
#endregion
namespace VitaNex.Collections
{
public sealed class SetPool<T> : ObjectPool<HashSet<T>>
{
public SetPool()
{ }
public SetPool(int capacity)
: base(capacity)
{ }
protected override bool Sanitize(HashSet<T> o)
{
o.Clear();
return o.Count == 0;
}
}
}

View File

@@ -0,0 +1,122 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.IO;
using Server;
using Server.Mobiles;
using VitaNex.IO;
#endregion
namespace VitaNex.Commands
{
public static class ExportBoundsCommand
{
public static void Initialize()
{
CommandUtility.Register(
"ExportBounds2D",
AccessLevel.GameMaster,
e =>
{
if (e != null && e.Mobile != null)
{
OnExportBounds2D(e.Mobile, e.GetString(0), e.GetString(1));
}
});
CommandUtility.RegisterAlias("ExportBounds2D", "XB2D");
CommandUtility.Register(
"ExportBounds3D",
AccessLevel.GameMaster,
e =>
{
if (e != null && e.Mobile != null)
{
OnExportBounds3D(e.Mobile, e.GetString(0), e.GetString(1));
}
});
CommandUtility.RegisterAlias("ExportBounds3D", "XB3D");
}
public static void OnExportBounds2D(Mobile m, string speech, string comment)
{
if (m == null || m.Deleted || !(m is PlayerMobile))
{
return;
}
if (String.IsNullOrWhiteSpace(speech))
{
speech = "Bounds";
}
BoundingBoxPicker.Begin(
m,
(from, map, start, end, state) =>
{
var r = new Rectangle2D(start, end.Clone2D(1, 1));
IOUtility.EnsureFile(VitaNexCore.DataDirectory + "/Export/Bounds/2D/" + IOUtility.GetSafeFileName(speech) + ".txt")
.AppendText(
false,
String.Format(
"new Rectangle2D({0}, {1}, {2}, {3}), //{4}",
//
r.Start.X,
r.Start.Y,
r.Width,
r.Height,
comment ?? String.Empty));
},
null);
}
public static void OnExportBounds3D(Mobile m, string speech, string comment)
{
if (m == null || m.Deleted || !(m is PlayerMobile))
{
return;
}
if (String.IsNullOrWhiteSpace(speech))
{
speech = "Bounds";
}
BoundingBoxPicker.Begin(
m,
(from, map, start, end, state) =>
{
var r = new Rectangle3D(start, end.Clone3D(1, 1));
IOUtility
.EnsureFile(VitaNexCore.DataDirectory + "/Export/Bounds/3D/" + IOUtility.GetSafeFileName(speech) + ".txt")
.AppendText(
false,
String.Format(
"new Rectangle3D({0}, {1}, {2}, {3}, {4}, {5}), //{6}",
//
r.Start.X,
r.Start.Y,
r.Start.Z,
r.Width,
r.Height,
r.Depth,
comment ?? String.Empty));
},
null);
}
}
}

View File

@@ -0,0 +1,100 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.IO;
using Server;
using Server.Mobiles;
using VitaNex.IO;
using VitaNex.Targets;
#endregion
namespace VitaNex.Commands
{
public static class ExportPointCommand
{
public static void Initialize()
{
CommandUtility.Register(
"ExportPoint2D",
AccessLevel.GameMaster,
e =>
{
if (e != null && e.Mobile != null)
{
OnExportPoint2D(e.Mobile, e.GetString(0), e.GetString(1));
}
});
CommandUtility.RegisterAlias("ExportPoint2D", "XP2D");
CommandUtility.Register(
"ExportPoint3D",
AccessLevel.GameMaster,
e =>
{
if (e != null && e.Mobile != null)
{
OnExportPoint3D(e.Mobile, e.GetString(0), e.GetString(1));
}
});
CommandUtility.RegisterAlias("ExportPoint3D", "XP3D");
}
public static void OnExportPoint2D(Mobile m, string speech, string comment)
{
if (m == null || m.Deleted || !(m is PlayerMobile))
{
return;
}
if (String.IsNullOrWhiteSpace(speech))
{
speech = "Points";
}
GenericSelectTarget<IPoint2D>.Begin(
m,
(from, p) =>
IOUtility
.EnsureFile(VitaNexCore.DataDirectory + "/Export/Points/2D/" + IOUtility.GetSafeFileName(speech) + ".txt")
.AppendText(false, String.Format("new Point2D({0}, {1}), //{2}", p.X, p.Y, comment ?? String.Empty)),
null,
-1,
true);
}
public static void OnExportPoint3D(Mobile m, string speech, string comment)
{
if (m == null || m.Deleted || !(m is PlayerMobile))
{
return;
}
if (String.IsNullOrWhiteSpace(speech))
{
speech = "Points";
}
GenericSelectTarget<IPoint3D>.Begin(
m,
(from, p) =>
IOUtility
.EnsureFile(VitaNexCore.DataDirectory + "/Export/Points/3D/" + IOUtility.GetSafeFileName(speech) + ".txt")
.AppendText(false, String.Format("new Point3D({0}, {1}, {2}), //{3}", p.X, p.Y, p.Z, comment ?? String.Empty)),
null,
-1,
true);
}
}
}

View File

@@ -0,0 +1,484 @@
#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 System.Text;
using Server;
using Server.Commands;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
using VitaNex.Targets;
using Skills = Server.Skills;
#endregion
namespace VitaNex.Commands
{
[Flags]
public enum FixMeFlags
{
None = 0x0000,
Mount = 0x0001,
Pets = 0x0002,
Equip = 0x0004,
Gumps = 0x0008,
Tags = 0x0010,
Skills = 0x0020,
Quests = 0x0040,
All = ~None
}
public static class FixMeCommand
{
public delegate void ResolveFlagsHandler(Mobile m, ref FixMeFlags flags);
public static event Action<Mobile> OnFixMount;
public static event Action<PlayerMobile> OnFixPets;
public static event Action<PlayerMobile> OnFixEquip;
public static event Action<Mobile> OnFixGumps;
public static event Action<Mobile> OnFixTags;
public static event Action<Mobile> OnFixSkills;
public static event Action<PlayerMobile> OnFixQuests;
public static event Action<FixMeGump> OnGumpSend;
public static event Action<Mobile, FixMeFlags> OnFix;
public static event ResolveFlagsHandler ResolveFlags;
public static FixMeFlags DisabledFlags { get; set; }
static FixMeCommand()
{
OnFixMount += FixMount;
OnFixPets += FixPets;
OnFixEquip += FixEquip;
OnFixGumps += FixGumps;
OnFixTags += FixTags;
OnFixSkills += FixSkills;
OnFixQuests += FixQuests;
}
public static void Configure()
{
CommandSystem.Register(
"FixMe",
AccessLevel.Player,
e =>
{
if (e == null || !(e.Mobile is PlayerMobile))
{
return;
}
var g = SuperGump.Send(new FixMeGump((PlayerMobile)e.Mobile));
if (OnGumpSend != null)
{
OnGumpSend(g);
}
});
CommandSystem.Register(
"FixThem",
AccessLevel.GameMaster,
e =>
{
if (e == null || !(e.Mobile is PlayerMobile))
{
return;
}
e.Mobile.SendMessage(0x22, "Target an online player to send them the FixMe gump.");
e.Mobile.Target = new MobileSelectTarget<PlayerMobile>(
(m, target) =>
{
if (target == null || target.Deleted)
{
return;
}
if (!target.IsOnline())
{
m.SendMessage(0x22, "{0} must be online.", target.RawName);
return;
}
m.SendMessage(0x55, "Opening FixMe gump for {0}...", target.RawName);
var g = SuperGump.Send(new FixMeGump(target));
if (OnGumpSend != null)
{
OnGumpSend(g);
}
},
m => m.SendMessage(0x22, "Target an on-line player to send them the FixMe gump."));
});
}
public static string GetDescription(this FixMeFlags flags)
{
var html = new StringBuilder();
switch (flags)
{
case FixMeFlags.Mount:
html.Append("Attempt to correct your mount if it appears to be glitched.");
break;
case FixMeFlags.Pets:
{
html.AppendLine("All pets will be stabled or teleported and your follower count will be normalized.");
html.Append("If mounted, the mount will not be included.");
}
break;
case FixMeFlags.Equip:
html.Append("All equipment will be validated, any invalid equipment will be unequipped.");
break;
case FixMeFlags.Gumps:
html.Append("All open gumps will be refreshed.");
break;
case FixMeFlags.Tags:
html.Append("All character and equipment attribute tags will be refreshed.");
break;
case FixMeFlags.Skills:
html.Append("All skills will be normalized if they are detected as invalid.");
break;
case FixMeFlags.Quests:
html.Append("All quests will be repaired if they are detected as invalid.");
break;
}
return html.ToString();
}
public static void FixMe(this Mobile m, FixMeFlags flags)
{
if (m == null || m.Deleted)
{
return;
}
var oldFlags = flags;
if (ResolveFlags != null)
{
ResolveFlags(m, ref flags);
}
if (flags.HasFlag(FixMeFlags.Mount) && OnFixMount != null)
{
OnFixMount(m);
m.SendMessage(0x55, "Your mount has been validated.");
}
else if (oldFlags.HasFlag(FixMeFlags.Mount))
{
m.SendMessage(0x22, "Fixing mounts is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Pets) && OnFixPets != null && m is PlayerMobile)
{
OnFixPets((PlayerMobile)m);
m.SendMessage(
0x55,
"Your pets have been stabled or teleported to you and your follower count has been normalized, it is now {0}.",
m.Followers);
}
else if (oldFlags.HasFlag(FixMeFlags.Pets))
{
m.SendMessage(0x22, "Fixing pets is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Equip) && OnFixEquip != null && m is PlayerMobile)
{
OnFixEquip((PlayerMobile)m);
m.SendMessage(0x55, "Your equipment has been validated.");
}
else if (oldFlags.HasFlag(FixMeFlags.Equip))
{
m.SendMessage(0x22, "Fixing equipment is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Gumps) && OnFixGumps != null)
{
OnFixGumps(m);
m.SendMessage(0x55, "Your gumps have been refreshed.");
}
else if (oldFlags.HasFlag(FixMeFlags.Gumps))
{
m.SendMessage(0x22, "Fixing gumps is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Tags) && OnFixTags != null)
{
OnFixTags(m);
m.SendMessage(0x55, "Your character and equipment tags have been refreshed.");
}
else if (oldFlags.HasFlag(FixMeFlags.Tags))
{
m.SendMessage(0x22, "Fixing character and equipment tags is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Skills) && OnFixSkills != null)
{
OnFixSkills(m);
m.SendMessage(0x55, "Your skills have been normalized.");
}
else if (oldFlags.HasFlag(FixMeFlags.Skills))
{
m.SendMessage(0x22, "Fixing skills is currently unavailable.");
}
if (flags.HasFlag(FixMeFlags.Quests) && OnFixQuests != null && m is PlayerMobile)
{
OnFixQuests((PlayerMobile)m);
m.SendMessage(0x55, "Your quests have been validated.");
}
else if (oldFlags.HasFlag(FixMeFlags.Quests))
{
m.SendMessage(0x22, "Fixing quests is currently unavailable.");
}
if (OnFix != null)
{
OnFix(m, flags);
}
m.SendMessage(0x55, "FixMe completed! If you still have issues, contact a member of staff.");
}
public static void FixMount(Mobile m)
{
if (!m.Mounted)
{
return;
}
var mountItem = m.FindItemOnLayer(Layer.Mount) as IMountItem;
if (mountItem != null)
{
if (mountItem.Mount == null || mountItem.Mount != m.Mount)
{
m.RemoveItem(mountItem as Item);
}
else if (mountItem.Mount.Rider == null)
{
mountItem.Mount.Rider = m;
}
}
else if (m.Mount != null && m.Mount.Rider == null)
{
m.Mount.Rider = m;
}
m.Delta(MobileDelta.Followers);
}
public static void FixPets(PlayerMobile m)
{
if (m.AllFollowers == null || m.AllFollowers.Count == 0)
{
return;
}
BaseCreature pet;
var count = m.AllFollowers.Count;
while (--count >= 0)
{
pet = m.AllFollowers[count] as BaseCreature;
if (pet == null || pet.IsStabled)
{
continue;
}
if (pet.Deleted || !pet.IsControlledBy(m))
{
m.AllFollowers.RemoveAt(count);
continue;
}
if (pet == m.Mount || pet.Stable(false))
{
continue;
}
pet.MoveToWorld(m.Location, m.Map);
pet.ControlTarget = m;
pet.ControlOrder = OrderType.Follow;
}
m.Followers = m.AllFollowers.OfType<BaseCreature>()
.Where(p => !p.IsStabled && p.Map == m.Map)
.Aggregate(0, (c, p) => c + p.ControlSlots);
m.Followers = Math.Max(0, m.Followers);
m.Delta(MobileDelta.Followers);
}
public static void FixEquip(PlayerMobile m)
{
m.ValidateEquipment();
}
public static void FixGumps(Mobile m)
{
if (!m.IsOnline())
{
return;
}
var gumps = m.NetState.Gumps.ToList();
foreach (var gump in gumps)
{
if (gump is SuperGump)
{
((SuperGump)gump).Refresh(true);
}
else
{
m.NetState.Send(new CloseGump(gump.TypeID, 0));
m.NetState.RemoveGump(gump);
gump.OnServerClose(m.NetState);
m.SendGump(gump);
}
}
gumps.Free(true);
}
public static void FixTags(Mobile m)
{
m.Items.ForEach(
item =>
{
if (item != null && !item.Deleted)
{
item.InvalidateProperties();
}
});
if (m.Backpack != null)
{
m.Backpack.InvalidateProperties();
var list = m.Backpack.FindItemsByType<Item>(true);
list.ForEach(
item =>
{
if (item != null && !item.Deleted)
{
item.InvalidateProperties();
}
});
}
m.InvalidateProperties();
}
public static void FixSkills(Mobile m)
{
if (m.Skills == null)
{
m.Skills = new Skills(m);
}
foreach (var skill in SkillInfo.Table.Select(si => m.Skills[si.SkillID]))
{
skill.Normalize();
}
}
public static void FixQuests(PlayerMobile m)
{
if (m.Quest == null)
{
return;
}
if (m.Quest.From == null)
{
m.Quest.From = m;
}
if (m.Quest.Objectives == null || m.Quest.Objectives.Count == 0 || m.Quest.Conversations == null ||
m.Quest.Conversations.Count == 0)
{
m.Quest.Cancel();
}
}
}
public sealed class FixMeGump : ListGump<FixMeFlags>
{
private static readonly FixMeFlags[] _FixMeFlags = default(FixMeFlags)
.GetValues<FixMeFlags>()
.Not(f => f == FixMeFlags.All || f == FixMeFlags.None)
.ToArray();
public FixMeGump(Mobile user, Gump parent = null)
: base(user, parent, title: "Fix Me!", emptyText: "There are no operations to display.")
{
Modal = true;
CanMove = false;
CanResize = false;
BlockSpeech = true;
BlockMovement = true;
}
protected override void CompileList(List<FixMeFlags> list)
{
list.Clear();
list.AddRange(_FixMeFlags.Not(f => FixMeCommand.DisabledFlags.HasFlag(f)));
base.CompileList(list);
}
protected override void SelectEntry(GumpButton button, FixMeFlags entry)
{
base.SelectEntry(button, entry);
var html = new StringBuilder();
html.AppendFormat("This operation will fix your {0}.", entry.ToString().ToLower());
html.AppendLine();
html.Append(entry.GetDescription());
html.AppendLine();
html.AppendLine("Do you want to continue?");
Send(
new ConfirmDialogGump(
User,
Refresh(),
title: "Confirm Operation",
html: html.ToString(),
onAccept: b =>
{
User.FixMe(entry);
Refresh(true);
}));
}
}
}

View File

@@ -0,0 +1,117 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Diagnostics;
using Server;
using Server.Network;
#endregion
namespace VitaNex.Commands
{
/// <summary>
/// Force full Garbage Collection cycle on all generations.
/// </summary>
public static class GCCommand
{
private static bool _Initialized;
private static bool _Optimizing;
public static void Initialize()
{
if (_Initialized)
{
return;
}
_Initialized = true;
CommandUtility.Register(
"GC",
AccessLevel.Administrator,
e =>
{
var message = true;
if (e.Arguments != null && e.Arguments.Length > 0)
{
message = e.GetBoolean(0);
}
Optimize(e.Mobile, message);
});
CommandUtility.RegisterAlias("GC", "Optimize");
}
public static void Optimize(bool message)
{
Optimize(null, message);
}
public static void Optimize(Mobile m, bool message)
{
if (World.Saving || World.Loading || _Optimizing)
{
return;
}
NetState.FlushAll();
NetState.Pause();
_Optimizing = true;
var now = DateTime.UtcNow;
if (message)
{
World.Broadcast(0x35, true, "[{0}]: The world is optimizing, please wait.", now.ToShortTimeString());
}
var watch = new Stopwatch();
watch.Start();
double mem = GC.GetTotalMemory(false);
GC.Collect();
mem -= GC.GetTotalMemory(false);
mem = (mem / 1024.0) / 1024.0;
watch.Stop();
_Optimizing = false;
if (m != null)
{
m.SendMessage("[{0}]: GC done in {1:F2} seconds.", now.ToShortTimeString(), watch.Elapsed.TotalSeconds);
m.SendMessage("[{0}]: GC reports {1:#,0.00} MB freed memory.", now.ToShortTimeString(), mem);
}
Console.WriteLine("[{0}]: GC done in {1:F2} seconds.", now.ToShortTimeString(), watch.Elapsed.TotalSeconds);
Console.WriteLine("[{0}]: GC reports {1:#,0.00} MB freed memory.", now.ToShortTimeString(), mem);
if (message)
{
World.Broadcast(
0x35,
true,
"[{0}]: World optimization complete. The entire process took {1:F1} seconds.",
DateTime.UtcNow.ToShortTimeString(),
watch.Elapsed.TotalSeconds);
}
NetState.Resume();
}
}
}

View File

@@ -0,0 +1,132 @@
#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.Linq;
using Server;
using Server.Commands;
using Server.Gumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Commands
{
public static class MyCommandsCommand
{
public static void Initialize()
{
CommandSystem.Register("MyCommands", AccessLevel.Player, e => new MyCommandsGump(e.Mobile).Send());
}
}
public class MyCommandsGump : ListGump<CommandEntry>
{
public MyCommandsGump(Mobile user, Gump parent = null)
: base(user, parent, title: "My Commands", emptyText: "No commands to display.")
{
Sorted = true;
Modal = false;
CanMove = false;
CanResize = false;
}
public override string GetSearchKeyFor(CommandEntry key)
{
return key != null ? key.Command : base.GetSearchKeyFor(null);
}
public override int SortCompare(CommandEntry a, CommandEntry b)
{
var res = 0;
if (a.CompareNull(b, ref res))
{
return res;
}
if (a.AccessLevel > b.AccessLevel)
{
return -1;
}
if (a.AccessLevel < b.AccessLevel)
{
return 1;
}
return String.Compare(a.Command, b.Command, StringComparison.OrdinalIgnoreCase);
}
protected override void CompileList(List<CommandEntry> list)
{
list.Clear();
var commands = CommandUtility.EnumerateCommands(User.AccessLevel);
commands = commands.Where(c => !Insensitive.Equals(c.Command, "MyCommands"));
list.AddRange(commands);
base.CompileList(list);
}
protected override void SelectEntry(GumpButton button, CommandEntry entry)
{
base.SelectEntry(button, entry);
User.SendMessage(0x55, "Using Command: {0}", entry.Command);
CommandSystem.Handle(User, String.Format("{0}{1}", CommandSystem.Prefix, entry.Command));
Refresh();
}
protected override string GetLabelText(int index, int pageIndex, CommandEntry entry)
{
return entry != null && !String.IsNullOrWhiteSpace(entry.Command)
? entry.Command[0].ToString(CultureInfo.InvariantCulture).ToUpper() + entry.Command.Substring(1)
: base.GetLabelText(index, pageIndex, entry);
}
protected override int GetLabelHue(int index, int pageIndex, CommandEntry entry)
{
if (entry == null)
{
return base.GetLabelHue(index, pageIndex, null);
}
if (entry.AccessLevel >= AccessLevel.Administrator)
{
return 0x516;
}
if (entry.AccessLevel > AccessLevel.GameMaster)
{
return 0x144;
}
if (entry.AccessLevel > AccessLevel.Counselor)
{
return 0x21;
}
if (entry.AccessLevel > AccessLevel.Player)
{
return 0x30;
}
return TextHue;
}
}
}

View File

@@ -0,0 +1,723 @@
#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.IO;
using System.Linq;
using System.Text;
using Server;
using Server.Accounting;
using Server.Commands;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using VitaNex.IO;
#endregion
namespace VitaNex.Commands
{
public static class PlayerBackup
{
public static void Configure()
{
EventSink.DeleteRequest += HandleDeleteRequest;
}
public static void Initialize()
{
CommandUtility.Register("BackupState", AccessLevel.Administrator, OnBackupCommand);
CommandUtility.Register("RestoreState", AccessLevel.Administrator, OnRestoreCommand);
}
private static void HandleDeleteRequest(DeleteRequestEventArgs e)
{
var state = e.State;
var index = e.Index;
var acct = state.Account as Account;
if (acct == null)
{
return;
}
var m = acct[index] as PlayerMobile;
if (m != null && !m.Deleted && m.GameTime.TotalHours >= 24)
{
try
{
BackupState(m, true);
}
catch
{ }
}
}
[Usage("BackupState [DisableLogs=false]"), Description("Writes a binary data file containing information for a character's Bank, Pack and Equipment.")]
public static void OnBackupCommand(CommandEventArgs e)
{
if (e.Mobile == null || e.Mobile.Deleted)
{
return;
}
e.Mobile.SendMessage("Target a PlayerMobile to backup...");
e.Mobile.BeginTarget<PlayerMobile>((m, t) =>
{
BackupState(t, !e.GetBoolean(0), out var count, out var fails);
if (fails > 0)
{
e.Mobile.SendMessage("Backup: {0:#,0} / {1:#,0} saved item states.", count - fails, count);
}
else
{
e.Mobile.SendMessage("Backup: {0:#,0} saved item states.", count);
}
}, null);
}
[Usage("RestoreState <Serial=-1, MoveExisting=false, Logging=true>"), Description("Reads a binary data file containing information for a character's Bank, Pack and Equipment.")]
public static void OnRestoreCommand(CommandEventArgs e)
{
if (e.Mobile == null || e.Mobile.Deleted)
{
return;
}
var serial = Serial.MinusOne;
var moveExisting = false;
var logging = true;
if (e.Arguments.Length > 0)
{
#if ServUOX
serial = e.GetSerial(0);
#else
serial = e.GetInt32(0);
#endif
}
if (e.Arguments.Length > 1)
{
moveExisting = e.GetBoolean(1);
}
if (e.Arguments.Length > 2)
{
logging = e.GetBoolean(2);
}
e.Mobile.SendMessage("Target a PlayerMobile to restore...");
e.Mobile.BeginTarget<PlayerMobile>((m, t) =>
{
RestoreState(t, serial, moveExisting, logging, out var created, out var deleted, out var ignored, out var moved);
e.Mobile.SendMessage("Restore: {0:#,0} created, {1:#,0} deleted, {2:#,0} ignored, and {3:#,0} moved item states.", created, deleted, ignored, moved);
}, null);
}
public static void BackupState(PlayerMobile m, bool logging)
{
BackupState(m, logging, out var count, out var fails);
}
public static void BackupState(PlayerMobile m, bool logging, out int count, out int fails)
{
var root = VitaNexCore.DataDirectory + "/PlayerBackup/" + m.Account.Username + "/" + m.Serial;
var idxFile = IOUtility.EnsureFile(root + ".idx", true);
var binFile = IOUtility.EnsureFile(root + ".bin", true);
var logFile = logging ? IOUtility.EnsureFile(root + ".log") : null;
var log = logging ? new StringBuilder() : null;
if (log != null)
{
log.AppendLine();
log.AppendLine(new string('*', 10));
log.AppendLine();
log.AppendLine("BACKUP:\tDate[{0}]\tMobile[{1}]", DateTime.UtcNow, m);
log.AppendLine();
}
var idxLength = 0L;
var idxCount = 0;
var idxFails = 0;
idxFile.Serialize(idx =>
{
var v = idx.SetVersion(1);
idx.Write(m.Serial.Value);
if (v > 0)
{
WriteLength(idx, false, idxLength, idxCount);
}
else
{
idx.Write(idxLength);
idx.Write(idxCount);
}
binFile.Serialize(bin =>
{
bin.SetVersion(0);
var items = m.FindItemsByType<Item>(true, i => i != null && !i.Deleted);
foreach (var item in items)
{
#if NEWPARENT
var parent = item.Parent != null ? item.Parent.Serial : Serial.MinusOne;
var logParent = item.Parent ?? (object)Serial.MinusOne;
#else
var parent = item.ParentEntity != null ? item.ParentEntity.Serial : Serial.MinusOne;
var logParent = item.ParentEntity ?? (object)Serial.MinusOne;
#endif
var pos = bin.Position;
Exception x = null;
string status;
try
{
item.Serialize(bin);
status = "SAVED";
}
catch (Exception e)
{
++idxFails;
x = e;
status = "ERROR";
}
var len = bin.Position - pos;
if (log != null)
{
log.AppendLine("WRITE:\tIndex[{0}]\t\tLength[{1}]\tStatus[{2}]\tItem[{3}]\t\t\tParent[{4}]", pos, len, status, item, logParent);
if (x != null)
{
log.AppendLine();
log.AppendLine(new string('*', 10));
log.AppendLine(x.ToString());
log.AppendLine(new string('*', 10));
log.AppendLine();
}
}
WriteIndex(idx, item.GetType(), item.Serial, parent, pos, len);
idxLength += len;
++idxCount;
}
});
WriteLength(idx, true, idxLength, idxCount);
});
count = idxCount;
fails = idxFails;
if (log == null)
{
return;
}
log.AppendLine();
log.AppendLine("RESULT:\tCount[{0}]\tFails[{1}]\tLength[{2}]", count - fails, fails, idxLength);
log.AppendLine();
logFile.AppendText(false, log.ToString());
}
public static void RestoreState(PlayerMobile m, Serial serial, bool moveExisting, bool logging)
{
RestoreState(m, serial, moveExisting, logging, out var created, out var deleted, out var ignored, out var moved);
}
public static void RestoreState(PlayerMobile m, Serial serial, bool moveExisting, bool logging, out int created, out int deleted, out int ignored, out int moved)
{
var pack = m.Backpack;
if (pack == null || pack.Deleted)
{
m.AddItem(pack = new Backpack
{
Movable = false
});
}
var bank = m.BankBox;
if (bank == null || bank.Deleted)
{
m.AddItem(bank = new BankBox(m)
{
Movable = false
});
}
if (serial == Serial.MinusOne)
{
serial = m.Serial;
}
var root = VitaNexCore.DataDirectory + "/PlayerBackup/" + m.Account.Username + "/" + serial;
var idxFile = IOUtility.EnsureFile(root + ".idx");
var binFile = IOUtility.EnsureFile(root + ".bin");
var logFile = logging ? IOUtility.EnsureFile(root + ".log") : null;
var log = logging ? new StringBuilder() : null;
if (log != null)
{
log.AppendLine();
log.AppendLine(new string('*', 10));
log.AppendLine();
log.AppendLine("RESTORE:\tDate[{0}]\tMobile[{1}]", DateTime.UtcNow, m);
log.AppendLine();
}
int idxCreated = 0, idxDeleted = 0, idxIgnored = 0, idxMoved = 0;
idxFile.Deserialize(idx =>
{
var v = idx.GetVersion();
int ser;
if (v > 0)
{
ser = idx.ReadInt();
}
else
{
ser = serial.Value;
}
if (ser != serial.Value)
{
if (log != null)
{
log.AppendLine("INVALID:\tSerial[{0:X8}]", ser);
}
return;
}
long idxLength;
int idxCount;
if (v > 0)
{
ReadLength(idx, false, out idxLength, out idxCount);
}
else
{
idxLength = idx.ReadLong();
idxCount = idx.ReadInt();
}
if (log != null)
{
log.AppendLine("INDEX:\tCount[{0}]\tLength[{1}]", idxCount, idxLength);
}
var items = new Tuple<Item, Serial, long, long, string>[idxCount];
binFile.Deserialize(bin =>
{
bin.GetVersion();
var restored = new Dictionary<Item, Serial>();
Backpack oldPack = null;
BankBox oldBank = null;
for (var i = 0; i < idxCount; i++)
{
ReadIndex(idx, out var type, out var s, out var parent, out var binIndex, out var binLength);
var valid = s.IsValid && s.IsItem;
var exists = World.Items.ContainsKey(s);
Item item = null;
if (exists)
{
item = World.Items[s];
if (item == null || item.Deleted)
{
World.Items.Remove(s);
exists = false;
}
}
object logItem;
string status;
if (!exists && valid && type.IsEqualOrChildOf<Item>())
{
item = type.CreateInstanceSafe<Item>(s);
if (item == null)
{
++idxIgnored;
logItem = s;
status = "NULL";
}
else if (item.Deleted)
{
++idxDeleted;
item = null;
logItem = s;
status = "DELETED";
}
else
{
++idxCreated;
World.AddItem(item);
logItem = item;
status = "CREATED";
}
}
else if (exists && valid && moveExisting && item.RootParent != m)
{
++idxMoved;
logItem = item;
status = "MOVE";
}
else
{
++idxIgnored;
item = null;
logItem = s;
status = exists ? "EXISTS" : "INVALID";
}
if (log != null)
{
log.AppendLine("DATA:\tIndex[{0}]\t\tLength[{1}]\tStatus[{2}]\tItem[{3}]\t\t\tParent[{4}]", binIndex, binLength, status, logItem, parent);
}
items[i] = Tuple.Create(item, parent, binIndex, binLength, status);
}
foreach (var t in items)
{
var item = t.Item1;
var parent = t.Item2;
var index = t.Item3;
var length = t.Item4;
var status = t.Item5;
bin.Seek(index, SeekOrigin.Begin);
if (item == null)
{
bin.Seek(index + length, SeekOrigin.Begin);
continue;
}
Exception x = null;
if (status == "MOVE")
{
bin.Seek(index + length, SeekOrigin.Begin);
status = "IGNORED";
}
else
{
try
{
item.Deserialize(bin);
status = "LOADED";
}
catch (Exception e)
{
--idxCreated;
++idxDeleted;
item.Delete();
x = e;
status = "ERROR";
}
}
if (log != null)
{
log.AppendLine("READ:\tIndex[{0}]\tLength[{1}]\tStatus[{2}]\tItem[{3}]\t\t\tParent[{4}]", index, length, status, item, parent);
if (x != null)
{
log.AppendLine();
log.AppendLine(new string('*', 10));
log.AppendLine(x.ToString());
log.AppendLine(new string('*', 10));
log.AppendLine();
}
}
if (parent == m.Serial)
{
if (item is BankBox)
{
oldBank = (BankBox)item;
}
else if (item is Backpack)
{
oldPack = (Backpack)item;
}
}
restored.Add(item, parent);
}
if (log != null)
{
log.AppendLine();
}
Point3D p;
foreach (var kv in restored.Where(kv => !kv.Key.Deleted).OrderBy(kv => kv.Value))
{
var item = kv.Key;
if ((item == oldPack || item == oldBank) && item != pack && item != bank)
{
if (item.Parent is Item)
{
((Item)item.Parent).RemoveItem(item);
}
else if (item.Parent is Mobile)
{
((Mobile)item.Parent).RemoveItem(item);
}
item.Parent = null;
continue;
}
var parent = World.FindEntity(kv.Value);
if (item != pack && item != bank && (item.Parent == oldPack || item.Parent == oldBank))
{
((Item)item.Parent).RemoveItem(item);
}
if (parent != null)
{
if (item == pack || item == bank)
{
m.AddItem(item);
}
else if (parent == pack || parent == oldPack)
{
p = item.Location;
pack.DropItem(item);
item.Location = p;
}
else if (parent == bank || parent == oldBank)
{
p = item.Location;
bank.DropItem(item);
item.Location = p;
}
else if (parent is Container)
{
if (parent.Deleted)
{
bank.DropItem(item);
}
else
{
p = item.Location;
((Container)parent).DropItem(item);
item.Location = p;
}
}
else if (parent is Mobile)
{
if (!m.EquipItem(item))
{
pack.DropItem(item);
}
}
else
{
bank.DropItem(item);
}
item.SetLastMoved();
item.UpdateTotals();
item.Delta(ItemDelta.Update);
}
else if (Cleanup.IsBuggable(item))
{
--idxCreated;
++idxDeleted;
item.Delete();
}
else
{
item.Internalize();
}
}
if (oldPack != null && oldPack != pack && !restored.ContainsKey(oldPack))
{
oldPack.Delete();
}
if (oldBank != null && oldBank != bank && !restored.ContainsKey(oldBank))
{
oldBank.Delete();
}
if (log != null)
{
log.AppendLine();
}
foreach (var kv in restored)
{
if (kv.Key.Deleted)
{
if (log != null)
{
log.AppendLine("DELETED:\tItem[{0}]\t\tParent[{1}]", kv.Key, kv.Value);
}
}
else if (kv.Key.RootParent == m && kv.Key.Map == Map.Internal && kv.Key.Location == Point3D.Zero)
{
if (log != null)
{
log.AppendLine("INTERNAL:\tItem[{0}]\t\tParent[{1}]", kv.Key, kv.Value);
}
}
else if (kv.Key.RootParent != m)
{
if (log != null)
{
log.AppendLine("IGNORED:\tItem[{0}]\t\tParent[{1}]", kv.Key, kv.Value);
}
}
else
{
if (log != null)
{
log.AppendLine("RESTORED:\tItem[{0}]\t\tParent[{1}]", kv.Key, kv.Key.Parent);
}
}
}
restored.Clear();
m.SendEverything();
});
});
created = idxCreated;
deleted = idxDeleted;
ignored = idxIgnored;
moved = idxMoved;
if (log == null)
{
return;
}
log.AppendLine();
log.AppendLine("RESULT:\tCreated[{0}]\t\tDeleted[{1}]\t\tIgnored[{2}]\t\tMoved[{3}]", created, deleted, ignored, moved);
logFile.AppendText(false, log.ToString());
}
private static void WriteLength(GenericWriter idx, bool reset, long length, int count)
{
var index = idx.Seek(0, SeekOrigin.Current);
idx.Seek(8, SeekOrigin.Begin);
idx.Write(length);
idx.Write(count);
if (reset)
{
idx.Seek(index, SeekOrigin.Begin);
}
}
private static void ReadLength(GenericReader idx, bool reset, out long length, out int count)
{
var index = idx.Seek(0, SeekOrigin.Current);
idx.Seek(8, SeekOrigin.Begin);
length = idx.ReadLong();
count = idx.ReadInt();
if (reset)
{
idx.Seek(index, SeekOrigin.Begin);
}
}
private static void WriteIndex(GenericWriter idx, Type type, Serial serial, Serial parent, long index, long length)
{
idx.WriteType(type);
idx.Write(serial);
idx.Write(parent);
idx.Write(index);
idx.Write(length);
}
private static void ReadIndex(GenericReader idx, out Type type, out Serial serial, out Serial parent, out long index, out long length)
{
type = idx.ReadType();
serial = idx.ReadSerial();
parent = idx.ReadSerial();
index = idx.ReadLong();
length = idx.ReadLong();
}
}
}

View File

@@ -0,0 +1,127 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Commands;
using Server.Commands.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
using VitaNex.Targets;
#endregion
namespace VitaNex.Commands
{
public class SayCommand : BaseCommand
{
public static void Initialize()
{
TargetCommands.Register(new SayCommand());
}
public SayCommand()
{
AccessLevel = AccessLevel.GameMaster;
Supports = CommandSupport.All;
Commands = new[] { "Say" };
ObjectTypes = ObjectTypes.All;
Usage = "Say <speech>";
Description = "Causes an object to say the given speech.";
}
public override void Execute(CommandEventArgs e, object o)
{
HandleTarget(e.Mobile as PlayerMobile, o as IPoint3D, e.ArgString);
}
public static void BeginTarget(PlayerMobile m, string speech)
{
if (m != null && !String.IsNullOrWhiteSpace(speech))
{
GenericSelectTarget<IPoint3D>.Begin(m, (user, target) => HandleTarget(m, target, speech), null);
}
}
public static bool HandleTarget(PlayerMobile m, IPoint3D target, string speech)
{
if (m == null || target == null || String.IsNullOrWhiteSpace(speech))
{
return false;
}
if (target is Item)
{
var item = (Item)target;
item.PublicOverheadMessage(MessageType.Regular, m.SpeechHue, false, speech);
return true;
}
if (target is Mobile)
{
var mobile = (Mobile)target;
mobile.Say(speech);
return true;
}
if (target is StaticTarget)
{
var t = (StaticTarget)target;
Send(m.Map, t.Location, t.ItemID, m.SpeechHue, t.Name, speech);
return true;
}
if (target is LandTarget)
{
var t = (LandTarget)target;
Send(m.Map, t.Location, 0, m.SpeechHue, t.Name, speech);
return true;
}
return false;
}
private static void Send(Map map, Point3D loc, int itemID, int hue, string name, string speech)
{
var fx = EffectItem.Create(loc, map, EffectItem.DefaultDuration);
Packet p = null;
var eable = map.GetClientsInRange(loc, Core.GlobalMaxUpdateRange);
foreach (var state in eable)
{
if (p == null)
{
p = Packet.Acquire(new UnicodeMessage(fx.Serial, itemID, MessageType.Label, hue, 1, "ENU", name, speech));
}
state.Send(p);
}
Packet.Release(p);
eable.Free();
}
}
}

View File

@@ -0,0 +1,397 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using VitaNex.Network;
#endregion
namespace VitaNex.FX
{
public class EffectInfo : IDisposable
{
protected Timer DelayTimer { get; set; }
public virtual event Action Callback;
public bool IsDisposed { get; private set; }
public bool Sending { get; protected set; }
/// <summary>
/// Represents the queue position of this effect.
/// The value is usually incremented based on the number of effect queues to be processed.
/// Currently set by BaseEffect during queue processing.
/// </summary>
public int QueueIndex { get; set; }
/// <summary>
/// Represents the process index of this effect.
/// The value is usually incremented based on the number of effects on a single point.
/// Currently set by BaseEffect during queue processing.
/// </summary>
public int ProcessIndex { get; set; }
public virtual IEntity Source { get; set; }
public virtual Map Map { get; set; }
public virtual int EffectID { get; set; }
public virtual int Hue { get; set; }
public virtual int Speed { get; set; }
public virtual int Duration { get; set; }
public virtual EffectRender Render { get; set; }
public virtual TimeSpan Delay { get; set; }
public virtual int SoundID { get; set; }
public EffectInfo(
IPoint3D source,
Map map,
int effectID,
int hue = 0,
int speed = 10,
int duration = 10,
EffectRender render = EffectRender.Normal,
TimeSpan? delay = null,
Action callback = null)
{
Map = map;
EffectID = effectID;
Hue = hue;
Speed = speed;
Duration = duration;
Render = render;
Delay = delay ?? TimeSpan.Zero;
if (callback != null)
{
Callback += callback;
}
SetSource(source);
}
~EffectInfo()
{
Dispose();
}
public virtual void SetSource(IPoint3D source)
{
if (IsDisposed || Source == source)
{
return;
}
if (source == null)
{
Source = null;
Map = null;
return;
}
if (source is IEntity)
{
Source = (IEntity)source;
Map = Source.Map;
return;
}
Source = new Entity(Serial.Zero, source.Clone3D(), Source != null ? Source.Map : Map);
}
public virtual void Send()
{
if (IsDisposed || Source == null || Sending)
{
return;
}
Sending = true;
if (Delay > TimeSpan.Zero)
{
DelayTimer = Timer.DelayCall(
Delay,
() =>
{
if (DelayTimer != null)
{
DelayTimer.Stop();
DelayTimer = null;
}
if (OnSend())
{
OnAfterSend();
}
});
}
else
{
if (OnSend())
{
OnAfterSend();
}
}
}
protected virtual bool OnSend()
{
if (IsDisposed || Source == null || Map == null)
{
return false;
}
if (SoundID > 0)
{
Effects.PlaySound(Source, Map, SoundID);
}
if (Source.Map == Map && (Source is Mobile || Source is Item))
{
Effects.SendTargetEffect(Source, EffectID, Speed, Duration, Hue, (int)Render);
}
else
{
Effects.SendLocationEffect(Source, Map, EffectID, Duration, Speed, Hue, (int)Render);
}
return true;
}
protected virtual void OnAfterSend()
{
if (IsDisposed)
{
return;
}
if (Callback != null)
{
Callback.Invoke();
}
Sending = false;
}
public virtual void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
if (DelayTimer != null)
{
DelayTimer.Stop();
DelayTimer = null;
}
Source = null;
Map = null;
EffectID = -1;
Hue = 0;
Speed = 0;
Duration = 0;
Render = EffectRender.Normal;
Delay = TimeSpan.Zero;
Callback = null;
Sending = false;
}
}
public class MovingEffectInfo : EffectInfo
{
protected Timer ImpactTimer { get; set; }
public virtual event Action ImpactCallback;
public virtual IEntity Target { get; set; }
public override int Duration
{
get => (int)(GetTravelTime().TotalMilliseconds / 100.0);
set => base.Duration = value;
}
public MovingEffectInfo(
IPoint3D source,
IPoint3D target,
Map map,
int effectID,
int hue = 0,
int speed = 10,
EffectRender render = EffectRender.Normal,
TimeSpan? delay = null,
Action callback = null)
: base(source, map, effectID, hue, speed, 0, render, delay, callback)
{
SetTarget(target);
}
public virtual void SetTarget(IPoint3D target)
{
if (IsDisposed || Target == target)
{
return;
}
if (target == null)
{
Target = null;
return;
}
if (target is IEntity)
{
Target = (IEntity)target;
return;
}
if (Target is Mobile)
{
((Mobile)Target).Location = target.Clone3D();
return;
}
if (Target is Item)
{
((Item)Target).Location = target.Clone3D();
return;
}
Target = new Entity(Serial.Zero, target.Clone3D(), Map);
}
public override void Send()
{
if (!IsDisposed && Source != null && Target != null && Map != null)
{
base.Send();
}
}
protected override bool OnSend()
{
if (IsDisposed || Source == null || Target == null || Map == null)
{
return false;
}
if (SoundID > 0)
{
Effects.PlaySound(Source, Map, SoundID);
}
Effects.SendMovingEffect(Source, Target, EffectID, Speed, Duration, false, false, Hue, (int)Render);
return true;
}
protected override void OnAfterSend()
{
if (IsDisposed)
{
return;
}
var delay = GetTravelTime();
if (delay > TimeSpan.Zero)
{
ImpactTimer = Timer.DelayCall(
delay,
() =>
{
if (ImpactTimer != null)
{
ImpactTimer.Stop();
ImpactTimer = null;
}
if (ImpactCallback != null)
{
ImpactCallback.Invoke();
ImpactCallback = null;
}
base.OnAfterSend();
});
}
else
{
if (ImpactCallback != null)
{
ImpactCallback.Invoke();
ImpactCallback = null;
}
base.OnAfterSend();
}
}
public void MovingImpact(Action callback)
{
if (IsDisposed || Sending || Source == null || Target == null || Map == null)
{
return;
}
if (callback != null)
{
ImpactCallback += callback;
}
Send();
}
public void MovingImpact(Action<MovingEffectInfo> callback)
{
if (IsDisposed || Sending || Source == null || Target == null || Map == null)
{
return;
}
if (callback != null)
{
ImpactCallback += () => callback(this);
}
Send();
}
public virtual TimeSpan GetTravelTime()
{
return Source.GetTravelTime(Target, Speed);
}
public override void Dispose()
{
if (IsDisposed)
{
return;
}
if (ImpactTimer != null)
{
ImpactTimer.Stop();
ImpactTimer = null;
}
base.Dispose();
Target = null;
}
}
}

View File

@@ -0,0 +1,319 @@
#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 Server;
#endregion
namespace VitaNex.FX
{
public class EffectQueue<TEffectInfo> : IDisposable, IEnumerable<TEffectInfo>
where TEffectInfo : EffectInfo
{
protected Timer DeferTimer { get; set; }
public bool IsDisposed { get; private set; }
public bool Processing { get; protected set; }
public int Processed { get; protected set; }
public Queue<TEffectInfo> Queue { get; private set; }
public virtual Action<TEffectInfo> Handler { get; set; }
public virtual Action<TEffectInfo> Mutator { get; set; }
public virtual Action Callback { get; set; }
public virtual bool Deferred { get; set; }
public int Count => Queue.Count;
public EffectQueue(Action callback = null, Action<TEffectInfo> handler = null, bool deferred = true)
{
Queue = new Queue<TEffectInfo>();
Callback = callback;
Handler = handler;
Deferred = deferred;
}
public EffectQueue(int capacity, Action callback = null, Action<TEffectInfo> handler = null, bool deferred = true)
{
Queue = new Queue<TEffectInfo>(capacity);
Callback = callback;
Handler = handler;
Deferred = deferred;
}
public EffectQueue(
IEnumerable<TEffectInfo> queue,
Action callback = null,
Action<TEffectInfo> handler = null,
bool deferred = true)
{
Queue = new Queue<TEffectInfo>(queue);
Callback = callback;
Handler = handler;
Deferred = deferred;
}
~EffectQueue()
{
Dispose();
}
public virtual void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
//GC.SuppressFinalize(this);
if (DeferTimer != null)
{
DeferTimer.Stop();
DeferTimer = null;
}
Processed = 0;
Processing = false;
Queue.Free(true);
Queue = null;
Handler = null;
Mutator = null;
Callback = null;
}
IEnumerator IEnumerable.GetEnumerator()
{
return Queue.GetEnumerator();
}
public virtual IEnumerator<TEffectInfo> GetEnumerator()
{
return Queue.GetEnumerator();
}
public void Add(TEffectInfo info)
{
Enqueue(info);
}
public virtual void Enqueue(TEffectInfo info)
{
if (!IsDisposed)
{
Queue.Enqueue(info);
}
}
public virtual TEffectInfo Dequeue()
{
return Queue.Dequeue();
}
public virtual void Clear()
{
Queue.Clear();
}
public virtual void Process()
{
if (IsDisposed /* || Processing*/)
{
return;
}
if (Queue.Count == 0)
{
OnProcessed();
return;
}
Processing = true;
var info = Dequeue();
if (!OnProcess(info))
{
++Processed;
Process();
return;
}
++Processed;
if (!Deferred)
{
Process();
return;
}
var delay = GetDeferDelay(info);
if (delay > TimeSpan.Zero)
{
DeferTimer = Timer.DelayCall(delay, InternalDeferredCallback);
return;
}
InternalDeferredCallback();
}
private void InternalDeferredCallback()
{
if (DeferTimer != null)
{
DeferTimer.Stop();
DeferTimer = null;
}
Process();
}
protected virtual bool OnProcess(TEffectInfo info)
{
if (IsDisposed || info == null || info.IsDisposed)
{
return false;
}
if (Mutator != null)
{
Mutator(info);
}
if (info.IsDisposed)
{
return false;
}
info.Send();
if (Handler != null)
{
Handler(info);
}
return true;
}
protected virtual void OnProcessed()
{
if (IsDisposed)
{
return;
}
if (Callback != null)
{
Callback();
}
Processed = 0;
Processing = false;
Queue.Free(false);
}
public virtual TimeSpan GetDeferDelay(TEffectInfo info)
{
return !IsDisposed && info != null
? TimeSpan.FromMilliseconds(info.Delay.TotalMilliseconds + ((info.Duration * 100.0) / info.Speed))
: TimeSpan.Zero;
}
}
public class EffectQueue : EffectQueue<EffectInfo>
{
public EffectQueue(Action callback = null, Action<EffectInfo> handler = null, bool deferred = true)
: base(callback, handler, deferred)
{ }
public EffectQueue(int capacity, Action callback = null, Action<EffectInfo> handler = null, bool deferred = true)
: base(capacity, callback, handler, deferred)
{ }
public EffectQueue(
IEnumerable<EffectInfo> queue,
Action callback = null,
Action<EffectInfo> handler = null,
bool deferred = true)
: base(queue, callback, handler, deferred)
{ }
}
public class MovingEffectQueue : EffectQueue<MovingEffectInfo>
{
protected Timer DelayTimer { get; set; }
public MovingEffectQueue(Action callback = null, Action<MovingEffectInfo> handler = null, bool deferred = true)
: base(callback, handler, deferred)
{ }
public MovingEffectQueue(
int capacity,
Action callback = null,
Action<MovingEffectInfo> handler = null,
bool deferred = true)
: base(capacity, callback, handler, deferred)
{ }
public MovingEffectQueue(
IEnumerable<MovingEffectInfo> queue,
Action callback = null,
Action<MovingEffectInfo> handler = null,
bool deferred = true)
: base(queue, callback, handler, deferred)
{ }
protected override bool OnProcess(MovingEffectInfo info)
{
if (IsDisposed || info == null)
{
return false;
}
info.Send();
if (Handler == null)
{
return true;
}
var d = GetDeferDelay(info);
if (d > TimeSpan.Zero)
{
Timer.DelayCall(d, h => h(info), Handler);
}
else
{
Handler(info);
}
return true;
}
public override TimeSpan GetDeferDelay(MovingEffectInfo info)
{
return info != null ? info.Delay + info.GetTravelTime() : TimeSpan.Zero;
}
}
}

View File

@@ -0,0 +1,363 @@
#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.Threading.Tasks;
using Server;
#endregion
namespace VitaNex.FX
{
public static class EffectUtility
{
public static readonly Point3D[][] EmptyPoints = new Point3D[0][];
}
public interface IEffect
{
IPoint3D Start { get; set; }
Map Map { get; set; }
Action Callback { get; set; }
bool Sending { get; }
void Send();
}
public abstract class BaseEffect<TQueue, TEffectInfo> : List<TQueue>, IEffect
where TQueue : EffectQueue<TEffectInfo>
where TEffectInfo : EffectInfo
{
public bool Processing { get; protected set; }
public int CurrentProcess { get; protected set; }
public TQueue CurrentQueue { get; private set; }
public bool Sending { get; protected set; }
public virtual IPoint3D Start { get; set; }
public virtual Map Map { get; set; }
public virtual int Repeat { get; set; }
public virtual TimeSpan Interval { get; set; }
public virtual Action<TEffectInfo> EffectHandler { get; set; }
public virtual Action<TEffectInfo> EffectMutator { get; set; }
public virtual Action Callback { get; set; }
public virtual bool EnableMutate { get; set; }
public virtual bool Reversed { get; set; }
public abstract TEffectInfo[] Effects { get; }
public BaseEffect(
IPoint3D start,
Map map,
int repeat = 0,
TimeSpan? interval = null,
Action<TEffectInfo> effectHandler = null,
Action callback = null)
{
Start = start;
Map = map;
Repeat = Math.Max(0, repeat);
Interval = interval ?? TimeSpan.FromMilliseconds(100);
EffectHandler = effectHandler;
Callback = callback;
}
public abstract TQueue CreateEffectQueue(IEnumerable<TEffectInfo> queue);
public abstract TEffectInfo CloneEffectInfo(TEffectInfo src);
public void Update()
{
this.Free(true);
if (Effects == null || Effects.Length == 0)
{
return;
}
var points = GetTargetPoints(CurrentProcess);
if (points == null || points.Length == 0)
{
return;
}
Capacity = points.Length;
this.SetAll(i => null);
for (var i = 0; i < points.Length; i++)
{
var list = points[i];
if (list == null || list.Length == 0)
{
continue;
}
var fx = new TEffectInfo[list.Length][];
fx.SetAll(fxi => new TEffectInfo[Effects.Length]);
Parallel.For(
0,
list.Length,
index =>
{
var p = list[index];
var pIndex = 0;
for (var ei = 0; ei < Effects.Length; ei++)
{
var e = CloneEffectInfo(Effects[ei]);
if (e == null || e.IsDisposed)
{
continue;
}
e.QueueIndex = index;
e.ProcessIndex = pIndex++;
e.Source = new Entity(Serial.Zero, p, Map);
e.Map = Map;
if (EnableMutate)
{
MutateEffect(e);
}
if (!e.IsDisposed)
{
fx[index][ei] = e;
}
}
});
var q = CreateEffectQueue(fx.Combine());
if (q.Mutator == null && EffectMutator != null)
{
q.Mutator = EffectMutator;
}
if (q.Handler == null && EffectHandler != null)
{
q.Handler = EffectHandler;
}
this[i] = q;
}
RemoveAll(l => l == null);
this.Free(false);
if (Reversed)
{
Reverse();
}
var idx = 0;
foreach (var cur in this)
{
if (++idx >= Count)
{
cur.Callback = InternalCallback;
break;
}
var next = this[idx];
cur.Callback = () => InternalCallback(next);
}
OnUpdated();
}
public virtual Point3D[][] GetTargetPoints(int dist)
{
return Start == null ? EffectUtility.EmptyPoints : new[] { new[] { Start.Clone3D() } };
}
protected virtual void OnUpdated()
{ }
public virtual void MutateEffect(TEffectInfo e)
{ }
public void Send()
{
if (Sending)
{
return;
}
Sending = true;
VitaNexCore.TryCatch(InternalSend, VitaNexCore.ToConsole);
}
public virtual void OnSend()
{ }
private void InternalSend()
{
Update();
if (Count == 0 || this[0] == null)
{
return;
}
Processing = true;
InternalMoveNext(this[0]);
OnSend();
}
private void InternalMoveNext(TQueue next)
{
CurrentQueue = next;
CurrentQueue.Process();
}
private void InternalCallback()
{
Sending = false;
if (Callback != null)
{
Callback();
}
if (++CurrentProcess <= Repeat)
{
if (Interval <= TimeSpan.Zero)
{
Send();
return;
}
Timer.DelayCall(Interval, Send);
return;
}
CurrentProcess = 0;
Processing = false;
this.Free(true);
}
private void InternalCallback(TQueue next)
{
Processing = true;
if (Interval <= TimeSpan.Zero)
{
InternalMoveNext(next);
return;
}
Timer.DelayCall(Interval, InternalMoveNext, next);
}
}
public abstract class BaseRangedEffect<TQueue, TEffectInfo> : BaseEffect<TQueue, TEffectInfo>
where TQueue : EffectQueue<TEffectInfo>
where TEffectInfo : EffectInfo
{
public virtual int Range { get; set; }
public virtual bool AverageZ { get; set; }
public virtual bool LOSCheck { get; set; }
public BaseRangedEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<TEffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, repeat, interval, effectHandler, callback)
{
Range = range;
AverageZ = true;
LOSCheck = false;
}
public override Point3D[][] GetTargetPoints(int count)
{
return Start.ScanRangeGet(Map, Range, ComputePoint, AverageZ);
}
protected virtual bool ComputePoint(ScanRangeResult r)
{
if (!r.Excluded && ExcludePoint(r.Current, r.Distance, Utility.GetDirection(Start, r.Current)))
{
r.Exclude();
}
return false;
}
protected virtual bool ExcludePoint(Point3D p, int range, Direction fromCenter)
{
return LOSCheck && !Map.LineOfSight(p, Start);
}
}
public abstract class BaseBoundsEffect<TQueue, TEffectInfo> : BaseEffect<TQueue, TEffectInfo>
where TQueue : EffectQueue<TEffectInfo>
where TEffectInfo : EffectInfo
{
public virtual Rectangle2D Bounds { get; set; }
public virtual bool AverageZ { get; set; }
public BaseBoundsEffect(
IPoint3D start,
Map map,
Rectangle2D bounds,
int repeat = 0,
TimeSpan? interval = null,
Action<TEffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, repeat, interval, effectHandler, callback)
{
Bounds = bounds;
AverageZ = true;
}
public override Point3D[][] GetTargetPoints(int count)
{
var points = new List<Point3D>[Math.Max(Bounds.Width, Bounds.Height)];
Bounds.ForEach(
p2d =>
{
var distance = (int)Math.Floor(Start.GetDistance(p2d));
points[distance].Add(p2d.ToPoint3D(AverageZ ? p2d.GetAverageZ(Map) : Start.Z));
});
var arr = points.ToMultiArray();
points.Free(true);
return arr;
}
}
}

View File

@@ -0,0 +1,427 @@
#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 Server;
using Server.Commands;
using VitaNex.Network;
#endregion
namespace VitaNex.FX
{
public enum ExplodeFX
{
None = 0,
Random,
Smoke,
Water,
Fire,
Earth,
Air,
Energy,
Poison
}
public static class ExplodeEffects
{
public static void Initialize()
{
CommandSystem.Register(
"ExplodeFXHide",
AccessLevel.GameMaster,
ce =>
{
if (ce == null || ce.Mobile == null)
{
return;
}
var m = ce.Mobile;
if (m.Hidden)
{
m.Hidden = false;
CommandSystem.Entries["ExplodeFX"].Handler(ce);
}
else
{
CommandSystem.Entries["ExplodeFX"].Handler(ce);
m.Hidden = true;
}
});
CommandSystem.Register(
"ExplodeFX",
AccessLevel.GameMaster,
ce =>
{
if (ce == null || ce.Mobile == null)
{
return;
}
var m = ce.Mobile;
if (ce.Arguments.Length < 1 || !Enum.TryParse(ce.Arguments[0], true, out ExplodeFX effect))
{
effect = ExplodeFX.None;
}
if (ce.Arguments.Length < 2 || !Int32.TryParse(ce.Arguments[1], out var range))
{
range = 5;
}
if (ce.Arguments.Length < 3 || !Int32.TryParse(ce.Arguments[2], out var speed))
{
speed = 10;
}
if (ce.Arguments.Length < 4 || !Int32.TryParse(ce.Arguments[3], out var repeat))
{
repeat = 0;
}
if (ce.Arguments.Length < 5 || !Int32.TryParse(ce.Arguments[4], out var reverse))
{
reverse = 0;
}
range = Math.Max(0, Math.Min(100, range));
speed = Math.Max(1, Math.Min(10, speed));
repeat = Math.Max(0, Math.Min(100, repeat));
reverse = Math.Max(0, Math.Min(1, reverse));
var e = effect.CreateInstance(
m.Location,
m.Map,
range,
repeat,
TimeSpan.FromMilliseconds(1000 - ((speed - 1) * 100)));
if (e != null)
{
e.Reversed = (reverse > 0);
e.Send();
}
else
{
m.SendMessage(0x55, "Usage: <effect> <range> <speed> <repeat> <reverse>");
}
});
}
public static BaseExplodeEffect CreateInstance(
this ExplodeFX type,
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
{
switch (type)
{
case ExplodeFX.None:
return null;
case ExplodeFX.Smoke:
return new SmokeExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Water:
return new WaterRippleEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Fire:
return new FireExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Earth:
return new EarthExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Air:
return new AirExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Energy:
return new EnergyExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
case ExplodeFX.Poison:
return new PoisonExplodeEffect(start, map, range, repeat, interval, effectHandler, callback);
default:
{
var rfx = (ExplodeFX[])Enum.GetValues(typeof(ExplodeFX));
do
{
type = rfx.GetRandom();
}
while (type == ExplodeFX.Random || type == ExplodeFX.None);
return CreateInstance(type, start, map, range, repeat, interval, effectHandler, callback);
}
}
}
}
}
namespace VitaNex.FX
{
public abstract class BaseExplodeEffect : BaseRangedEffect<EffectQueue, EffectInfo>
{
public BaseExplodeEffect(
IPoint3D start,
Map map,
int range = 2,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
public override EffectQueue CreateEffectQueue(IEnumerable<EffectInfo> queue)
{
return new EffectQueue(queue, null, EffectHandler, false);
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
return new EffectInfo(null, null, src.EffectID, src.Hue, src.Speed, src.Duration, src.Render, src.Delay);
}
}
public class SmokeExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[] { new EffectInfo(null, null, 14120, 0, 10, 10, EffectRender.SemiTransparent) };
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public SmokeExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
}
public class WaterRippleEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[] { new EffectInfo(null, null, -1, 0, 10, 30) };
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public WaterRippleEffect(
IPoint3D start,
Map map,
int range = 3,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null || e.EffectID != -1)
{
return;
}
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Up:
case Direction.North:
e.EffectID = 8099;
break;
case Direction.Down:
case Direction.South:
e.EffectID = 8114;
break;
case Direction.Right:
case Direction.East:
e.EffectID = 8109;
break;
case Direction.Left:
case Direction.West:
e.EffectID = 8104;
break;
}
}
}
public class FireExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 14089, 0, 10, 20, EffectRender.SemiTransparent),
new EffectInfo(null, null, 13401, 0, 10, 20, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public FireExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
}
public class EarthExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, -1, 0, 10, 20),
new EffectInfo(null, null, 14120, 0, 10, 20, EffectRender.SemiTransparent, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public EarthExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null || e.EffectID != -1)
{
return;
}
e.EffectID = Utility.RandomMinMax(4963, 4973);
e.Source = new Entity(Serial.Zero, e.Source.Location.Clone3D(zOffset: 5), e.Map);
}
}
public class AirExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 14217, 899, 10, 20, EffectRender.Lighten),
new EffectInfo(null, null, 14284, 899, 10, 30, EffectRender.LightenMore, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public AirExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
}
public class EnergyExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 14170, 0, 10, 20, EffectRender.LightenMore),
new EffectInfo(null, null, 14201, 0, 10, 30, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public EnergyExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e != null && e.EffectID == 14201)
{
e.Source = new Entity(Serial.Zero, e.Source.Location.Clone3D(zOffset: -5), e.Map);
}
}
}
public class PoisonExplodeEffect : BaseExplodeEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 14217, 65, 10, 30, EffectRender.Darken),
new EffectInfo(null, null, 14120, 65, 10, 30, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public PoisonExplodeEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e != null)
{
e.Hue = Utility.RandomMinMax(550, 580);
}
}
}
}

View File

@@ -0,0 +1,303 @@
#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 Server;
using Server.Commands;
using VitaNex.Network;
using Geo = Server.Misc.Geometry;
#endregion
namespace VitaNex.FX
{
public enum SpecialFX
{
None = 0,
Random,
FirePentagram
//-FireSpiral
}
public static class SpecialEffects
{
public static void Initialize()
{
CommandSystem.Register(
"SpecialFXHide",
AccessLevel.GameMaster,
ce =>
{
if (ce == null || ce.Mobile == null)
{
return;
}
var m = ce.Mobile;
if (m.Hidden)
{
m.Hidden = false;
CommandSystem.Entries["SpecialFX"].Handler(ce);
}
else
{
CommandSystem.Entries["SpecialFX"].Handler(ce);
m.Hidden = true;
}
});
CommandSystem.Register(
"SpecialFX",
AccessLevel.GameMaster,
ce =>
{
if (ce == null || ce.Mobile == null)
{
return;
}
var m = ce.Mobile;
if (ce.Arguments.Length < 1 || !Enum.TryParse(ce.Arguments[0], true, out SpecialFX effect))
{
effect = SpecialFX.None;
}
if (ce.Arguments.Length < 2 || !Int32.TryParse(ce.Arguments[1], out var range))
{
range = 5;
}
if (ce.Arguments.Length < 3 || !Int32.TryParse(ce.Arguments[2], out var speed))
{
speed = 10;
}
if (ce.Arguments.Length < 4 || !Int32.TryParse(ce.Arguments[3], out var repeat))
{
repeat = 0;
}
if (ce.Arguments.Length < 5 || !Int32.TryParse(ce.Arguments[4], out var reverse))
{
reverse = 0;
}
range = Math.Max(0, Math.Min(100, range));
speed = Math.Max(1, Math.Min(10, speed));
repeat = Math.Max(0, Math.Min(100, repeat));
reverse = Math.Max(0, Math.Min(1, reverse));
var e = effect.CreateInstance(
m.Location,
m.Map,
range,
repeat,
TimeSpan.FromMilliseconds(1000 - ((speed - 1) * 100)));
if (e != null)
{
e.Reversed = (reverse > 0);
e.Send();
}
else
{
m.SendMessage(0x55, "Usage: <effect> <range> <speed> <repeat> <reverse>");
}
});
}
public static BaseSpecialEffect CreateInstance(
this SpecialFX type,
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
{
switch (type)
{
case SpecialFX.None:
return null;
case SpecialFX.FirePentagram:
return new FirePentagramEffect(start, map, range, repeat, interval, effectHandler, callback);
/*case SpecialFX.FireSpiral:
return new FireSpiralEffect(start, map, range, repeat, interval, effectHandler, callback);*/
default:
{
var rfx = (SpecialFX[])Enum.GetValues(typeof(SpecialFX));
do
{
type = rfx.GetRandom();
}
while (type == SpecialFX.Random || type == SpecialFX.None);
return CreateInstance(type, start, map, range, repeat, interval, effectHandler, callback);
}
}
}
}
}
namespace VitaNex.FX
{
public abstract class BaseSpecialEffect : BaseRangedEffect<EffectQueue, EffectInfo>
{
public BaseSpecialEffect(
IPoint3D start,
Map map,
int range = 2,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
public override EffectQueue CreateEffectQueue(IEnumerable<EffectInfo> queue)
{
return new EffectQueue(queue, null, EffectHandler, false);
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
return new EffectInfo(null, null, src.EffectID, src.Hue, src.Speed, src.Duration, src.Render, src.Delay);
}
}
public class FirePentagramEffect : BaseSpecialEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 14089, 0, 10, 20, EffectRender.SemiTransparent),
new EffectInfo(null, null, 13401, 0, 10, 20, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public FirePentagramEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
private const double Section = 72;
private static readonly double[][] _Lines =
{
new[] {0, Section * 2}, new[] {Section * 2, Section * 4}, new[] {Section * 4, Section}, new[] {Section, Section * 3},
new[] {Section * 3, 0}
};
public override Point3D[][] GetTargetPoints(int count)
{
var points = new List<Point3D>[_Lines.Length];
points.SetAll(i => new List<Point3D>());
_Lines.For(
(i, list) =>
{
var start = Start.Clone3D(
(int)Math.Round(Range * Math.Sin(Geo.DegreesToRadians(list[0]))),
(int)Math.Round(Range * Math.Cos(Geo.DegreesToRadians(list[0]))));
var end = Start.Clone3D(
(int)Math.Round(Range * Math.Sin(Geo.DegreesToRadians(list[1]))),
(int)Math.Round(Range * Math.Cos(Geo.DegreesToRadians(list[1]))));
if (AverageZ)
{
start = start.GetWorldTop(Map);
end = end.GetWorldTop(Map);
}
points[i].AddRange(start.GetLine3D(end, Map));
});
return points.ToMultiArray();
}
}
/*public class FireSpiralEffect : BaseSpecialEffect
{
public static EffectInfo[] Info
{
get
{
return new[]
{
new EffectInfo(null, null, 14089, 0, 10, 20, EffectRender.SemiTransparent),
new EffectInfo(null, null, 13401, 0, 10, 20, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
}
}
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects { get { return _Effects; } }
public FireSpiralEffect(
IPoint3D start,
Map map,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{ }
public override Point3D[][] GetTargetPoints(int count)
{
List<List<Point3D>> points = new List<List<Point3D>>(Range + 1);
points.SetAll(i => new List<Point3D>());
for (int r = 0; r <= Range; r++)
{
int bound = r * r;
int area = (int)(Math.PI * bound);
int x, y;
for (int t = 0; t <= area; t++)
{
x = (int)(r * Math.Cos(t)) + Start.X;
y = (int)(r * Math.Sin(t)) + Start.Y;
if (x * x + y * y <= bound)
{
points[r].Add(new Point3D(x, y, AverageZ ? Map.GetAverageZ(x, y) : Start.Z));
}
}
}
return points.ToMultiArray();
}
}*/
}

View File

@@ -0,0 +1,668 @@
#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 System.Threading.Tasks;
using Server;
using Server.Commands;
using Server.Movement;
using VitaNex.Network;
#endregion
namespace VitaNex.FX
{
public enum WaveFX
{
None = 0,
Random,
Water,
Fire,
Earth,
Air,
Energy,
Poison,
Tornado
}
public static class WaveEffects
{
public static void Initialize()
{
CommandSystem.Register(
"WaveFX",
AccessLevel.GameMaster,
ce =>
{
var m = ce.Mobile;
if (ce.Arguments.Length < 1 || !Enum.TryParse(ce.Arguments[0], true, out WaveFX effect))
{
effect = WaveFX.None;
}
if (ce.Arguments.Length < 2 || !Int32.TryParse(ce.Arguments[1], out var range))
{
range = 5;
}
if (ce.Arguments.Length < 3 || !Int32.TryParse(ce.Arguments[2], out var speed))
{
speed = 10;
}
if (ce.Arguments.Length < 4 || !Int32.TryParse(ce.Arguments[3], out var repeat))
{
repeat = 0;
}
if (ce.Arguments.Length < 5 || !Int32.TryParse(ce.Arguments[4], out var reverse))
{
reverse = 0;
}
range = Math.Max(0, Math.Min(100, range));
speed = Math.Max(1, Math.Min(10, speed));
repeat = Math.Max(0, Math.Min(100, repeat));
reverse = Math.Max(0, Math.Min(1, reverse));
var e = effect.CreateInstance(
m.Location,
m.Map,
m.Direction,
range,
repeat,
TimeSpan.FromMilliseconds(1000 - ((speed - 1) * 100)));
if (e != null)
{
e.Reversed = (reverse > 0);
e.Send();
}
else
{
m.SendMessage(0x55, "Usage: <effect> <range> <speed> <repeat> <reverse>");
}
});
}
public static BaseWaveEffect CreateInstance(
this WaveFX type,
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
{
switch (type)
{
case WaveFX.None:
return null;
case WaveFX.Fire:
return new FireWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Water:
return new WaterWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Earth:
return new EarthWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Air:
return new AirWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Energy:
return new EnergyWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Poison:
return new PoisonWaveEffect(start, map, d, range, repeat, interval, effectHandler, callback);
case WaveFX.Tornado:
return new TornadoEffect(start, map, d, range, repeat, interval, effectHandler, callback);
default:
{
var rfx = (WaveFX[])Enum.GetValues(typeof(WaveFX));
do
{
type = rfx.GetRandom();
}
while (type == WaveFX.Random || type == WaveFX.None);
return CreateInstance(type, start, map, d, range, repeat, interval, effectHandler, callback);
}
}
}
}
public abstract class BaseWaveEffect : BaseRangedEffect<EffectQueue, EffectInfo>
{
public virtual Direction Direction { get; set; }
public BaseWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, range, repeat, interval, effectHandler, callback)
{
Direction = d & Direction.ValueMask;
}
public override EffectQueue CreateEffectQueue(IEnumerable<EffectInfo> queue)
{
return new EffectQueue(queue, null, EffectHandler, false);
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
return new EffectInfo(null, null, src.EffectID, src.Hue, src.Speed, src.Duration, src.Render, src.Delay);
}
protected override bool ExcludePoint(Point3D p, int range, Direction fromCenter)
{
switch (Direction & Direction.Mask)
{
case Direction.Up:
return !(fromCenter == Direction.West || fromCenter == Direction.Up || fromCenter == Direction.North);
case Direction.North:
return !(fromCenter == Direction.Up || fromCenter == Direction.North || fromCenter == Direction.Right);
case Direction.Right:
return !(fromCenter == Direction.North || fromCenter == Direction.Right || fromCenter == Direction.East);
case Direction.East:
return !(fromCenter == Direction.Right || fromCenter == Direction.East || fromCenter == Direction.Down);
case Direction.Down:
return !(fromCenter == Direction.East || fromCenter == Direction.Down || fromCenter == Direction.South);
case Direction.South:
return !(fromCenter == Direction.Down || fromCenter == Direction.South || fromCenter == Direction.Left);
case Direction.Left:
return !(fromCenter == Direction.South || fromCenter == Direction.Left || fromCenter == Direction.West);
case Direction.West:
return !(fromCenter == Direction.Left || fromCenter == Direction.West || fromCenter == Direction.Up);
}
return true;
}
}
public class WaterWaveEffect : BaseWaveEffect
{
public static bool DisplayElemental = true;
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 8459, 0, 10, 20),
new EffectInfo(null, null, 14089, 85, 10, 30, EffectRender.SemiTransparent, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, -1, 0, 10, 40, EffectRender.Normal, TimeSpan.FromMilliseconds(400))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public WaterWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
if (src != null && src.EffectID == 8459 && !DisplayElemental)
{
return null;
}
return base.CloneEffectInfo(src);
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null || e.EffectID != -1)
{
return;
}
switch (Direction)
{
case Direction.North:
{
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Up:
case Direction.North:
case Direction.Right:
e.EffectID = 8099;
break;
}
}
break;
case Direction.East:
{
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Down:
case Direction.East:
case Direction.Right:
e.EffectID = 8109;
break;
}
}
break;
case Direction.South:
{
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Down:
case Direction.South:
case Direction.Left:
e.EffectID = 8114;
break;
}
}
break;
case Direction.West:
{
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Up:
case Direction.West:
case Direction.Left:
e.EffectID = 8104;
break;
}
}
break;
default:
{
switch (Utility.GetDirection(Start, e.Source))
{
case Direction.Up:
case Direction.North:
e.EffectID = 8099;
break;
case Direction.Right:
case Direction.East:
e.EffectID = 8109;
break;
case Direction.Down:
case Direction.South:
e.EffectID = 8114;
break;
case Direction.Left:
case Direction.West:
e.EffectID = 8104;
break;
}
}
break;
}
}
}
public class FireWaveEffect : BaseWaveEffect
{
public static bool DisplayElemental = true;
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 8435, 0, 10, 20),
new EffectInfo(null, null, 14089, 0, 10, 20, EffectRender.SemiTransparent, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, 13401, 0, 10, 20, EffectRender.Normal, TimeSpan.FromMilliseconds(200))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public FireWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
if (src != null && src.EffectID == 8435 && !DisplayElemental)
{
return null;
}
return base.CloneEffectInfo(src);
}
}
public class EarthWaveEffect : BaseWaveEffect
{
public static bool DisplayElemental = true;
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 8407, 0, 10, 20),
new EffectInfo(null, null, -1, 0, 10, 20, EffectRender.Normal, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, 14120, 0, 10, 20, EffectRender.SemiTransparent, TimeSpan.FromMilliseconds(400))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public EarthWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
if (src != null && src.EffectID == 8407 && !DisplayElemental)
{
return null;
}
return base.CloneEffectInfo(src);
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null || e.EffectID != -1)
{
return;
}
e.EffectID = Utility.RandomMinMax(4963, 4973);
e.Source = new Entity(Serial.Zero, e.Source.Location.Clone3D(zOffset: 5), e.Map);
}
}
public class AirWaveEffect : BaseWaveEffect
{
public static bool DisplayElemental = true;
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 8429, 0, 10, 20),
new EffectInfo(null, null, 14217, 899, 10, 30, EffectRender.Lighten, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, 14284, 899, 10, 40, EffectRender.LightenMore, TimeSpan.FromMilliseconds(400))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public AirWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override EffectInfo CloneEffectInfo(EffectInfo src)
{
if (src != null && src.EffectID == 8429 && !DisplayElemental)
{
return null;
}
return base.CloneEffectInfo(src);
}
}
public class EnergyWaveEffect : BaseWaveEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, 8448, 0, 10, 20),
new EffectInfo(null, null, 14170, 0, 10, 30, EffectRender.LightenMore, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, 14201, 0, 10, 40, EffectRender.Normal, TimeSpan.FromMilliseconds(400))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public EnergyWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null)
{
return;
}
switch (e.EffectID)
{
case 8448:
e.Source = new Entity(Serial.Zero, e.Source.Location.Clone3D(zOffset: -10), e.Map);
break;
case 14201:
e.Source = new Entity(Serial.Zero, e.Source.Location.Clone3D(zOffset: -5), e.Map);
break;
}
}
}
public class PoisonWaveEffect : BaseWaveEffect
{
public static EffectInfo[] Info => new[]
{
new EffectInfo(null, null, -1, 0, 10, 20),
new EffectInfo(null, null, 14217, 65, 10, 30, EffectRender.Darken, TimeSpan.FromMilliseconds(200)),
new EffectInfo(null, null, 14120, 65, 10, 40, EffectRender.Normal, TimeSpan.FromMilliseconds(400))
};
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public PoisonWaveEffect(
IPoint3D start,
Map map,
Direction d,
int range = 5,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
if (e == null)
{
return;
}
switch (e.EffectID)
{
case -1:
e.EffectID = Utility.RandomMinMax(11666, 11668);
break;
default:
e.Hue = Utility.RandomMinMax(550, 580);
break;
}
}
}
public class TornadoEffect : BaseWaveEffect
{
public static EffectInfo[] Info => new[] { new EffectInfo(null, null, 14284, 899, 10, 10, EffectRender.ShadowOutline) };
private readonly EffectInfo[] _Effects = Info;
public override EffectInfo[] Effects => _Effects;
public int Size { get; set; }
public int Climb { get; set; }
public int Height { get; set; }
public bool CanMove { get; set; }
public TornadoEffect(
IPoint3D start,
Map map,
Direction d,
int range = 10,
int repeat = 0,
TimeSpan? interval = null,
Action<EffectInfo> effectHandler = null,
Action callback = null)
: base(start, map, d, range, repeat, interval, effectHandler, callback)
{
EnableMutate = true;
Size = 5;
Climb = 5;
Height = 80;
CanMove = true;
}
protected override bool ExcludePoint(Point3D p, int range, Direction fromCenter)
{
return false;
}
public override void MutateEffect(EffectInfo e)
{
base.MutateEffect(e);
e.Duration = 7 + (int)(Interval.TotalMilliseconds / 100.0);
switch (Utility.Random(3))
{
case 0:
e.Render = EffectRender.Darken;
break;
case 1:
e.Render = EffectRender.SemiTransparent;
break;
case 2:
e.Render = EffectRender.ShadowOutline;
break;
}
}
public override Point3D[][] GetTargetPoints(int count)
{
var start = Start.Clone3D();
int x = 0, y = 0;
if (CanMove)
{
Movement.Offset(Direction, ref x, ref y);
}
var end = start.Clone3D(Range * x, Range * y);
if (AverageZ)
{
start = start.GetWorldTop(Map);
end = end.GetWorldTop(Map);
}
var path = CanMove ? start.GetLine3D(end, Map, AverageZ) : new[] { start };
var points = new List<Point3D>[path.Length];
points.SetAll(i => new List<Point3D>());
var climb = Climb;
var size = Size;
double height = Height;
Action<int> a = i =>
{
var step = path[i];
for (var z = 0; z < height; z += climb)
{
var mm = (int)Math.Max(0, size * (z / height));
points[i].AddRange(step.ScanRangeGet(Map, mm, mm, ComputePoint, false).Combine().Select(p => p.Clone3D(0, 0, z)));
}
};
if (path.Length < 10)
{
for (var i = 0; i < path.Length; i++)
{
a(i);
}
}
else
{
Parallel.For(0, path.Length, a);
}
return points.FreeToMultiArray(true);
}
}
}

View 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;
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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;
}
}
}
}
}
}

View File

@@ -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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View File

@@ -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);
}
}
}

View 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
}
}

View 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);
}
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View 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
}
}
}

View File

@@ -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();
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}
}
}

View 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;
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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));
}
}
}

View 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);
}
}
}
}

View 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
}
}

View 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;
}
}
}

View File

@@ -0,0 +1,81 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections;
using System.Collections.Generic;
using System.Linq;
#endregion
namespace Server
{
public abstract class BaseFilter : IFilter
{
public abstract string Name { get; }
public abstract bool IsDefault { get; }
public abstract FilterOptions Options { get; }
public BaseFilter()
{ }
public BaseFilter(GenericReader reader)
{
Deserialize(reader);
}
public abstract void Clear();
public virtual bool Filter(object obj)
{
return IsDefault || obj != null;
}
public virtual IEnumerable Shake(IEnumerable objects)
{
return objects.Cast<object>().Where(Filter);
}
public abstract void Serialize(GenericWriter writer);
public abstract void Deserialize(GenericReader reader);
}
public abstract class BaseFilter<T> : BaseFilter, IFilter<T>
{
public BaseFilter()
{ }
public BaseFilter(GenericReader reader)
: base(reader)
{ }
public virtual bool Filter(T obj)
{
return IsDefault || obj != null;
}
public override sealed bool Filter(object obj)
{
return obj is T && Filter((T)obj);
}
public virtual IEnumerable<T> Shake(IEnumerable<T> objects)
{
return objects.Where(Filter);
}
public override sealed IEnumerable Shake(IEnumerable objects)
{
return Shake(objects.OfType<T>());
}
}
}

View File

@@ -0,0 +1,239 @@
#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.Drawing;
using System.Linq;
using Server.Gumps;
using Server.Mobiles;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace Server
{
public class FilterGump : TreeGump
{
private PlayerMobile _Owner;
public PlayerMobile Owner => _Owner == User ? _Owner : (_Owner = User as PlayerMobile);
public bool UseOwnFilter
{
get => Owner != null && Owner.UseOwnFilter;
set
{
if (Owner != null)
{
Owner.UseOwnFilter = value;
}
}
}
public IFilter OwnerFilter => Owner != null ? Owner.GetFilter(MainFilter.GetType()) : null;
public IFilter Filter => UseOwnFilter ? OwnerFilter ?? MainFilter : MainFilter;
public IFilter MainFilter { get; private set; }
public Action<Mobile, IFilter> ApplyHandler { get; set; }
public FilterGump(Mobile user, Gump parent, IFilter filter, Action<Mobile, IFilter> onApply)
: base(user, parent)
{
MainFilter = filter;
ApplyHandler = onApply;
Width = 800;
Height = 500;
}
protected override void Compile()
{
Title = "Filtering: " + Filter.Name;
base.Compile();
}
protected override bool OnBeforeSend()
{
if (MainFilter == null)
{
return false;
}
return base.OnBeforeSend();
}
protected override void OnClosed(bool all)
{
base.OnClosed(all);
if (ApplyHandler != null)
{
ApplyHandler(User, Filter);
}
}
protected override void CompileNodes(Dictionary<TreeGumpNode, Action<Rectangle, int, TreeGumpNode>> list)
{
base.CompileNodes(list);
foreach (var c in Filter.Options.Categories)
{
list[c] = AddFilterOptions;
}
}
protected virtual void AddFilterOptions(Rectangle b, int i, TreeGumpNode n)
{
var cols = (int)(b.Width / (b.Width / 3.0));
var rows = (int)(b.Height / 30.0);
var cellW = (int)(b.Width / (double)cols);
var cellH = (int)(b.Height / (double)rows);
var opts = Filter.Options.Where(o => Insensitive.Equals(o.Category, n.Name)).ToList();
if (opts.Count == 0)
{
return;
}
i = -1;
int c, x, r, y;
for (r = 0; r < rows && opts.InBounds(i + 1); r++)
{
y = b.Y + (r * cellH);
for (c = 0; c < cols && opts.InBounds(i + 1); c++)
{
x = b.X + (c * cellW);
var o = opts[++i];
if (o.IsEmpty)
{
if (c == 0)
{
--c;
continue;
}
break;
}
AddOptionCell(x, y, cellW, cellH, o);
}
}
opts.Free(true);
}
protected virtual void AddOptionCell(int x, int y, int w, int h, FilterOption o)
{
y += (h / 2) - 10;
if (o.IsSelected(Filter))
{
AddImage(x + 5, y, 9904);
AddHtml(x + 35, y + 2, w - 40, 40, FormatText(Color.LawnGreen, o.Name), false, false);
}
else
{
AddButton(x + 5, y, 9903, 9905, btn => Refresh(o.Select(Filter)));
AddHtml(x + 35, y + 2, w - 40, 40, FormatText(Color.White, o.Name), false, false);
}
}
protected override void CompileLayout(SuperGumpLayout layout)
{
base.CompileLayout(layout);
layout.Replace("panel/right/overlay", () => AddImageTiled(265, 68, Width - 290, Height - 50, 2624));
layout.Add(
"cpanel",
() =>
{
var x = 0;
var y = Height + 43;
var w = Width;
AddBackground(x, y, w, 150, 9260);
AddBackground(x + 15, y + 15, 234, 120, 9270);
AddImageTiled(x + 25, y + 25, 214, 100, 1280);
var use = String.Format("Use {0} Filter", UseOwnFilter ? "Main" : "My");
AddButton(
x + 25,
y + 25,
4006,
4007,
b =>
{
UseOwnFilter = !UseOwnFilter;
Refresh(true);
}); // Use [My|Book] Filter
AddHtml(x + 60, y + 27, 164, 40, FormatText(Color.Goldenrod, use), false, false);
AddButton(
x + 25,
y + 50,
4021,
4022,
b =>
{
Filter.Clear();
Refresh(true);
}); //Clear
AddHtml(x + 60, y + 52, 164, 40, FormatText(Color.OrangeRed, "Clear"), false, false);
AddButton(x + 25, y + 75, 4024, 4025, Close); //Apply
AddHtml(x + 60, y + 77, 164, 40, FormatText(Color.Gold, "Apply"), false, false);
x += 239;
AddBackground(x + 15, y + 15, w - 270, 120, 9270);
AddImageTiled(x + 25, y + 25, w - 290, 100, 1280);
AddHtml(x + 30, y + 25, w - 295, 100, GetFilteringText(), false, true);
});
}
protected virtual string FormatOption(FilterOption o)
{
return FormatText(
Color.PaleGoldenrod,
"{0}: {1}",
FormatText(Color.PaleGoldenrod, o.Category),
FormatText(Color.LawnGreen, o.Name));
}
protected virtual string GetFilteringText()
{
return String.Join("\n", Filter.Options.Where(o => o.IsSelected(Filter)).Select(FormatOption));
}
protected string FormatText(Color c, string text, params object[] args)
{
return String.Format(text, args).WrapUOHtmlColor(c, false);
}
}
}

View File

@@ -0,0 +1,30 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace Server
{
public struct FilterGumpEntry
{
public FilterOption Option { get; private set; }
public bool IsCategory { get; private set; }
public int Col { get; private set; }
public int Row { get; private set; }
public FilterGumpEntry(FilterOption option, bool isCategory, int col, int row)
: this()
{
Option = option;
IsCategory = isCategory;
Col = col;
Row = row;
}
}
}

View File

@@ -0,0 +1,67 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
#endregion
namespace Server
{
public struct FilterOption
{
public string Category { get; private set; }
public string Name { get; private set; }
public string Property { get; private set; }
public object Value { get; private set; }
public bool IsDefault { get; private set; }
public bool IsEmpty => String.IsNullOrWhiteSpace(Name) || String.IsNullOrWhiteSpace(Property);
public FilterOption(string category)
: this(category, String.Empty, String.Empty, null, false)
{ }
public FilterOption(string category, string name, string property, object value, bool isDefault)
: this()
{
Category = category;
Name = name;
Property = property;
Value = value;
IsDefault = isDefault;
}
public bool IsSelected(IFilter filter)
{
if (filter != null && !String.IsNullOrWhiteSpace(Property))
{
if (filter.GetPropertyValue(Property, out var value))
{
return Equals(value, Value);
}
}
return false;
}
public bool Select(IFilter filter)
{
if (filter != null && !String.IsNullOrWhiteSpace(Property))
{
return filter.SetPropertyValue(Property, Value);
}
return false;
}
}
}

View File

@@ -0,0 +1,68 @@
#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;
#endregion
namespace Server
{
public class FilterOptions : List<FilterOption>
{
public IEnumerable<FilterOption> this[string category] => this.Where(e => Insensitive.Equals(e.Category, category));
public IEnumerable<FilterOption> this[string category, string name] => this.Where(e => Insensitive.Equals(e.Category, category) && Insensitive.Equals(e.Name, name));
public IEnumerable<string> Categories => this.ToLookup(e => e.Category, e => e).Select(g => g.Key);
public FilterOptions()
{ }
public FilterOptions(int capacity)
: base(capacity)
{ }
public FilterOptions(IEnumerable<FilterOption> entries)
: base(entries)
{ }
public void Add(string category)
{
Add(new FilterOption(category));
}
public void Add(string category, string name, string property, object value, bool isDefault)
{
Add(new FilterOption(category, name, property, value, isDefault));
}
public bool Remove(string category)
{
return RemoveAll(e => Insensitive.Equals(e.Category, category)) > 0;
}
public bool Remove(string category, string name)
{
return RemoveAll(e => Insensitive.Equals(e.Category, category) && Insensitive.Equals(e.Name, name)) > 0;
}
public int Total(string category)
{
return this.Count(e => Insensitive.Equals(e.Category, category));
}
public int Total(string category, string name)
{
return this.Count(e => Insensitive.Equals(e.Category, category) && Insensitive.Equals(e.Name, name));
}
}
}

View 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.IO;
using System.Linq;
using Server.Mobiles;
using VitaNex;
using VitaNex.IO;
#endregion
namespace Server
{
public static class Filters
{
private static readonly Dictionary<PlayerMobile, List<IFilter>> _Filters;
private static readonly FileInfo _Persistence;
private static bool _Configured;
static Filters()
{
_Filters = new Dictionary<PlayerMobile, List<IFilter>>();
_Persistence = IOUtility.EnsureFile(VitaNexCore.SavesDirectory + "/Filters/Profiles.bin");
}
public static void Configure()
{
if (_Configured)
{
return;
}
_Configured = true;
EventSink.WorldLoad += Load;
EventSink.WorldSave += Save;
}
private static void Save(WorldSaveEventArgs e)
{
_Persistence.Serialize(SerializeFilters);
}
private static void Load()
{
_Persistence.Deserialize(DeserializeFilters);
}
public static IEnumerable<IFilter> GetFilters(this PlayerMobile m)
{
return (_Filters.GetValue(m) ?? Enumerable.Empty<IFilter>()).AsEnumerable();
}
public static IFilter GetFilter(this PlayerMobile m, Type type)
{
if (!_Filters.TryGetValue(m, out var filters) || filters == null)
{
filters = _Filters[m] = new List<IFilter>();
}
var filter = filters.Find(f => f.TypeEquals(type));
if (filter == null)
{
filters.Add(filter = type.CreateInstance<IFilter>());
}
return filter;
}
public static TFilter GetFilter<TFilter>(this PlayerMobile m)
where TFilter : IFilter
{
if (!_Filters.TryGetValue(m, out var filters) || filters == null)
{
filters = _Filters[m] = new List<IFilter>();
}
var type = typeof(TFilter);
var filter = (TFilter)filters.Find(f => f.TypeEquals(type));
if (filter == null)
{
filters.Add(filter = typeof(TFilter).CreateInstance<TFilter>());
}
return filter;
}
private static void SerializeFilters(GenericWriter writer)
{
writer.SetVersion(0);
writer.WriteDictionary(
_Filters,
(w, m, f) =>
{
w.Write(m);
w.WriteBlockList(
f,
(w2, o) =>
{
w2.WriteType(o);
o.Serialize(w2);
});
});
}
private static void DeserializeFilters(GenericReader reader)
{
reader.GetVersion();
reader.ReadDictionary(
r =>
{
var m = r.ReadMobile<PlayerMobile>();
var f = r.ReadBlockList(
r2 =>
{
var t = r2.ReadType();
var o = t.CreateInstanceSafe<IFilter>(r2);
if (o != null)
{
return o;
}
o = t.CreateInstanceSafe<IFilter>();
if (o != null)
{
o.Deserialize(r2);
}
return o;
});
return new KeyValuePair<PlayerMobile, List<IFilter>>(m, f);
},
_Filters);
}
}
}

View File

@@ -0,0 +1,41 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections;
using System.Collections.Generic;
#endregion
namespace Server
{
public interface IFilter
{
string Name { get; }
bool IsDefault { get; }
FilterOptions Options { get; }
bool Filter(object obj);
IEnumerable Shake(IEnumerable objects);
void Clear();
void Serialize(GenericWriter writer);
void Deserialize(GenericReader reader);
}
public interface IFilter<T> : IFilter
{
bool Filter(T obj);
IEnumerable<T> Shake(IEnumerable<T> objects);
}
}

View File

@@ -0,0 +1,618 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server.Items;
#endregion
namespace Server
{
public interface ICoords : IPoint2D
{
int Long { get; }
int Lat { get; }
bool East { get; }
bool South { get; }
}
[PropertyObject]
public sealed class Coords : ICoords, IComparable, IComparable<Coords>, IEquatable<Coords>
{
public static Coords Zero => new Coords(Map.Internal, 0, 0);
private bool _East;
private int _Lat;
private int _LatMins;
private int _Long;
private int _LongMins;
private Map _Map;
private Point2D _Point;
private bool _South;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public Map Map
{
get => _Map ?? (_Map = Map.Internal);
set
{
_Map = value ?? Map.Internal;
Compute();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int LongMins => _LongMins;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int LatMins => _LatMins;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int X
{
get => _Point.X;
set
{
_Point.X = value;
Compute();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Y
{
get => _Point.Y;
set
{
_Point.Y = value;
Compute();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Long => _Long;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Lat => _Lat;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool East => _East;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool South => _South;
public Coords(Map map, IPoint2D p)
: this(map, p.X, p.Y)
{ }
public Coords(Map map, int x, int y)
{
_Map = map;
_Point = new Point2D(x, y);
Compute();
}
public Coords(GenericReader reader)
{
Deserialize(reader);
}
public void Compute()
{
if (!Sextant.Format(
_Point.ToPoint3D(),
_Map,
ref _Long,
ref _Lat,
ref _LongMins,
ref _LatMins,
ref _East,
ref _South))
{
Clear();
}
}
public void Clear()
{
_Map = Map.Internal;
_Point = Point2D.Zero;
_Long = _LongMins = _Lat = _LatMins = 0;
_East = _South = false;
}
public Point2D ToPoint2D()
{
return new Point2D(_Point);
}
public Point3D ToPoint3D()
{
return new Point3D(_Point, (_Map != null && _Map != Map.Internal) ? _Map.GetAverageZ(_Point.X, _Point.Y) : 0);
}
public override string ToString()
{
return String.Format(
"{0}° {1}'{2}, {3}° {4}'{5}",
_Lat,
_LatMins,
_South ? "S" : "N",
_Long,
_LongMins,
_East ? "E" : "W");
}
public int CompareTo(object other)
{
return other == null || !(other is Coords) ? 0 : CompareTo((Coords)other);
}
public int CompareTo(Coords other)
{
return _Point.CompareTo(other._Point);
}
public override int GetHashCode()
{
unchecked
{
return (_Point.GetHashCode() * 397) ^ _Map.MapIndex;
}
}
public bool Equals(Coords other)
{
return _Point == other._Point && _Map == other._Map;
}
public bool Equals(ICoords other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return _Long == other.Long && _Lat == other.Lat && _South == other.South && _East == other.East;
}
public bool Equals(Map other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return _Map == other;
}
public bool Equals(IPoint3D other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return _Point.X == other.X && _Point.Y == other.Y;
}
public bool Equals(IPoint2D other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return _Point.X == other.X && _Point.Y == other.Y;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (obj is Coords)
{
return Equals((Coords)obj);
}
if (obj is Map)
{
return Equals((Map)obj);
}
if (obj is ICoords)
{
return Equals((ICoords)obj);
}
if (obj is IPoint3D)
{
return Equals((IPoint3D)obj);
}
if (obj is IPoint2D)
{
return Equals((IPoint2D)obj);
}
return false;
}
public void Serialize(GenericWriter writer)
{
writer.Write(_Map);
writer.Write(_Point);
}
public void Deserialize(GenericReader reader)
{
_Map = reader.ReadMap();
_Point = reader.ReadPoint2D();
Compute();
}
#region Conversion Operators
public static implicit operator Coords(Mobile m)
{
return m == null ? Zero : new Coords(m.Map, m.Location);
}
public static implicit operator Coords(Item i)
{
return i == null ? Zero : new Coords(i.Map, i.Location);
}
public static implicit operator Coords(Entity e)
{
return e == null ? Zero : new Coords(e.Map, e.Location);
}
public static implicit operator Point2D(Coords c)
{
return ReferenceEquals(c, null) ? Point2D.Zero : new Point2D(c.X, c.Y);
}
public static implicit operator Point3D(Coords c)
{
return ReferenceEquals(c, null) ? Point3D.Zero : new Point3D(c.X, c.Y, 0);
}
public static implicit operator Map(Coords c)
{
return ReferenceEquals(c, null) ? Map.Internal : c.Map;
}
#endregion Conversion Operators
#region Point2D Operators
public static bool operator ==(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l.Equals(r);
}
public static bool operator !=(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return true;
}
return !l.Equals(r);
}
public static bool operator >(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point > r;
}
public static bool operator <(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point < r;
}
public static bool operator >=(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point >= r;
}
public static bool operator <=(Coords l, Point2D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point <= r;
}
public static bool operator ==(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r.Equals(l);
}
public static bool operator !=(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return !r.Equals(l);
}
public static bool operator >(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l > r._Point;
}
public static bool operator <(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l < r._Point;
}
public static bool operator >=(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l >= r._Point;
}
public static bool operator <=(Point2D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l <= r._Point;
}
#endregion Point2D Operators
#region Point3D Operators
public static bool operator ==(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l.Equals(r);
}
public static bool operator !=(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return true;
}
return !l.Equals(r);
}
public static bool operator >(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point > r;
}
public static bool operator <(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point < r;
}
public static bool operator >=(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point >= r;
}
public static bool operator <=(Coords l, Point3D r)
{
if (ReferenceEquals(l, null))
{
return false;
}
return l._Point <= r;
}
public static bool operator ==(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r.Equals(l);
}
public static bool operator !=(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return !r.Equals(l);
}
public static bool operator >(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r._Point <= l;
}
public static bool operator <(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r._Point >= l;
}
public static bool operator >=(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r._Point < l;
}
public static bool operator <=(Point3D l, Coords r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return r._Point > l;
}
#endregion Point3D Operators
#region Coords Operators
public static bool operator ==(Coords l, Coords r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
return l.Equals(r);
}
public static bool operator !=(Coords l, Coords r)
{
if (ReferenceEquals(l, null))
{
return !ReferenceEquals(r, null);
}
return l.Equals(r);
}
public static bool operator >(Coords l, Coords r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X > r.X && l.Y > r.Y;
}
public static bool operator <(Coords l, Coords r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X < r.X && l.Y < r.Y;
}
public static bool operator >=(Coords l, Coords r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X >= r.X && l.Y >= r.Y;
}
public static bool operator <=(Coords l, Coords r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X <= r.X && l.Y <= r.Y;
}
#endregion Coords Operators
}
}

View File

@@ -0,0 +1,354 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
#endregion
namespace Server
{
public interface IMapPoint : IPoint3D
{
bool Internal { get; }
Map Map { get; set; }
Point3D Location { get; set; }
}
[PropertyObject]
public sealed class MapPoint
: IMapPoint, IEquatable<MapPoint>, IEquatable<IMapPoint>, IEquatable<Map>, IEquatable<IPoint3D>, IEquatable<IPoint2D>
{
public static MapPoint Empty => new MapPoint(Map.Internal, Point3D.Zero);
private Map _Map = Map.Internal;
private Point3D _Location = Point3D.Zero;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public Map Map { get => _Map ?? (_Map = Map.Internal); set => _Map = value ?? Map.Internal; }
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public Point3D Location { get => _Location; set => _Location = value; }
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int X { get => _Location.X; set => _Location = new Point3D(Math.Max(0, value), Y, Z); }
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Y { get => _Location.Y; set => _Location = new Point3D(X, Math.Max(0, value), Z); }
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Z
{
get => _Location.Z;
set => _Location = new Point3D(X, Y, Math.Max(-128, Math.Min(128, value)));
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Internal => _Map == null || _Map == Map.Internal;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Zero => _Location == Point3D.Zero;
public bool InternalOrZero => Internal || Zero;
public MapPoint(Map map, IPoint2D p, int z)
: this(map, p.X, p.Y, z)
{ }
public MapPoint(Map map, IPoint3D p)
: this(map, p.X, p.Y, p.Z)
{ }
public MapPoint(Map map, int x, int y, int z)
{
_Map = map ?? Map.Internal;
_Location = new Point3D(x, y, z);
}
public MapPoint(GenericReader reader)
{
Deserialize(reader);
}
public bool MoveToWorld(Mobile m)
{
if (InternalOrZero)
{
return false;
}
m.MoveToWorld(this, Map);
return true;
}
public bool MoveToWorld(Item i)
{
if (InternalOrZero)
{
return false;
}
i.MoveToWorld(this, Map);
return true;
}
public override string ToString()
{
return String.Format("{0} ({1}, {2}, {3})", Map.Name, X, Y, Z);
}
public override int GetHashCode()
{
unchecked
{
var hash = Map == null ? -1 : Map.MapID ^ Map.MapIndex;
hash = (hash * 397) ^ X;
hash = (hash * 397) ^ Y;
hash = (hash * 397) ^ Z;
return hash;
}
}
public bool Equals(MapPoint other)
{
return !ReferenceEquals(other, null) && Map == other.Map && Location == other.Location;
}
public bool Equals(IMapPoint other)
{
return !ReferenceEquals(other, null) && Map == other.Map && Location == other.Location;
}
public bool Equals(Map other)
{
return !ReferenceEquals(other, null) && Map == other;
}
public bool Equals(IPoint3D other)
{
return !ReferenceEquals(other, null) && X == other.X && Y == other.Y && Z == other.Z;
}
public bool Equals(IPoint2D other)
{
return !ReferenceEquals(other, null) && X == other.X && Y == other.Y;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, null))
{
return false;
}
if (obj is MapPoint)
{
return Equals((MapPoint)obj);
}
if (obj is Map)
{
return Equals((Map)obj);
}
if (obj is IMapPoint)
{
return Equals((IMapPoint)obj);
}
if (obj is IPoint3D)
{
return Equals((IPoint3D)obj);
}
if (obj is IPoint2D)
{
return Equals((IPoint2D)obj);
}
return false;
}
public void Serialize(GenericWriter writer)
{
writer.Write(Location);
writer.Write(Map);
}
public void Deserialize(GenericReader reader)
{
Location = reader.ReadPoint3D();
Map = reader.ReadMap();
}
#region Conversion Operators
public static implicit operator MapPoint(Mobile m)
{
return m == null ? Empty : new MapPoint(m.Map, m.Location);
}
public static implicit operator MapPoint(Item i)
{
return i == null ? Empty : new MapPoint(i.Map, i.Location);
}
public static implicit operator MapPoint(Entity e)
{
return e == null ? Empty : new MapPoint(e.Map, e.Location);
}
public static implicit operator Point3D(MapPoint m)
{
return ReferenceEquals(m, null) ? Point3D.Zero : m.Location;
}
public static implicit operator Map(MapPoint m)
{
return ReferenceEquals(m, null) ? Map.Internal : m.Map;
}
#endregion Conversion Operators
#region MapPoint Operators
public static bool operator ==(MapPoint l, MapPoint r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(MapPoint l, MapPoint r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
public static bool operator ==(MapPoint l, IMapPoint r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(MapPoint l, IMapPoint r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
public static bool operator ==(IMapPoint l, MapPoint r)
{
return ReferenceEquals(r, null) ? ReferenceEquals(l, null) : r.Equals(l);
}
public static bool operator !=(IMapPoint l, MapPoint r)
{
return ReferenceEquals(r, null) ? !ReferenceEquals(l, null) : !r.Equals(l);
}
/*
public static bool operator >(MapPoint l, MapPoint r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X > r.X && l.Y > r.Y && l.Z > r.Z;
}
public static bool operator >(MapPoint l, IMapPoint r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X > r.X && l.Y > r.Y && l.Z > r.Z;
}
public static bool operator <(MapPoint l, MapPoint r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X < r.X && l.Y < r.Y && l.Z < r.Z;
}
public static bool operator <(MapPoint l, IMapPoint r)
{
if (ReferenceEquals(l, null) || ReferenceEquals(r, null))
{
return false;
}
return l.X < r.X && l.Y < r.Y && l.Z < r.Z;
}
public static bool operator >=(MapPoint l, MapPoint r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X >= r.X && l.Y >= r.Y && l.Z >= r.Z;
}
public static bool operator >=(MapPoint l, IMapPoint r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X >= r.X && l.Y >= r.Y && l.Z >= r.Z;
}
public static bool operator <=(MapPoint l, MapPoint r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X <= r.X && l.Y <= r.Y && l.Z <= r.Z;
}
public static bool operator <=(MapPoint l, IMapPoint r)
{
if (ReferenceEquals(l, null))
{
return ReferenceEquals(r, null);
}
if (ReferenceEquals(r, null))
{
return false;
}
return l.X <= r.X && l.Y <= r.Y && l.Z <= r.Z;
}
*/
#endregion MapPoint Operators
}
}

View File

@@ -0,0 +1,341 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
#endregion
namespace Server
{
[Parsable, PropertyObject]
public struct Angle
: IEquatable<Angle>, IEquatable<int>, IEquatable<double>, IComparable<Angle>, IComparable<int>, IComparable<double>
{
public const double D2R = Math.PI / 180.0;
public const double R2D = 180.0 / Math.PI;
public static readonly Angle Zero = 0;
public static readonly Angle MinValue = -360;
public static readonly Angle MaxValue = 360;
public static Angle FromDirection(Direction dir)
{
int x = 0, y = 0;
Movement.Movement.Offset(dir & Direction.Mask, ref x, ref y);
return FromPoints(0, 0, x, y);
}
public static Angle FromPoints(IPoint2D p1, IPoint2D p2)
{
return FromPoints(p1.X, p1.Y, p2.X, p2.Y);
}
public static Angle FromPoints(IPoint2D p1, IPoint2D p2, IPoint2D p3)
{
return FromPoints(p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y);
}
public static Angle FromPoints(int x1, int y1, int x2, int y2)
{
return Math.Atan2(y2, x2) - Math.Atan2(y1, x1);
}
public static Angle FromPoints(int x1, int y1, int x2, int y2, int x3, int y3)
{
return FromPoints(x2, y2, x1, y1) - FromPoints(x2, y2, x3, y3);
}
public static Angle FromDegrees(int degrees)
{
return degrees;
}
public static Angle FromRadians(double radians)
{
return radians;
}
public static Angle GetPitch(IPoint3D p1, IPoint3D p2)
{
int x = p2.X - p1.X, y = p2.Y - p1.Y, z = p2.Z - p1.Z;
return -Math.Atan2(z, Math.Sqrt((x * x) + (y * y)));
}
public static Angle GetYaw(IPoint2D p, IPoint2D left, IPoint2D right)
{
return Math.Abs(FromPoints(p, left) - FromPoints(p, right));
}
public static bool InLOS(IPoint2D p1, IPoint2D target, Direction d, Angle yaw, double distance)
{
return GetLOS(p1, d, yaw, distance).Contains(target);
}
public static Triangle2D GetLOS(IPoint2D p, Direction d, Angle yaw, double distance)
{
var a = FromDirection(d);
var p2 = GetPoint2D(p.X, p.Y, a - yaw, distance);
var p3 = GetPoint2D(p.X, p.Y, a + yaw, distance);
return new Triangle2D(p, p2, p3);
}
public static IEnumerable<Point2D> PlotLOS(IPoint2D p, Direction d, Angle yaw, double distance)
{
var a = FromDirection(d);
var p2 = GetPoint2D(p.X, p.Y, a - yaw, distance);
var p3 = GetPoint2D(p.X, p.Y, a + yaw, distance);
return Triangle2D.Plot(p, p2, p3);
}
public static void Transform(ref Point3D p, Angle angle, double offset)
{
int x = p.X, y = p.Y, z = p.Z;
Transform(ref x, ref y, angle, offset);
p = new Point3D(x, y, z);
}
public static void Transform(ref Point2D p, Angle angle, double offset)
{
int x = p.X, y = p.Y;
Transform(ref x, ref y, angle, offset);
p = new Point2D(x, y);
}
public static void Transform(ref int x, ref int y, Angle angle, double offset)
{
x += (int)(offset * Math.Cos(angle._Radians));
y += (int)(offset * Math.Sin(angle._Radians));
}
public static Point2D GetPoint2D(int x, int y, Angle angle, double distance)
{
return new Point2D(x + (int)(distance * Math.Cos(angle._Radians)), y + (int)(distance * Math.Sin(angle._Radians)));
}
public static Point3D GetPoint3D(int x, int y, int z, Angle angle, double distance)
{
return new Point3D(
x + (int)(distance * Math.Cos(angle._Radians)),
y + (int)(distance * Math.Sin(angle._Radians)),
z);
}
public static bool TryParse(string value, out Angle angle)
{
try
{
angle = Parse(value);
return true;
}
catch
{
angle = Zero;
return false;
}
}
public static Angle Parse(string value)
{
value = value ?? String.Empty;
value = value.Trim();
int d;
double r;
if (!value.Contains(","))
{
if (Int32.TryParse(value, out d))
{
return d;
}
if (Double.TryParse(value, out r))
{
return r;
}
}
else
{
value = value.Trim('(', ')', ' ');
var i = value.IndexOf(',');
if (Int32.TryParse(value.Substring(0, i).Trim(), out d))
{
return d;
}
if (Double.TryParse(value.Substring(i + 1).Trim(), out r))
{
return r;
}
}
throw new FormatException(
"The specified angle must be represented by Int32 (Degrees) or Double (Radians) using the format " + //
"'###', '#.##', or '(###, #.##)'");
}
private readonly int _Degrees;
private readonly double _Radians;
[CommandProperty(AccessLevel.Counselor)]
public int Degrees => _Degrees;
[CommandProperty(AccessLevel.Counselor)]
public double Radians => _Radians;
public Angle(Angle angle)
{
_Degrees = angle._Degrees;
_Radians = angle._Radians;
}
public Angle(int degrees)
{
_Degrees = degrees;
_Radians = _Degrees * D2R;
}
public Angle(double radians)
: this((int)(radians * R2D))
{ }
public Angle(int x1, int y1, int x2, int y2)
: this(Math.Atan2(y2, x2) - Math.Atan2(y1, x1))
{ }
public Angle(IPoint2D p1, IPoint2D p2)
: this(p1.X, p1.Y, p2.X, p2.Y)
{ }
public void Transform(ref Point3D p, double offset)
{
Transform(ref p, this, offset);
}
public void Transform(ref Point2D p, double offset)
{
Transform(ref p, this, offset);
}
public void Transform(ref int x, ref int y, double offset)
{
Transform(ref x, ref y, this, offset);
}
public Point2D GetPoint2D(int x, int y, double distance)
{
return GetPoint2D(x, y, this, distance);
}
public Point3D GetPoint3D(int x, int y, int z, double distance)
{
return GetPoint3D(x, y, z, this, distance);
}
public override int GetHashCode()
{
return _Degrees;
}
public override bool Equals(object obj)
{
return (obj is Angle && Equals((Angle)obj)) || (obj is int && Equals((int)obj)) ||
(obj is double && Equals((double)obj));
}
public bool Equals(Angle angle)
{
return _Degrees == angle._Degrees;
}
public bool Equals(int degrees)
{
return _Degrees == degrees;
}
public bool Equals(double radians)
{
return _Radians == radians;
}
public int CompareTo(Angle angle)
{
return _Degrees.CompareTo(angle._Degrees);
}
public int CompareTo(int degrees)
{
return _Degrees.CompareTo(degrees);
}
public int CompareTo(double radians)
{
return _Radians.CompareTo(radians);
}
public override string ToString()
{
return String.Format("({0}, {1})", _Degrees, _Radians);
}
public Angle Normalize()
{
return _Degrees % 360;
}
#region Operators
public static Angle operator --(Angle a)
{
return a._Degrees - 1;
}
public static Angle operator ++(Angle a)
{
return a._Degrees + 1;
}
public static implicit operator int(Angle a)
{
return a._Degrees;
}
public static implicit operator double(Angle a)
{
return a._Radians;
}
public static implicit operator Angle(int d)
{
return new Angle(d);
}
public static implicit operator Angle(double r)
{
return new Angle(r);
}
#endregion Operators
}
}

View File

@@ -0,0 +1,338 @@
#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 Server.Targeting;
#endregion
namespace Server
{
public interface IBlock3D : IPoint3D, IEquatable<IBlock3D>, IEnumerable<IPoint3D>
{
int H { get; set; }
bool Intersects(Item e);
bool Intersects(Mobile e);
bool Intersects(IEntity e);
bool Intersects(IPoint3D p);
bool Intersects(IBlock3D b);
bool Intersects(int z);
bool Intersects(int x, int y, int z);
bool Intersects(int x, int y, int z, int h);
IEnumerable<IPoint3D> Scan();
}
public struct Block3D : IBlock3D
{
public static readonly Block3D Empty = new Block3D(0, 0, 0, 0);
public static bool Intersects(IPoint3D a, IPoint3D b)
{
return Create(a).Intersects(Create(b));
}
public static Block3D Create(IPoint3D o)
{
if (o is Mobile)
{
return new Block3D(o, 18);
}
if (o is Item)
{
return new Block3D(o, Math.Max(1, ((Item)o).ItemData.CalcHeight));
}
if (o is LandTarget)
{
return new Block3D(o, 1);
}
if (o is StaticTarget)
{
return new Block3D(o, TileData.ItemTable[((StaticTarget)o).ItemID].CalcHeight);
}
return new Block3D(o, 5);
}
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public int H { get; set; }
public Block3D(IBlock3D b)
: this(b.X, b.Y, b.Z, b.H)
{ }
public Block3D(IPoint3D p, int h)
: this(p.X, p.Y, p.Z, h)
{ }
public Block3D(int x, int y, int z, int h)
: this()
{
X = x;
Y = y;
Z = z;
H = h;
}
public bool Intersects(IEntity e)
{
if (e is Item)
{
return Intersects((Item)e);
}
if (e is Mobile)
{
return Intersects((Mobile)e);
}
return Intersects(e.X, e.Y, e.Z);
}
public bool Intersects(IPoint3D p)
{
if (p is Item)
{
return Intersects((Item)p);
}
if (p is Mobile)
{
return Intersects((Mobile)p);
}
if (p is LandTarget)
{
return Intersects((LandTarget)p);
}
if (p is StaticTarget)
{
return Intersects((StaticTarget)p);
}
return Intersects(p.X, p.Y, p.Z);
}
public bool Intersects(Point3D p, int h)
{
return Intersects(p.X, p.Y, p.Z, h);
}
public bool Intersects(LandTarget o)
{
return Intersects(o.X, o.Y, o.Z, 1);
}
public bool Intersects(StaticTarget o)
{
return Intersects(o.X, o.Y, o.Z, Math.Max(1, TileData.ItemTable[o.ItemID].CalcHeight));
}
public bool Intersects(Mobile m)
{
return Intersects(m.X, m.Y, m.Z, 18);
}
public bool Intersects(Item i)
{
return Intersects(i.X, i.Y, i.Z, Math.Max(1, i.ItemData.CalcHeight));
}
public bool Intersects(Block3D b)
{
return Intersects(b.X, b.Y, b.Z, b.H);
}
public bool Intersects(IBlock3D b)
{
return Intersects(b.X, b.Y, b.Z, b.H);
}
public bool Intersects(int z)
{
return Intersects(X, Y, z);
}
public bool Intersects(int z, int h)
{
return Intersects(X, Y, z, h);
}
public bool Intersects(int x, int y, int z)
{
return Intersects(x, y, z, 0);
}
public bool Intersects(Rectangle2D b, int z, int h)
{
return X >= b.Start.X && X < b.End.X && Y >= b.Start.Y && Y < b.End.Y && Intersects(X, Y, z, h);
}
public bool Intersects(Rectangle3D b)
{
var z = Math.Min(b.Start.Z, b.End.Z);
var h = Math.Abs(b.Depth);
return X >= b.Start.X && X < b.End.X && Y >= b.Start.Y && Y < b.End.Y && Intersects(X, Y, z, h);
}
public bool Intersects(int x, int y, int z, int h)
{
if (x != X || y != Y)
{
return false;
}
if (z == Z || z + h == Z + H)
{
return true;
}
if (z >= Z && z <= Z + H)
{
return true;
}
if (Z >= z && Z <= z + h)
{
return true;
}
if (z <= Z && z + h >= Z)
{
return true;
}
if (Z <= z && Z + H >= z)
{
return true;
}
return false;
}
public Block3D Offset(int x = 0, int y = 0, int z = 0, int h = 0)
{
X += x;
Y += y;
Z += z;
H += h;
return this;
}
public Block3D Delta(int x = 0, int y = 0, int z = 0, int h = 0)
{
X -= x;
Y -= y;
Z -= z;
H -= h;
return this;
}
public Block3D Normalize(int x = 0, int y = 0, int z = 0, int h = 0)
{
X = x - X;
Y = y - Y;
Z = z - Z;
H = h - H;
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IPoint3D> GetEnumerator()
{
return Scan().GetEnumerator();
}
public IEnumerable<IPoint3D> Scan()
{
for (var z = Z; z <= Z + H; z++)
{
yield return this.ToPoint3D(z);
}
}
public override string ToString()
{
return String.Format("{0}, {1}, {2}, {3}", X, Y, Z, H);
}
public override int GetHashCode()
{
unchecked
{
var hash = 0;
hash = (hash * 397) ^ X;
hash = (hash * 397) ^ Y;
hash = (hash * 397) ^ Z;
hash = (hash * 397) ^ H;
return hash;
}
}
public override bool Equals(object obj)
{
return obj is IBlock3D && Equals((IBlock3D)obj);
}
public bool Equals(IBlock3D b)
{
return !ReferenceEquals(b, null) && X == b.X && Y == b.Y && Z == b.Z && H == b.H;
}
public static bool operator ==(Block3D a, IBlock3D b)
{
return a.Equals(b);
}
public static bool operator !=(Block3D a, IBlock3D b)
{
return !a.Equals(b);
}
public static bool operator ==(IBlock3D a, Block3D b)
{
return b.Equals(a);
}
public static bool operator !=(IBlock3D a, Block3D b)
{
return !b.Equals(a);
}
public static implicit operator Block3D(Point3D p)
{
return new Block3D(p, 0);
}
public static implicit operator Point3D(Block3D p)
{
return new Point3D(p.X, p.Y, p.Z);
}
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace Server
{
public enum Direction4
{
North = Direction.North,
East = Direction.East,
South = Direction.South,
West = Direction.West
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace Server
{
public enum Direction45
{
Up = Direction.Up,
Right = Direction.Right,
Down = Direction.Down,
Left = Direction.Left
}
}

View File

@@ -0,0 +1,339 @@
#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
{
[NoSort, Parsable, PropertyObject]
public struct Line2D : IPoint2D
{
public static readonly Line2D Empty = new Line2D(0, 0, 0, 0);
private static void Swap<T>(ref T a, ref T b)
{
var t = a;
a = b;
b = t;
}
private static IEnumerable<Point2D> Plot(int x1, int y1, int x2, int y2)
{
var delta = Math.Abs(y2 - y1) > Math.Abs(x2 - x1);
if (delta)
{
Swap(ref x1, ref y1);
Swap(ref x2, ref y2);
}
if (x1 > x2)
{
Swap(ref x1, ref x2);
Swap(ref y1, ref y2);
}
var dX = x2 - x1;
var dY = Math.Abs(y2 - y1);
var eX = dX / 2;
var sY = y1 < y2 ? 1 : -1;
var y = y1;
for (var x = x1; x <= x2; x++)
{
if (delta)
{
yield return new Point2D(y, x);
}
else
{
yield return new Point2D(x, y);
}
eX -= dY;
if (eX < 0)
{
y += sY;
eX += dX;
}
}
}
public static IEnumerable<Point2D> Plot(IPoint2D start, IPoint2D end)
{
return Plot(start.X, start.Y, end.X, end.Y).OrderBy(p => GetLength(start, p));
}
public static double GetLength(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 GetLength(Line2D line)
{
return GetLength(line.Start, line.End);
}
public static IEnumerable<Point2D> Intersect(Line2D[] lines1, Line2D[] lines2)
{
return lines1.Ensure().SelectMany(l => Intersect(l, lines2));
}
public static IEnumerable<Point2D> Intersect(Line2D line, Line2D[] lines)
{
return lines.Ensure().Select(l => Intersect(line, l)).Where(p => p != null).Select(p => p.Value);
}
public static Point2D? Intersect(IPoint2D a1, IPoint2D b1, IPoint2D a2, IPoint2D b2)
{
if ((a1.X == a2.X && a1.Y == a2.Y) || (a1.X == b2.X && a1.Y == b2.Y))
{
return new Point2D(a1.X, a1.Y);
}
if ((b1.X == b2.X && b1.Y == b2.Y) || (b1.X == a2.X && b1.Y == a2.Y))
{
return new Point2D(b1.X, b1.Y);
}
var da1 = b1.Y - a1.Y;
var da2 = a1.X - b1.X;
var da3 = da1 * a1.X + da2 * a1.Y;
var db1 = b2.Y - a2.Y;
var db2 = a2.X - b2.X;
var db3 = db1 * a2.X + db2 * a2.Y;
var delta = da1 * db2 - db1 * da2;
if (delta != 0)
{
return new Point2D((db2 * da3 - da2 * db3) / delta, (da1 * db3 - db1 * da3) / delta);
}
return null;
}
public static Point2D? Intersect(Line2D line, IPoint2D a, IPoint2D b)
{
return Intersect(line._Start, line._End, a, b);
}
public static Point2D? Intersect(Line2D l1, Line2D l2)
{
return Intersect(l1._Start, l1._End, l2._Start, l2._End);
}
public static bool Intersects(Line2D[] lines1, Line2D[] lines2)
{
return Intersect(lines1, lines2).Any();
}
public static bool Intersects(Line2D line, Line2D[] lines)
{
return Intersect(line, lines).Any();
}
public static bool Intersects(Line2D line, IPoint2D a, IPoint2D b)
{
return Intersect(line, a, b) != null;
}
public static bool Intersects(IPoint2D a1, IPoint2D b1, IPoint2D a2, IPoint2D b2)
{
return Intersect(a1, b1, a2, b2) != null;
}
public static bool Intersects(Line2D l1, Line2D l2)
{
return Intersect(l1, l2) != null;
}
public static bool TryParse(string value, out Line2D l)
{
try
{
l = Parse(value);
return true;
}
catch
{
l = Empty;
return false;
}
}
public static Line2D Parse(string value)
{
var param = value.Split('+');
if (param.Length >= 2 && param.All(p => p.Contains(',')))
{
return new Line2D(Point2D.Parse(param[0]), Point2D.Parse(param[1]));
}
throw new FormatException(
"The specified line must be represented by two Point2D coords using the format " + //
"'(x1,y1)+(x2,y2)'");
}
private Point2D _Start, _End;
private Angle _Rotation;
private double _Length;
[CommandProperty(AccessLevel.Counselor)]
public int X
{
get => _Start.X;
set
{
_Start.X = value;
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
}
[CommandProperty(AccessLevel.Counselor)]
public int Y
{
get => _Start.Y;
set
{
_Start.Y = value;
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
}
[CommandProperty(AccessLevel.Counselor)]
public Point2D Start
{
get => _Start;
set
{
_Start = value;
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
}
[CommandProperty(AccessLevel.Counselor)]
public Point2D End
{
get => _End;
set
{
_End = value;
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
}
[CommandProperty(AccessLevel.Counselor)]
public Angle Rotation
{
get => _Rotation;
set
{
_Rotation = value;
_End = _Rotation.GetPoint2D(_Start.X, _Start.Y, _Length);
}
}
[CommandProperty(AccessLevel.Counselor)]
public double Length
{
get => _Length;
set
{
_Length = value;
_End = _Rotation.GetPoint2D(_Start.X, _Start.Y, _Length);
}
}
public Line2D(IPoint2D start, IPoint2D end)
{
_Start = new Point2D(start);
_End = new Point2D(end);
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
public Line2D(int xStart, int yStart, int xEnd, int yEnd)
{
_Start = new Point2D(xStart, yStart);
_End = new Point2D(xEnd, yEnd);
_Rotation = Angle.FromPoints(_Start, _End);
_Length = _Start.GetDistance(_End);
}
public Line2D(IPoint2D start, Angle angle, double length)
{
_Rotation = angle;
_Length = length;
_Start = new Point2D(start.X, start.Y);
_End = _Rotation.GetPoint2D(start.X, start.Y, _Length);
}
public Line2D(int xStart, int yStart, Angle angle, double length)
{
_Rotation = angle;
_Length = length;
_Start = new Point2D(xStart, yStart);
_End = _Rotation.GetPoint2D(xStart, yStart, _Length);
}
public IEnumerable<Point2D> Intersect(Line2D[] lines)
{
return Intersect(this, lines);
}
public Point2D? Intersect(Line2D line)
{
return Intersect(this, line);
}
public bool Intersects(Line2D line)
{
return Intersects(this, line);
}
public bool Intersects(Line2D[] lines)
{
return Intersects(this, lines);
}
public bool Intersects(IPoint2D a2, IPoint2D b2)
{
return Intersects(this, a2, b2);
}
public override string ToString()
{
return String.Format("{0}+{1}", _Start, _End);
}
}
}

View File

@@ -0,0 +1,113 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Cube3D : Shape3D
{
private int _Radius;
private bool _Hollow;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Radius
{
get => _Radius;
set
{
if (_Radius == value)
{
return;
}
_Radius = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Hollow
{
get => _Hollow;
set
{
if (_Hollow == value)
{
return;
}
_Hollow = value;
Render();
}
}
public Cube3D(int radius)
: this(Point3D.Zero, radius)
{ }
public Cube3D(IPoint3D center, int radius)
: this(center, radius, false)
{ }
public Cube3D(IPoint3D center, int radius, bool hollow)
: base(center)
{
_Radius = radius;
_Hollow = hollow;
}
/// <summary>
/// This cube always has an odd width, height and depth, never even.
/// This preserves the center point.
/// </summary>
protected override void OnRender()
{
const int h = 5;
for (var z = -Radius; z <= Radius; z++)
{
for (var x = -Radius; x <= Radius; x++)
{
for (var y = -Radius; y <= Radius; y++)
{
if (!Hollow || (z == -Radius || z == Radius || x == -Radius || x == Radius || y == -Radius || y == Radius))
{
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
}
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Radius);
writer.Write(_Hollow);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_Radius = reader.ReadInt();
_Hollow = reader.ReadBool();
}
}
}

View File

@@ -0,0 +1,148 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Cylinder3D : Shape3D
{
private int _Radius;
private bool _Hollow;
private bool _EndCaps;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Radius
{
get => _Radius;
set
{
if (_Radius == value)
{
return;
}
_Radius = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Hollow
{
get => _Hollow;
set
{
if (_Hollow == value)
{
return;
}
_Hollow = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool EndCaps
{
get => _EndCaps;
set
{
if (_EndCaps == value)
{
return;
}
_EndCaps = value;
Render();
}
}
public Cylinder3D(int radius)
: this(Point3D.Zero, radius)
{ }
public Cylinder3D(IPoint3D center, int radius)
: this(center, radius, false)
{ }
public Cylinder3D(IPoint3D center, int radius, bool hollow)
: this(center, radius, hollow, true)
{
Hollow = hollow;
}
public Cylinder3D(IPoint3D center, int radius, bool hollow, bool endCaps)
: base(center)
{
_Radius = radius;
_Hollow = hollow;
_EndCaps = endCaps;
}
public Cylinder3D(GenericReader reader)
: base(reader)
{ }
protected override void OnRender()
{
const int h = 5;
for (var z = -Radius; z <= Radius; z++)
{
if (Hollow && !EndCaps && (z == -Radius || z == Radius))
{
continue;
}
for (var x = -Radius; x <= Radius; x++)
{
for (var y = -Radius; y <= Radius; y++)
{
var dist = (int)Math.Sqrt(x * x + y * y);
if ((!Hollow || z == -Radius || z == Radius || dist >= Radius) && dist <= Radius)
{
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
}
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Radius);
writer.Write(_Hollow);
writer.Write(_EndCaps);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_Radius = reader.ReadInt();
_Hollow = reader.ReadBool();
_EndCaps = reader.ReadBool();
}
}
}

View File

@@ -0,0 +1,114 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Disc3D : Shape3D
{
private int _Radius;
private bool _Hollow;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Radius
{
get => _Radius;
set
{
if (_Radius == value)
{
return;
}
_Radius = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Hollow
{
get => _Hollow;
set
{
if (_Hollow == value)
{
return;
}
_Hollow = value;
Render();
}
}
public Disc3D(int radius)
: this(Point3D.Zero, radius)
{ }
public Disc3D(IPoint3D center, int radius)
: this(center, radius, false)
{ }
public Disc3D(IPoint3D center, int radius, bool hollow)
: base(center)
{
_Radius = radius;
_Hollow = hollow;
}
public Disc3D(GenericReader reader)
: base(reader)
{ }
protected override void OnRender()
{
const int h = 5;
for (var x = -Radius; x <= Radius; x++)
{
for (var y = -Radius; y <= Radius; y++)
{
var dist = (int)Math.Sqrt(x * x + y * y);
if ((!Hollow || dist >= Radius) && dist <= Radius)
{
Add(new Block3D(Center.Clone3D(x, y), h));
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Radius);
writer.Write(_Hollow);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_Radius = reader.ReadInt();
_Hollow = reader.ReadBool();
}
}
}

View File

@@ -0,0 +1,110 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Plane3D : Shape3D
{
private int _Radius;
private bool _Hollow;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Radius
{
get => _Radius;
set
{
if (_Radius == value)
{
return;
}
_Radius = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Hollow
{
get => _Hollow;
set
{
if (_Hollow == value)
{
return;
}
_Hollow = value;
Render();
}
}
public Plane3D(int radius)
: this(Point3D.Zero, radius)
{ }
public Plane3D(IPoint3D center, int radius)
: this(center, radius, false)
{ }
public Plane3D(IPoint3D center, int radius, bool hollow)
: base(center)
{
_Radius = radius;
_Hollow = hollow;
}
/// <summary>
/// This plane always has an odd width, height and depth, never even.
/// This preserves the center point.
/// </summary>
protected override void OnRender()
{
const int h = 5;
for (var x = -Radius; x <= Radius; x++)
{
for (var y = -Radius; y <= Radius; y++)
{
if (!Hollow || (x == -Radius || x == Radius || y == -Radius || y == Radius))
{
Add(new Block3D(Center.Clone3D(x, y), h));
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Radius);
writer.Write(_Hollow);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_Radius = reader.ReadInt();
_Hollow = reader.ReadBool();
}
}
}

View File

@@ -0,0 +1,121 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Ring3D : Shape3D
{
private int _RadiusMin;
private int _RadiusMax;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int RadiusMin
{
get => _RadiusMin;
set
{
if (_RadiusMin == value)
{
return;
}
_RadiusMin = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int RadiusMax
{
get => _RadiusMax;
set
{
if (_RadiusMax == value)
{
return;
}
_RadiusMax = value;
Render();
}
}
public Ring3D(int radius)
: this(radius, radius)
{ }
public Ring3D(int radiusMin, int radiusMax)
: this(Point3D.Zero, radiusMin, radiusMax)
{ }
public Ring3D(IPoint3D center, int radius)
: this(center, radius, radius)
{ }
public Ring3D(IPoint3D center, int radiusMin, int radiusMax)
: base(center)
{
_RadiusMin = Math.Min(radiusMin, radiusMax);
_RadiusMax = Math.Max(radiusMin, radiusMax);
}
public Ring3D(GenericReader reader)
: base(reader)
{ }
protected override void OnRender()
{
var min = Math.Min(RadiusMin, RadiusMax);
var max = Math.Max(RadiusMin, RadiusMax);
const int h = 5;
for (var x = -max; x <= max; x++)
{
for (var y = -max; y <= max; y++)
{
var dist = (int)Math.Sqrt(x * x + y * y);
if (dist >= min && dist <= max)
{
Add(new Block3D(Center.Clone3D(x, y), h));
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_RadiusMin);
writer.Write(_RadiusMax);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_RadiusMin = reader.ReadInt();
_RadiusMax = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,276 @@
#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 Server;
#endregion
namespace VitaNex.Geometry
{
[PropertyObject]
public abstract class Shape3D : DynamicWireframe, IPoint3D
{
private bool _InitialRender;
public override List<Block3D> Blocks
{
get
{
if (!_InitialRender)
{
Render();
}
return base.Blocks;
}
set => base.Blocks = value;
}
public override int Volume
{
get
{
if (!_InitialRender)
{
Render();
}
return base.Volume;
}
}
protected Point3D _Center;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public Point3D Center
{
get => _Center;
set
{
if (_Center == value)
{
return;
}
_Center = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int X
{
get => _Center.X;
set
{
if (_Center.X == value)
{
return;
}
_Center.X = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Y
{
get => _Center.Y;
set
{
if (_Center.Z == value)
{
return;
}
_Center.Y = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Z
{
get => _Center.Z;
set
{
if (_Center.Z == value)
{
return;
}
_Center.Z = value;
Render();
}
}
public Shape3D()
: this(Point3D.Zero)
{ }
public Shape3D(IPoint3D center)
{
_Center = center.Clone3D();
}
public Shape3D(GenericReader reader)
: base(reader)
{ }
public void Render()
{
if (Rendering)
{
return;
}
_InitialRender = Rendering = true;
Clear();
OnRender();
Rendering = false;
}
protected abstract void OnRender();
public override void Add(Block3D item)
{
if (!_InitialRender)
{
Render();
}
base.Add(item);
}
public override void AddRange(IEnumerable<Block3D> collection)
{
if (!_InitialRender)
{
Render();
}
base.AddRange(collection);
}
public override bool Remove(Block3D item)
{
if (!_InitialRender)
{
Render();
}
return base.Remove(item);
}
public override int RemoveAll(Predicate<Block3D> match)
{
if (!_InitialRender)
{
Render();
}
return base.RemoveAll(match);
}
public override void RemoveAt(int index)
{
if (!_InitialRender)
{
Render();
}
base.RemoveAt(index);
}
public override void RemoveRange(int index, int count)
{
if (!_InitialRender)
{
Render();
}
base.RemoveRange(index, count);
}
public override void ForEach(Action<Block3D> action)
{
if (!_InitialRender)
{
Render();
}
base.ForEach(action);
}
public override IEnumerator<Block3D> GetEnumerator()
{
if (!_InitialRender)
{
Render();
}
return base.GetEnumerator();
}
public override Block3D this[int index]
{
get
{
if (!_InitialRender)
{
Render();
}
return base[index];
}
set
{
if (!_InitialRender)
{
Render();
}
base[index] = value;
}
}
public override void Serialize(GenericWriter writer)
{
if (!_InitialRender)
{
Render();
}
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Center);
}
public override void Deserialize(GenericReader reader)
{
_InitialRender = true;
base.Deserialize(reader);
reader.GetVersion();
_Center = reader.ReadPoint3D();
}
}
}

View File

@@ -0,0 +1,136 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Geometry
{
public class Sphere3D : Shape3D
{
private int _Radius;
private bool _Hollow;
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public int Radius
{
get => _Radius;
set
{
if (_Radius == value)
{
return;
}
_Radius = value;
Render();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
public bool Hollow
{
get => _Hollow;
set
{
if (_Hollow == value)
{
return;
}
_Hollow = value;
Render();
}
}
public Sphere3D(int radius)
: this(Point3D.Zero, radius)
{ }
public Sphere3D(IPoint3D center, int radius)
: this(center, radius, false)
{ }
public Sphere3D(IPoint3D center, int radius, bool hollow)
: base(center)
{
_Radius = radius;
_Hollow = hollow;
}
public Sphere3D(GenericReader reader)
: base(reader)
{ }
protected override void OnRender()
{
const int h = 5;
var layers = Radius * 2;
for (var z = -layers; z <= layers; z++)
{
var p = z / Math.Max(1.0, layers);
var r = 2 * Radius;
if (p < 0.5)
{
r = (int)Math.Ceiling(r * p);
}
else if (p > 0.5)
{
r = (int)Math.Ceiling(r - (r * p));
}
else
{
r = Radius;
}
for (var x = -r; x <= r; x++)
{
for (var y = -r; y <= r; y++)
{
var dist = (int)Math.Sqrt(x * x + y * y);
if ((!Hollow || z == -layers || z == layers || dist >= r) && dist <= r)
{
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
}
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(_Radius);
writer.Write(_Hollow);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
_Radius = reader.ReadInt();
_Hollow = reader.ReadBool();
}
}
}

View File

@@ -0,0 +1,315 @@
#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
{
[NoSort, Parsable, PropertyObject]
public struct Triangle2D : IPoint2D
{
public static readonly Triangle2D Empty = new Triangle2D(0, 0, 0, 0, 0, 0);
public static IEnumerable<Point2D> Plot(IPoint2D a, IPoint2D b, IPoint2D c)
{
foreach (var p in Line2D.Plot(a, b).Skip(1))
{
yield return p;
}
foreach (var p in Line2D.Plot(b, c).Skip(1))
{
yield return p;
}
foreach (var p in Line2D.Plot(c, a).Skip(1))
{
yield return p;
}
}
public static bool Contains(IPoint2D p, IPoint2D a, IPoint2D b, IPoint2D c)
{
var x = p.X - a.X;
var y = p.Y - a.Y;
var delta = (b.X - a.X) * y - (b.Y - a.Y) * x > 0;
if ((c.X - a.X) * y - (c.Y - a.Y) * x > 0 == delta)
{
return false;
}
if ((c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X) > 0 != delta)
{
return false;
}
return true;
}
public static bool Contains(int x, int y, IPoint2D a, IPoint2D b, IPoint2D c)
{
return Contains(new Point2D(x, y), a, b, c);
}
public static IEnumerable<Point2D> Intersect(Triangle2D t1, Triangle2D t2)
{
return Line2D.Intersect(new[] { t1._AB, t1._BC, t1._CA }, new[] { t2._AB, t2._BC, t2._CA });
}
public static IEnumerable<Point2D> Intersect(Triangle2D t, Rectangle2D r)
{
return Line2D.Intersect(
new[] { t._AB, t._BC, t._CA },
new[]
{
new Line2D(r.X, r.Y, r.X + r.Width, r.Y), new Line2D(r.X + r.Width, r.Y, r.X + r.Width, r.Y + r.Height),
new Line2D(r.X, r.Y, r.X, r.Y + r.Height), new Line2D(r.X, r.Y + r.Height, r.X + r.Width, r.Y + r.Height)
});
}
public static bool Intersects(Triangle2D t1, Triangle2D t2)
{
return Intersect(t1, t2).Any();
}
public static bool Intersects(Triangle2D t, Rectangle2D r)
{
return Intersect(t, r).Any();
}
public static bool TryParse(string value, out Triangle2D t)
{
try
{
t = Parse(value);
return true;
}
catch
{
t = Empty;
return false;
}
}
public static Triangle2D Parse(string value)
{
var param = value.Split('+');
if (param.Length >= 3 && param.All(p => p.Contains(',')))
{
return new Triangle2D(Point2D.Parse(param[0]), Point2D.Parse(param[1]), Point2D.Parse(param[2]));
}
throw new FormatException(
"The specified triangle must be represented by three Point2D coords using the format " + //
"'(x1,y1)+(x2,y2)+(x3,y3)'");
}
private Point2D _A, _B, _C;
private Line2D _AB, _BC, _CA;
private Line2D _AC, _CB, _BA;
[CommandProperty(AccessLevel.Counselor)]
public int X
{
get => _A.X;
set
{
_A.X = value;
_AB.Start = _BA.End = _AC.Start = _CA.End = _A;
}
}
[CommandProperty(AccessLevel.Counselor)]
public int Y
{
get => _A.Y;
set
{
_A.Y = value;
_AB.Start = _BA.End = _AC.Start = _CA.End = _A;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Point2D A { get => _A; set => _A = _AB.Start = _BA.End = _AC.Start = _CA.End = value; }
[CommandProperty(AccessLevel.Counselor)]
public Point2D B { get => _B; set => _B = _BC.Start = _CB.End = _BA.Start = _AB.End = value; }
[CommandProperty(AccessLevel.Counselor)]
public Point2D C { get => _C; set => _C = _CA.Start = _AC.End = _CB.Start = _BC.End = value; }
[CommandProperty(AccessLevel.Counselor)]
public Line2D AB
{
get => _AB;
set
{
_AB = value;
_A = _BA.End = _AB.Start;
_B = _BA.Start = _AB.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Line2D BC
{
get => _BC;
set
{
_BC = value;
_B = _CB.End = _BC.Start;
_C = _CB.Start = _BC.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Line2D CA
{
get => _CA;
set
{
_CA = value;
_C = _AC.End = _CA.Start;
_A = _AC.Start = _CA.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Line2D AC
{
get => _AC;
set
{
_AC = value;
_A = _CA.End = _AC.Start;
_C = _CA.Start = _AC.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Line2D CB
{
get => _CB;
set
{
_CB = value;
_C = _BC.End = _CB.Start;
_B = _BC.Start = _CB.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Line2D BA
{
get => _BA;
set
{
_BA = value;
_B = _AB.End = _BA.Start;
_A = _AB.Start = _BA.End;
}
}
[CommandProperty(AccessLevel.Counselor)]
public Angle ABC => Angle.FromPoints(_A, _B, _C);
[CommandProperty(AccessLevel.Counselor)]
public Angle BCA => Angle.FromPoints(_B, _C, _A);
[CommandProperty(AccessLevel.Counselor)]
public Angle CAB => Angle.FromPoints(_C, _A, _B);
public Triangle2D(IPoint2D a, IPoint2D b, IPoint2D c)
{
_A = new Point2D(a);
_B = new Point2D(b);
_C = new Point2D(c);
_AB = new Line2D(_A, _B);
_BC = new Line2D(_B, _C);
_CA = new Line2D(_C, _A);
_AC = new Line2D(_A, _C);
_CB = new Line2D(_C, _B);
_BA = new Line2D(_B, _A);
}
public Triangle2D(int x1, int y1, int x2, int y2, int x3, int y3)
{
_A = new Point2D(x1, y1);
_B = new Point2D(x2, y2);
_C = new Point2D(x3, y3);
_AB = new Line2D(_A, _B);
_BC = new Line2D(_B, _C);
_CA = new Line2D(_C, _A);
_AC = new Line2D(_A, _C);
_CB = new Line2D(_C, _B);
_BA = new Line2D(_B, _A);
}
public bool Contains(IPoint2D p)
{
return Contains(p, _A, _B, _C);
}
public bool Contains(int x, int y)
{
return Contains(x, y, _A, _B, _C);
}
public IEnumerable<Point2D> Intersect(Triangle2D t)
{
return Intersect(this, t);
}
public IEnumerable<Point2D> Intersect(Rectangle2D r)
{
return Intersect(this, r);
}
public bool Intersects(Triangle2D t)
{
return Intersects(this, t);
}
public bool Intersects(Rectangle2D r)
{
return Intersects(this, r);
}
public IEnumerable<Point2D> Plot()
{
return Plot(_A, _B, _C);
}
public override string ToString()
{
return String.Format("{0}+{1}+{2}", _A, _B, _C);
}
}
}

View File

@@ -0,0 +1,469 @@
#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 VitaNex.Collections;
#endregion
namespace Server
{
public interface IWireframe : IEnumerable<Block3D>
{
bool Intersects(IBlock3D b);
bool Intersects(int x, int y, int z);
bool Intersects(int x, int y, int z, int h);
bool Intersects(IWireframe frame);
Rectangle3D GetBounds();
IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0);
}
public sealed class Wireframe : IEquatable<Wireframe>, IWireframe
{
public static readonly Wireframe Empty = new Wireframe(0);
public Block3D[] Blocks { get; private set; }
public int Volume => Blocks.Length;
public int Length => Blocks.Length;
public Wireframe(params IBlock3D[] blocks)
: this(blocks.Ensure().Select(b => new Block3D(b)))
{ }
public Wireframe(IEnumerable<IBlock3D> blocks)
: this(blocks.Ensure().Select(b => new Block3D(b)))
{ }
public Wireframe(Wireframe frame)
: this(frame.Blocks)
{ }
public Wireframe(int capacity)
{
Blocks = new Block3D[capacity];
}
public Wireframe(params Block3D[] blocks)
{
Blocks = blocks.Ensure().ToArray();
}
public Wireframe(IEnumerable<Block3D> blocks)
{
Blocks = blocks.Ensure().ToArray();
}
public bool Intersects(IPoint3D p)
{
return Intersects(p.X, p.Y, p.Z);
}
public bool Intersects(IPoint3D p, int h)
{
return Intersects(p.X, p.Y, p.Z, h);
}
public bool Intersects(IBlock3D b)
{
return Intersects(b.X, b.Y, b.Z, b.H);
}
public bool Intersects(int x, int y, int z)
{
return Intersects(x, y, z, 0);
}
public bool Intersects(int x, int y, int z, int h)
{
return Blocks.Any(b => b.Intersects(x, y, z, h));
}
public bool Intersects(IWireframe frame)
{
return frame != null && Blocks.Any(b => frame.Intersects(b));
}
public Rectangle3D GetBounds()
{
Point3D min = Point3D.Zero, max = Point3D.Zero;
foreach (var b in Blocks)
{
min.X = Math.Min(min.X, b.X);
min.Y = Math.Min(min.Y, b.Y);
min.Z = Math.Min(min.Z, b.Z);
max.X = Math.Max(max.X, b.X);
max.Y = Math.Max(max.Y, b.Y);
max.Z = Math.Max(max.Z, b.Z + b.H);
}
return new Rectangle3D(min, max);
}
public IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0)
{
return Blocks.Select(b => b.Offset(x, y, z, h));
}
public IEnumerator<Block3D> GetEnumerator()
{
return Blocks.AsEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Block3D this[int index]
{
get
{
if (index < 0 || index >= Blocks.Length)
{
return Block3D.Empty;
}
return Blocks[index];
}
set
{
if (index >= 0 && index < Blocks.Length)
{
Blocks[index] = value;
_Hash = null;
}
}
}
private int? _Hash;
public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value;
public override int GetHashCode()
{
return HashCode;
}
public override bool Equals(object obj)
{
return obj is Wireframe && Equals((Wireframe)obj);
}
public bool Equals(Wireframe other)
{
return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode());
}
public override string ToString()
{
return String.Format("Wireframe ({0:#,0} blocks)", Length);
}
public static bool operator ==(Wireframe l, Wireframe r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(Wireframe l, Wireframe r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
}
public class DynamicWireframe : IEquatable<DynamicWireframe>, IWireframe
{
public bool Rendering { get; protected set; }
public virtual List<Block3D> Blocks { get; set; }
public virtual int Volume => Blocks.Count;
public int Count => Blocks.Count;
public DynamicWireframe(params IBlock3D[] blocks)
: this(blocks.Ensure().Select(b => new Block3D(b)))
{ }
public DynamicWireframe(IEnumerable<IBlock3D> blocks)
: this(blocks.Ensure().Select(b => new Block3D(b)))
{ }
public DynamicWireframe(Wireframe frame)
: this(frame.Blocks)
{ }
public DynamicWireframe()
: this(0x100)
{ }
public DynamicWireframe(int capacity)
{
Blocks = new List<Block3D>(capacity);
}
public DynamicWireframe(params Block3D[] blocks)
{
Blocks = blocks.Ensure().ToList();
}
public DynamicWireframe(IEnumerable<Block3D> blocks)
{
Blocks = blocks.Ensure().ToList();
}
public DynamicWireframe(GenericReader reader)
{
Rendering = true;
Deserialize(reader);
Rendering = false;
}
public void Flatten()
{
var list = ListPool<Block3D>.AcquireObject();
list.AddRange(this);
Clear();
AddRange(list.Flatten());
ObjectPool.Free(ref list);
}
public bool Intersects(IPoint3D p)
{
return Intersects(p.X, p.Y, p.Z);
}
public bool Intersects(IBlock3D b)
{
return Intersects(b.X, b.Y, b.Z, b.H);
}
public bool Intersects(int x, int y, int z)
{
return Intersects(x, y, z, 0);
}
public bool Intersects(int x, int y, int z, int h)
{
return Blocks.Any(b => b.Intersects(x, y, z, h));
}
public bool Intersects(IWireframe frame)
{
return frame != null && Blocks.Any(b => frame.Intersects(b));
}
public Rectangle3D GetBounds()
{
Point3D min = Point3D.Zero, max = Point3D.Zero;
foreach (var b in Blocks)
{
min.X = Math.Min(min.X, b.X);
min.Y = Math.Min(min.Y, b.Y);
min.Z = Math.Min(min.Z, b.Z);
max.X = Math.Max(max.X, b.X);
max.Y = Math.Max(max.Y, b.Y);
max.Z = Math.Max(max.Z, b.Z + b.H);
}
return new Rectangle3D(min, max);
}
public IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0)
{
return Blocks.Select(b => b.Offset(x, y, z, h));
}
public virtual void Clear()
{
Blocks.Free(true);
_Hash = null;
}
public virtual void Add(Block3D item)
{
if (item != null)
{
Blocks.Add(item);
_Hash = null;
}
}
public virtual void AddRange(IEnumerable<Block3D> collection)
{
if (collection != null)
{
Blocks.AddRange(collection);
_Hash = null;
}
}
public virtual bool Remove(Block3D item)
{
if (item == null)
{
return false;
}
var success = Blocks.Remove(item);
Blocks.Free(false);
_Hash = null;
return success;
}
public virtual int RemoveAll(Predicate<Block3D> match)
{
if (match == null)
{
return 0;
}
var success = Blocks.RemoveAll(match);
Blocks.Free(false);
_Hash = null;
return success;
}
public virtual void RemoveAt(int index)
{
if (!Blocks.InBounds(index))
{
return;
}
Blocks.RemoveAt(index);
Blocks.Free(false);
_Hash = null;
}
public virtual void RemoveRange(int index, int count)
{
if (!Blocks.InBounds(index))
{
return;
}
Blocks.RemoveRange(index, count);
Blocks.Free(false);
_Hash = null;
}
public virtual void ForEach(Action<Block3D> action)
{
Blocks.ForEach(action);
}
public virtual IEnumerator<Block3D> GetEnumerator()
{
return Blocks.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public virtual Block3D this[int index]
{
get
{
if (index < 0 || index >= Blocks.Count)
{
return Block3D.Empty;
}
return Blocks[index];
}
set
{
if (index >= 0 && index < Blocks.Count)
{
Blocks[index] = value;
_Hash = null;
}
}
}
private int? _Hash;
public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value;
public override int GetHashCode()
{
return HashCode;
}
public override bool Equals(object obj)
{
return obj is DynamicWireframe && Equals((DynamicWireframe)obj);
}
public bool Equals(DynamicWireframe other)
{
return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode());
}
public override string ToString()
{
return String.Format("DynamicWireframe ({0:#,0} blocks)", Count);
}
public virtual void Serialize(GenericWriter writer)
{
writer.SetVersion(0);
writer.WriteList(Blocks, (w, b) => w.WriteBlock3D(b));
}
public virtual void Deserialize(GenericReader reader)
{
reader.GetVersion();
Blocks = reader.ReadList(r => reader.ReadBlock3D());
}
public static bool operator ==(DynamicWireframe l, DynamicWireframe r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(DynamicWireframe l, DynamicWireframe r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
}
}

View File

@@ -0,0 +1,139 @@
#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.IO;
using System.Linq;
#endregion
namespace VitaNex.IO
{
public sealed class ConfigFileInfo
{
private static readonly string[] _CommentSymbols = { "##", "//" };
private static readonly string[][] _MassCommentSymbols = { new[] { "/#", "#/" }, new[] { "/*", "*/" } };
private static FileInfo GetFileInfo(string path)
{
path = path ?? String.Empty;
return new FileInfo(IOUtility.GetSafeFilePath(path, true));
}
public FileInfo File { get; set; }
public DirectoryInfo Directory => File != null ? File.Directory : null;
public string Name => File != null ? File.Name : String.Empty;
public string Extension => File != null ? File.Extension : String.Empty;
public long Length => File != null ? File.Length : 0;
public bool Exists => File != null && File.Exists;
public FileAttributes Attributes
{
get => File != null ? File.Attributes : FileAttributes.Normal;
set
{
if (File != null)
{
File.Attributes = value;
}
}
}
public ConfigFileInfo(string path)
: this(GetFileInfo(path))
{ }
public ConfigFileInfo(FileInfo file)
{
File = file;
}
private static bool IsComment(string line, string symbol, out int idx)
{
idx = -1;
if (String.IsNullOrWhiteSpace(line))
{
return false;
}
idx = line.IndexOf(symbol, StringComparison.Ordinal);
return idx >= 0;
}
public string[] ReadAllLines()
{
var lines = new List<string>();
if (File != null && File.Exists && File.Length > 0)
{
using (var stream = File.OpenText())
{
var idx = -1;
var comment = false;
while (!stream.EndOfStream)
{
var line = (stream.ReadLine() ?? String.Empty).Trim();
if (_CommentSymbols.Any(
symbol => IsComment(line, symbol, out idx) && idx > 0 && idx + symbol.Length < line.Length))
{
line = line.Substring(idx);
}
foreach (var symbols in _MassCommentSymbols)
{
if (!comment)
{
if (IsComment(line, symbols[0], out idx))
{
if (idx > 0 && idx + symbols[0].Length < line.Length)
{
line = line.Substring(0, idx);
}
comment = true;
}
}
if (!comment || !IsComment(line, symbols[1], out var cIdx))
{
continue;
}
if (cIdx > idx && cIdx + symbols[1].Length < line.Length)
{
line = line.Substring(cIdx + symbols[1].Length);
}
comment = false;
}
if (!comment)
{
lines.Add(line);
}
}
}
}
return lines.ToArray();
}
}
}

View File

@@ -0,0 +1,131 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.IO;
using System.Threading;
using Server;
#endregion
namespace VitaNex.IO
{
public class BinaryDataStore<T1, T2> : DataStore<T1, T2>
{
private readonly ManualResetEvent _Sync = new ManualResetEvent(true);
public FileInfo Document { get; set; }
public Func<GenericWriter, bool> OnSerialize { get; set; }
public Func<GenericReader, bool> OnDeserialize { get; set; }
public bool Async { get; set; }
public BinaryDataStore(string root, string name)
: this(IOUtility.EnsureDirectory(root), name)
{ }
public BinaryDataStore(DirectoryInfo root, string name)
: base(root, name)
{
Document = IOUtility.EnsureFile(root.FullName + "/" + name + ((name.IndexOf('.') != -1) ? String.Empty : ".bin"));
}
public override DataStoreResult Export()
{
_Sync.WaitOne();
var res = base.Export();
if (res != DataStoreResult.OK)
{
_Sync.Set();
}
else if (!_Sync.WaitOne(0))
{
Status = DataStoreStatus.Exporting;
}
return res;
}
protected override void OnExport()
{
_Sync.Reset();
if (Async)
{
Document.SerializeAsync(OnExport);
}
else
{
Document.Serialize(OnExport);
}
}
protected virtual void OnExport(GenericWriter writer)
{
try
{
var handled = false;
if (OnSerialize != null)
{
handled = OnSerialize(writer);
}
if (!handled)
{
Serialize(writer);
}
}
finally
{
if (Status == DataStoreStatus.Exporting)
{
Status = DataStoreStatus.Idle;
}
_Sync.Set();
}
}
protected override void OnImport()
{
if (Document.Exists && Document.Length > 0)
{
Document.Deserialize(OnImport);
}
}
protected virtual void OnImport(GenericReader reader)
{
var handled = false;
if (OnDeserialize != null)
{
handled = OnDeserialize(reader);
}
if (!handled)
{
Deserialize(reader);
}
}
protected virtual void Serialize(GenericWriter writer)
{ }
protected virtual void Deserialize(GenericReader reader)
{ }
}
}

View File

@@ -0,0 +1,490 @@
#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.IO;
#endregion
namespace VitaNex.IO
{
public enum DataStoreStatus
{
Idle,
Disposed,
Initializing,
Importing,
Exporting,
Copying
}
public enum DataStoreResult
{
Null,
Busy,
Error,
OK
}
public interface IDataStore
{
DirectoryInfo Root { get; set; }
string Name { get; set; }
DataStoreStatus Status { get; }
List<Exception> Errors { get; }
bool HasErrors { get; }
DataStoreResult Import();
DataStoreResult Export();
}
public static class DateStoreIndex
{
public static int Value { get; set; }
}
public sealed class DataStoreComparer<TKey> : IEqualityComparer<TKey>
{
public static DataStoreComparer<TKey> Default { get; private set; }
static DataStoreComparer()
{
Default = new DataStoreComparer<TKey>();
}
private IEqualityComparer<TKey> _Impl;
public IEqualityComparer<TKey> Impl
{
get => _Impl ?? EqualityComparer<TKey>.Default;
set => _Impl = value ?? EqualityComparer<TKey>.Default;
}
public DataStoreComparer()
: this(null)
{ }
public DataStoreComparer(IEqualityComparer<TKey> impl)
{
Impl = impl;
}
public bool Equals(TKey x, TKey y)
{
return Impl.Equals(x, y);
}
public int GetHashCode(TKey obj)
{
return Impl.GetHashCode(obj);
}
}
public abstract class DataStore<TKey, TVal> : Dictionary<TKey, TVal>, IDataStore, IDisposable
{
public readonly object SyncRoot = new object();
public new TVal this[TKey key]
{
get
{
lock (SyncRoot)
{
return base[key];
}
}
set
{
lock (SyncRoot)
{
base[key] = value;
}
}
}
public new DataStoreComparer<TKey> Comparer => (DataStoreComparer<TKey>)base.Comparer;
public virtual DirectoryInfo Root { get; set; }
public virtual string Name { get; set; }
public DataStoreStatus Status { get; protected set; }
public List<Exception> Errors { get; protected set; }
public bool HasErrors => Errors.Count > 0;
public bool IsDisposed => Status == DataStoreStatus.Disposed;
public DataStore(string root, string name = null)
: this(IOUtility.EnsureDirectory(root), name)
{ }
public DataStore(DirectoryInfo root, string name = null)
: base(DataStoreComparer<TKey>.Default)
{
++DateStoreIndex.Value;
Status = DataStoreStatus.Initializing;
Errors = new List<Exception>();
if (String.IsNullOrWhiteSpace(name))
{
name = "DataStore" + DateStoreIndex.Value;
}
Name = name;
try
{
Root = root.EnsureDirectory(false);
}
catch
{
Root = IOUtility.EnsureDirectory(VitaNexCore.SavesDirectory + "/DataStores/" + Name);
}
Status = DataStoreStatus.Idle;
}
~DataStore()
{
Dispose();
}
public virtual DataStoreResult Import()
{
try
{
if (Status != DataStoreStatus.Idle)
{
return DataStoreResult.Busy;
}
lock (SyncRoot)
{
Errors.Free(true);
}
Status = DataStoreStatus.Importing;
try
{
lock (SyncRoot)
{
OnImport();
}
}
catch (Exception e1)
{
lock (SyncRoot)
{
Errors.Add(e1);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
Status = DataStoreStatus.Idle;
return DataStoreResult.OK;
}
catch (Exception e2)
{
lock (SyncRoot)
{
Errors.Add(e2);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
}
public virtual DataStoreResult Export()
{
try
{
if (Status != DataStoreStatus.Idle)
{
return DataStoreResult.Busy;
}
lock (SyncRoot)
{
Errors.Free(true);
}
Status = DataStoreStatus.Exporting;
try
{
lock (SyncRoot)
{
OnExport();
}
}
catch (Exception e1)
{
lock (SyncRoot)
{
Errors.Add(e1);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
Status = DataStoreStatus.Idle;
return DataStoreResult.OK;
}
catch (Exception e2)
{
lock (SyncRoot)
{
Errors.Add(e2);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
}
public virtual DataStoreResult CopyTo(IDictionary<TKey, TVal> dbTarget)
{
return CopyTo(dbTarget, true);
}
public virtual DataStoreResult CopyTo(IDictionary<TKey, TVal> dbTarget, bool replace)
{
try
{
lock (SyncRoot)
{
Errors.Free(true);
}
if (Status != DataStoreStatus.Idle)
{
return DataStoreResult.Busy;
}
if (this == dbTarget)
{
return DataStoreResult.OK;
}
Status = DataStoreStatus.Copying;
lock (SyncRoot)
{
foreach (var kvp in this)
{
dbTarget[kvp.Key] = kvp.Value;
}
}
try
{
lock (SyncRoot)
{
OnCopiedTo(dbTarget);
}
}
catch (Exception e1)
{
lock (SyncRoot)
{
Errors.Add(e1);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
Status = DataStoreStatus.Idle;
return DataStoreResult.OK;
}
catch (Exception e2)
{
lock (SyncRoot)
{
Errors.Add(e2);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
}
protected virtual void OnCopiedTo(IDictionary<TKey, TVal> dbTarget)
{ }
public virtual DataStoreResult CopyFrom(IDictionary<TKey, TVal> dbSource)
{
return CopyFrom(dbSource, true);
}
public virtual DataStoreResult CopyFrom(IDictionary<TKey, TVal> dbSource, bool replace)
{
try
{
lock (SyncRoot)
{
Errors.Free(true);
}
if (Status != DataStoreStatus.Idle)
{
return DataStoreResult.Busy;
}
if (this == dbSource)
{
return DataStoreResult.OK;
}
Status = DataStoreStatus.Copying;
lock (SyncRoot)
{
foreach (var kvp in dbSource)
{
this[kvp.Key] = kvp.Value;
}
}
try
{
lock (SyncRoot)
{
OnCopiedFrom(dbSource);
}
}
catch (Exception e1)
{
lock (SyncRoot)
{
Errors.Add(e1);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
Status = DataStoreStatus.Idle;
return DataStoreResult.OK;
}
catch (Exception e2)
{
lock (SyncRoot)
{
Errors.Add(e2);
}
Status = DataStoreStatus.Idle;
return DataStoreResult.Error;
}
}
protected virtual void OnCopiedFrom(IDictionary<TKey, TVal> dbSource)
{ }
protected virtual void OnImport()
{ }
protected virtual void OnExport()
{ }
public virtual new void Add(TKey key, TVal value)
{
lock (SyncRoot)
{
base.Add(key, value);
}
}
public virtual new bool Remove(TKey key)
{
lock (SyncRoot)
{
return base.Remove(key);
}
}
public virtual new bool ContainsKey(TKey key)
{
lock (SyncRoot)
{
return base.ContainsKey(key);
}
}
public virtual new bool ContainsValue(TVal value)
{
lock (SyncRoot)
{
return base.ContainsValue(value);
}
}
public virtual new void Clear()
{
lock (SyncRoot)
{
base.Clear();
}
}
public virtual new bool TryGetValue(TKey key, out TVal value)
{
lock (SyncRoot)
{
return base.TryGetValue(key, out value);
}
}
public void Dispose()
{
if (Status == DataStoreStatus.Disposed)
{
return;
}
Status = DataStoreStatus.Disposed;
Clear();
lock (SyncRoot)
{
Errors.Free(true);
}
Name = null;
Root = null;
}
public override string ToString()
{
return Name ?? base.ToString();
}
}
public class DataStore<T> : DataStore<int, T>
{
public DataStore(string root, string name = null)
: base(root, name)
{ }
public DataStore(DirectoryInfo root, string name = null)
: base(root, name)
{ }
}
}

View File

@@ -0,0 +1,112 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.IO;
using Server;
#endregion
namespace VitaNex.IO
{
public class BinaryDirectoryDataStore<TKey, TVal> : DirectoryDataStore<TKey, TVal>
{
public Func<GenericWriter, TKey, TVal, bool> OnSerialize { get; set; }
public Func<GenericReader, Tuple<TKey, TVal>> OnDeserialize { get; set; }
public bool Async { get; set; }
public BinaryDirectoryDataStore(string root, string name, string fileExt)
: this(IOUtility.EnsureDirectory(root + "/" + name), name, fileExt)
{ }
public BinaryDirectoryDataStore(DirectoryInfo root, string name, string fileExt)
: base(root, name)
{
FileExtension = String.IsNullOrWhiteSpace(fileExt) ? "vnc" : fileExt;
}
protected override void OnExport(FileInfo file, TKey key, TVal val)
{
if (Async)
{
file.SerializeAsync(writer => OnExport(writer, key, val));
}
else
{
file.Serialize(writer => OnExport(writer, key, val));
}
}
protected virtual void OnExport(GenericWriter writer, TKey key, TVal val)
{
var handled = false;
if (OnSerialize != null)
{
handled = OnSerialize(writer, key, val);
}
if (!handled)
{
Serialize(writer, key, val);
}
}
protected override void OnImport(FileInfo file, out TKey key, out TVal val)
{
var keyBox = default(TKey);
var valBox = default(TVal);
if (file == null || !file.Exists || file.Length == 0)
{
key = keyBox;
val = valBox;
return;
}
file.Deserialize(reader =>
{
var handled = false;
if (OnDeserialize != null)
{
var entry = OnDeserialize(reader);
if (entry != null)
{
keyBox = entry.Item1;
valBox = entry.Item2;
handled = true;
}
}
if (!handled)
{
Deserialize(reader, out keyBox, out valBox);
}
});
key = keyBox;
val = valBox;
}
protected virtual void Serialize(GenericWriter writer, TKey key, TVal val)
{ }
protected virtual void Deserialize(GenericReader reader, out TKey key, out TVal val)
{
key = default(TKey);
val = default(TVal);
}
}
}

View File

@@ -0,0 +1,104 @@
#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.IO;
using System.Linq;
#endregion
namespace VitaNex.IO
{
public abstract class DirectoryDataStore<TKey, TVal> : DataStore<TKey, TVal>
{
public virtual string FileExtension { get; set; }
public DirectoryDataStore(DirectoryInfo root)
: base(root)
{
FileExtension = "vnc";
}
public DirectoryDataStore(DirectoryInfo root, string name)
: base(root, name)
{
FileExtension = "vnc";
}
public DirectoryDataStore(DirectoryInfo root, string name, string fileExt)
: base(root, name)
{
FileExtension = String.IsNullOrWhiteSpace(fileExt) ? "vnc" : fileExt;
}
protected override void OnExport()
{
Root.EmptyDirectory(false);
foreach (var kv in this)
{
OnExport(kv);
}
}
protected virtual void OnExport(KeyValuePair<TKey, TVal> kv)
{
var key = kv.Key;
var value = kv.Value;
var fileName = IOUtility.GetSafeFileName(String.Format("{0} ({1}).{2}", key, value, FileExtension), '%');
try
{
OnExport(IOUtility.EnsureFile(Root.FullName + "/" + fileName, true), key, value);
}
catch (Exception e)
{
lock (SyncRoot)
{
Errors.Add(e);
}
}
}
protected override void OnImport()
{
foreach (var file in Root.GetFiles().Where(file => file.Name.EndsWith("." + FileExtension)))
{
OnImport(file);
}
}
protected virtual void OnImport(FileInfo file)
{
try
{
OnImport(file, out var key, out var val);
if (key != null && val != null)
{
this[key] = val;
}
}
catch (Exception e)
{
lock (SyncRoot)
{
Errors.Add(e);
}
}
}
protected abstract void OnExport(FileInfo file, TKey key, TVal val);
protected abstract void OnImport(FileInfo file, out TKey key, out TVal val);
}
}

View File

@@ -0,0 +1,89 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.IO;
using System.Xml;
#endregion
namespace VitaNex.IO
{
public class XmlDataStore<T1, T2> : DataStore<T1, T2>
{
public FileInfo Document { get; set; }
public Func<XmlDocument, bool> OnSerialize { get; set; }
public Func<XmlDocument, bool> OnDeserialize { get; set; }
public XmlDataStore(string root, string name)
: this(IOUtility.EnsureDirectory(root), name)
{ }
public XmlDataStore(DirectoryInfo root, string name)
: base(root, name)
{
Document = IOUtility.EnsureFile(root.FullName + "/" + name + ((name.IndexOf('.') != -1) ? String.Empty : ".xml"));
}
protected override void OnExport()
{
using (var stream = Document.Open(FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var doc = new XmlDocument();
var handled = false;
if (OnSerialize != null)
{
handled = OnSerialize(doc);
}
if (!handled)
{
WriteXml(doc);
}
doc.Save(stream);
}
}
protected override void OnImport()
{
if (!Document.Exists || Document.Length == 0)
{
return;
}
using (var stream = Document.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var doc = new XmlDocument();
doc.Load(stream);
var handled = false;
if (OnDeserialize != null)
{
handled = OnDeserialize(doc);
}
if (!handled)
{
ReadXml(doc);
}
}
}
protected virtual void WriteXml(XmlDocument doc)
{ }
protected virtual void ReadXml(XmlDocument doc)
{ }
}
}

View File

@@ -0,0 +1,873 @@
#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.IO;
using System.Linq;
using Server;
#endregion
namespace VitaNex.IO
{
public struct FileMime : IEquatable<FileMime>, IComparable<FileMime>
{
private static readonly Dictionary<string, FileMime> _Registry;
public static IEnumerable<FileMime> Registry => _Registry.Values;
public static readonly FileMime Default = new FileMime(null, null);
static FileMime()
{
_Registry = new Dictionary<string, FileMime>(StringComparer.OrdinalIgnoreCase);
#region Definitions
Register("323", "text/h323");
Register("3g2", "video/3gpp2");
Register("3gp", "video/3gpp");
Register("3gp2", "video/3gpp2");
Register("3gpp", "video/3gpp");
Register("7z", "application/x-7z-compressed");
Register("aa", "audio/audible");
Register("AAC", "audio/aac");
Register("aaf", "application/octet-stream");
Register("aax", "audio/vnd.audible.aax");
Register("ac3", "audio/ac3");
Register("aca", "application/octet-stream");
Register("accda", "application/msaccess.addin");
Register("accdb", "application/msaccess");
Register("accdc", "application/msaccess.cab");
Register("accde", "application/msaccess");
Register("accdr", "application/msaccess.runtime");
Register("accdt", "application/msaccess");
Register("accdw", "application/msaccess.webapplication");
Register("accft", "application/msaccess.ftemplate");
Register("acx", "application/internet-property-stream");
Register("AddIn", "text/xml");
Register("ade", "application/msaccess");
Register("adobebridge", "application/x-bridge-url");
Register("adp", "application/msaccess");
Register("ADT", "audio/vnd.dlna.adts");
Register("ADTS", "audio/aac");
Register("afm", "application/octet-stream");
Register("ai", "application/postscript");
Register("aif", "audio/x-aiff");
Register("aifc", "audio/aiff");
Register("aiff", "audio/aiff");
Register("air", "application/vnd.adobe.air-application-installer-package+zip");
Register("amc", "application/x-mpeg");
Register("application", "application/x-ms-application");
Register("art", "image/x-jg");
Register("asa", "application/xml");
Register("asax", "application/xml");
Register("ascx", "application/xml");
Register("asd", "application/octet-stream");
Register("asf", "video/x-ms-asf");
Register("ashx", "application/xml");
Register("asi", "application/octet-stream");
Register("asm", "text/plain");
Register("asmx", "application/xml");
Register("aspx", "application/xml");
Register("asr", "video/x-ms-asf");
Register("asx", "video/x-ms-asf");
Register("atom", "application/atom+xml");
Register("au", "audio/basic");
Register("avi", "video/x-msvideo");
Register("axs", "application/olescript");
Register("bas", "text/plain");
Register("bcpio", "application/x-bcpio");
Register("bin", "application/octet-stream");
Register("bmp", "image/bmp");
Register("c", "text/plain");
Register("cab", "application/octet-stream");
Register("caf", "audio/x-caf");
Register("calx", "application/vnd.ms-office.calx");
Register("cat", "application/vnd.ms-pki.seccat");
Register("cc", "text/plain");
Register("cd", "text/plain");
Register("cdda", "audio/aiff");
Register("cdf", "application/x-cdf");
Register("cer", "application/x-x509-ca-cert");
Register("chm", "application/octet-stream");
Register("class", "application/x-java-applet");
Register("clp", "application/x-msclip");
Register("cmx", "image/x-cmx");
Register("cnf", "text/plain");
Register("cod", "image/cis-cod");
Register("config", "application/xml");
Register("contact", "text/x-ms-contact");
Register("coverage", "application/xml");
Register("cpio", "application/x-cpio");
Register("cpp", "text/plain");
Register("crd", "application/x-mscardfile");
Register("crl", "application/pkix-crl");
Register("crt", "application/x-x509-ca-cert");
Register("cs", "text/plain");
Register("csdproj", "text/plain");
Register("csh", "application/x-csh");
Register("csproj", "text/plain");
Register("css", "text/css");
Register("csv", "text/csv");
Register("cur", "application/octet-stream");
Register("cxx", "text/plain");
Register("dat", "application/octet-stream");
Register("datasource", "application/xml");
Register("dbproj", "text/plain");
Register("dcr", "application/x-director");
Register("def", "text/plain");
Register("deploy", "application/octet-stream");
Register("der", "application/x-x509-ca-cert");
Register("dgml", "application/xml");
Register("dib", "image/bmp");
Register("dif", "video/x-dv");
Register("dir", "application/x-director");
Register("disco", "text/xml");
Register("dll", "application/x-msdownload");
Register("dll.config", "text/xml");
Register("dlm", "text/dlm");
Register("doc", "application/msword");
Register("docm", "application/vnd.ms-word.document.macroEnabled.12");
Register("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
Register("dot", "application/msword");
Register("dotm", "application/vnd.ms-word.template.macroEnabled.12");
Register("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
Register("dsp", "application/octet-stream");
Register("dsw", "text/plain");
Register("dtd", "text/xml");
Register("dtsConfig", "text/xml");
Register("dv", "video/x-dv");
Register("dvi", "application/x-dvi");
Register("dwf", "drawing/x-dwf");
Register("dwp", "application/octet-stream");
Register("dxr", "application/x-director");
Register("eml", "message/rfc822");
Register("emz", "application/octet-stream");
Register("eot", "application/octet-stream");
Register("eps", "application/postscript");
Register("etl", "application/etl");
Register("etx", "text/x-setext");
Register("evy", "application/envoy");
Register("exe", "application/octet-stream");
Register("exe.config", "text/xml");
Register("fdf", "application/vnd.fdf");
Register("fif", "application/fractals");
Register("filters", "Application/xml");
Register("fla", "application/octet-stream");
Register("flr", "x-world/x-vrml");
Register("flv", "video/x-flv");
Register("form", "application/x-www-form-urlencoded");
Register("fsscript", "application/fsharp-script");
Register("fsx", "application/fsharp-script");
Register("generictest", "application/xml");
Register("gif", "image/gif");
Register("group", "text/x-ms-group");
Register("gsm", "audio/x-gsm");
Register("gtar", "application/x-gtar");
Register("gz", "application/x-gzip");
Register("h", "text/plain");
Register("hash", "text/plain");
Register("hdf", "application/x-hdf");
Register("hdml", "text/x-hdml");
Register("hhc", "application/x-oleobject");
Register("hhk", "application/octet-stream");
Register("hhp", "application/octet-stream");
Register("hlp", "application/winhlp");
Register("hpp", "text/plain");
Register("hqx", "application/mac-binhex40");
Register("hta", "application/hta");
Register("htc", "text/x-component");
Register("htm", "text/html");
Register("html", "text/html");
Register("htt", "text/webviewhtml");
Register("hxa", "application/xml");
Register("hxc", "application/xml");
Register("hxd", "application/octet-stream");
Register("hxe", "application/xml");
Register("hxf", "application/xml");
Register("hxh", "application/octet-stream");
Register("hxi", "application/octet-stream");
Register("hxk", "application/xml");
Register("hxq", "application/octet-stream");
Register("hxr", "application/octet-stream");
Register("hxs", "application/octet-stream");
Register("hxt", "text/html");
Register("hxv", "application/xml");
Register("hxw", "application/octet-stream");
Register("hxx", "text/plain");
Register("i", "text/plain");
Register("ico", "image/x-icon");
Register("ics", "application/octet-stream");
Register("idl", "text/plain");
Register("ief", "image/ief");
Register("iii", "application/x-iphone");
Register("inc", "text/plain");
Register("inf", "application/octet-stream");
Register("inl", "text/plain");
Register("ins", "application/x-internet-signup");
Register("ipa", "application/x-itunes-ipa");
Register("ipg", "application/x-itunes-ipg");
Register("ipproj", "text/plain");
Register("ipsw", "application/x-itunes-ipsw");
Register("iqy", "text/x-ms-iqy");
Register("isp", "application/x-internet-signup");
Register("ite", "application/x-itunes-ite");
Register("itlp", "application/x-itunes-itlp");
Register("itms", "application/x-itunes-itms");
Register("itpc", "application/x-itunes-itpc");
Register("IVF", "video/x-ivf");
Register("jar", "application/java-archive");
Register("java", "application/octet-stream");
Register("jck", "application/liquidmotion");
Register("jcz", "application/liquidmotion");
Register("jfif", "image/pjpeg");
Register("jnlp", "application/x-java-jnlp-file");
Register("jpb", "application/octet-stream");
Register("jpe", "image/jpeg");
Register("jpeg", "image/jpeg");
Register("jpg", "image/jpeg");
Register("js", "application/x-javascript");
Register("json", "application/json");
Register("jsx", "text/jscript");
Register("jsxbin", "text/plain");
Register("latex", "application/x-latex");
Register("library-ms", "application/windows-library+xml");
Register("lit", "application/x-ms-reader");
Register("loadtest", "application/xml");
Register("lpk", "application/octet-stream");
Register("lsf", "video/x-la-asf");
Register("lst", "text/plain");
Register("lsx", "video/x-la-asf");
Register("lzh", "application/octet-stream");
Register("m13", "application/x-msmediaview");
Register("m14", "application/x-msmediaview");
Register("m1v", "video/mpeg");
Register("m2t", "video/vnd.dlna.mpeg-tts");
Register("m2ts", "video/vnd.dlna.mpeg-tts");
Register("m2v", "video/mpeg");
Register("m3u", "audio/x-mpegurl");
Register("m3u8", "audio/x-mpegurl");
Register("m4a", "audio/m4a");
Register("m4b", "audio/m4b");
Register("m4p", "audio/m4p");
Register("m4r", "audio/x-m4r");
Register("m4v", "video/x-m4v");
Register("mac", "image/x-macpaint");
Register("mak", "text/plain");
Register("man", "application/x-troff-man");
Register("manifest", "application/x-ms-manifest");
Register("map", "text/plain");
Register("master", "application/xml");
Register("mda", "application/msaccess");
Register("mdb", "application/x-msaccess");
Register("mde", "application/msaccess");
Register("mdp", "application/octet-stream");
Register("me", "application/x-troff-me");
Register("mfp", "application/x-shockwave-flash");
Register("mht", "message/rfc822");
Register("mhtml", "message/rfc822");
Register("mid", "audio/mid");
Register("midi", "audio/mid");
Register("mix", "application/octet-stream");
Register("mk", "text/plain");
Register("mmf", "application/x-smaf");
Register("mno", "text/xml");
Register("mny", "application/x-msmoney");
Register("mod", "video/mpeg");
Register("mov", "video/quicktime");
Register("movie", "video/x-sgi-movie");
Register("mp2", "video/mpeg");
Register("mp2v", "video/mpeg");
Register("mp3", "audio/mpeg");
Register("mp4", "video/mp4");
Register("mp4v", "video/mp4");
Register("mpa", "video/mpeg");
Register("mpe", "video/mpeg");
Register("mpeg", "video/mpeg");
Register("mpf", "application/vnd.ms-mediapackage");
Register("mpg", "video/mpeg");
Register("mpp", "application/vnd.ms-project");
Register("mpv2", "video/mpeg");
Register("mqv", "video/quicktime");
Register("ms", "application/x-troff-ms");
Register("msi", "application/octet-stream");
Register("mso", "application/octet-stream");
Register("mts", "video/vnd.dlna.mpeg-tts");
Register("mtx", "application/xml");
Register("mul", "application/octet-stream");
Register("mvb", "application/x-msmediaview");
Register("mvc", "application/x-miva-compiled");
Register("mxp", "application/x-mmxp");
Register("nc", "application/x-netcdf");
Register("nsc", "video/x-ms-asf");
Register("nws", "message/rfc822");
Register("ocx", "application/octet-stream");
Register("oda", "application/oda");
Register("odc", "text/x-ms-odc");
Register("odh", "text/plain");
Register("odl", "text/plain");
Register("odp", "application/vnd.oasis.opendocument.presentation");
Register("ods", "application/oleobject");
Register("odt", "application/vnd.oasis.opendocument.text");
Register("one", "application/onenote");
Register("onea", "application/onenote");
Register("onepkg", "application/onenote");
Register("onetmp", "application/onenote");
Register("onetoc", "application/onenote");
Register("onetoc2", "application/onenote");
Register("orderedtest", "application/xml");
Register("osdx", "application/opensearchdescription+xml");
Register("p10", "application/pkcs10");
Register("p12", "application/x-pkcs12");
Register("p7b", "application/x-pkcs7-certificates");
Register("p7c", "application/pkcs7-mime");
Register("p7m", "application/pkcs7-mime");
Register("p7r", "application/x-pkcs7-certreqresp");
Register("p7s", "application/pkcs7-signature");
Register("pbm", "image/x-portable-bitmap");
Register("pcast", "application/x-podcast");
Register("pct", "image/pict");
Register("pcx", "application/octet-stream");
Register("pcz", "application/octet-stream");
Register("pdf", "application/pdf");
Register("pfb", "application/octet-stream");
Register("pfm", "application/octet-stream");
Register("pfx", "application/x-pkcs12");
Register("pgm", "image/x-portable-graymap");
Register("pic", "image/pict");
Register("pict", "image/pict");
Register("pkgdef", "text/plain");
Register("pkgundef", "text/plain");
Register("pko", "application/vnd.ms-pki.pko");
Register("pls", "audio/scpls");
Register("pma", "application/x-perfmon");
Register("pmc", "application/x-perfmon");
Register("pml", "application/x-perfmon");
Register("pmr", "application/x-perfmon");
Register("pmw", "application/x-perfmon");
Register("png", "image/png");
Register("pnm", "image/x-portable-anymap");
Register("pnt", "image/x-macpaint");
Register("pntg", "image/x-macpaint");
Register("pnz", "image/png");
Register("post", "application/x-www-form-urlencoded");
Register("pot", "application/vnd.ms-powerpoint");
Register("potm", "application/vnd.ms-powerpoint.template.macroEnabled.12");
Register("potx", "application/vnd.openxmlformats-officedocument.presentationml.template");
Register("ppa", "application/vnd.ms-powerpoint");
Register("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12");
Register("ppm", "image/x-portable-pixmap");
Register("pps", "application/vnd.ms-powerpoint");
Register("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12");
Register("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow");
Register("ppt", "application/vnd.ms-powerpoint");
Register("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12");
Register("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
Register("prf", "application/pics-rules");
Register("prm", "application/octet-stream");
Register("prx", "application/octet-stream");
Register("ps", "application/postscript");
Register("psc1", "application/PowerShell");
Register("psd", "application/octet-stream");
Register("psess", "application/xml");
Register("psm", "application/octet-stream");
Register("psp", "application/octet-stream");
Register("pub", "application/x-mspublisher");
Register("pwz", "application/vnd.ms-powerpoint");
Register("qht", "text/x-html-insertion");
Register("qhtm", "text/x-html-insertion");
Register("qt", "video/quicktime");
Register("qti", "image/x-quicktime");
Register("qtif", "image/x-quicktime");
Register("qtl", "application/x-quicktimeplayer");
Register("qxd", "application/octet-stream");
Register("ra", "audio/x-pn-realaudio");
Register("ram", "audio/x-pn-realaudio");
Register("rar", "application/octet-stream");
Register("ras", "image/x-cmu-raster");
Register("rat", "application/rat-file");
Register("rc", "text/plain");
Register("rc2", "text/plain");
Register("rct", "text/plain");
Register("rdlc", "application/xml");
Register("resx", "application/xml");
Register("rf", "image/vnd.rn-realflash");
Register("rgb", "image/x-rgb");
Register("rgs", "text/plain");
Register("rm", "application/vnd.rn-realmedia");
Register("rmi", "audio/mid");
Register("rmp", "application/vnd.rn-rn_music_package");
Register("roff", "application/x-troff");
Register("rpm", "audio/x-pn-realaudio-plugin");
Register("rqy", "text/x-ms-rqy");
Register("rtf", "application/rtf");
Register("rtx", "text/richtext");
Register("ruleset", "application/xml");
Register("s", "text/plain");
Register("safariextz", "application/x-safari-safariextz");
Register("scd", "application/x-msschedule");
Register("sct", "text/scriptlet");
Register("sd2", "audio/x-sd2");
Register("sdp", "application/sdp");
Register("sea", "application/octet-stream");
Register("searchConnector-ms", "application/windows-search-connector+xml");
Register("setpay", "application/set-payment-initiation");
Register("setreg", "application/set-registration-initiation");
Register("settings", "application/xml");
Register("sgimb", "application/x-sgimb");
Register("sgml", "text/sgml");
Register("sh", "application/x-sh");
Register("shar", "application/x-shar");
Register("shtml", "text/html");
Register("sit", "application/x-stuffit");
Register("sitemap", "application/xml");
Register("skin", "application/xml");
Register("sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12");
Register("sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide");
Register("slk", "application/vnd.ms-excel");
Register("sln", "text/plain");
Register("slupkg-ms", "application/x-ms-license");
Register("smd", "audio/x-smd");
Register("smi", "application/octet-stream");
Register("smx", "audio/x-smd");
Register("smz", "audio/x-smd");
Register("snd", "audio/basic");
Register("snippet", "application/xml");
Register("snp", "application/octet-stream");
Register("sol", "text/plain");
Register("sor", "text/plain");
Register("spc", "application/x-pkcs7-certificates");
Register("spl", "application/futuresplash");
Register("src", "application/x-wais-source");
Register("srf", "text/plain");
Register("SSISDeploymentManifest", "text/xml");
Register("ssm", "application/streamingmedia");
Register("sst", "application/vnd.ms-pki.certstore");
Register("stl", "application/vnd.ms-pki.stl");
Register("sv4cpio", "application/x-sv4cpio");
Register("sv4crc", "application/x-sv4crc");
Register("svc", "application/xml");
Register("swf", "application/x-shockwave-flash");
Register("t", "application/x-troff");
Register("tar", "application/x-tar");
Register("tcl", "application/x-tcl");
Register("testrunconfig", "application/xml");
Register("testsettings", "application/xml");
Register("tex", "application/x-tex");
Register("texi", "application/x-texinfo");
Register("texinfo", "application/x-texinfo");
Register("tgz", "application/x-compressed");
Register("thmx", "application/vnd.ms-officetheme");
Register("thn", "application/octet-stream");
Register("tif", "image/tiff");
Register("tiff", "image/tiff");
Register("tlh", "text/plain");
Register("tli", "text/plain");
Register("toc", "application/octet-stream");
Register("tr", "application/x-troff");
Register("trm", "application/x-msterminal");
Register("trx", "application/xml");
Register("ts", "video/vnd.dlna.mpeg-tts");
Register("tsv", "text/tab-separated-values");
Register("ttf", "application/octet-stream");
Register("tts", "video/vnd.dlna.mpeg-tts");
Register("txt", "text/plain");
Register("u32", "application/octet-stream");
Register("uls", "text/iuls");
Register("uoo", "application/octet-stream");
Register("uop", "application/octet-stream");
Register("user", "text/plain");
Register("ustar", "application/x-ustar");
Register("vb", "text/plain");
Register("vbdproj", "text/plain");
Register("vbk", "video/mpeg");
Register("vbproj", "text/plain");
Register("vbs", "text/vbscript");
Register("vcf", "text/x-vcard");
Register("vcproj", "application/xml");
Register("vcs", "text/plain");
Register("vcxproj", "application/xml");
Register("vddproj", "text/plain");
Register("vdp", "text/plain");
Register("vdproj", "text/plain");
Register("vdx", "application/vnd.ms-visio.viewer");
Register("vml", "text/xml");
Register("vscontent", "application/xml");
Register("vsct", "text/xml");
Register("vsd", "application/vnd.visio");
Register("vsi", "application/ms-vsi");
Register("vsix", "application/vsix");
Register("vsixlangpack", "text/xml");
Register("vsixmanifest", "text/xml");
Register("vsmdi", "application/xml");
Register("vspscc", "text/plain");
Register("vss", "application/vnd.visio");
Register("vsscc", "text/plain");
Register("vssettings", "text/xml");
Register("vssscc", "text/plain");
Register("vst", "application/vnd.visio");
Register("vstemplate", "text/xml");
Register("vsto", "application/x-ms-vsto");
Register("vsw", "application/vnd.visio");
Register("vsx", "application/vnd.visio");
Register("vtx", "application/vnd.visio");
Register("wav", "audio/wav");
Register("wave", "audio/wav");
Register("wax", "audio/x-ms-wax");
Register("wbk", "application/msword");
Register("wbmp", "image/vnd.wap.wbmp");
Register("wcm", "application/vnd.ms-works");
Register("wdb", "application/vnd.ms-works");
Register("wdp", "image/vnd.ms-photo");
Register("webarchive", "application/x-safari-webarchive");
Register("webtest", "application/xml");
Register("wiq", "application/xml");
Register("wiz", "application/msword");
Register("wks", "application/vnd.ms-works");
Register("WLMP", "application/wlmoviemaker");
Register("wlpginstall", "application/x-wlpg-detect");
Register("wlpginstall3", "application/x-wlpg3-detect");
Register("wm", "video/x-ms-wm");
Register("wma", "audio/x-ms-wma");
Register("wmd", "application/x-ms-wmd");
Register("wmf", "application/x-msmetafile");
Register("wml", "text/vnd.wap.wml");
Register("wmlc", "application/vnd.wap.wmlc");
Register("wmls", "text/vnd.wap.wmlscript");
Register("wmlsc", "application/vnd.wap.wmlscriptc");
Register("wmp", "video/x-ms-wmp");
Register("wmv", "video/x-ms-wmv");
Register("wmx", "video/x-ms-wmx");
Register("wmz", "application/x-ms-wmz");
Register("wpl", "application/vnd.ms-wpl");
Register("wps", "application/vnd.ms-works");
Register("wri", "application/x-mswrite");
Register("wrl", "x-world/x-vrml");
Register("wrz", "x-world/x-vrml");
Register("wsc", "text/scriptlet");
Register("wsdl", "text/xml");
Register("wvx", "video/x-ms-wvx");
Register("x", "application/directx");
Register("xaf", "x-world/x-vrml");
Register("xaml", "application/xaml+xml");
Register("xap", "application/x-silverlight-app");
Register("xbap", "application/x-ms-xbap");
Register("xbm", "image/x-xbitmap");
Register("xdr", "text/plain");
Register("xht", "application/xhtml+xml");
Register("xhtml", "application/xhtml+xml");
Register("xla", "application/vnd.ms-excel");
Register("xlam", "application/vnd.ms-excel.addin.macroEnabled.12");
Register("xlc", "application/vnd.ms-excel");
Register("xld", "application/vnd.ms-excel");
Register("xlk", "application/vnd.ms-excel");
Register("xll", "application/vnd.ms-excel");
Register("xlm", "application/vnd.ms-excel");
Register("xls", "application/vnd.ms-excel");
Register("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12");
Register("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12");
Register("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
Register("xlt", "application/vnd.ms-excel");
Register("xltm", "application/vnd.ms-excel.template.macroEnabled.12");
Register("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template");
Register("xlw", "application/vnd.ms-excel");
Register("xml", "text/xml");
Register("xmta", "application/xml");
Register("xof", "x-world/x-vrml");
Register("XOML", "text/plain");
Register("xpm", "image/x-xpixmap");
Register("xps", "application/vnd.ms-xpsdocument");
Register("xrm-ms", "text/xml");
Register("xsc", "application/xml");
Register("xsd", "text/xml");
Register("xsf", "text/xml");
Register("xsl", "text/xml");
Register("xslt", "text/xml");
Register("xsn", "application/octet-stream");
Register("xss", "application/xml");
Register("xtp", "application/octet-stream");
Register("xwd", "image/x-xwindowdump");
Register("z", "application/x-compress");
Register("zip", "application/x-zip-compressed");
#endregion
}
private static readonly string[] _TextTypes =
{
"text/", "/xml", "+xml", "/html", "+html", "/javascript", "/x-javascript", "+x-javascript", "/json", "+json",
"/vbscript", "+vbscript", "/css", "+css"
};
private static readonly string[] _ImageTypes =
{
"image/", "/bmp", "/png", "/jpeg", "/pjpeg", "/tiff", "/pict", "/x-icon", "/x-portable-anymap", "/x-portable-pixmap",
"/x-portable-bitmap", "/x-xpixmap", "/x-xbitmap", "/x-xwindowdump", "/x-macpaint"
};
public static bool IsCommonText(FileMime mime)
{
return mime.MimeType.ContainsAny(true, _TextTypes);
}
public static bool IsCommonImage(FileMime mime)
{
return mime.MimeType.ContainsAny(true, _ImageTypes);
}
public static bool Exists(string ext)
{
if (ext != null)
{
ext = ext.Trim('.');
ext = ext.Trim();
return _Registry.ContainsKey(ext);
}
return false;
}
public static void Register(string ext, string type)
{
if (ext != null)
{
ext = ext.Trim('.');
ext = ext.Trim();
_Registry[ext] = new FileMime(ext, type);
}
}
public static bool Unregister(string ext)
{
if (ext == null)
{
return false;
}
ext = ext.Trim('.');
ext = ext.Trim();
return _Registry.Remove(ext);
}
public static FileMime ReverseLookup(string type)
{
ReverseLookup(type, out var mime);
return mime;
}
public static bool ReverseLookup(string type, out FileMime mime)
{
type = type ?? String.Empty;
type = type.Trim();
if (type.Contains('/'))
{
var i = type.IndexOf(' ');
if (i > -1)
{
foreach (var t in type.Split(' ').Where(s => s.Contains('/')))
{
if (ReverseLookup(t, out mime))
{
return true;
}
}
}
else
{
type = type.Trim();
type = type.TrimEnd(';');
foreach (var m in _Registry.Values.Where(m => Insensitive.Equals(m.MimeType, type)))
{
mime = m;
return true;
}
}
}
mime = Default;
return false;
}
public static FileMime Lookup(FileInfo file)
{
return Lookup(file.Extension);
}
public static FileMime Lookup(string path)
{
Lookup(path, out var mime);
return mime;
}
public static bool Lookup(FileInfo file, out FileMime mime)
{
return Lookup(file.Extension, out mime);
}
public static bool Lookup(string path, out FileMime mime)
{
path = path ?? String.Empty;
path = path.Trim();
var ext = path;
var i = ext.LastIndexOf('.');
if (i > -1)
{
ext = ext.Substring(i + 1);
ext = ext.Trim();
}
else
{
i = ext.IndexOf(' ');
if (i > -1)
{
ext = ext.Substring(0, i);
}
}
if (_Registry.TryGetValue(ext, out mime))
{
return true;
}
i = path.IndexOf(' ');
if (i > -1)
{
path = path.Substring(0, i);
}
if (ReverseLookup(path, out mime))
{
return true;
}
mime = Default;
return false;
}
private readonly string _Extension;
private readonly string _MimeType;
public string Extension => _Extension;
public string MimeType => _MimeType;
public bool IsDefault => _Extension == "*";
private FileMime(string ext, string type)
{
_Extension = ext ?? "*";
_MimeType = type ?? "application/octet-stream";
}
public bool IsCommonText()
{
return IsCommonText(this);
}
public bool IsCommonImage()
{
return IsCommonImage(this);
}
public bool IsMatch(FileInfo file)
{
return Lookup(file) == this;
}
public bool IsMatch(string path)
{
return Lookup(path) == this;
}
public override string ToString()
{
return MimeType;
}
public override int GetHashCode()
{
return Extension.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is FileMime && Equals((FileMime)obj);
}
public bool Equals(FileMime mime)
{
return Insensitive.Equals(Extension, mime.Extension);
}
public int CompareTo(FileMime mime)
{
return Insensitive.Compare(Extension, mime.Extension);
}
public static bool operator ==(FileMime l, FileMime r)
{
return l.Equals(r);
}
public static bool operator !=(FileMime l, FileMime r)
{
return !l.Equals(r);
}
public static bool operator ==(FileMime l, string r)
{
return l.Equals(Lookup(r));
}
public static bool operator !=(FileMime l, string r)
{
return !l.Equals(Lookup(r));
}
public static bool operator ==(string l, FileMime r)
{
return Lookup(l).Equals(r);
}
public static bool operator !=(string l, FileMime r)
{
return !Lookup(l).Equals(r);
}
public static implicit operator string(FileMime mime)
{
return mime.MimeType;
}
public static implicit operator FileMime(string path)
{
return Lookup(path);
}
public static implicit operator FileMime(FileInfo file)
{
return Lookup(file);
}
}
}

View File

@@ -0,0 +1,292 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Server;
#endregion
namespace VitaNex.IO
{
public static class IOUtility
{
public static char PathSeparator => Path.DirectorySeparatorChar;
/// <summary>
/// Parses a given file path and returns the same path with any syntax errors removed.
/// Syntax errors can include double seperators such as 'path/to//file.txt'
/// </summary>
/// <param name="initialPath">The initial path string to parse.</param>
/// <param name="incFileName">
/// Determines whether to append a file name to the parsed path.
/// This will only append if a file name is specified in the initial path.
/// </param>
/// <returns>The parsed path string with syntax errors removed.</returns>
public static string GetSafeFilePath(string initialPath, bool incFileName)
{
var sb = new StringBuilder();
var split = initialPath.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < split.Length; i++)
{
if (i < split.Length - 1)
{
sb.AppendFormat("{0}{1}", split[i], PathSeparator);
}
else if (incFileName)
{
sb.AppendFormat("{0}", split[i]);
}
}
if (Core.Unix && sb[0] != PathSeparator)
{
sb.Insert(0, PathSeparator);
}
return sb.ToString();
}
public static string GetFileName(string path)
{
return Path.GetFileName(path);
}
/// <summary>
/// Gets a safe file name string by replacing all invalid characters with a specified char filter
/// </summary>
/// <param name="name">String to parse</param>
/// <param name="replace">
/// Replacement char for invalid chars
/// </param>
/// <returns></returns>
public static string GetSafeFileName(string name, char replace = '_')
{
return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replace));
}
public static string GetUnusedFilePath(string path, string name)
{
var fullPath = GetSafeFilePath(path + PathSeparator + name, true);
for (var i = 2; File.Exists(fullPath) && i <= 1000; ++i)
{
var split = name.Split('.');
fullPath = split.Length == 2
? GetSafeFilePath(path + PathSeparator + split[0] + i + "." + split[1], true)
: GetSafeFilePath(path + PathSeparator + name + i, true);
}
return fullPath;
}
/// <summary>
/// Invalidates the given file path and returns the cleaned path string with the appended file name.
/// Unlike SafeFilePath, this method does not remove syntax errors.
/// </summary>
/// <param name="filePath">The file path to invalidate.</param>
/// <param name="fileName">The file name to append.</param>
/// <returns>The cleaned path string with the appended file name.</returns>
public static string GetValidFilePath(string filePath, string fileName)
{
var lookup = filePath.Substring(filePath.Length - 1, 1).IndexOfAny(new[] { '\\', '/' });
var hasEndSep = lookup != -1;
if (hasEndSep)
{
filePath = filePath.Substring(0, lookup);
}
var split = filePath.Split('\\', '/');
var validPath = split.Aggregate("", (current, t) => current + (t + PathSeparator));
if (fileName.Length > 0)
{
validPath += fileName.TrimStart('\\', '/');
}
else
{
validPath = validPath.TrimEnd('\\', '/');
}
if (Core.Unix && !validPath.StartsWith(PathSeparator.ToString(CultureInfo.InvariantCulture)))
{
validPath = PathSeparator + validPath;
}
return validPath;
}
/// <summary>
/// Ensures a files' existence
/// </summary>
/// <param name="name">File path</param>
/// <param name="replace">True: replace the file if it exists</param>
/// <returns>FileInfo representing the file ensured for 'name'</returns>
public static FileInfo EnsureFile(string name, bool replace = false)
{
return new FileInfo(GetSafeFilePath(name, true)).EnsureFile(replace);
}
/// <summary>
/// Parses a given directory path and returns the same path with any syntax errors removed.
/// Syntax errors can include double seperators such as 'path/to//directory'
/// </summary>
/// <param name="initialPath">The initial path string to parse.</param>
/// <returns>The parsed path string with syntax errors removed.</returns>
public static string GetSafeDirectoryPath(string initialPath)
{
if (initialPath.LastIndexOf('.') >= 0)
{
var file = Path.GetFileName(initialPath);
if (!String.IsNullOrWhiteSpace(file))
{
initialPath = initialPath.Replace(file, String.Empty);
}
}
var sb = new StringBuilder();
var split = initialPath.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var t in split)
{
sb.AppendFormat("{0}{1}", t, PathSeparator);
}
if (Core.Unix && sb[0] != PathSeparator)
{
sb.Insert(0, PathSeparator);
}
return sb.ToString();
}
public static string GetUnusedDirectoryPath(string path, string name)
{
var fullPath = GetSafeDirectoryPath(path + PathSeparator + name);
for (var i = 2; Directory.Exists(fullPath) && i <= 1000; ++i)
{
fullPath = GetSafeDirectoryPath(path + PathSeparator + name + i);
}
return fullPath;
}
/// <summary>
/// Invalidates the given directory path and returns the cleaned path string.
/// Unlike GetSafeDirectoryPath, this method does not remove syntax errors.
/// </summary>
/// <param name="path">The directory path to invalidate.</param>
/// <returns>The cleaned directory path string.</returns>
public static string GetValidDirectoryPath(string path)
{
var lookup = path.Substring(path.Length - 1, 1).IndexOfAny(new[] { '\\', '/' });
var hasEndSep = lookup != -1;
if (hasEndSep)
{
path = path.Substring(0, lookup);
}
var split = path.Split('\\', '/');
var validPath = split.Aggregate("", (current, t) => current + (t + PathSeparator));
if (!validPath.EndsWith("\\") && !validPath.EndsWith("/"))
{
validPath += PathSeparator;
}
if (Core.Unix && !validPath.StartsWith(PathSeparator.ToString(CultureInfo.InvariantCulture)))
{
validPath = PathSeparator + validPath;
}
return validPath;
}
/// <summary>
/// Ensures a directories' existence
/// </summary>
/// <param name="name">Directory path</param>
/// <param name="replace">True: replace the directory if it exists</param>
/// <returns>DirectoryInfo representing the directory ensured for 'name'</returns>
public static DirectoryInfo EnsureDirectory(string name, bool replace = false)
{
return new DirectoryInfo(GetSafeDirectoryPath(name)).EnsureDirectory(replace);
}
/// <summary>
/// Gets the base directory, relative the current Executing Assembly location.
/// </summary>
/// <returns>Fully qualified directory path for the the current Executing Assembly location.</returns>
public static string GetBaseDirectory()
{
return GetSafeDirectoryPath(GetSafeFilePath(Assembly.GetExecutingAssembly().Location, false));
}
/// <summary>
/// Gets the base executable path, relative the current Executing Assembly location.
/// </summary>
/// <returns>Fully qualified executable path for the the current Executing Assembly location.</returns>
public static string GetExePath()
{
return GetSafeFilePath(Core.ExePath, true);
}
/// <summary>
/// Reverses the directory seperator character in the given path string.
/// \ becomes / and vice-versa.
/// </summary>
/// <param name="path">The path to reverse.</param>
/// <returns>The given path with the directory seperator characters reversed.</returns>
public static string ReversePath(string path)
{
var split = path.Split('\\');
if (split.Length > 0)
{
return path.Replace("\\", "/");
}
split = path.Split('/');
if (split.Length > 0)
{
return path.Replace("/", "\\");
}
return path;
}
public static FileStream OpenRead(string path, bool create = false, bool replace = false)
{
return new FileInfo(GetSafeFilePath(path, true)).OpenRead(create, replace);
}
public static FileStream OpenWrite(string path, bool create = false, bool replace = false)
{
return new FileInfo(GetSafeFilePath(path, true)).OpenWrite(create, replace);
}
}
}

View File

@@ -0,0 +1,261 @@
#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.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using Server;
using VitaNex.Crypto;
#endregion
namespace VitaNex.IO
{
public sealed class VirtualAsset : Grid<Color>, IEquatable<VirtualAsset>
{
private static readonly object _CacheLock = new object();
public static readonly VirtualAsset Empty = new VirtualAsset();
public static Dictionary<string, VirtualAsset> AssetCache { get; private set; }
public static int CacheCapacity { get; set; }
static VirtualAsset()
{
AssetCache = new Dictionary<string, VirtualAsset>(CacheCapacity = 512);
}
public static bool IsNullOrEmpty(VirtualAsset asset)
{
return asset == null || asset == Empty || asset.Hash == Empty.Hash || asset.Capacity == 0 || asset.Count == 0;
}
public static VirtualAsset CreateInstance(FileInfo file)
{
return CreateInstance(file, true);
}
public static VirtualAsset CreateInstance(FileInfo file, bool cache)
{
return CreateInstance(file, cache, false);
}
public static VirtualAsset CreateInstance(FileInfo file, bool cache, bool reload)
{
if (file == null || !file.Exists)
{
return Empty;
}
return VitaNexCore.TryCatchGet(
() =>
{
var hash = CryptoGenerator.GenString(CryptoHashType.MD5, file.FullName);
VirtualAsset a;
lock (_CacheLock)
{
if (!AssetCache.TryGetValue(hash, out a))
{
a = Empty;
}
}
if (reload || IsNullOrEmpty(a))
{
using (var img = new Bitmap(file.FullName, true))
{
a = new VirtualAsset(file, img);
}
}
if (IsNullOrEmpty(a))
{
return Empty;
}
lock (_CacheLock)
{
if (cache)
{
AssetCache[a.Hash] = a;
}
else
{
AssetCache.Remove(a.Hash);
}
if (AssetCache.Count > CacheCapacity)
{
AssetCache.Pop();
}
}
return a;
});
}
public static bool IsValidAsset(string path)
{
if (String.IsNullOrWhiteSpace(path))
{
return false;
}
path = path.ToLower();
return path.EndsWith("bmp") || path.EndsWith("jpg") || path.EndsWith("jpeg") || path.EndsWith("png") ||
path.EndsWith("gif") || path.EndsWith("tiff") || path.EndsWith("exif");
}
public static VirtualAsset LoadAsset(string path)
{
if (!IsValidAsset(path))
{
return Empty;
}
if (!Insensitive.StartsWith(path, "http://") && !Insensitive.StartsWith(path, "https://"))
{
return LoadAsset(new FileInfo(path));
}
return LoadAsset(new Uri(path));
}
public static VirtualAsset LoadAsset(Uri url)
{
if (url == null)
{
return Empty;
}
return VitaNexCore.TryCatchGet(
() =>
{
if (!IsValidAsset(url.LocalPath))
{
return Empty;
}
var file = new FileInfo(VitaNexCore.DataDirectory + "/Assets/" + url.Host + "/" + url.LocalPath);
if (!file.Exists)
{
file = file.EnsureFile();
using (var c = new WebClient())
{
c.DownloadFile(url, file.FullName);
}
}
return LoadAsset(file);
});
}
public static VirtualAsset LoadAsset(FileInfo file)
{
if (file == null || !IsValidAsset(file.FullName))
{
return Empty;
}
return VitaNexCore.TryCatchGet(
() =>
{
var asset = CreateInstance(file);
if (IsNullOrEmpty(asset))
{
return Empty;
}
if (file.Exists)
{
return asset;
}
file.EnsureFile();
using (var img = new Bitmap(asset.Width, asset.Height))
{
asset.ForEach(img.SetPixel);
img.Save(file.FullName);
}
return asset;
});
}
public string File { get; private set; }
public string Name { get; private set; }
public string Hash { get; private set; }
private VirtualAsset()
: base(0, 0)
{
File = String.Empty;
Name = String.Empty;
Hash = CryptoGenerator.GenString(CryptoHashType.MD5, File);
DefaultValue = Color.Transparent;
}
private VirtualAsset(FileInfo file, Bitmap img)
: base(img.Width, img.Height)
{
File = file.FullName;
Name = Path.GetFileName(File);
Hash = CryptoGenerator.GenString(CryptoHashType.MD5, File);
DefaultValue = Color.Transparent;
SetAllContent(img.GetPixel);
}
public override string ToString()
{
return File;
}
public override int GetHashCode()
{
return Hash.Aggregate(Hash.Length, (h, c) => unchecked((h * 397) ^ c));
}
public override bool Equals(object obj)
{
return obj is VirtualAsset && Equals((VirtualAsset)obj);
}
public bool Equals(VirtualAsset other)
{
return !ReferenceEquals(other, null) && Hash == other.Hash;
}
public static bool operator ==(VirtualAsset l, VirtualAsset r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(VirtualAsset l, VirtualAsset r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
}
}

View File

@@ -0,0 +1,137 @@
#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;
#endregion
namespace VitaNex.IO
{
public class VirtualDirectory : IEquatable<VirtualDirectory>, IEquatable<string>
{
public VirtualDirectory Parent { get; private set; }
public string Name { get; private set; }
public string FullName { get; private set; }
public bool HasParent => Parent != null;
public bool IsRoot => !HasParent;
public bool IsEmpty => String.IsNullOrWhiteSpace(FullName);
public int Depth => GetParents().Count();
public VirtualDirectory(string path)
{
FullName = path != null ? IOUtility.GetSafeDirectoryPath(path).TrimEnd(IOUtility.PathSeparator) : String.Empty;
var parents = FullName.Split(new[] { IOUtility.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
if (parents.Length == 0)
{
Name = FullName;
return;
}
Name = parents.LastOrDefault() ?? FullName;
if (parents.Length > 1)
{
Parent = new VirtualDirectory(String.Join("/", parents.Take(parents.Length - 1)));
}
}
public virtual bool IsChildOf(VirtualDirectory d)
{
if (d == null)
{
return false;
}
var p = Parent;
while (p != null)
{
if (p == d)
{
return true;
}
p = p.Parent;
}
return false;
}
public virtual IEnumerable<VirtualDirectory> GetParents()
{
var c = this;
while (c.HasParent)
{
c = c.Parent;
yield return c;
}
}
public override int GetHashCode()
{
unchecked
{
var hash = FullName.Length;
hash = (hash * 397) ^ FullName.ToLower().GetHashCode();
return hash;
}
}
public override bool Equals(object obj)
{
return (obj is string && Equals((string)obj)) || (obj is VirtualDirectory && Equals((VirtualDirectory)obj));
}
public virtual bool Equals(VirtualDirectory other)
{
return !ReferenceEquals(other, null) && Equals(other.FullName);
}
public virtual bool Equals(string other)
{
return Insensitive.Equals(
FullName,
other != null ? IOUtility.GetSafeDirectoryPath(other).TrimEnd(IOUtility.PathSeparator) : String.Empty);
}
public static bool operator ==(VirtualDirectory l, VirtualDirectory r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(VirtualDirectory l, VirtualDirectory r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
public static implicit operator VirtualDirectory(string path)
{
return new VirtualDirectory(path);
}
public static implicit operator string(VirtualDirectory path)
{
return ReferenceEquals(path, null) ? String.Empty : path.FullName;
}
}
}

View File

@@ -0,0 +1,913 @@
#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;
using Server.ContextMenus;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
#endregion
namespace VitaNex.Items
{
public class RuneCodex : Item, ISecurable
{
public sealed class UICache : IEquatable<UICache>, IEquatable<PlayerMobile>
{
public enum ViewMode
{
Categories,
Entries
}
public PlayerMobile User { get; private set; }
public RuneCodexCategory Category { get; set; }
public Point2D CategoryScroll { get; set; }
public Point2D CategoryPoint { get; set; }
public RuneCodexEntry Entry { get; set; }
public Point2D EntryScroll { get; set; }
public Point2D EntryPoint { get; set; }
public ViewMode Mode { get; set; }
public bool EditMode { get; set; }
public UICache(PlayerMobile user)
{
User = user;
}
public override int GetHashCode()
{
return User == null ? 0 : User.Serial.Value;
}
public override bool Equals(object obj)
{
if (obj is UICache)
{
return Equals((UICache)obj);
}
if (obj is PlayerMobile)
{
return Equals((PlayerMobile)obj);
}
return false;
}
public bool Equals(UICache other)
{
return other != null && Equals(other.User);
}
public bool Equals(PlayerMobile other)
{
return User == other;
}
}
public static string DefaultDescription = "World Locations";
private string _Descripton = DefaultDescription;
private int _Charges;
[CommandProperty(AccessLevel.GameMaster)]
public string Descripton { get => _Descripton; set => SetDescription(value); }
[CommandProperty(AccessLevel.GameMaster)]
public RuneCodexCategoryGrid Categories { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public SecureLevel Level { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int Charges
{
get => _Charges;
set
{
_Charges = Math.Max(0, value);
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int RecallChargeCost { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int GateChargeCost { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int CloneEntryChargeCost { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool EditLocked { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool AddLocked { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool RemoveLocked { get; set; }
public Dictionary<Type, int> ChargeTypes { get; private set; }
public List<UICache> Users { get; private set; }
[Constructable]
public RuneCodex()
: this(1000)
{ }
[Constructable]
public RuneCodex(int charges)
: base(0x22C5)
{
Users = new List<UICache>();
ChargeTypes = new Dictionary<Type, int>
{
{typeof(Gold), 100}
};
Categories = new RuneCodexCategoryGrid();
Charges = Math.Max(0, charges);
CloneEntryChargeCost = 5;
RecallChargeCost = 1;
GateChargeCost = 2;
Name = "Rune Codex";
Weight = 1.0;
Hue = 74;
LootType = LootType.Blessed;
}
public RuneCodex(Serial serial)
: base(serial)
{
Users = new List<UICache>();
}
public virtual bool CanAddCategories(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!AddLocked && IsAccessibleTo(m));
}
public virtual bool CanEditCategories(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!EditLocked && IsAccessibleTo(m));
}
public virtual bool CanRemoveCategories(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!RemoveLocked && IsAccessibleTo(m));
}
public virtual bool CanAddEntries(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!AddLocked && IsAccessibleTo(m));
}
public virtual bool CanEditEntries(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!EditLocked && IsAccessibleTo(m));
}
public virtual bool CanRemoveEntries(Mobile m)
{
return m.AccessLevel > AccessLevel.Counselor || BlessedFor == m || (!RemoveLocked && IsAccessibleTo(m));
}
public override bool IsAccessibleTo(Mobile check)
{
return check.AccessLevel > AccessLevel.Counselor || BlessedFor == check || base.IsAccessibleTo(check);
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
SetSecureLevelEntry.AddTo(from, this, list);
}
public override void OnDoubleClick(Mobile m)
{
if (!this.CheckDoubleClick(m, true, false, 3) || !(m is PlayerMobile))
{
return;
}
var pm = (PlayerMobile)m;
var ui = Users.FirstOrDefault(uic => uic.User == pm) ?? new UICache(pm);
Users.Update(ui);
new RuneCodexGump(pm, this).Send();
}
public void SetDescription(string desc)
{
_Descripton = String.IsNullOrWhiteSpace(desc) ? DefaultDescription : desc;
InvalidateProperties();
}
public virtual bool CanChargeWith(Mobile m, Item item, out int cost, bool message)
{
cost = 0;
if (m == null || m.Deleted || item == null || item.Deleted || !item.IsAccessibleTo(m))
{
return false;
}
var t = item.GetType();
if (ChargeTypes.ContainsKey(t))
{
cost = ChargeTypes[t];
return true;
}
if (message)
{
m.SendMessage("That item is not accepted for charging this codex.");
}
return false;
}
public virtual bool AddCharges(Mobile m, Item item, bool message)
{
if (m == null || m.Deleted || item == null || item.Deleted || !item.IsAccessibleTo(m))
{
return false;
}
if (!CanChargeWith(m, item, out var cost, message))
{
return false;
}
if (item.Amount < cost)
{
if (message)
{
m.SendMessage("One charge costs {0:#,0} {1}.", cost, item.ResolveName(m));
}
return false;
}
var c = (int)Math.Min((long)(Charges + (int)Math.Floor(item.Amount / (double)cost)), Int32.MaxValue) - Charges;
if (c <= 0)
{
return false;
}
var con = c * cost;
item.Consume(con);
Charges += c;
if (message)
{
m.SendMessage(
"You added {0:#,0} charge{1} to the codex and consumed {2:#,0} {3}.",
c,
c != 1 ? "s" : String.Empty,
con,
item.ResolveName());
}
InvalidateProperties();
return true;
}
public virtual bool AddRunebook(Mobile m, Runebook book, RuneCodexCategory cat, bool message)
{
if (m == null || m.Deleted || book == null || book.Deleted || !book.IsAccessibleTo(m))
{
return false;
}
if (cat == null)
{
var pm = m as PlayerMobile;
if (pm != null)
{
var ui = Users.FirstOrDefault(uic => uic.User == pm);
if (ui != null)
{
cat = ui.Category ?? Categories[ui.CategoryPoint.X, ui.CategoryPoint.Y];
}
else
{
cat = Categories[0, 0];
}
}
else
{
cat = Categories[0, 0];
}
}
if (book.Entries == null || book.Entries.Count == 0)
{
if (message)
{
m.SendMessage("That rune book is empty.");
}
return false;
}
if (Categories.Count >= Categories.Capacity)
{
if (message)
{
m.SendMessage("This rune codex can't hold more categories.");
}
return false;
}
if (cat != null && cat.AddRunebook(m, book, message))
{
InvalidateProperties();
return true;
}
return false;
}
public virtual bool AddRune(Mobile m, RecallRune rune, RuneCodexCategory cat, bool message)
{
if (m == null || m.Deleted || rune == null || rune.Deleted || !rune.IsAccessibleTo(m))
{
return false;
}
var pm = m as PlayerMobile;
var loc = Point2D.Zero;
if (cat == null)
{
if (pm != null)
{
var ui = Users.FirstOrDefault(uic => uic.User == pm);
if (ui != null)
{
cat = ui.Category ?? Categories[ui.CategoryPoint.X, ui.CategoryPoint.Y];
loc = ui.EntryPoint;
}
else
{
cat = Categories[0, 0];
}
}
else
{
cat = Categories[0, 0];
}
}
if (!rune.Marked || rune.Target == Point3D.Zero || rune.TargetMap == Map.Internal)
{
if (message)
{
m.SendMessage("That rune is blank.");
}
return false;
}
if (cat != null)
{
if (cat.Entries.Count >= cat.Entries.Capacity)
{
if (message)
{
m.SendMessage("The rune codex category \"{0}\" can't hold more runes.", cat.Description);
}
return false;
}
if (cat.SetRune(m, rune, loc, message))
{
InvalidateProperties();
return true;
}
}
return false;
}
public bool Add(Mobile m, Item item, RuneCodexCategory cat, bool message)
{
if (m == null || m.Deleted || item == null || item.Deleted || !item.IsAccessibleTo(m))
{
return false;
}
if (item is RecallRune)
{
return AddRune(m, (RecallRune)item, cat, message);
}
if (item is Runebook)
{
return AddRunebook(m, (Runebook)item, cat, message);
}
#region Master Runebook Support
//Using Reflection for shards that don't have it installed.
var t = item.GetType();
if (Insensitive.Equals(t.Name, "MasterRunebook"))
{
var pi = t.GetProperty("Books");
if (pi != null && pi.CanRead)
{
var obj = pi.GetValue(item, null);
if (obj is ICollection)
{
var ex = new Queue<Runebook>(((ICollection)obj).OfType<Runebook>().Where(r => r.Entries.Count > 0));
if (ex.Count == 0)
{
if (message)
{
m.SendMessage("That master rune book is empty.");
}
return false;
}
if (Categories.Count + ex.Count > Categories.Capacity)
{
if (message)
{
m.SendMessage("That master rune book won't fit in this rune codex.");
}
return false;
}
var extracted = 0;
while (ex.Count > 0)
{
var b = ex.Dequeue();
if (AddRunebook(m, b, cat, message))
{
++extracted;
}
}
if (extracted > 0)
{
if (message)
{
m.SendMessage(
"You extract {0:#,0} book{1} from the master rune book and add them to the codex.",
extracted,
extracted != 1 ? "s" : String.Empty);
}
return true;
}
if (message)
{
m.SendMessage("There was nothing in the master rune book to extract.");
}
}
}
return false;
}
#endregion Master Runebook Support
if (AddCharges(m, item, message))
{
return item.Deleted;
}
if (message)
{
m.SendMessage("Drop a rune book or recall rune on the codex to add them.");
}
return false;
}
public bool Remove(RuneCodexCategory cat)
{
for (var x = 0; x < Categories.Width; x++)
{
for (var y = 0; y < Categories.Height; y++)
{
if (Categories[x, y] != cat)
{
continue;
}
Categories[x, y] = null;
InvalidateProperties();
return true;
}
}
return false;
}
public bool Drop(Mobile m, RuneCodexCategory cat, bool message)
{
if (m == null || m.Deleted || cat == null)
{
return false;
}
if (cat.Entries == null || cat.Entries.Count == 0)
{
if (message)
{
m.SendMessage("The category \"{0}\" is empty.", cat.Name);
}
return false;
}
var cost = CloneEntryChargeCost * cat.Entries.Count;
if (!ConsumeCharges(cost))
{
if (message)
{
m.SendMessage("This action requires {0:#,0} charge{1}.", cost, cost != 1 ? "s" : String.Empty);
}
return false;
}
var entries = new Queue<RuneCodexEntry>(cat.Entries.Not(e => e == null));
var book = new Runebook();
var count = 1;
while (entries.Count > 0)
{
var entry = entries.Dequeue();
if (entry == null)
{
continue;
}
book.Entries.Add(
new RunebookEntry(
entry.Location,
entry.Location,
entry.Name,
BaseHouse.FindHouseAt(entry.Location, entry.Location, 16)));
if (book.Entries.Count < 16 && entries.Count > 0)
{
continue;
}
m.AddToBackpack(book);
if (entries.Count == 0)
{
continue;
}
book = new Runebook();
++count;
}
if (message)
{
m.SendMessage(
"You created {0:#,0} rune book{1} and consumed {2:#,0} charge{3} from the codex.",
count,
count != 1 ? "s" : String.Empty,
cost,
cost != 1 ? "s" : String.Empty);
}
return true;
}
public bool Drop(Mobile m, RuneCodexEntry entry, bool message)
{
if (m == null || m.Deleted || entry == null)
{
return false;
}
if (!ConsumeCharges(CloneEntryChargeCost))
{
m.SendMessage(
"This action requires {0:#,0} charge{1}.",
CloneEntryChargeCost,
CloneEntryChargeCost != 1 ? "s" : String.Empty);
return false;
}
m.AddToBackpack(
new RecallRune
{
Marked = true,
Target = entry.Location,
TargetMap = entry.Location,
Description = entry.Name,
House = BaseHouse.FindHouseAt(entry.Location, entry.Location, 16)
});
if (message)
{
m.SendMessage(
"You create a recall rune and consume {0:#,0} charge{1} from the codex.",
CloneEntryChargeCost,
CloneEntryChargeCost != 1 ? "s" : String.Empty);
}
return true;
}
public bool Recall(Mobile m, RuneCodexEntry entry, bool message)
{
if (m == null || m.Deleted || entry == null)
{
return false;
}
if (!ConsumeCharges(RecallChargeCost))
{
m.SendMessage(
"This action requires {0:#,0} charge{1}.",
RecallChargeCost,
RecallChargeCost != 1 ? "s" : String.Empty);
return false;
}
if (!entry.Recall(m))
{
Charges += RecallChargeCost;
return false;
}
return true;
}
public bool Gate(Mobile m, RuneCodexEntry entry, bool message)
{
if (m == null || m.Deleted || entry == null)
{
return false;
}
if (!ConsumeCharges(GateChargeCost))
{
m.SendMessage("This action requires {0:#,0} charge{1}.", GateChargeCost, GateChargeCost != 1 ? "s" : String.Empty);
return false;
}
if (!entry.Gate(m))
{
Charges += GateChargeCost;
return false;
}
return true;
}
public override bool OnDragDrop(Mobile m, Item dropped)
{
return Add(m, dropped, null, true);
}
public override void OnAfterDuped(Item newItem)
{
base.OnAfterDuped(newItem);
var c = newItem as RuneCodex;
if (c == null)
{
return;
}
c.AddLocked = AddLocked;
c.EditLocked = EditLocked;
c.RemoveLocked = RemoveLocked;
c.CloneEntryChargeCost = CloneEntryChargeCost;
c.RecallChargeCost = RecallChargeCost;
c.GateChargeCost = GateChargeCost;
c.Charges = Charges;
c.Descripton = Descripton;
c.Categories = new RuneCodexCategoryGrid();
c.ChargeTypes = new Dictionary<Type, int>(ChargeTypes);
c.Users = new List<UICache>();
RuneCodexCategory cata, catb;
RuneCodexEntry entrya, entryb;
for (var cx = 0; cx < Categories.Width; cx++)
{
for (var cy = 0; cy < Categories.Height; cy++)
{
cata = Categories[cx, cy];
if (cata == null)
{
continue;
}
catb = new RuneCodexCategory(cata.Name, cata.Description, cata.Hue);
c.Categories.SetContent(cx, cy, catb);
for (var ex = 0; ex < cata.Entries.Width; ex++)
{
for (var ey = 0; ey < cata.Entries.Width; ey++)
{
entrya = cata.Entries[ex, ey];
if (entrya == null)
{
continue;
}
entryb = new RuneCodexEntry(entrya.Name, entrya.Description, entrya.Location);
catb.Entries.SetContent(ex, ey, entryb);
}
}
}
}
}
public virtual bool ConsumeCharges(int amount)
{
amount = Math.Max(0, amount);
if (Charges < amount)
{
return false;
}
Charges -= amount;
return true;
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
// charges: ~1_val~
list.Add(1060741, Charges.ToString("#,0"));
var eTotal = 0;
var eCap = 0;
foreach (var c in Categories.Not(c => c == null))
{
eTotal += c.Entries.Count;
eCap += c.Entries.Capacity;
}
list.Add("Categories: {0} / {1}\nEntries: {2} / {3}", Categories.Count, Categories.Capacity, eTotal, eCap);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(3);
switch (version)
{
case 3:
writer.WriteFlag(Level);
goto case 2;
case 2:
writer.Write(RemoveLocked);
goto case 1;
case 1:
{
writer.Write(EditLocked);
writer.Write(AddLocked);
writer.Write(CloneEntryChargeCost);
writer.WriteDictionary(
ChargeTypes,
(k, v) =>
{
writer.WriteType(k);
writer.Write(v);
});
}
goto case 0;
case 0:
{
writer.Write(Charges);
writer.Write(RecallChargeCost);
writer.Write(GateChargeCost);
writer.Write(_Descripton);
Categories.Serialize(writer);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 3:
Level = reader.ReadFlag<SecureLevel>();
goto case 2;
case 2:
RemoveLocked = reader.ReadBool();
goto case 1;
case 1:
{
EditLocked = reader.ReadBool();
AddLocked = reader.ReadBool();
CloneEntryChargeCost = reader.ReadInt();
ChargeTypes = reader.ReadDictionary(
() =>
{
var k = reader.ReadType();
var v = reader.ReadInt();
return new KeyValuePair<Type, int>(k, v);
});
}
goto case 0;
case 0:
{
Charges = reader.ReadInt();
RecallChargeCost = reader.ReadInt();
GateChargeCost = reader.ReadInt();
_Descripton = reader.ReadString();
Categories = new RuneCodexCategoryGrid(reader);
}
break;
}
if (version > 0)
{
return;
}
Charges = 1000;
CloneEntryChargeCost = 5;
RecallChargeCost = 1;
GateChargeCost = 2;
ChargeTypes = new Dictionary<Type, int>
{
{typeof(Gold), 100}
};
}
}
}

Some files were not shown because too many files have changed in this diff Show More