Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
19
Scripts/SubSystem/VitaNex/Core/.gitignore
vendored
Normal file
19
Scripts/SubSystem/VitaNex/Core/.gitignore
vendored
Normal 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
|
||||
361
Scripts/SubSystem/VitaNex/Core/Build/CSharpCompiler.cs
Normal file
361
Scripts/SubSystem/VitaNex/Core/Build/CSharpCompiler.cs
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Scripts/SubSystem/VitaNex/Core/Collections/Pools/GridPool.cs
Normal file
33
Scripts/SubSystem/VitaNex/Core/Collections/Pools/GridPool.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Scripts/SubSystem/VitaNex/Core/Collections/Pools/ListPool.cs
Normal file
39
Scripts/SubSystem/VitaNex/Core/Collections/Pools/ListPool.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
209
Scripts/SubSystem/VitaNex/Core/Collections/Pools/ObjectPool.cs
Normal file
209
Scripts/SubSystem/VitaNex/Core/Collections/Pools/ObjectPool.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Scripts/SubSystem/VitaNex/Core/Collections/Pools/SetPool.cs
Normal file
34
Scripts/SubSystem/VitaNex/Core/Collections/Pools/SetPool.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Scripts/SubSystem/VitaNex/Core/Commands/ExportBounds.cs
Normal file
122
Scripts/SubSystem/VitaNex/Core/Commands/ExportBounds.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/SubSystem/VitaNex/Core/Commands/ExportPoint.cs
Normal file
100
Scripts/SubSystem/VitaNex/Core/Commands/ExportPoint.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
484
Scripts/SubSystem/VitaNex/Core/Commands/FixMe.cs
Normal file
484
Scripts/SubSystem/VitaNex/Core/Commands/FixMe.cs
Normal 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);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Scripts/SubSystem/VitaNex/Core/Commands/GC.cs
Normal file
117
Scripts/SubSystem/VitaNex/Core/Commands/GC.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Scripts/SubSystem/VitaNex/Core/Commands/MyCommands.cs
Normal file
132
Scripts/SubSystem/VitaNex/Core/Commands/MyCommands.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
723
Scripts/SubSystem/VitaNex/Core/Commands/PlayerBackup.cs
Normal file
723
Scripts/SubSystem/VitaNex/Core/Commands/PlayerBackup.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Scripts/SubSystem/VitaNex/Core/Commands/Say.cs
Normal file
127
Scripts/SubSystem/VitaNex/Core/Commands/Say.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
397
Scripts/SubSystem/VitaNex/Core/Effects/EffectInfo.cs
Normal file
397
Scripts/SubSystem/VitaNex/Core/Effects/EffectInfo.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
319
Scripts/SubSystem/VitaNex/Core/Effects/EffectQueue.cs
Normal file
319
Scripts/SubSystem/VitaNex/Core/Effects/EffectQueue.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
363
Scripts/SubSystem/VitaNex/Core/Effects/FX/BaseFX.cs
Normal file
363
Scripts/SubSystem/VitaNex/Core/Effects/FX/BaseFX.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
427
Scripts/SubSystem/VitaNex/Core/Effects/FX/ExplosionFX.cs
Normal file
427
Scripts/SubSystem/VitaNex/Core/Effects/FX/ExplosionFX.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
303
Scripts/SubSystem/VitaNex/Core/Effects/FX/SpecialFX.cs
Normal file
303
Scripts/SubSystem/VitaNex/Core/Effects/FX/SpecialFX.cs
Normal 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();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
668
Scripts/SubSystem/VitaNex/Core/Effects/FX/WaveFX.cs
Normal file
668
Scripts/SubSystem/VitaNex/Core/Effects/FX/WaveFX.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AccountExtUtility
|
||||
{
|
||||
public static bool IsOnline(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).Any();
|
||||
}
|
||||
|
||||
public static Mobile GetOnlineMobile(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static TMob GetOnlineMobile<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc)
|
||||
{
|
||||
return GetMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] != null && (predicate == null || predicate(acc[i])))
|
||||
{
|
||||
yield return acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return GetMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] is TMob && (predicate == null || predicate((TMob)acc[i])))
|
||||
{
|
||||
yield return (TMob)acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return GetSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this Account acc)
|
||||
{
|
||||
return FindSharedAccounts(acc).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return FindSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this Account acc)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var a in Accounts.GetAccounts().AsParallel().OfType<Account>().Where(a => IsSharedWith(acc, a)))
|
||||
{
|
||||
yield return a;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this IAccount acc, IAccount a)
|
||||
{
|
||||
return IsSharedWith(acc as Account, a as Account);
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this Account acc, Account a)
|
||||
{
|
||||
return acc != null && a != null && (acc == a || acc.LoginIPs.Any(a.LoginIPs.Contains));
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && (a == b || a.Account == b.Account);
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, IAccount b)
|
||||
{
|
||||
return a != null && b != null && a.Account == b;
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this IAccount a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && a == b.Account;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AddonExtUtility
|
||||
{
|
||||
static AddonExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
}
|
||||
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static int ComputeHash(IAddon addon)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = -1;
|
||||
|
||||
hash = (hash * 397) ^ addon.GetTypeHashCode();
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
hash = (hash * 397) ^ comp.Count;
|
||||
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.GetTypeHashCode());
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.ItemID);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this IAddon addon)
|
||||
{
|
||||
if (addon == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = ComputeHash(addon);
|
||||
|
||||
var mcl = ComponentsCache.GetValue(hash);
|
||||
|
||||
if (mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
mcl = new MultiComponentList(MultiComponentList.Empty);
|
||||
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
|
||||
foreach (var c in comp)
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
x1 = Math.Min(off.X, x1);
|
||||
y1 = Math.Min(off.Y, y1);
|
||||
|
||||
x2 = Math.Max(off.X, x2);
|
||||
y2 = Math.Max(off.Y, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mcl.Resize(1 + (x2 - x1), 1 + (y2 - y1));
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
|
||||
foreach (var c in comp.OfType<Item>())
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
off = off.Clone3D(Math.Abs(x1), Math.Abs(y1));
|
||||
|
||||
mcl.Add(c.ItemID, off.X, off.Y, off.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addon is Item)
|
||||
{
|
||||
((Item)addon).Delete();
|
||||
}
|
||||
|
||||
return ComponentsCache[hash] = mcl;
|
||||
}
|
||||
}
|
||||
}
|
||||
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class BodyExtUtility
|
||||
{
|
||||
public static Dictionary<int, string> Names { get; private set; }
|
||||
|
||||
static BodyExtUtility()
|
||||
{
|
||||
Names = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
public static string GetName(this Body body)
|
||||
{
|
||||
if (body.IsEmpty)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
|
||||
if (Names.TryGetValue(body.BodyID, out var name) && !String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
var itemID = ShrinkTable.Lookup(body.BodyID) & TileData.MaxItemValue;
|
||||
|
||||
if (itemID == ShrinkTable.DefaultItemID)
|
||||
{
|
||||
name = String.Empty;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = ClilocLNG.NULL.GetRawString(itemID + (itemID < 0x4000 ? 1020000 : 1078872));
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = TileData.ItemTable[itemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = name.SpaceWords().ToUpperWords();
|
||||
|
||||
name = String.Concat(" ", name, " ");
|
||||
|
||||
if (body.IsHuman || body.IsGhost)
|
||||
{
|
||||
if (body >= 400 && body <= 403)
|
||||
{
|
||||
name = "Human";
|
||||
}
|
||||
else if (body >= 605 && body <= 608)
|
||||
{
|
||||
name = "Elf";
|
||||
}
|
||||
else if ((body >= 666 && body <= 667) || (body >= 694 && body <= 695))
|
||||
{
|
||||
name = "Gargoyle";
|
||||
}
|
||||
|
||||
if (body.IsMale && !Insensitive.Contains(name, "Male"))
|
||||
{
|
||||
name += " Male";
|
||||
}
|
||||
else if (body.IsFemale && !Insensitive.Contains(name, "Female"))
|
||||
{
|
||||
name += " Female";
|
||||
}
|
||||
|
||||
if (body.IsGhost && !Insensitive.Contains(name, "Ghost"))
|
||||
{
|
||||
name += " Ghost";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (itemID)
|
||||
{
|
||||
case 9611:
|
||||
name = "Evil Mage";
|
||||
break;
|
||||
case 9776:
|
||||
name = "Wanderer Of The Void";
|
||||
break;
|
||||
case 11676:
|
||||
name = "Charger";
|
||||
break;
|
||||
case 38990:
|
||||
name = "Baby Dragon Turtle";
|
||||
break;
|
||||
case 40369:
|
||||
name = "Aztec Golem";
|
||||
break;
|
||||
case 40374:
|
||||
name = "Myrmadex Queen";
|
||||
break;
|
||||
case 40420:
|
||||
name = "Spector";
|
||||
break;
|
||||
case 40429:
|
||||
name = "T-Rex";
|
||||
break;
|
||||
case 40501:
|
||||
name = "Rainbow Unicorn";
|
||||
break;
|
||||
case 40661:
|
||||
name = "Windrunner";
|
||||
break;
|
||||
case 40704:
|
||||
name = "Sabertooth Tiger";
|
||||
break;
|
||||
case 40705:
|
||||
name = "Small Platinum Dragon";
|
||||
break;
|
||||
case 40706:
|
||||
name = "Platinum Dragon";
|
||||
break;
|
||||
case 40710:
|
||||
name = "Small Crimson Dragon";
|
||||
break;
|
||||
case 40711:
|
||||
name = "Crimson Dragon";
|
||||
break;
|
||||
case 40713:
|
||||
name = "Small Fox";
|
||||
break;
|
||||
case 40714:
|
||||
name = "Small Stygian Dragon";
|
||||
break;
|
||||
case 40718:
|
||||
name = "Stygian Dragon";
|
||||
break;
|
||||
case 40976:
|
||||
name = "Eastern Dragon";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
name = name.Replace(" Fr ", " Frame ");
|
||||
|
||||
name = name.Replace("Frame", String.Empty);
|
||||
name = name.Replace("Statuette", String.Empty);
|
||||
name = name.Replace("Statue", String.Empty);
|
||||
|
||||
name = name.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
Names[body.BodyID] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static int GetPaperdoll(this Body body)
|
||||
{
|
||||
return ArtworkSupport.LookupGump(body);
|
||||
}
|
||||
|
||||
public static bool HasPaperdoll(this Body body)
|
||||
{
|
||||
return GetPaperdoll(body) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class ContainerExtUtility
|
||||
{
|
||||
public static bool HasItem<TItem>(
|
||||
this Container container,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<TItem, bool> predicate = null)
|
||||
where TItem : Item
|
||||
{
|
||||
return predicate == null
|
||||
? HasItem(container, typeof(TItem), amount, children)
|
||||
: HasItem(container, typeof(TItem), amount, children, i => predicate(i as TItem));
|
||||
}
|
||||
|
||||
public static bool HasItem(
|
||||
this Container container,
|
||||
Type type,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || type == null || amount < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long total = 0;
|
||||
|
||||
total = container.FindItemsByType(type, true)
|
||||
.Where(i => i != null && !i.Deleted && i.TypeEquals(type, children) && (predicate == null || predicate(i)))
|
||||
.Aggregate(total, (c, i) => c + i.Amount);
|
||||
|
||||
return total >= amount;
|
||||
}
|
||||
|
||||
public static bool HasItems(
|
||||
this Container container,
|
||||
Type[] types,
|
||||
int[] amounts = null,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || types == null || types.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amounts == null)
|
||||
{
|
||||
amounts = new int[0];
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < types.Length; i++)
|
||||
{
|
||||
var t = types[i];
|
||||
var amount = amounts.InBounds(i) ? amounts[i] : 1;
|
||||
|
||||
if (HasItem(container, t, amount, children, predicate))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count >= types.Length;
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return DropItemStack(c, c.RootParent as Mobile, item);
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Mobile m, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
c.DropItem(item);
|
||||
|
||||
if (item.Stackable)
|
||||
{
|
||||
MergeStacks(c, item.GetType(), m);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void MergeStacks<T>(this Container c, Mobile m)
|
||||
where T : Item
|
||||
{
|
||||
MergeStacks(c, typeof(T), m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Mobile m)
|
||||
{
|
||||
MergeStacks(c, null, m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Type t, Mobile m)
|
||||
{
|
||||
if (c == null || c.Deleted || (t != null && t.TypeEquals<Container>(true)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var i = c.Items.Count;
|
||||
|
||||
while (--i >= 1)
|
||||
{
|
||||
var o = c.Items[i];
|
||||
|
||||
if (!o.Stackable || (t != null && !o.TypeEquals(t, false)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var s in c.Items.Take(i).NotType<Item, Container>().Where(s => t == null || s.TypeEquals(t, false)))
|
||||
{
|
||||
if (s.StackWith(m, o))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class CreatureExtUtility
|
||||
{
|
||||
public static TMobile GetMaster<TMobile>(this BaseCreature creature)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
return creature != null ? creature.GetMaster() as TMobile : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class EntityExtUtility
|
||||
{
|
||||
public static ObjectPropertyList GetOPL(this IEntity e)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, headerOnly);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer, headerOnly);
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader();
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(lng);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(viewer);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList();
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(lng);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(viewer);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, lng));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, viewer));
|
||||
}
|
||||
|
||||
public static string ResolveName(this IEntity e, Mobile viewer = null)
|
||||
{
|
||||
if (e is Item)
|
||||
{
|
||||
return ((Item)e).ResolveName(viewer);
|
||||
}
|
||||
|
||||
if (e is Mobile)
|
||||
{
|
||||
return ((Mobile)e).GetFullName(viewer);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(e.Name))
|
||||
{
|
||||
return e.GetTypeName(false);
|
||||
}
|
||||
|
||||
return e.Name;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IEntity e)
|
||||
{
|
||||
if (e != null && e.Map != null && e.Map != Map.Internal)
|
||||
{
|
||||
return e.IsInside(e.Map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IEntity e)
|
||||
{
|
||||
return !IsInside(e);
|
||||
}
|
||||
|
||||
public static bool Intersects(this IEntity e, IPoint3D o)
|
||||
{
|
||||
return Block3D.Intersects(e, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
@@ -0,0 +1,765 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class GeoExtUtility
|
||||
{
|
||||
public static Point3D ToPoint3D(this IPoint3D p)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this IPoint2D p, int z = 0)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, z);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this IPoint3D p)
|
||||
{
|
||||
return new Point2D(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this StaticTile t)
|
||||
{
|
||||
return new Point2D(t.X, t.Y);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this StaticTile t)
|
||||
{
|
||||
return new Point3D(t.X, t.Y, t.Z);
|
||||
}
|
||||
|
||||
public static string ToCoordsString(this IPoint2D p, Map map)
|
||||
{
|
||||
return ToCoords(p, map).ToString();
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IPoint2D p, Map m)
|
||||
{
|
||||
return new Coords(m, p);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IEntity e)
|
||||
{
|
||||
return e == null ? Coords.Zero : new Coords(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Coords.Zero;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
return new Coords(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this StaticTile t, Map m)
|
||||
{
|
||||
return new Coords(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint2D p, Map m, int z = 0)
|
||||
{
|
||||
return new MapPoint(m, p, z);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint3D p, Map m)
|
||||
{
|
||||
return new MapPoint(m, p);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IEntity e)
|
||||
{
|
||||
return e == null ? MapPoint.Empty : new MapPoint(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return MapPoint.Empty;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
|
||||
return new MapPoint(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this StaticTile t, Map m)
|
||||
{
|
||||
return new MapPoint(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static IEnumerable<Block3D> Flatten(this IEnumerable<Block3D> blocks)
|
||||
{
|
||||
foreach (var o in blocks.GroupBy(o => o.ToPoint2D()))
|
||||
{
|
||||
var v = new Block3D(o.Key.X, o.Key.Y, o.Min(b => b.Z), 0);
|
||||
|
||||
v.H = o.Max(b => b.Z + b.H) - v.Z;
|
||||
|
||||
yield return v;
|
||||
}
|
||||
}
|
||||
|
||||
public static Direction GetDirection(this IPoint2D from, IPoint2D to)
|
||||
{
|
||||
int dx = to.X - from.X, dy = to.Y - from.Y, adx = Math.Abs(dx), ady = Math.Abs(dy);
|
||||
|
||||
if (adx >= ady * 3)
|
||||
{
|
||||
if (dx > 0)
|
||||
{
|
||||
return Direction.East;
|
||||
}
|
||||
|
||||
return Direction.West;
|
||||
}
|
||||
|
||||
if (ady >= adx * 3)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.South;
|
||||
}
|
||||
|
||||
return Direction.North;
|
||||
}
|
||||
|
||||
if (dx > 0)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Down;
|
||||
}
|
||||
|
||||
return Direction.Right;
|
||||
}
|
||||
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Left;
|
||||
}
|
||||
|
||||
return Direction.Up;
|
||||
}
|
||||
|
||||
public static Direction4 GetDirection4(this Direction dir, bool clockwise = true)
|
||||
{
|
||||
dir = dir & Direction.Mask;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case Direction.Up:
|
||||
return clockwise ? Direction4.North : Direction4.West;
|
||||
case Direction.Right:
|
||||
return clockwise ? Direction4.East : Direction4.North;
|
||||
case Direction.Down:
|
||||
return clockwise ? Direction4.South : Direction4.East;
|
||||
case Direction.Left:
|
||||
return clockwise ? Direction4.West : Direction4.South;
|
||||
}
|
||||
|
||||
return (Direction4)dir;
|
||||
}
|
||||
|
||||
public static Point2D[] GetLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return PlotLine2D(start, end).ToArray();
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return GetLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
return PlotLine3D(start, end, map, avgZ).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> PlotLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Line2D.Plot(start, end);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return PlotLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
var dist = GetDistance(start, end);
|
||||
var dZ = end.Z - start.Z;
|
||||
|
||||
return Line2D.Plot(start, end)
|
||||
.Select(
|
||||
(p, i) =>
|
||||
{
|
||||
var z = start.Z;
|
||||
|
||||
if (avgZ && map != null)
|
||||
{
|
||||
z = map.GetAverageZ(p.X, p.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
z += (int)(dZ * (i / dist));
|
||||
}
|
||||
|
||||
return new Point3D(p, z);
|
||||
});
|
||||
}
|
||||
|
||||
public static Point2D Rotate2D(this IPoint2D from, IPoint2D to, int count)
|
||||
{
|
||||
var rx = from.X - to.X;
|
||||
var ry = from.Y - to.Y;
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var temp = rx;
|
||||
rx = -ry;
|
||||
ry = temp;
|
||||
}
|
||||
|
||||
return new Point2D(to.X + rx, to.Y + ry);
|
||||
}
|
||||
|
||||
public static Point3D Rotate3D(this IPoint3D from, IPoint3D to, int count)
|
||||
{
|
||||
return new Point3D(Rotate2D(from, to, count), from.Z);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, IPoint2D t)
|
||||
{
|
||||
return new Point2D(p.X + t.X, p.Y + t.Y);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, int xOffset = 0, int yOffset = 0)
|
||||
{
|
||||
return new Point2D(p.X + xOffset, p.Y + yOffset);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, IPoint3D t)
|
||||
{
|
||||
return new Point3D(p.X + t.X, p.Y + t.Y, p.Z + t.Z);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, int xOffset = 0, int yOffset = 0, int zOffset = 0)
|
||||
{
|
||||
return new Point3D(p.X + xOffset, p.Y + yOffset, p.Z + zOffset);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, IPoint2D end, double percent)
|
||||
{
|
||||
return Lerp2D(start, end.X, end.Y, percent);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, int x, int y, double percent)
|
||||
{
|
||||
return Clone2D(start, (int)((x - start.X) * percent), (int)((y - start.Y) * percent));
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, IPoint3D end, double percent)
|
||||
{
|
||||
return Lerp3D(start, end.X, end.Y, end.Z, percent);
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, int x, int y, int z, double percent)
|
||||
{
|
||||
return Clone3D(
|
||||
start,
|
||||
(int)((x - start.X) * percent),
|
||||
(int)((y - start.Y) * percent),
|
||||
(int)((z - start.Z) * percent));
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return new Point2D(start.X - end.X, start.Y - end.Y);
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, int endX, int endY)
|
||||
{
|
||||
return new Point2D(start.X - endX, start.Y - endY);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return new Point3D(start.X - end.X, start.Y - end.Y, start.Z - end.Z);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, int endX, int endY, int endZ)
|
||||
{
|
||||
return new Point3D(start.X - endX, start.Y - endY, start.Z - endZ);
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Math.Abs(Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2)));
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return Math.Abs(
|
||||
Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2) + (Math.Pow(end.Z - start.Z, 2) / 44.0)));
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint2D start, IPoint2D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint3D start, IPoint3D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
var z1 = (double)start.Z;
|
||||
var z2 = (double)end.Z;
|
||||
|
||||
var zDiff = Math.Abs(z2 - z1);
|
||||
|
||||
if (zDiff >= 5)
|
||||
{
|
||||
span -= (zDiff / 5.0) * 0.1;
|
||||
}
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static object GetTopSurface(this Map map, Point3D p, bool multis)
|
||||
{
|
||||
if (map == Map.Internal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
object surface = null;
|
||||
var surfaceZ = Int32.MinValue;
|
||||
|
||||
var lt = map.Tiles.GetLandTile(p.X, p.Y);
|
||||
|
||||
if (!lt.Ignored)
|
||||
{
|
||||
var avgZ = map.GetAverageZ(p.X, p.Y);
|
||||
|
||||
if (avgZ <= p.Z)
|
||||
{
|
||||
surface = lt;
|
||||
surfaceZ = avgZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var staticTiles = map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
|
||||
ItemData id;
|
||||
int tileZ;
|
||||
|
||||
foreach (var tile in staticTiles)
|
||||
{
|
||||
id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tileZ = tile.Z + id.CalcHeight;
|
||||
|
||||
if (tileZ <= surfaceZ || tileZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = tile;
|
||||
surfaceZ = tileZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
var sector = map.GetSector(p.X, p.Y);
|
||||
|
||||
int itemZ;
|
||||
|
||||
var items = sector.Items.Where(
|
||||
o => o.ItemID <= TileData.MaxItemValue && !o.Movable && !(o is BaseMulti) && o.AtWorldPoint(p.X, p.Y));
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
id = item.ItemData;
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemZ = item.Z + id.CalcHeight;
|
||||
|
||||
if (itemZ <= surfaceZ || itemZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = item;
|
||||
surfaceZ = itemZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint2D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
return GetSurfaceTop(ToPoint3D(p, Region.MaxZ), map, items, multis);
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint3D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
var o = GetTopSurface(map, ToPoint3D(p, Region.MaxZ), multis);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
if (o is LandTile)
|
||||
{
|
||||
var t = (LandTile)o;
|
||||
return ToPoint3D(p, t.Z + t.Height);
|
||||
}
|
||||
|
||||
if (o is StaticTile)
|
||||
{
|
||||
var t = (StaticTile)o;
|
||||
return ToPoint3D(p, t.Z + TileData.ItemTable[t.ID].CalcHeight);
|
||||
}
|
||||
|
||||
if (o is Item && items)
|
||||
{
|
||||
var t = (Item)o;
|
||||
return ToPoint3D(p, t.Z + t.ItemData.CalcHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint2D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint3D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetTopZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetTopZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return points.Max(p => GetTopZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetAverageZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetAverageZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (int)points.Average(p => GetAverageZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (( ,A,_,A,
|
||||
/// )) ,{=^;^=}
|
||||
/// (( {,,}#{,,}
|
||||
/// `{,,}{,,}
|
||||
/// </summary>
|
||||
public static int GetAverageZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void GetAverageZ(this IPoint2D p, Map map, out int cur, out int avg, out int top)
|
||||
{
|
||||
var land = new
|
||||
{
|
||||
T = map.Tiles.GetLandTile(p.X, p.Y),
|
||||
L = map.Tiles.GetLandTile(p.X, p.Y + 1),
|
||||
R = map.Tiles.GetLandTile(p.X + 1, p.Y),
|
||||
B = map.Tiles.GetLandTile(p.X + 1, p.Y + 1)
|
||||
};
|
||||
|
||||
var surf = new
|
||||
{
|
||||
T = GetSurfaceTop(p, map, false, false),
|
||||
L = GetSurfaceTop(Clone2D(p, 0, 1), map, false, false),
|
||||
R = GetSurfaceTop(Clone2D(p, 1), map, false, false),
|
||||
B = GetSurfaceTop(Clone2D(p, 1, 1), map, false, false)
|
||||
};
|
||||
|
||||
var zT = (land.T.Ignored || surf.T.Z > Region.MinZ) ? surf.T.Z : land.T.Z;
|
||||
var zL = (land.L.Ignored || surf.L.Z > Region.MinZ) ? surf.L.Z : land.L.Z;
|
||||
var zR = (land.R.Ignored || surf.R.Z > Region.MinZ) ? surf.R.Z : land.R.Z;
|
||||
var zB = (land.B.Ignored || surf.B.Z > Region.MinZ) ? surf.B.Z : land.B.Z;
|
||||
|
||||
cur = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL < cur)
|
||||
{
|
||||
cur = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR < cur)
|
||||
{
|
||||
cur = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB < cur)
|
||||
{
|
||||
cur = zB;
|
||||
}
|
||||
|
||||
top = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL > top)
|
||||
{
|
||||
top = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR > top)
|
||||
{
|
||||
top = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB > top)
|
||||
{
|
||||
top = zB;
|
||||
}
|
||||
|
||||
if (cur <= Region.MinZ)
|
||||
{
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
if (top <= Region.MinZ)
|
||||
{
|
||||
top = 0;
|
||||
}
|
||||
|
||||
if (zT <= Region.MinZ)
|
||||
{
|
||||
zT = 0;
|
||||
}
|
||||
|
||||
if (zL <= Region.MinZ)
|
||||
{
|
||||
zL = 0;
|
||||
}
|
||||
|
||||
if (zR <= Region.MinZ)
|
||||
{
|
||||
zR = 0;
|
||||
}
|
||||
|
||||
if (zB <= Region.MinZ)
|
||||
{
|
||||
zB = 0;
|
||||
}
|
||||
|
||||
var vL = zL + zR;
|
||||
|
||||
if (vL < 0)
|
||||
{
|
||||
--vL;
|
||||
}
|
||||
|
||||
var vR = zT + zB;
|
||||
|
||||
if (vR < 0)
|
||||
{
|
||||
--vR;
|
||||
}
|
||||
|
||||
avg = Math.Abs(zT - zB) > Math.Abs(zL - zR) ? vL / 2 : vR / 2;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint3D p, Map map)
|
||||
{
|
||||
if (p != null && map != null && map != Map.Internal)
|
||||
{
|
||||
return IsInside(p, p.Z, map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint3D p, Map map)
|
||||
{
|
||||
return !IsInside(p, map);
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
if (p == null || map == null || map == Map.Internal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p is Item)
|
||||
{
|
||||
z += Math.Max(0, ((Item)p).ItemData.Height) + 1;
|
||||
}
|
||||
|
||||
z = Math.Max(Region.MinZ, Math.Min(Region.MaxZ, z));
|
||||
|
||||
return !map.CanFit(p.X, p.Y, z, Region.MaxZ - z, true, false, false);
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
return !IsInside(p, z, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
#endregion
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public static class GumpExtUtility
|
||||
{
|
||||
public static bool TryGetX(this GumpEntry e, out int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x);
|
||||
}
|
||||
|
||||
public static bool TrySetX(this GumpEntry e, int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x);
|
||||
}
|
||||
|
||||
public static bool TryOffsetX(this GumpEntry e, int x)
|
||||
{
|
||||
|
||||
if (TryGetX(e, out var ox))
|
||||
{
|
||||
return TrySetX(e, ox + x);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetY(this GumpEntry e, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetY(this GumpEntry e, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetY(this GumpEntry e, int y)
|
||||
{
|
||||
|
||||
if (TryGetY(e, out var oy))
|
||||
{
|
||||
return TrySetY(e, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetWidth(this GumpEntry e, out int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width);
|
||||
}
|
||||
|
||||
public static bool TrySetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width);
|
||||
}
|
||||
|
||||
public static bool TryOffsetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
|
||||
if (TryGetWidth(e, out var ow))
|
||||
{
|
||||
return TrySetWidth(e, ow + width);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetHeight(this GumpEntry e, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
|
||||
if (TryGetHeight(e, out var oh))
|
||||
{
|
||||
return TrySetHeight(e, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetPosition(this GumpEntry e, out int x, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
|
||||
if (TryGetPosition(e, out var ox, out var oy))
|
||||
{
|
||||
return TrySetPosition(e, ox + x, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetSize(this GumpEntry e, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetSize(e, out var ow, out var oh))
|
||||
{
|
||||
return TrySetSize(e, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetBounds(this GumpEntry e, out int x, out int y, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
x = ((IGumpEntryVector)e).X;
|
||||
y = ((IGumpEntryVector)e).Y;
|
||||
width = ((IGumpEntryVector)e).Width;
|
||||
height = ((IGumpEntryVector)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y) & //
|
||||
e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
((IGumpEntryVector)e).X = x;
|
||||
((IGumpEntryVector)e).Y = y;
|
||||
((IGumpEntryVector)e).Width = width;
|
||||
((IGumpEntryVector)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y) & //
|
||||
e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetBounds(e, out var ox, out var oy, out var ow, out var oh))
|
||||
{
|
||||
return TrySetBounds(e, ox + x, oy + y, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds(this Gump g)
|
||||
{
|
||||
int x = g.X, y = g.Y, w = 0, h = 0;
|
||||
|
||||
if (g is SuperGump)
|
||||
{
|
||||
var sg = (SuperGump)g;
|
||||
|
||||
x += sg.XOffset;
|
||||
y += sg.YOffset;
|
||||
|
||||
if (sg.Modal)
|
||||
{
|
||||
x += sg.ModalXOffset;
|
||||
y += sg.ModalYOffset;
|
||||
}
|
||||
|
||||
w = sg.OuterWidth;
|
||||
h = sg.OuterHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var e in g.Entries)
|
||||
{
|
||||
e.TryGetPosition(out var ex, out var ey);
|
||||
|
||||
e.TryGetSize(out var ew, out var eh);
|
||||
|
||||
w = Math.Max(ex + ew, w);
|
||||
h = Math.Max(ey + eh, h);
|
||||
}
|
||||
}
|
||||
|
||||
return new Rectangle2D(x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
@@ -0,0 +1,926 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[Flags]
|
||||
public enum GiveFlags
|
||||
{
|
||||
None = 0x0,
|
||||
Pack = 0x1,
|
||||
Bank = 0x2,
|
||||
Corpse = 0x4,
|
||||
Feet = 0x8,
|
||||
|
||||
Delete = 0x40000000,
|
||||
|
||||
PackBank = Pack | Bank,
|
||||
PackCorpse = Pack | Corpse,
|
||||
PackFeet = Pack | Feet,
|
||||
PackDelete = Pack | Delete,
|
||||
|
||||
PackBankCorpse = PackBank | Corpse,
|
||||
PackBankFeet = PackBank | Feet,
|
||||
PackBankDelete = PackBank | Delete,
|
||||
|
||||
PackBankCorpseFeet = PackBankCorpse | Feet,
|
||||
PackBankCorpseDelete = PackBankCorpse | Delete,
|
||||
PackBankFeetDelete = PackBankFeet | Delete,
|
||||
|
||||
PackBankCorpseFeetDelete = PackBankCorpseFeet | Delete,
|
||||
|
||||
PackCorpseFeet = PackCorpse | Feet,
|
||||
PackCorpseDelete = PackCorpse | Delete,
|
||||
PackCorpseFeetDelete = PackCorpseFeet | Delete,
|
||||
|
||||
PackFeetDelete = PackFeet | Delete,
|
||||
|
||||
BankCorpse = Bank | Corpse,
|
||||
BankFeet = Bank | Feet,
|
||||
BankDelete = Bank | Delete,
|
||||
|
||||
BankCorpseFeet = BankCorpse | Feet,
|
||||
BankCorpseDelete = BankCorpse | Delete,
|
||||
BankFeetDelete = BankFeet | Delete,
|
||||
|
||||
BankCorpseFeetDelete = BankCorpseFeet | Delete,
|
||||
|
||||
CorpseFeet = Corpse | Feet,
|
||||
CorpseDelete = Corpse | Delete,
|
||||
|
||||
CorpseFeetDelete = CorpseFeet | Delete,
|
||||
|
||||
FeetDelete = Feet | Delete,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
|
||||
public static class ItemExtUtility
|
||||
{
|
||||
public static T BinaryClone<T>(this T item)
|
||||
where T : Item
|
||||
{
|
||||
var t = item.GetType();
|
||||
|
||||
var o = t.CreateInstanceSafe<T>(Serial.NewItem);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var w = ms.GetBinaryWriter();
|
||||
|
||||
item.Serialize(w);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var r = ms.GetBinaryReader();
|
||||
|
||||
o.Deserialize(r);
|
||||
|
||||
w.Close();
|
||||
r.Close();
|
||||
}
|
||||
|
||||
var m = o.Parent as Mobile;
|
||||
|
||||
o.Amount = 1;
|
||||
|
||||
if (o.Items != null)
|
||||
{
|
||||
o.Items.Clear();
|
||||
}
|
||||
|
||||
o.Internalize();
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
o.OnRemoved(m);
|
||||
|
||||
m.OnItemRemoved(o);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
o.Delete();
|
||||
o = null;
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public static void InvalidateProperties<T>(this Item item)
|
||||
{
|
||||
if (item is T)
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties<T>(item.Items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvalidateProperties(this Item item, Type type)
|
||||
{
|
||||
if (item.TypeEquals(type))
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties(item.Items[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetAnimID(this Item item)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupAnimation(item.ItemID) : 0;
|
||||
}
|
||||
|
||||
public static int GetGumpID(this Item item, bool female)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupGump(item.ItemID, female) : 0;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetGumpBounds(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return PaperdollBounds.Empty;
|
||||
}
|
||||
|
||||
if (item.Layer == Layer.TwoHanded)
|
||||
{
|
||||
if (item is BaseRanged)
|
||||
{
|
||||
return PaperdollBounds.MainHand;
|
||||
}
|
||||
|
||||
if (item is BaseEquipableLight || item is BaseShield)
|
||||
{
|
||||
return PaperdollBounds.OffHand;
|
||||
}
|
||||
}
|
||||
|
||||
return PaperdollBounds.Find(item.Layer);
|
||||
}
|
||||
|
||||
public static Mobile FindOwner(this Item item)
|
||||
{
|
||||
return FindOwner<Mobile>(item);
|
||||
}
|
||||
|
||||
public static TMobile FindOwner<TMobile>(this Item item)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var owner = item.RootParent as TMobile;
|
||||
|
||||
if (owner == null)
|
||||
{
|
||||
var h = BaseHouse.FindHouseAt(item);
|
||||
|
||||
if (h != null)
|
||||
{
|
||||
owner = h.Owner as TMobile;
|
||||
}
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
public static GiveFlags GiveTo(this Item item, Mobile m, GiveFlags flags = GiveFlags.All, bool message = true)
|
||||
{
|
||||
if (item == null || item.Deleted || m == null || m.Deleted || flags == GiveFlags.None)
|
||||
{
|
||||
return GiveFlags.None;
|
||||
}
|
||||
|
||||
var pack = flags.HasFlag(GiveFlags.Pack);
|
||||
var bank = flags.HasFlag(GiveFlags.Bank);
|
||||
var feet = flags.HasFlag(GiveFlags.Feet);
|
||||
var corpse = flags.HasFlag(GiveFlags.Corpse);
|
||||
var delete = flags.HasFlag(GiveFlags.Delete);
|
||||
|
||||
if (pack && (m.Backpack == null || m.Backpack.Deleted || !m.Backpack.CheckHold(m, item, false)))
|
||||
{
|
||||
pack = false;
|
||||
flags &= ~GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && (!m.Player || !m.BankBox.CheckHold(m, item, false)))
|
||||
{
|
||||
bank = false;
|
||||
flags &= ~GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && (m.Alive || m.Corpse == null || m.Corpse.Deleted))
|
||||
{
|
||||
corpse = false;
|
||||
flags &= ~GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet && (m.Map == null || m.Map == Map.Internal) && (m.LogoutMap == null || m.LogoutMap == Map.Internal))
|
||||
{
|
||||
feet = false;
|
||||
flags &= ~GiveFlags.Feet;
|
||||
}
|
||||
|
||||
var result = VitaNexCore.TryCatchGet(
|
||||
f =>
|
||||
{
|
||||
if (pack && m.Backpack.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && m.BankBox.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && m.Corpse.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet)
|
||||
{
|
||||
if (m.Map != null && m.Map != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.Location, m.Map);
|
||||
|
||||
if (m.Player)
|
||||
{
|
||||
item.SendInfoTo(m.NetState);
|
||||
}
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
|
||||
if (m.LogoutMap != null && m.LogoutMap != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.LogoutLocation, m.LogoutMap);
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete)
|
||||
{
|
||||
item.Delete();
|
||||
|
||||
return GiveFlags.Delete;
|
||||
}
|
||||
|
||||
return GiveFlags.None;
|
||||
},
|
||||
flags);
|
||||
|
||||
if (!message || result == GiveFlags.None || result == GiveFlags.Delete)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var amount = String.Empty;
|
||||
var name = ResolveName(item, m);
|
||||
|
||||
var p = item.Stackable && item.Amount > 1;
|
||||
|
||||
if (p)
|
||||
{
|
||||
amount = item.Amount.ToString("#,0") + " ";
|
||||
|
||||
if (!Insensitive.EndsWith(name, "s") && !Insensitive.EndsWith(name, "z"))
|
||||
{
|
||||
name += "s";
|
||||
}
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case GiveFlags.Pack:
|
||||
m.SendMessage("{0}{1} {2} been placed in your pack.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Bank:
|
||||
m.SendMessage("{0}{1} {2} been placed in your bank.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Corpse:
|
||||
m.SendMessage("{0}{1} {2} been placed in your corpse.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Feet:
|
||||
m.SendMessage("{0}{1} {2} been placed at your feet.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool WasReceived(this GiveFlags flags)
|
||||
{
|
||||
return flags != GiveFlags.None && flags != GiveFlags.Delete;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Item, List<object>> _Actions = new Dictionary<Item, List<object>>();
|
||||
|
||||
public static bool BeginAction(this Item item, object toLock)
|
||||
{
|
||||
|
||||
if (!_Actions.TryGetValue(item, out var actions) || actions == null)
|
||||
{
|
||||
ObjectPool.Acquire(out actions);
|
||||
|
||||
_Actions[item] = actions;
|
||||
}
|
||||
|
||||
if (!actions.Contains(toLock))
|
||||
{
|
||||
actions.Add(toLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanBeginAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
return actions == null || !actions.Contains(toLock);
|
||||
}
|
||||
|
||||
public static void EndAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
if (actions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actions.Remove(toLock);
|
||||
|
||||
if (actions.Count == 0)
|
||||
{
|
||||
_Actions.Remove(item);
|
||||
|
||||
ObjectPool.Free(ref actions);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item, T> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item, T>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item)
|
||||
{
|
||||
return ResolveName(item, Clilocs.DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, Mobile viewer)
|
||||
{
|
||||
return ResolveName(item, viewer.GetLanguage());
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, ClilocLNG lng)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
var label = item.GetOPLHeader(lng);
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.Replace("\t", " ").Replace("\u0009", " ").Replace("<br>", "\n").Replace("<BR>", "\n").Trim();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripHtml(false);
|
||||
label = label.Trim();
|
||||
|
||||
int idx;
|
||||
|
||||
if ((idx = label.IndexOf('\n')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
label = label.Substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart('\n');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
|
||||
if ((idx = label.IndexOf(' ')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
|
||||
if (Int32.TryParse(label.Substring(0, idx), NumberStyles.Number, CultureInfo.InvariantCulture, out var amount))
|
||||
{
|
||||
label = label.Substring(idx + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart(' ');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.Name != null)
|
||||
{
|
||||
label = item.Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.DefaultName != null)
|
||||
{
|
||||
label = item.DefaultName;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.LabelNumber > 0)
|
||||
{
|
||||
label = lng.GetString(item.LabelNumber);
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && TileData.ItemTable.InBounds(item.ItemID))
|
||||
{
|
||||
label = TileData.ItemTable[item.ItemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label))
|
||||
{
|
||||
label = item.GetType().Name.SpaceWords();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item)
|
||||
{
|
||||
|
||||
return CheckUsesRemaining(item, false, out var uses);
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, false, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, bool deplete, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, deplete ? 1 : 0, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, int deplete, out int uses)
|
||||
{
|
||||
uses = -1;
|
||||
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(item is IUsesRemaining))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var u = (IUsesRemaining)item;
|
||||
|
||||
if (u.UsesRemaining <= 0)
|
||||
{
|
||||
uses = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deplete > 0)
|
||||
{
|
||||
if (u.UsesRemaining < deplete)
|
||||
{
|
||||
uses = u.UsesRemaining;
|
||||
return false;
|
||||
}
|
||||
|
||||
u.UsesRemaining = Math.Max(0, u.UsesRemaining - deplete);
|
||||
}
|
||||
|
||||
uses = u.UsesRemaining;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckUse(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
return CheckDoubleClick(item, from, handle, allowDead, range, packOnly, inTrade, inDisplay, access);
|
||||
}
|
||||
|
||||
public static bool CheckDoubleClick(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
if (item == null || item.Deleted || from == null || from.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.AccessLevel < access)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("You do not have sufficient access to use this item.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.CanSee(item) && !(item is IAddon))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can't be seen.");
|
||||
item.OnDoubleClickCantSee(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item.IsAccessibleTo(from))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickNotAccessible(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.InSecureTrade && !inTrade)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((item.Parent == null && !item.Movable && !item.IsLockedDown && !item.IsSecure && !item.InSecureTrade) ||
|
||||
IsShopItem(item)) && !inDisplay)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can not be accessed because it is part of a display.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.Alive && !allowDead)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickDead(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (range >= 0 && !packOnly && !from.InRange(item, range))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
if (range > 0)
|
||||
{
|
||||
from.SendMessage("You must be within {0:#,0} paces to use this item.", range);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You must be standing on this item to use it.");
|
||||
}
|
||||
|
||||
item.OnDoubleClickOutOfRange(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packOnly && item.RootParent != from)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
// This item must be in your backpack.
|
||||
from.SendLocalizedMessage(1054107);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsShopItem(this Item item)
|
||||
{
|
||||
return HasParent(item, "Server.Mobiles.GenericBuyInfo+DisplayCache");
|
||||
}
|
||||
|
||||
public static bool IsParentOf(this Item item, Item child)
|
||||
{
|
||||
if (item == null || child == null || item == child)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = child.Parent as Item;
|
||||
|
||||
while (p != null && p != item)
|
||||
{
|
||||
p = p.Parent as Item;
|
||||
}
|
||||
|
||||
return item == p;
|
||||
}
|
||||
|
||||
public static bool HasParent<TEntity>(this Item item)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return HasParent(item, typeof(TEntity));
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, string typeName)
|
||||
{
|
||||
if (item == null || String.IsNullOrWhiteSpace(typeName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = Type.GetType(typeName, false, false) ?? ScriptCompiler.FindTypeByFullName(typeName, false) ??
|
||||
ScriptCompiler.FindTypeByName(typeName, false);
|
||||
|
||||
return HasParent(item, t);
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, Type t)
|
||||
{
|
||||
if (item == null || t == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = item.Parent;
|
||||
|
||||
while (p is Item)
|
||||
{
|
||||
if (p.GetType().IsEqualOrChildOf(t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var i = (Item)p;
|
||||
|
||||
if (i.Parent == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p = i.Parent;
|
||||
}
|
||||
|
||||
return p is Mobile && p.GetType().IsEqualOrChildOf(t);
|
||||
}
|
||||
|
||||
public static bool IsEquipped(this Item item)
|
||||
{
|
||||
return item != null && item.Parent is Mobile && ((Mobile)item.Parent).FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
public static bool IsEquippedBy(this Item item, Mobile m)
|
||||
{
|
||||
return item != null && item.Parent == m && m.FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
#region *OverheadMessage
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text, NetState state)
|
||||
{
|
||||
if (state == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
state.Send(new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, NetState state)
|
||||
{
|
||||
PrivateOverheadMessage(item, type, hue, number, "", state);
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, string args, NetState state)
|
||||
{
|
||||
if (state != null)
|
||||
{
|
||||
state.Send(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
}
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number)
|
||||
{
|
||||
NonlocalOverheadMessage(item, type, hue, number, "");
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number, string args)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var p = Packet.Acquire(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Packet p;
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
p = new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text);
|
||||
}
|
||||
|
||||
p.Acquire();
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class LayerExtUtility
|
||||
{
|
||||
private const Layer _Face = (Layer)15;
|
||||
private const Layer _ShopMax = (Layer)30;
|
||||
|
||||
private const Layer _PlateArms = (Layer)255;
|
||||
private const Layer _ChainTunic = (Layer)254;
|
||||
private const Layer _LeatherShorts = (Layer)253;
|
||||
|
||||
public static Layer[] LayerOrder =
|
||||
{
|
||||
Layer.Cloak, Layer.Bracelet, Layer.Ring, Layer.Shirt, Layer.Pants, Layer.InnerLegs, Layer.Shoes, _LeatherShorts,
|
||||
Layer.Arms, Layer.InnerTorso, _LeatherShorts, _PlateArms, Layer.MiddleTorso, Layer.OuterLegs, Layer.Neck,
|
||||
Layer.Gloves, Layer.OuterTorso, Layer.Waist, Layer.OneHanded, Layer.TwoHanded, _Face, Layer.FacialHair, Layer.Hair,
|
||||
Layer.Helm, Layer.Talisman
|
||||
};
|
||||
|
||||
public static Layer[] EquipLayers =
|
||||
{
|
||||
Layer.Arms, Layer.Bracelet, Layer.Cloak, Layer.Earrings, Layer.Gloves, Layer.Helm, Layer.InnerLegs, Layer.InnerTorso,
|
||||
Layer.MiddleTorso, Layer.Neck, Layer.OneHanded, Layer.OuterLegs, Layer.OuterTorso, Layer.Pants, Layer.Ring,
|
||||
Layer.Shirt, Layer.Shoes, Layer.Talisman, Layer.TwoHanded, Layer.Waist, Layer.Mount
|
||||
};
|
||||
|
||||
public static int[] LayerTable { get; private set; }
|
||||
|
||||
static LayerExtUtility()
|
||||
{
|
||||
LayerTable = new int[256];
|
||||
|
||||
for (var i = 0; i < LayerOrder.Length; ++i)
|
||||
{
|
||||
LayerTable[(int)LayerOrder[i]] = LayerOrder.Length - i;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetOrderIndex(this Layer layer)
|
||||
{
|
||||
return LayerOrder.IndexOf(layer);
|
||||
}
|
||||
|
||||
public static bool IsEquip(this Layer layer)
|
||||
{
|
||||
return EquipLayers.Contains(layer);
|
||||
}
|
||||
|
||||
public static bool IsMount(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Mount;
|
||||
}
|
||||
|
||||
public static bool IsPack(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Backpack;
|
||||
}
|
||||
|
||||
public static bool IsBank(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Bank;
|
||||
}
|
||||
|
||||
public static bool IsPackOrBank(this Layer layer)
|
||||
{
|
||||
return IsPack(layer) || IsBank(layer);
|
||||
}
|
||||
|
||||
public static bool IsFace(this Layer layer)
|
||||
{
|
||||
return layer == _Face;
|
||||
}
|
||||
|
||||
public static bool IsHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Hair;
|
||||
}
|
||||
|
||||
public static bool IsFacialHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.FacialHair;
|
||||
}
|
||||
|
||||
public static bool IsHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsShop(this Layer layer)
|
||||
{
|
||||
return layer == Layer.ShopBuy || layer == Layer.ShopResale || layer == Layer.ShopSell || layer == _ShopMax;
|
||||
}
|
||||
|
||||
public static bool IsInvalid(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Invalid;
|
||||
}
|
||||
|
||||
public static bool IsValid(this Layer layer)
|
||||
{
|
||||
return IsEquip(layer) || IsPackOrBank(layer) || IsFaceOrHair(layer);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayer(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderBy(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayerDescending(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderByDescending(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayer(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderBy(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayerDescending(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderByDescending(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Item> items)
|
||||
{
|
||||
if (items != null && items.Count > 1)
|
||||
{
|
||||
items.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Layer> layers)
|
||||
{
|
||||
if (layers != null && layers.Count > 1)
|
||||
{
|
||||
layers.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Item item, Item other)
|
||||
{
|
||||
var res = 0;
|
||||
|
||||
if (item.CompareNull(other, ref res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
return CompareLayer(Fix(item.Layer, item.ItemID), Fix(other.Layer, other.ItemID));
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Layer layer, Layer other)
|
||||
{
|
||||
return LayerTable[(int)other] - LayerTable[(int)layer];
|
||||
}
|
||||
|
||||
public static bool IsOrdered(this Layer layer)
|
||||
{
|
||||
return LayerTable[(int)layer] > 0;
|
||||
}
|
||||
|
||||
public static Layer Fix(this Layer layer, int itemID)
|
||||
{
|
||||
if (itemID == 0x1410 || itemID == 0x1417) // platemail arms
|
||||
{
|
||||
return _PlateArms;
|
||||
}
|
||||
|
||||
if (itemID == 0x13BF || itemID == 0x13C4) // chainmail tunic
|
||||
{
|
||||
return _ChainTunic;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C08 || itemID == 0x1C09) // leather skirt
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C00 || itemID == 0x1C01) // leather shorts
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetPaperdollBounds(this Layer layer)
|
||||
{
|
||||
return PaperdollBounds.Find(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MapExtUtility
|
||||
{
|
||||
#region StaticWaterTiles
|
||||
public static List<int> StaticWaterTiles = new List<int>
|
||||
{
|
||||
5465,
|
||||
6038,
|
||||
6039,
|
||||
6040,
|
||||
6041,
|
||||
6042,
|
||||
6043,
|
||||
6044,
|
||||
13422,
|
||||
13423,
|
||||
13424,
|
||||
13425,
|
||||
13426,
|
||||
13427,
|
||||
13428,
|
||||
13429,
|
||||
13430,
|
||||
13431,
|
||||
13432,
|
||||
13433,
|
||||
13434,
|
||||
13435,
|
||||
13436,
|
||||
13437,
|
||||
13438,
|
||||
13439,
|
||||
13440,
|
||||
13441,
|
||||
13442,
|
||||
13443,
|
||||
13445,
|
||||
13456,
|
||||
13457,
|
||||
13458,
|
||||
13459,
|
||||
13460,
|
||||
13461,
|
||||
13462,
|
||||
13463,
|
||||
13464,
|
||||
13465,
|
||||
13466,
|
||||
13467,
|
||||
13468,
|
||||
13469,
|
||||
13470,
|
||||
13471,
|
||||
13472,
|
||||
13473,
|
||||
13474,
|
||||
13475,
|
||||
13476,
|
||||
13477,
|
||||
13478,
|
||||
13479,
|
||||
13480,
|
||||
13481,
|
||||
13482,
|
||||
13483,
|
||||
13494,
|
||||
13495,
|
||||
13496,
|
||||
13497,
|
||||
13498,
|
||||
13499,
|
||||
13500,
|
||||
13501,
|
||||
13502,
|
||||
13503,
|
||||
13504,
|
||||
13505,
|
||||
13506,
|
||||
13507,
|
||||
13508,
|
||||
13509,
|
||||
13510,
|
||||
13511,
|
||||
13512,
|
||||
13513,
|
||||
13514,
|
||||
13515,
|
||||
13516,
|
||||
13517,
|
||||
13518,
|
||||
13519,
|
||||
13520,
|
||||
13521,
|
||||
13522,
|
||||
13523,
|
||||
13524,
|
||||
13525,
|
||||
13597,
|
||||
13598,
|
||||
13599,
|
||||
13600,
|
||||
13601,
|
||||
13602,
|
||||
13603,
|
||||
13604,
|
||||
13605,
|
||||
13606,
|
||||
13607,
|
||||
13608,
|
||||
13609,
|
||||
13610,
|
||||
13611,
|
||||
13612,
|
||||
13613,
|
||||
13614,
|
||||
13615,
|
||||
13616
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandWaterTiles
|
||||
public static List<int> LandWaterTiles = new List<int>
|
||||
{
|
||||
168,
|
||||
169,
|
||||
170,
|
||||
171,
|
||||
310,
|
||||
311,
|
||||
|
||||
#region Coastlines
|
||||
76,
|
||||
77,
|
||||
78,
|
||||
79,
|
||||
80,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
92,
|
||||
93,
|
||||
94,
|
||||
95,
|
||||
96,
|
||||
97,
|
||||
98,
|
||||
99,
|
||||
100,
|
||||
101,
|
||||
102,
|
||||
103,
|
||||
104,
|
||||
105,
|
||||
106,
|
||||
107,
|
||||
108,
|
||||
109,
|
||||
110,
|
||||
111
|
||||
#endregion
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandCoastlineTiles
|
||||
public static List<int> LandCoastlineTiles = new List<int>
|
||||
{
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
50
|
||||
};
|
||||
#endregion
|
||||
|
||||
public static bool IsWater(this Item item)
|
||||
{
|
||||
return StaticWaterTiles.Contains(item.ItemID) || item.ItemData.Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(item.Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTarget targ)
|
||||
{
|
||||
return LandWaterTiles.Contains(targ.TileID) || TileData.LandTable[targ.TileID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[targ.TileID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTarget targ)
|
||||
{
|
||||
return StaticWaterTiles.Contains(targ.ItemID) || TileData.ItemTable[targ.ItemID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[targ.ItemID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTile tile)
|
||||
{
|
||||
return LandWaterTiles.Contains(tile.ID) || TileData.LandTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTile tile)
|
||||
{
|
||||
return StaticWaterTiles.Contains(tile.ID) || TileData.ItemTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsCoastline(this LandTile tile)
|
||||
{
|
||||
return LandCoastlineTiles.Contains(tile.ID) || (TileData.LandTable[tile.ID].Flags == TileFlag.Impassable &&
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "sand"));
|
||||
}
|
||||
|
||||
public static bool HasWater(this Map map, IPoint2D p)
|
||||
{
|
||||
return IsWater(GetLandTile(map, p)) || GetStaticTiles(map, p).Any(IsWater);
|
||||
}
|
||||
|
||||
public static bool HasLand(this Map map, IPoint2D p)
|
||||
{
|
||||
return !GetLandTile(map, p).Ignored;
|
||||
}
|
||||
|
||||
public static LandTile GetLandTile(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetLandTile(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p, bool multis)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetInnerBounds2D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle2D(0, 0, Math.Min(5120, map.Width), map.Height);
|
||||
case 3:
|
||||
return new Rectangle2D(512, 0, map.Width - 512, map.Height);
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetInnerBounds3D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle3D(0, 0, Region.MinZ, Math.Min(5120, map.Width), map.Height, Region.MaxZ - Region.MinZ);
|
||||
case 3:
|
||||
return new Rectangle3D(512, 0, Region.MinZ, map.Width - 512, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds2D(this Map map)
|
||||
{
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds3D(this Map map)
|
||||
{
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MultiExtUtility
|
||||
{
|
||||
static MultiExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
WireframeCache = new Dictionary<int, Wireframe>();
|
||||
BoundsCache = new Dictionary<int, Rectangle3D>();
|
||||
}
|
||||
|
||||
#region Components
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi)
|
||||
{
|
||||
return GetComponents(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetComponents(multiID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (ComponentsCache.TryGetValue(multiID, out var mcl) && mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
ComponentsCache[multiID] = mcl = MultiData.GetComponents(multiID);
|
||||
|
||||
// Minax Fortress
|
||||
if (multiID == 0x1388)
|
||||
{
|
||||
// That tree...
|
||||
mcl.Remove(3405, 17, -13, 15);
|
||||
mcl.Remove(3406, 18, -14, 15);
|
||||
mcl.Remove(3393, 18, -14, 17);
|
||||
}
|
||||
|
||||
if (mcl.List.Length == 0)
|
||||
{
|
||||
mcl.Resize(1, 1);
|
||||
mcl.Add(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
return mcl;
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, int x, int y, int w, int h, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, new Rectangle2D(x, y, w, h), z, d);
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle2D bounds, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, bounds.ToRectangle3D(z, d));
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle3D bounds)
|
||||
{
|
||||
for (var z = bounds.Start.Z; z < bounds.End.Z; z++)
|
||||
{
|
||||
for (var x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
for (var y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
mcl.Add(itemID, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Wireframes
|
||||
public static Dictionary<int, Wireframe> WireframeCache { get; private set; }
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset, int hOffset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset, hOffset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, 0);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, offset.H);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset, int hOffset)
|
||||
{
|
||||
var o = GetWireframe(multi, multiID);
|
||||
|
||||
return new Wireframe(o.Select(b => b.Offset(offset.X, offset.Y, offset.Z, hOffset)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID < 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetWireframe(multiID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (WireframeCache.TryGetValue(multiID, out var frame))
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
frame = GetWireframe(GetComponents(multiID));
|
||||
|
||||
WireframeCache[multiID] = frame;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IPoint3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Select(b => b.Offset(offset.X, offset.Y, offset.Z)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IBlock3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Offset(offset.X, offset.Y, offset.Z, offset.H));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Wireframe.Empty;
|
||||
}
|
||||
|
||||
var frame = new Block3D[mcl.List.Length];
|
||||
|
||||
frame.SetAll(
|
||||
i =>
|
||||
{
|
||||
var o = mcl.List[i];
|
||||
var h = Math.Max(5, TileData.ItemTable[o.m_ItemID].Height);
|
||||
|
||||
return new Block3D(o.m_OffsetX, o.m_OffsetY, o.m_OffsetZ, h);
|
||||
});
|
||||
|
||||
return new Wireframe(frame);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Bounds
|
||||
public static Dictionary<int, Rectangle3D> BoundsCache { get; private set; }
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi)
|
||||
{
|
||||
return GetBoundsOffset(multi, multi.Location);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi, Point3D offset)
|
||||
{
|
||||
return GetBounds(multi).Resize(offset.X, offset.Y, offset.Z);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi)
|
||||
{
|
||||
return GetBounds(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetBounds(multiID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (BoundsCache.TryGetValue(multiID, out var bounds))
|
||||
{
|
||||
return bounds;
|
||||
}
|
||||
|
||||
var mcl = GetComponents(multiID);
|
||||
|
||||
int minZ = mcl.List.Min(t => t.m_OffsetZ);
|
||||
var maxZ = mcl.List.Max(t => t.m_OffsetZ + Math.Max(1, TileData.ItemTable[t.m_ItemID].Height));
|
||||
|
||||
if (multiID >= 24 && multiID <= 71)
|
||||
{
|
||||
if (multiID >= 24 && multiID <= 35)
|
||||
{
|
||||
maxZ = Math.Max(80, maxZ);
|
||||
}
|
||||
else if (multiID >= 36 && multiID <= 47)
|
||||
{
|
||||
maxZ = Math.Max(100, maxZ);
|
||||
}
|
||||
else if (multiID >= 48 && multiID <= 59)
|
||||
{
|
||||
maxZ = Math.Max(90, maxZ);
|
||||
}
|
||||
else if (multiID >= 60 && multiID <= 63)
|
||||
{
|
||||
maxZ = Math.Max(20, maxZ);
|
||||
}
|
||||
else if (multiID >= 64 && multiID <= 71)
|
||||
{
|
||||
maxZ = Math.Max(110, maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
bounds = new Rectangle3D(mcl.Min.X, mcl.Min.Y, minZ, mcl.Width + 1, mcl.Height + 1, maxZ - minZ);
|
||||
|
||||
BoundsCache[multiID] = bounds;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public static bool Contains(Point2D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(Point3D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(IPoint3D p)
|
||||
{
|
||||
return Contains(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(int x, int y)
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
|
||||
x -= X + mcl.Min.m_X;
|
||||
y -= Y + mcl.Min.m_Y;
|
||||
|
||||
return x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height && mcl.Tiles[x][y].Length > 0;
|
||||
}
|
||||
*/
|
||||
|
||||
public static bool IsEmpty(this MultiComponentList mcl, int x, int y)
|
||||
{
|
||||
return x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height || mcl.Tiles[x][y].Length == 0;
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.Z == z);
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int itemID, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.ID == itemID && t.Z == z);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetAbsoluteBounds(this MultiComponentList mcl)
|
||||
{
|
||||
return new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
#if !ServUOX
|
||||
using System;
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class NetStateExtUtility
|
||||
{
|
||||
private static readonly ClientVersion _70500 = new ClientVersion(7, 0, 50, 0);
|
||||
private static readonly ClientVersion _70610 = new ClientVersion(7, 0, 61, 0);
|
||||
|
||||
public static bool IsEnhanced(this NetState state)
|
||||
{
|
||||
#if ServUOX
|
||||
return state?.IsEnhancedClient == true;
|
||||
#else
|
||||
var v = state.Version;
|
||||
|
||||
if (v == null || (v.Major == 0 && v.Minor == 0 && v.Revision == 0 && v.Patch == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.GetPropertyValue("IsEnhancedClient", out bool ec))
|
||||
{
|
||||
ec = v.Major >= 67 || v.Type == ClientType.UOTD;
|
||||
}
|
||||
|
||||
return ec;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool SupportsUltimaStore(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70500;
|
||||
}
|
||||
|
||||
public static bool SupportsEndlessJourney(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70610;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum NotorietyType
|
||||
{
|
||||
None = 0,
|
||||
Innocent = Notoriety.Innocent,
|
||||
Ally = Notoriety.Ally,
|
||||
CanBeAttacked = Notoriety.CanBeAttacked,
|
||||
Criminal = Notoriety.Criminal,
|
||||
Enemy = Notoriety.Enemy,
|
||||
Murderer = Notoriety.Murderer,
|
||||
Invulnerable = Notoriety.Invulnerable
|
||||
}
|
||||
|
||||
public static class NotorietyExtUtility
|
||||
{
|
||||
public static int GetHue(this NotorietyType noto)
|
||||
{
|
||||
return Notoriety.GetHue((int)noto);
|
||||
}
|
||||
|
||||
public static Color GetColor(this NotorietyType noto)
|
||||
{
|
||||
switch ((int)noto)
|
||||
{
|
||||
case Notoriety.Innocent:
|
||||
return Color.SkyBlue;
|
||||
case Notoriety.Ally:
|
||||
return Color.LawnGreen;
|
||||
case Notoriety.CanBeAttacked:
|
||||
case Notoriety.Criminal:
|
||||
return Color.Silver;
|
||||
case Notoriety.Enemy:
|
||||
return Color.Orange;
|
||||
case Notoriety.Murderer:
|
||||
return Color.IndianRed;
|
||||
case Notoriety.Invulnerable:
|
||||
return Color.Yellow;
|
||||
}
|
||||
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Network;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Network
|
||||
{
|
||||
public static class PacketExtUtility
|
||||
{
|
||||
#if ServUOX
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset;
|
||||
|
||||
if (p.PacketID == 0x1A)
|
||||
{
|
||||
offset = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 8;
|
||||
}
|
||||
|
||||
return Rewrite(p, offset, (ushort)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#else
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemHS p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingOld p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingOld p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingSA p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, bool value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, sbyte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, byte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, short value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, ushort value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, int value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, uint value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
private static bool Rewrite<T>(PacketWriter writer, int offset, bool reset, Action<T> write, T value)
|
||||
{
|
||||
var pos = -1L;
|
||||
|
||||
try
|
||||
{
|
||||
pos = writer.Position;
|
||||
|
||||
writer.Position = offset;
|
||||
|
||||
write(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reset && pos >= 0)
|
||||
{
|
||||
writer.Position = pos;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] GetBuffer(this Packet packet)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
if (writer != null)
|
||||
{
|
||||
return writer.ToArray();
|
||||
}
|
||||
|
||||
if (GetCompiledBuffer(packet, out var buffer))
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public static bool GetCompiledBuffer(this Packet packet, out byte[] buffer)
|
||||
{
|
||||
return packet.GetFieldValue("m_CompiledBuffer", out buffer);
|
||||
}
|
||||
|
||||
public static bool SetCompiledBuffer(this Packet packet, byte[] buffer)
|
||||
{
|
||||
return packet.SetFieldValue("m_CompiledBuffer", buffer);
|
||||
}
|
||||
|
||||
public static PacketWriter GetWriter(this Packet packet)
|
||||
{
|
||||
#if ServUOX
|
||||
return packet?.Stream;
|
||||
#else
|
||||
return packet?.UnderlyingStream;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public static class PlayerMobileExtUtility
|
||||
{
|
||||
public static ClientVersion GetClientVersion(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version : new ClientVersion(null);
|
||||
}
|
||||
|
||||
public static ClientType GetClientType(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version.Type : ClientType.Regular;
|
||||
}
|
||||
|
||||
public static bool HasClient(this PlayerMobile player, ClientType type)
|
||||
{
|
||||
return player.IsOnline() && player.NetState.Version.Type == type;
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, MapPoint mp)
|
||||
{
|
||||
FixMap(m, mp.Map, mp.Location);
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, Map def, Point3D loc)
|
||||
{
|
||||
if (m == null || m.Deleted || def == null || def == Map.Internal || loc == Point3D.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.LogoutMap == null || m.LogoutMap == Map.Internal)
|
||||
{
|
||||
m.LogoutLocation = loc.ToPoint3D();
|
||||
m.LogoutMap = def;
|
||||
}
|
||||
|
||||
if (m.Map != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.IsOnline())
|
||||
{
|
||||
BaseCreature.TeleportPets(m, loc, def);
|
||||
m.MoveToWorld(loc, def);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.Location = loc;
|
||||
m.Internalize();
|
||||
m.AutoStablePets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,247 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle2DExtUtility
|
||||
{
|
||||
public static Point2D GetRandomPoint(this Rectangle2D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine(this IEnumerable<Rectangle2D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D ToRectangle3D(this Rectangle2D r, int floor = 0, int roof = 0)
|
||||
{
|
||||
return new Rectangle3D(r.X, r.Y, floor, r.Width, r.Height, roof);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle2D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle2D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
public static Point2D GetCenter(this Rectangle2D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle2D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize(this Rectangle2D r, int xOff = 0, int yOff = 0, int wOff = 0, int hOff = 0)
|
||||
{
|
||||
return new Rectangle2D(r.X + xOff, r.Y + yOff, r.Width + wOff, r.Height + hOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice(this Rectangle2D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
int ow, oh;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle2D(x, y, ow, oh);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle2D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints(this Rectangle2D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle2D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle2D r, Rectangle2D or)
|
||||
{
|
||||
return GetBorder(r).Union(GetBorder(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle3DExtUtility
|
||||
{
|
||||
public static Point3D GetRandomPoint(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point3D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y),
|
||||
Utility.RandomMinMax(bounds.Start.Z, bounds.End.Z));
|
||||
}
|
||||
|
||||
public static Point2D GetRandomPoint2D(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine2D(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D Combine(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0,
|
||||
minX = Int32.MaxValue,
|
||||
minY = Int32.MaxValue,
|
||||
maxX = Int32.MinValue,
|
||||
maxY = Int32.MinValue,
|
||||
minZ = Region.MaxZ,
|
||||
maxZ = Region.MinZ;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
minZ = Math.Min(minZ, Math.Min(r.Start.Z, r.End.Z));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
maxZ = Math.Max(maxZ, Math.Max(r.Start.Z, r.End.Z));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle3D(new Point3D(minX, minY, minZ), new Point3D(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects)
|
||||
{
|
||||
return ZFix(rects, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects, int zMin, int zMax)
|
||||
{
|
||||
if (rects == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var r in rects.Select(r => r.ZFix(zMin, zMax)))
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect)
|
||||
{
|
||||
return ZFix(rect, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect, int zMin, int zMax)
|
||||
{
|
||||
return new Rectangle3D(rect.Start.ToPoint3D(Math.Min(zMin, zMax)), rect.End.ToPoint3D(Math.Max(zMin, zMax)));
|
||||
}
|
||||
|
||||
public static Rectangle2D ToRectangle2D(this Rectangle3D r)
|
||||
{
|
||||
return new Rectangle2D(r.Start, r.End);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle3D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height * r.Depth;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle3D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this RegionRect[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this List<RegionRect> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<RegionRect> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint2D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint3D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y)
|
||||
{
|
||||
return x >= rect.Start.X && y >= rect.Start.Y && x < rect.End.X && y < rect.End.Y;
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y, int z)
|
||||
{
|
||||
return Contains(rect, x, y) && z >= rect.Start.Z && z < rect.End.Z;
|
||||
}
|
||||
|
||||
public static Point2D GetCenter2D(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static Point3D GetCenter(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone3D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static int GetVolume(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height * r.Depth;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize2D(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
return ToRectangle2D(r).Resize(xOff, yOff, wOff, hOff);
|
||||
}
|
||||
|
||||
public static Rectangle3D Resize(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
var s = r.Start;
|
||||
|
||||
return new Rectangle3D(s.X + xOff, s.Y + yOff, s.Z + zOff, r.Width + wOff, r.Height + hOff, r.Depth + dOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice2D(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
return ToRectangle2D(rect).Slice(w, h);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> Slice(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y, z = Math.Min(rect.Start.Z, rect.End.Z);
|
||||
int ow, oh, od = rect.Depth;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle3D(x, y, z, ow, oh, od);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle3D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints2D(this Rectangle3D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> EnumeratePoints(this Rectangle3D r)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach2D(this Rectangle3D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints2D(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle3D r, Action<Point3D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder2D(r, 1);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r, int size)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size, z1 = r.Start.Z + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size, z2 = r.End.Z - size;
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
if (z >= z1 || z <= z2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects2D(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
return GetBorder2D(r).Any(GetBorder2D(or).Contains);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
var minZL = Math.Min(r.Start.Z, r.End.Z);
|
||||
var maxZL = Math.Max(r.Start.Z, r.End.Z);
|
||||
|
||||
var minZR = Math.Min(or.Start.Z, or.End.Z);
|
||||
var maxZR = Math.Max(or.Start.Z, or.End.Z);
|
||||
|
||||
if (minZL > maxZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxZL < minZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetBorder2D(r).Union(GetBorder2D(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
@@ -0,0 +1,618 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Crypto;
|
||||
using VitaNex.FX;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class RegionExtUtility
|
||||
{
|
||||
public class RegionSerial : CryptoHashCode
|
||||
{
|
||||
public override string Value => base.Value.Replace("-", String.Empty);
|
||||
|
||||
public RegionSerial(Region r)
|
||||
: base(
|
||||
CryptoHashType.MD5,
|
||||
r.GetType().FullName + r.Map.Name + r.Name + r.Area.GetBoundsHashCode() + TimeStamp.UtcNow.Stamp +
|
||||
Utility.RandomDouble())
|
||||
{ }
|
||||
|
||||
public RegionSerial(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PreviewRegion : Region, IEquatable<Region>
|
||||
{
|
||||
private static ulong _UID;
|
||||
|
||||
public RegionSerial Serial { get; private set; }
|
||||
|
||||
public PollTimer Timer { get; private set; }
|
||||
public EffectInfo[] Effects { get; private set; }
|
||||
|
||||
public DateTime Expire { get; set; }
|
||||
public int EffectID { get; set; }
|
||||
public int EffectHue { get; set; }
|
||||
public EffectRender EffectRender { get; set; }
|
||||
|
||||
public PreviewRegion(Region r)
|
||||
: this(r.Name, r.Map, r.Area)
|
||||
{
|
||||
Serial = GetSerial(r);
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle2D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle3D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
EffectID = 1801;
|
||||
EffectHue = 85;
|
||||
EffectRender = EffectRender.ShadowOutline;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public override void OnRegister()
|
||||
{
|
||||
base.OnRegister();
|
||||
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
if (Effects == null)
|
||||
{
|
||||
var effects = new EffectInfo[Area.Length][,];
|
||||
|
||||
effects.SetAll(i => new EffectInfo[Area[i].Width, Area[i].Height]);
|
||||
|
||||
for (var index = 0; index < Area.Length; index++)
|
||||
{
|
||||
var b = Area[index];
|
||||
|
||||
var xSpacing = Math.Max(1, Math.Min(16, b.Width / 8));
|
||||
var ySpacing = Math.Max(1, Math.Min(16, b.Height / 8));
|
||||
|
||||
var minX = Math.Min(b.Start.X, b.End.X);
|
||||
var maxX = Math.Max(b.Start.X, b.End.X);
|
||||
|
||||
var minY = Math.Min(b.Start.Y, b.End.Y);
|
||||
var maxY = Math.Max(b.Start.Y, b.End.Y);
|
||||
|
||||
Parallel.For(
|
||||
minX,
|
||||
maxX,
|
||||
x => Parallel.For(
|
||||
minY,
|
||||
maxY,
|
||||
y =>
|
||||
{
|
||||
if (x != b.Start.X && x != b.End.X - 1 && x % xSpacing != 0 //
|
||||
&& y != b.Start.Y && y != b.End.Y - 1 && y % ySpacing != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var idxX = x - minX;
|
||||
var idxY = y - minY;
|
||||
|
||||
effects[index][idxX, idxY] = new EffectInfo(
|
||||
new Point3D(x, y, 0),
|
||||
Map,
|
||||
EffectID,
|
||||
EffectHue,
|
||||
1,
|
||||
25,
|
||||
EffectRender);
|
||||
}));
|
||||
}
|
||||
|
||||
Effects = effects.SelectMany(list => list.OfType<EffectInfo>()).ToArray();
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.SetSource(e.Source.ToPoint3D(e.Source.GetAverageZ(e.Map)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Timer == null)
|
||||
{
|
||||
Timer = PollTimer.FromSeconds(
|
||||
1.0,
|
||||
() =>
|
||||
{
|
||||
if (DateTime.UtcNow > Expire)
|
||||
{
|
||||
Unregister();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Send();
|
||||
}
|
||||
},
|
||||
() => Registered);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer.Running = true;
|
||||
}
|
||||
|
||||
_Previews.Update(Serial, this);
|
||||
}
|
||||
|
||||
public override void OnUnregister()
|
||||
{
|
||||
base.OnUnregister();
|
||||
|
||||
if (Timer != null)
|
||||
{
|
||||
Timer.Running = false;
|
||||
Timer = null;
|
||||
}
|
||||
|
||||
if (Effects != null)
|
||||
{
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
|
||||
Effects.SetAll(i => null);
|
||||
Effects = null;
|
||||
}
|
||||
|
||||
Expire = DateTime.UtcNow;
|
||||
|
||||
_Previews.Remove(Serial);
|
||||
}
|
||||
|
||||
public bool Equals(Region other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && Serial.Equals(GetSerial(other));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<RegionSerial, Region> _Regions;
|
||||
private static readonly Dictionary<RegionSerial, PreviewRegion> _Previews;
|
||||
|
||||
static RegionExtUtility()
|
||||
{
|
||||
_Regions = new Dictionary<RegionSerial, Region>();
|
||||
_Previews = new Dictionary<RegionSerial, PreviewRegion>();
|
||||
}
|
||||
|
||||
public static RegionSerial GetSerial(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
return ((PreviewRegion)r).Serial;
|
||||
}
|
||||
|
||||
lock (_Regions)
|
||||
{
|
||||
if (_Regions.ContainsValue(r))
|
||||
{
|
||||
return _Regions.GetKey(r);
|
||||
}
|
||||
|
||||
var s = new RegionSerial(r);
|
||||
|
||||
_Regions.Update(s, r);
|
||||
|
||||
//Console.WriteLine("Region Serial: ('{0}', '{1}', '{2}') = {3}", r.GetType().Name, r.Map, r.Name, s.ValueHash);
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle2D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle3D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
this Region r,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent)
|
||||
{
|
||||
if (r == null || r.Area == null || r.Area.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hue < 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
|
||||
if (effect <= 0)
|
||||
{
|
||||
effect = 1801;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.EffectID = effect;
|
||||
pr.EffectHue = hue;
|
||||
pr.EffectRender = render;
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null && pr.Area.GetBoundsHashCode() != r.Area.GetBoundsHashCode())
|
||||
{
|
||||
pr.Unregister();
|
||||
pr = null;
|
||||
}
|
||||
|
||||
if (pr == null)
|
||||
{
|
||||
pr = new PreviewRegion(r)
|
||||
{
|
||||
EffectHue = hue,
|
||||
EffectID = effect,
|
||||
EffectRender = render
|
||||
};
|
||||
}
|
||||
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
public static void ClearPreview(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.Unregister();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null)
|
||||
{
|
||||
pr.Unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p, Map m)
|
||||
{
|
||||
return s.Owner == m && s.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Region r, Point3D p, Map m)
|
||||
{
|
||||
return r.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects.Values.SelectMany(o => o))
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
public static bool Contains(this RegionRect r, Point3D p, Map m)
|
||||
{
|
||||
return r.Region.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects)
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect r, Point3D p)
|
||||
{
|
||||
return r.Rect.Contains(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion Create<TRegion>(params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
return Create(typeof(TRegion), args) as TRegion;
|
||||
}
|
||||
|
||||
public static Region Create(Type type, params object[] args)
|
||||
{
|
||||
return type.CreateInstanceSafe<Region>(args);
|
||||
}
|
||||
|
||||
public static TRegion Clone<TRegion>(this TRegion region, params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (region == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fields = region.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var remove = new[]
|
||||
{
|
||||
"Serial",
|
||||
"Name",
|
||||
"Map",
|
||||
"Parent",
|
||||
"Area",
|
||||
"Sectors",
|
||||
"ChildLevel",
|
||||
"Registered"
|
||||
};
|
||||
|
||||
foreach (var entry in remove)
|
||||
{
|
||||
if (!fields.Remove("m_" + entry))
|
||||
{
|
||||
fields.Remove("_" + entry);
|
||||
}
|
||||
}
|
||||
|
||||
region.Unregister();
|
||||
|
||||
var reg = Create(region.GetType(), args) as TRegion;
|
||||
|
||||
if (reg != null)
|
||||
{
|
||||
fields.Serialize(reg);
|
||||
reg.Register();
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool IsPartOf<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf<TRegion>();
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion<TRegion>() : null;
|
||||
}
|
||||
#else
|
||||
public static bool IsPartOf<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf(typeof(TRegion));
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion(typeof(TRegion)) as TRegion : null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null ? GetRegion<TRegion>(m.Region) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null && GetRegion<TRegion>(m.Region) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && GetRegion(m, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && GetRegion(m, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Region r)
|
||||
{
|
||||
return m != null && m.Region != null && m.Region.IsPartOf(r);
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Region.Find(i.GetWorldLocation(), i.Map);
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? GetRegion<TRegion>(reg) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, string name)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, Type type)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && GetRegion<TRegion>(reg) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Type type)
|
||||
{
|
||||
return i != null && GetRegion(i, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, string name)
|
||||
{
|
||||
return i != null && GetRegion(i, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Region r)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && reg.IsPartOf(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum SkillCategory
|
||||
{
|
||||
None = 0,
|
||||
Combat,
|
||||
Healing,
|
||||
Magic,
|
||||
Bardic,
|
||||
Rogue,
|
||||
Knowledge,
|
||||
Craft,
|
||||
Harvest
|
||||
}
|
||||
|
||||
public enum SkillIcon
|
||||
{
|
||||
None = 1033,
|
||||
Combat = 1008,
|
||||
Healing = 1037,
|
||||
Magic = 1006,
|
||||
Bardic = 1031,
|
||||
Rogue = 1002,
|
||||
Knowledge = 1034,
|
||||
Craft = 1030,
|
||||
Harvest = 1036
|
||||
}
|
||||
|
||||
public static class SkillExtUtility
|
||||
{
|
||||
public static readonly SkillName[] EmptySkills = new SkillName[0];
|
||||
|
||||
public static readonly SkillName[] AllSkills = default(SkillName).GetValues<SkillName>();
|
||||
|
||||
public static readonly SkillName[] CombatSkills =
|
||||
{
|
||||
SkillName.Archery, SkillName.Fencing, SkillName.Focus, SkillName.Macing, SkillName.Parry, SkillName.Swords,
|
||||
SkillName.Tactics, SkillName.Wrestling, SkillName.Bushido
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HealingSkills =
|
||||
{
|
||||
SkillName.Healing, SkillName.Veterinary
|
||||
};
|
||||
|
||||
public static readonly SkillName[] MagicSkills =
|
||||
{
|
||||
SkillName.EvalInt, SkillName.Inscribe, SkillName.Magery, SkillName.Meditation, SkillName.Chivalry,
|
||||
SkillName.Necromancy, SkillName.MagicResist, SkillName.Spellweaving, SkillName.SpiritSpeak
|
||||
};
|
||||
|
||||
public static readonly SkillName[] BardicSkills =
|
||||
{SkillName.Discordance, SkillName.Musicianship, SkillName.Peacemaking, SkillName.Provocation};
|
||||
|
||||
public static readonly SkillName[] RogueSkills =
|
||||
{
|
||||
SkillName.Begging, SkillName.DetectHidden, SkillName.Hiding, SkillName.Lockpicking, SkillName.Poisoning,
|
||||
SkillName.RemoveTrap, SkillName.Snooping, SkillName.Stealing, SkillName.Stealth, SkillName.Ninjitsu
|
||||
};
|
||||
|
||||
public static readonly SkillName[] KnowledgeSkills =
|
||||
{
|
||||
SkillName.Anatomy, SkillName.AnimalLore, SkillName.AnimalTaming, SkillName.ArmsLore, SkillName.Camping,
|
||||
SkillName.Forensics, SkillName.Herding, SkillName.ItemID, SkillName.TasteID, SkillName.Tracking
|
||||
};
|
||||
|
||||
public static readonly SkillName[] CraftSkills =
|
||||
{
|
||||
SkillName.Alchemy, SkillName.Blacksmith, SkillName.Fletching, SkillName.Carpentry, SkillName.Cooking,
|
||||
SkillName.Cartography, SkillName.Tailoring, SkillName.Tinkering, SkillName.Imbuing
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HarvestSkills =
|
||||
{
|
||||
SkillName.Fishing, SkillName.Mining, SkillName.Lumberjacking
|
||||
};
|
||||
|
||||
public static readonly SkillCategory[] Categories =
|
||||
{
|
||||
SkillCategory.Combat, SkillCategory.Healing, SkillCategory.Magic, SkillCategory.Bardic, SkillCategory.Rogue,
|
||||
SkillCategory.Knowledge, SkillCategory.Craft, SkillCategory.Harvest
|
||||
};
|
||||
|
||||
public static readonly SkillIcon[] Icons =
|
||||
{
|
||||
SkillIcon.None, SkillIcon.Combat, SkillIcon.Healing, SkillIcon.Magic, SkillIcon.Bardic, SkillIcon.Rogue,
|
||||
SkillIcon.Knowledge, SkillIcon.Craft, SkillIcon.Harvest
|
||||
};
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName)).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills, Expansion ex)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName), ex).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills)
|
||||
{
|
||||
return OfExpansion(skills, Core.Expansion);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills, Expansion ex)
|
||||
{
|
||||
foreach (var sk in skills)
|
||||
{
|
||||
switch (sk)
|
||||
{
|
||||
case SkillName.Chivalry:
|
||||
case SkillName.Focus:
|
||||
case SkillName.Necromancy:
|
||||
case SkillName.SpiritSpeak:
|
||||
{
|
||||
if (ex >= Expansion.AOS)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Bushido:
|
||||
case SkillName.Ninjitsu:
|
||||
{
|
||||
if (ex >= Expansion.SE)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Spellweaving:
|
||||
{
|
||||
if (ex >= Expansion.ML)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Imbuing:
|
||||
case SkillName.Throwing:
|
||||
case SkillName.Mysticism:
|
||||
{
|
||||
if (ex >= Expansion.SA)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
yield return sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SkillName[] GetSkills(this SkillCategory cat)
|
||||
{
|
||||
switch (cat)
|
||||
{
|
||||
case SkillCategory.Combat:
|
||||
return CombatSkills;
|
||||
case SkillCategory.Healing:
|
||||
return HealingSkills;
|
||||
case SkillCategory.Magic:
|
||||
return MagicSkills;
|
||||
case SkillCategory.Bardic:
|
||||
return BardicSkills;
|
||||
case SkillCategory.Rogue:
|
||||
return RogueSkills;
|
||||
case SkillCategory.Knowledge:
|
||||
return KnowledgeSkills;
|
||||
case SkillCategory.Craft:
|
||||
return CraftSkills;
|
||||
case SkillCategory.Harvest:
|
||||
return HarvestSkills;
|
||||
}
|
||||
|
||||
return EmptySkills;
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillCategory cat)
|
||||
{
|
||||
return Icons[(int)cat];
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillInfo info)
|
||||
{
|
||||
return GetIcon((SkillName)info.SkillID);
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillName skill)
|
||||
{
|
||||
return GetIcon(GetCategory(skill));
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillInfo info)
|
||||
{
|
||||
return (int)GetIcon(info);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillCategory cat)
|
||||
{
|
||||
return (int)GetIcon(cat);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillName skill)
|
||||
{
|
||||
return (int)GetIcon(skill);
|
||||
}
|
||||
|
||||
public static bool IsLocked(this Skill skill, SkillLock locked)
|
||||
{
|
||||
return skill.Lock == locked;
|
||||
}
|
||||
|
||||
public static bool IsCapped(this Skill skill)
|
||||
{
|
||||
return skill.Base >= skill.Cap;
|
||||
}
|
||||
|
||||
public static bool IsZero(this Skill skill)
|
||||
{
|
||||
return skill.Base <= 0;
|
||||
}
|
||||
|
||||
public static bool IsZeroOrCapped(this Skill skill)
|
||||
{
|
||||
return IsZero(skill) || IsCapped(skill);
|
||||
}
|
||||
|
||||
public static bool WillCap(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base + value >= skill.Cap) : (skill.Base + value > skill.Cap);
|
||||
}
|
||||
|
||||
public static bool WillZero(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base - value <= 0) : (skill.Base - value < 0);
|
||||
}
|
||||
|
||||
public static bool DecreaseBase(this Skill skill, double value, bool ignoreZero = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreZero || (!IsZero(skill) && !WillZero(skill, value, false)))
|
||||
{
|
||||
skill.Base -= value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IncreaseBase(this Skill skill, double value, bool ignoreCap = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Cap - skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreCap || (!IsCapped(skill) && !WillCap(skill, value, false)))
|
||||
{
|
||||
skill.Base += value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetBase(this Skill skill, double value, bool ignoreLimits = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Max(0, Math.Min(skill.Cap, value));
|
||||
}
|
||||
|
||||
if (ignoreLimits || (value < skill.Base && !IsZero(skill) && !WillZero(skill, skill.Base - value, false)) ||
|
||||
(value > skill.Base && !IsCapped(skill) && !WillCap(skill, value - skill.Base, false)))
|
||||
{
|
||||
skill.Base = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void DecreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap - value);
|
||||
}
|
||||
|
||||
public static void IncreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap + value);
|
||||
}
|
||||
|
||||
public static void SetCap(this Skill skill, double value)
|
||||
{
|
||||
skill.Cap = Math.Max(0, value);
|
||||
Normalize(skill);
|
||||
}
|
||||
|
||||
public static void Normalize(this Skill skill)
|
||||
{
|
||||
if (IsCapped(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = skill.CapFixedPoint;
|
||||
}
|
||||
|
||||
if (IsZero(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetName(this SkillName skill)
|
||||
{
|
||||
return SkillInfo.Table[(int)skill].Name;
|
||||
}
|
||||
|
||||
public static bool CheckCategory(this SkillName skill, SkillCategory category)
|
||||
{
|
||||
return GetCategory(skill) == category;
|
||||
}
|
||||
|
||||
public static SkillCategory GetCategory(this SkillName skill)
|
||||
{
|
||||
if (IsCombat(skill))
|
||||
{
|
||||
return SkillCategory.Combat;
|
||||
}
|
||||
|
||||
if (IsHealing(skill))
|
||||
{
|
||||
return SkillCategory.Healing;
|
||||
}
|
||||
|
||||
if (IsMagic(skill))
|
||||
{
|
||||
return SkillCategory.Magic;
|
||||
}
|
||||
|
||||
if (IsBardic(skill))
|
||||
{
|
||||
return SkillCategory.Bardic;
|
||||
}
|
||||
|
||||
if (IsRogue(skill))
|
||||
{
|
||||
return SkillCategory.Rogue;
|
||||
}
|
||||
|
||||
if (IsKnowledge(skill))
|
||||
{
|
||||
return SkillCategory.Knowledge;
|
||||
}
|
||||
|
||||
if (IsCraft(skill))
|
||||
{
|
||||
return SkillCategory.Craft;
|
||||
}
|
||||
|
||||
if (IsHarvest(skill))
|
||||
{
|
||||
return SkillCategory.Harvest;
|
||||
}
|
||||
|
||||
return SkillCategory.None;
|
||||
}
|
||||
|
||||
public static bool IsCombat(this SkillName skill)
|
||||
{
|
||||
return CombatSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHealing(this SkillName skill)
|
||||
{
|
||||
return HealingSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsMagic(this SkillName skill)
|
||||
{
|
||||
return MagicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsBardic(this SkillName skill)
|
||||
{
|
||||
return BardicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsRogue(this SkillName skill)
|
||||
{
|
||||
return RogueSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsKnowledge(this SkillName skill)
|
||||
{
|
||||
return KnowledgeSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsCraft(this SkillName skill)
|
||||
{
|
||||
return CraftSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHarvest(this SkillName skill)
|
||||
{
|
||||
return HarvestSkills.Contains(skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Spells;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class SpellExtUtility
|
||||
{
|
||||
public static SpellInfo GetSpellInfo(this ISpell s)
|
||||
{
|
||||
return SpellUtility.GetSpellInfo(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
457
Scripts/SubSystem/VitaNex/Core/Extensions/System/ChronExt.cs
Normal file
457
Scripts/SubSystem/VitaNex/Core/Extensions/System/ChronExt.cs
Normal file
@@ -0,0 +1,457 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Text;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
[Flags]
|
||||
public enum Months
|
||||
{
|
||||
None = 0x000,
|
||||
January = 0x001,
|
||||
Febuary = 0x002,
|
||||
March = 0x004,
|
||||
April = 0x008,
|
||||
May = 0x010,
|
||||
June = 0x020,
|
||||
July = 0x040,
|
||||
August = 0x080,
|
||||
September = 0x100,
|
||||
October = 0x200,
|
||||
November = 0x400,
|
||||
December = 0x800,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
|
||||
public enum TimeUnit
|
||||
{
|
||||
Years,
|
||||
Months,
|
||||
Weeks,
|
||||
Days,
|
||||
Hours,
|
||||
Minutes,
|
||||
Seconds,
|
||||
Milliseconds
|
||||
}
|
||||
|
||||
public static class ChronExtUtility
|
||||
{
|
||||
public static bool InRange(this TimeSpan now, TimeSpan start, TimeSpan end)
|
||||
{
|
||||
if (start <= end)
|
||||
{
|
||||
return now >= start && now <= end;
|
||||
}
|
||||
|
||||
return now >= start || now <= end;
|
||||
}
|
||||
|
||||
public static bool InRange(this DateTime now, DateTime start, DateTime end)
|
||||
{
|
||||
if (now.Year < end.Year)
|
||||
{
|
||||
return now >= start;
|
||||
}
|
||||
|
||||
if (now.Year > start.Year)
|
||||
{
|
||||
return now <= end;
|
||||
}
|
||||
|
||||
return now >= start && now <= end;
|
||||
}
|
||||
|
||||
public static double GetTotal(this TimeSpan time, TimeUnit unit)
|
||||
{
|
||||
var total = (double)time.Ticks;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case TimeUnit.Years:
|
||||
total = time.TotalDays / 365.2422;
|
||||
break;
|
||||
case TimeUnit.Months:
|
||||
total = time.TotalDays / 30.43685;
|
||||
break;
|
||||
case TimeUnit.Weeks:
|
||||
total = time.TotalDays / 7.0;
|
||||
break;
|
||||
case TimeUnit.Days:
|
||||
total = time.TotalDays;
|
||||
break;
|
||||
case TimeUnit.Hours:
|
||||
total = time.TotalHours;
|
||||
break;
|
||||
case TimeUnit.Minutes:
|
||||
total = time.TotalMinutes;
|
||||
break;
|
||||
case TimeUnit.Seconds:
|
||||
total = time.TotalSeconds;
|
||||
break;
|
||||
case TimeUnit.Milliseconds:
|
||||
total = time.TotalMilliseconds;
|
||||
break;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public static DateTime Interpolate(this DateTime start, DateTime end, double percent)
|
||||
{
|
||||
return new DateTime((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeSpan Interpolate(this TimeSpan start, TimeSpan end, double percent)
|
||||
{
|
||||
return new TimeSpan((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeStamp Interpolate(this TimeStamp start, TimeStamp end, double percent)
|
||||
{
|
||||
return new TimeStamp((long)(start.Ticks + ((end.Ticks - start.Ticks) * percent)));
|
||||
}
|
||||
|
||||
public static TimeStamp ToTimeStamp(this DateTime date)
|
||||
{
|
||||
return new TimeStamp(date);
|
||||
}
|
||||
|
||||
public static Months GetMonth(this DateTime date)
|
||||
{
|
||||
switch (date.Month)
|
||||
{
|
||||
case 1:
|
||||
return Months.January;
|
||||
case 2:
|
||||
return Months.Febuary;
|
||||
case 3:
|
||||
return Months.March;
|
||||
case 4:
|
||||
return Months.April;
|
||||
case 5:
|
||||
return Months.May;
|
||||
case 6:
|
||||
return Months.June;
|
||||
case 7:
|
||||
return Months.July;
|
||||
case 8:
|
||||
return Months.August;
|
||||
case 9:
|
||||
return Months.September;
|
||||
case 10:
|
||||
return Months.October;
|
||||
case 11:
|
||||
return Months.November;
|
||||
case 12:
|
||||
return Months.December;
|
||||
default:
|
||||
return Months.None;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this TimeZoneInfo tzo, bool dst)
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
if (tzo.Id == "UTC")
|
||||
{
|
||||
return tzo.Id;
|
||||
}
|
||||
|
||||
string value;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
value = tzo.DaylightName.Replace("Daylight Time", String.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = tzo.StandardName.Replace("Standard Time", String.Empty);
|
||||
}
|
||||
|
||||
foreach (var c in value)
|
||||
{
|
||||
if (!Char.IsWhiteSpace(c) && Char.IsLetter(c) && Char.IsUpper(c))
|
||||
{
|
||||
build.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
build.Append(dst ? "-DT" : "-ST");
|
||||
|
||||
value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this DateTime date, string format = "t D d M y")
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
build.EnsureCapacity(format.Length * 2);
|
||||
|
||||
var noformat = false;
|
||||
|
||||
for (var i = 0; i < format.Length; i++)
|
||||
{
|
||||
if (format[i] == '#')
|
||||
{
|
||||
noformat = !noformat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (noformat)
|
||||
{
|
||||
build.Append(format[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '\\':
|
||||
build.Append((i + 1 < format.Length) ? Convert.ToString(format[++i]) : String.Empty);
|
||||
break;
|
||||
case 'x':
|
||||
case 'z':
|
||||
{
|
||||
var utc = date.Kind == DateTimeKind.Utc;
|
||||
var tzo = utc ? TimeZoneInfo.Utc : TimeZoneInfo.Local;
|
||||
|
||||
build.Append(ToSimpleString(tzo, false));
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
case 'Z':
|
||||
{
|
||||
var utc = date.Kind == DateTimeKind.Utc;
|
||||
var tzo = utc ? TimeZoneInfo.Utc : TimeZoneInfo.Local;
|
||||
|
||||
build.Append(ToSimpleString(tzo, date.IsDaylightSavingTime()));
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
build.Append(date.DayOfWeek);
|
||||
break;
|
||||
case 'd':
|
||||
build.Append(date.Day);
|
||||
break;
|
||||
case 'M':
|
||||
build.Append(GetMonth(date));
|
||||
break;
|
||||
case 'm':
|
||||
build.Append(date.Month);
|
||||
break;
|
||||
case 'y':
|
||||
build.Append(date.Year);
|
||||
break;
|
||||
case 't':
|
||||
{
|
||||
var tf = String.Empty;
|
||||
|
||||
if (i + 1 < format.Length)
|
||||
{
|
||||
if (format[i + 1] == '@')
|
||||
{
|
||||
++i;
|
||||
|
||||
while (++i < format.Length && format[i] != '@')
|
||||
{
|
||||
tf += format[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build.Append(ToSimpleString(date.TimeOfDay, !String.IsNullOrWhiteSpace(tf) ? tf : "h-m-s"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
build.Append(format[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToSimpleString(this TimeSpan time, string format = "h-m-s")
|
||||
{
|
||||
var build = ObjectPool<StringBuilder>.AcquireObject();
|
||||
|
||||
build.EnsureCapacity(format.Length * 2);
|
||||
|
||||
var noformat = false;
|
||||
var nopadding = false;
|
||||
var zeroValue = false;
|
||||
var zeroEmpty = 0;
|
||||
|
||||
string fFormat, dFormat;
|
||||
object append;
|
||||
|
||||
for (var i = 0; i < format.Length; i++)
|
||||
{
|
||||
if (format[i] == '#')
|
||||
{
|
||||
noformat = !noformat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (noformat)
|
||||
{
|
||||
build.Append(format[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '!':
|
||||
nopadding = !nopadding;
|
||||
continue;
|
||||
}
|
||||
|
||||
fFormat = zeroEmpty > 0 ? (nopadding ? "{0:#.#}" : "{0:#.##}") : (nopadding ? "{0:0.#}" : "{0:0.##}");
|
||||
dFormat = zeroEmpty > 0 ? (nopadding ? "{0:#}" : "{0:##}") : (nopadding ? "{0:0}" : "{0:00}");
|
||||
|
||||
append = null;
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case '<':
|
||||
++zeroEmpty;
|
||||
break;
|
||||
case '>':
|
||||
{
|
||||
if (zeroEmpty == 0 || (zeroEmpty > 0 && --zeroEmpty == 0))
|
||||
{
|
||||
zeroValue = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
{
|
||||
if (i + 1 < format.Length)
|
||||
{
|
||||
append = format[++i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
append = ToSimpleString(TimeZoneInfo.Utc, false);
|
||||
break;
|
||||
case 'X':
|
||||
append = ToSimpleString(TimeZoneInfo.Utc, DateTime.UtcNow.IsDaylightSavingTime());
|
||||
break;
|
||||
case 'z':
|
||||
append = ToSimpleString(TimeZoneInfo.Local, false);
|
||||
break;
|
||||
case 'Z':
|
||||
append = ToSimpleString(TimeZoneInfo.Local, DateTime.Now.IsDaylightSavingTime());
|
||||
break;
|
||||
case 'D':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalDays);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalHours);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalMinutes);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
append = String.Format(fFormat, time.TotalSeconds);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
append = String.Format(dFormat, time.Days);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
{
|
||||
append = String.Format(dFormat, time.Hours);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
{
|
||||
append = String.Format(dFormat, time.Minutes);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
append = String.Format(dFormat, time.Seconds);
|
||||
zeroValue = String.IsNullOrWhiteSpace((string)append);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
append = format[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (append != null && (!zeroValue || zeroEmpty <= 0))
|
||||
{
|
||||
build.Append(append);
|
||||
}
|
||||
}
|
||||
|
||||
var value = build.ToString();
|
||||
|
||||
ObjectPool.Free(ref build);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string ToDirectoryName(this DateTime date, string format = "D d M y")
|
||||
{
|
||||
return ToSimpleString(date, format);
|
||||
}
|
||||
|
||||
public static string ToFileName(this DateTime date, string format = "D d M y")
|
||||
{
|
||||
return ToSimpleString(date, format);
|
||||
}
|
||||
|
||||
public static string ToDirectoryName(this TimeSpan time, string format = "h-m")
|
||||
{
|
||||
return ToSimpleString(time, format);
|
||||
}
|
||||
|
||||
public static string ToFileName(this TimeSpan time, string format = "h-m")
|
||||
{
|
||||
return ToSimpleString(time, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Scripts/SubSystem/VitaNex/Core/Extensions/System/ColorExt.cs
Normal file
105
Scripts/SubSystem/VitaNex/Core/Extensions/System/ColorExt.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ColorExtUtility
|
||||
{
|
||||
public static Color ToColor(this KnownColor color)
|
||||
{
|
||||
return Color.FromKnownColor(color);
|
||||
}
|
||||
|
||||
public static Color555 ToColor555(this Color value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ushort ToArgb555(this Color value)
|
||||
{
|
||||
return ToColor555(value);
|
||||
}
|
||||
|
||||
public static int ToRgb(this Color value)
|
||||
{
|
||||
return value.ToArgb() & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
public static Color Interpolate(this Color source, Color target, double percent)
|
||||
{
|
||||
if (percent <= 0.0)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
if (percent >= 1.0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
var r = (int)(source.R + (target.R - source.R) * percent);
|
||||
var g = (int)(source.G + (target.G - source.G) * percent);
|
||||
var b = (int)(source.B + (target.B - source.B) * percent);
|
||||
|
||||
return Color.FromArgb(255, r, g, b);
|
||||
}
|
||||
|
||||
public static Color FixBlackTransparency(this Color source)
|
||||
{
|
||||
if (source.IsEmpty || source.A <= 0 || source.R >= 0x08 || source.G >= 0x08 || source.B >= 0x08)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
var r = source.R;
|
||||
var g = source.G;
|
||||
var b = source.B;
|
||||
|
||||
if (r != g || r != b)
|
||||
{
|
||||
var rd = 0x08 - r;
|
||||
var gd = 0x08 - g;
|
||||
var bd = 0x08 - b;
|
||||
|
||||
if (rd < gd && rd < bd)
|
||||
{
|
||||
r = 0x08;
|
||||
}
|
||||
else if (gd < rd && gd < bd)
|
||||
{
|
||||
g = 0x08;
|
||||
}
|
||||
else if (bd < rd && bd < gd)
|
||||
{
|
||||
b = 0x08;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 0x08;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 0x08;
|
||||
}
|
||||
|
||||
source = Color.FromArgb(source.A, r, g, b);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
||||
396
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumExt.cs
Normal file
396
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumExt.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class EnumExtUtility
|
||||
{
|
||||
public static string ToString(this Enum e, bool friendly)
|
||||
{
|
||||
return friendly ? GetFriendlyName(e) : GetName(e);
|
||||
}
|
||||
|
||||
public static string GetName(this Enum e)
|
||||
{
|
||||
return EnumCache.GetName(e);
|
||||
}
|
||||
|
||||
public static string GetFriendlyName(this Enum e)
|
||||
{
|
||||
return EnumCache.GetFriendlyName(e);
|
||||
}
|
||||
|
||||
public static string GetDescription(this Enum e)
|
||||
{
|
||||
return EnumCache.GetDescription(e);
|
||||
}
|
||||
|
||||
public static T GetAttribute<T>(this Enum e) where T : Attribute
|
||||
{
|
||||
return GetAttributes<T>(e).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetAttributes<T>(this Enum e) where T : Attribute
|
||||
{
|
||||
var type = e.GetType();
|
||||
var info = type.GetMember(e.ToString());
|
||||
|
||||
if (info.IsNullOrEmpty() || info[0] == null)
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
var attributes = info[0].GetCustomAttributes(typeof(T), false);
|
||||
|
||||
if (attributes.IsNullOrEmpty())
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
return attributes.OfType<T>();
|
||||
}
|
||||
|
||||
public static TEnum Normalize<TEnum>(this Enum e)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
var type = typeof(TEnum);
|
||||
var flag = default(TEnum);
|
||||
|
||||
if (!type.IsEnum)
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse(e.ToString(), out flag) || (!type.HasCustomAttribute<FlagsAttribute>(true) && !Enum.IsDefined(type, flag)))
|
||||
{
|
||||
flag = default(TEnum);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static bool IsValid(this Enum e)
|
||||
{
|
||||
return Enum.IsDefined(e.GetType(), e);
|
||||
}
|
||||
|
||||
public static TCast[] Split<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetValues<TCast>(e, true);
|
||||
}
|
||||
|
||||
public static TCast[] GetValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static TCast[] GetValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, local).ToArray();
|
||||
}
|
||||
|
||||
public static TCast[] GetAbsoluteValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return GetAbsoluteValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static TCast[] GetAbsoluteValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateAbsoluteValues<TCast>(e, local).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateAbsoluteValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateAbsoluteValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateAbsoluteValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, local).Where(o => !Equals(o, 0) && !Equals(o, String.Empty)).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateValues<TCast>(this Enum e) where TCast : IConvertible
|
||||
{
|
||||
return EnumerateValues<TCast>(e, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<TCast> EnumerateValues<TCast>(this Enum e, bool local) where TCast : IConvertible
|
||||
{
|
||||
var eType = e.GetType();
|
||||
var vType = typeof(TCast);
|
||||
var vals = EnumCache.EnumerateValues(eType);
|
||||
|
||||
if (local)
|
||||
{
|
||||
vals = vals.Where(e.HasFlag);
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(char)))
|
||||
{
|
||||
return vals.Select(Convert.ToChar).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(sbyte)))
|
||||
{
|
||||
return vals.Select(Convert.ToSByte).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(byte)))
|
||||
{
|
||||
return vals.Select(Convert.ToByte).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(short)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt16).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(ushort)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt16).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(int)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt32).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(uint)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt32).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(long)))
|
||||
{
|
||||
return vals.Select(Convert.ToInt64).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(ulong)))
|
||||
{
|
||||
return vals.Select(Convert.ToUInt64).Cast<TCast>();
|
||||
}
|
||||
|
||||
if (vType.IsEqual(typeof(string)))
|
||||
{
|
||||
return vals.Select(Convert.ToString).Cast<TCast>();
|
||||
}
|
||||
|
||||
return vals.Cast<TCast>();
|
||||
}
|
||||
|
||||
public static bool AnyFlags<TEnum>(this Enum e, IEnumerable<TEnum> flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.Any(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().Any(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AnyFlags<TEnum>(this Enum e, params TEnum[] flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.Any(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().Any(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AllFlags<TEnum>(this Enum e, IEnumerable<TEnum> flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.All(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().All(e.HasFlag);
|
||||
}
|
||||
|
||||
public static bool AllFlags<TEnum>(this Enum e, params TEnum[] flags)
|
||||
#if MONO
|
||||
where TEnum : struct, IComparable, IFormattable, IConvertible
|
||||
#else
|
||||
where TEnum : struct, Enum
|
||||
#endif
|
||||
{
|
||||
if (!e.GetType().HasCustomAttribute<FlagsAttribute>(true))
|
||||
{
|
||||
return flags != null && flags.All(o => Equals(e, o));
|
||||
}
|
||||
|
||||
return flags != null && flags.Cast<Enum>().All(e.HasFlag);
|
||||
}
|
||||
|
||||
private static class EnumCache
|
||||
{
|
||||
public class Entry
|
||||
{
|
||||
public readonly Enum[] Values;
|
||||
public readonly string[] Names, FriendlyNames, Descriptions;
|
||||
|
||||
public Entry(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
Values = new Enum[0];
|
||||
Names = new string[0];
|
||||
FriendlyNames = new string[0];
|
||||
Descriptions = new string[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Values = Enum.GetValues(type).CastToArray<Enum>();
|
||||
Names = Enum.GetNames(type);
|
||||
|
||||
FriendlyNames = new string[Names.Length];
|
||||
Descriptions = new string[Names.Length];
|
||||
|
||||
for (var i = 0; i < Values.Length; i++)
|
||||
{
|
||||
FriendlyNames[i] = Names[i].SpaceWords();
|
||||
Descriptions[i] = String.Join("\n", GetAttributes<DescriptionAttribute>(Values[i]).Where(o => !String.IsNullOrWhiteSpace(o.Description)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Entry _Empty = new Entry(null);
|
||||
|
||||
private static readonly Dictionary<Type, Entry> _Cache = new Dictionary<Type, Entry>();
|
||||
|
||||
public static Entry Lookup(Type type)
|
||||
{
|
||||
if (type == null || !type.IsEnum)
|
||||
{
|
||||
return _Empty;
|
||||
}
|
||||
|
||||
if (!_Cache.TryGetValue(type, out var result))
|
||||
{
|
||||
_Cache[type] = result = new Entry(type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string[] GetNames(Type type)
|
||||
{
|
||||
return Lookup(type).Names;
|
||||
}
|
||||
|
||||
public static Enum[] GetValues(Type type)
|
||||
{
|
||||
return Lookup(type).Values;
|
||||
}
|
||||
|
||||
public static string[] GetDescriptions(Type type)
|
||||
{
|
||||
return Lookup(type).Descriptions;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateNames(Type type)
|
||||
{
|
||||
return GetNames(type);
|
||||
}
|
||||
|
||||
public static IEnumerable<Enum> EnumerateValues(Type type)
|
||||
{
|
||||
return GetValues(type);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateDescriptions(Type type)
|
||||
{
|
||||
return GetDescriptions(type);
|
||||
}
|
||||
|
||||
public static string GetName(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.Names[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static string GetFriendlyName(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.FriendlyNames[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static string GetDescription(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
var index = Array.IndexOf(entry.Values, e);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return entry.Descriptions[index];
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static int GetIndex(Enum e)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var entry = Lookup(type);
|
||||
|
||||
return Array.IndexOf(entry.Values, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2607
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumerableExt.cs
Normal file
2607
Scripts/SubSystem/VitaNex/Core/Extensions/System/EnumerableExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.IO;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ExceptionExtUtility
|
||||
{
|
||||
public static void ToConsole(this Exception e, bool simple = false, bool log = false)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (VitaNexCore.ConsoleLock)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine(simple ? e.Message : e.ToString());
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Log(this Exception e, FileInfo file = null)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
file = file ?? VitaNexCore.LogFile;
|
||||
|
||||
var now = String.Format("***ERROR LOG [{0}]***", DateTime.Now);
|
||||
|
||||
lock (VitaNexCore.IOLock)
|
||||
{
|
||||
file.AppendText(false, String.Empty, now, e.Message, e.ToString(), e.HelpLink, String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
508
Scripts/SubSystem/VitaNex/Core/Extensions/System/IOExt.cs
Normal file
508
Scripts/SubSystem/VitaNex/Core/Extensions/System/IOExt.cs
Normal file
@@ -0,0 +1,508 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace System.IO
|
||||
{
|
||||
public static class IOExtUtility
|
||||
{
|
||||
public static FileMime GetMimeType(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return FileMime.Lookup(file);
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllBytes(file.FullName);
|
||||
}
|
||||
|
||||
public static string[] ReadAllLines(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllLines(file.FullName);
|
||||
}
|
||||
|
||||
public static string ReadAllText(this FileInfo file)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
return File.ReadAllText(file.FullName);
|
||||
}
|
||||
|
||||
public static void WriteAllBytes(this FileInfo file, byte[] bytes)
|
||||
{
|
||||
File.WriteAllBytes(file.FullName, bytes);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, string[] contents)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, string[] contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, IEnumerable<string> contents)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllLines(this FileInfo file, IEnumerable<string> contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllLines(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllText(this FileInfo file, string contents)
|
||||
{
|
||||
File.WriteAllText(file.FullName, contents);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteAllText(this FileInfo file, string contents, Encoding encoding)
|
||||
{
|
||||
File.WriteAllText(file.FullName, contents, encoding);
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
public static bool GetAttribute(this FileInfo file, FileAttributes attr)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
return file.Attributes.HasFlag(attr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void SetAttribute(this FileInfo file, FileAttributes attr, bool value)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
file.Attributes |= attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Attributes &= ~attr;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHidden(this FileInfo file, bool value)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
SetAttribute(file, FileAttributes.Hidden, value);
|
||||
}
|
||||
|
||||
public static FileStream OpenRead(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
}
|
||||
|
||||
public static FileStream OpenWrite(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.Write, FileShare.Write);
|
||||
}
|
||||
|
||||
public static FileStream OpenAppend(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Append, FileAccess.Write, FileShare.Write);
|
||||
}
|
||||
|
||||
public static FileStream Open(this FileInfo file, bool create = false, bool replace = false)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
file = EnsureFile(file, replace);
|
||||
}
|
||||
|
||||
return file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
|
||||
public static void AppendText(this FileInfo file, bool truncate, params string[] lines)
|
||||
{
|
||||
if (lines == null || lines.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
file = EnsureFile(file, false);
|
||||
}
|
||||
else if (truncate)
|
||||
{
|
||||
file = EnsureFile(file, true);
|
||||
}
|
||||
|
||||
using (var fs = OpenAppend(file))
|
||||
{
|
||||
var data = String.Join(Environment.NewLine, lines) + Environment.NewLine;
|
||||
var buffer = Encoding.UTF8.GetBytes(data);
|
||||
|
||||
fs.Write(buffer, 0, buffer.Length);
|
||||
fs.Flush();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a files' existence
|
||||
/// </summary>
|
||||
/// <returns>FileInfo representing the file ensured for 'info'</returns>
|
||||
public static FileInfo EnsureFile(this FileInfo file)
|
||||
{
|
||||
return EnsureFile(file, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a files' existence
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="replace">True: replace the file if it exists</param>
|
||||
/// <returns>FileInfo representing the file ensured for 'info'</returns>
|
||||
public static FileInfo EnsureFile(this FileInfo file, bool replace)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
EnsureDirectory(file.Directory, false);
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
using (var fs = file.Create())
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
else if (replace)
|
||||
{
|
||||
VitaNexCore.TryCatch(file.Delete);
|
||||
|
||||
using (var fs = file.Create())
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a directories' existence
|
||||
/// </summary>
|
||||
/// <returns>DirectoryInfo representing the directory ensured for 'info'</returns>
|
||||
public static DirectoryInfo EnsureDirectory(this DirectoryInfo dir)
|
||||
{
|
||||
return EnsureDirectory(dir, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a directories' existence
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <param name="replace">True: replace the directory if it exists</param>
|
||||
/// <returns>DirectoryInfo representing the directory ensured for 'info'</returns>
|
||||
public static DirectoryInfo EnsureDirectory(this DirectoryInfo dir, bool replace)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
}
|
||||
else if (replace)
|
||||
{
|
||||
EmptyDirectory(dir, true);
|
||||
|
||||
VitaNexCore.TryCatch(dir.Delete, true);
|
||||
|
||||
dir.Create();
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory with the option to include sub directories
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="incDirs">True: includes sub directories</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, bool incDirs)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var f in dir.EnumerateFiles())
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
if (incDirs)
|
||||
{
|
||||
foreach (var d in dir.EnumerateDirectories())
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, including all sub-directories and files that are older than the
|
||||
/// given age.
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="age">Age at which a directory or file is considered old enough to be deleted</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, TimeSpan age)
|
||||
{
|
||||
EmptyDirectory(dir, age, "*", SearchOption.AllDirectories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, only deleting files that meet the mask criteria and are older than
|
||||
/// the given age.
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="age">Age at which a directory or file is considered old enough to be deleted</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, TimeSpan age, string mask, SearchOption option)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var expire = DateTime.UtcNow.Subtract(age);
|
||||
|
||||
foreach (var d in AllDirectories(dir, mask, option).Where(d => d.CreationTimeUtc < expire))
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
|
||||
foreach (var f in AllFiles(dir, mask, option).Where(f => f.CreationTimeUtc < expire))
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empties the contents of the specified directory, only deleting files that meet the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to empty</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void EmptyDirectory(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
dir.Refresh();
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var d in AllDirectories(dir, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Delete, true);
|
||||
}
|
||||
|
||||
foreach (var f in AllFiles(dir, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(f.Delete);
|
||||
}
|
||||
|
||||
dir.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the specified directory to the specified target directory, only including files that meet
|
||||
/// the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to copy</param>
|
||||
/// <param name="dest">Directory to copy to</param>
|
||||
public static void CopyDirectory(this DirectoryInfo source, DirectoryInfo dest)
|
||||
{
|
||||
CopyDirectory(source, dest, "*", SearchOption.AllDirectories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the specified directory to the specified target directory, only including files that meet
|
||||
/// the mask criteria
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to copy</param>
|
||||
/// <param name="dest">Directory to copy to</param>
|
||||
/// <param name="mask">String mask to use to filter file names</param>
|
||||
/// <param name="option">Search options</param>
|
||||
public static void CopyDirectory(this DirectoryInfo source, DirectoryInfo dest, string mask, SearchOption option)
|
||||
{
|
||||
source.Refresh();
|
||||
|
||||
if (!source.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDirectory(dest, false);
|
||||
|
||||
foreach (var f in AllFiles(source, mask, option))
|
||||
{
|
||||
VitaNexCore.TryCatch(
|
||||
() =>
|
||||
{
|
||||
var t = new FileInfo(f.FullName.Replace(source.FullName, dest.FullName));
|
||||
|
||||
EnsureDirectory(t.Directory);
|
||||
|
||||
f.CopyTo(t.FullName, true);
|
||||
});
|
||||
}
|
||||
|
||||
source.Refresh();
|
||||
dest.Refresh();
|
||||
}
|
||||
|
||||
public static IEnumerable<DirectoryInfo> AllDirectories(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
foreach (var d in dir.EnumerateDirectories(mask).Where(d => d != dir))
|
||||
{
|
||||
if (option == SearchOption.AllDirectories)
|
||||
{
|
||||
foreach (var s in AllDirectories(d, mask, SearchOption.AllDirectories).Where(s => s != d))
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
|
||||
yield return d;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<FileInfo> AllFiles(this DirectoryInfo dir, string mask, SearchOption option)
|
||||
{
|
||||
if (option == SearchOption.AllDirectories)
|
||||
{
|
||||
foreach (var f in dir.EnumerateDirectories()
|
||||
.Where(d => d != dir)
|
||||
.SelectMany(d => AllFiles(d, mask, SearchOption.AllDirectories)))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var f in dir.EnumerateFiles(mask))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
Scripts/SubSystem/VitaNex/Core/Extensions/System/IPAddressExt.cs
Normal file
115
Scripts/SubSystem/VitaNex/Core/Extensions/System/IPAddressExt.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class IPAddressExtUtility
|
||||
{
|
||||
private static readonly Regex _AddressPattern = new Regex(@"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})");
|
||||
|
||||
private static IPAddress _Public;
|
||||
|
||||
public static IPAddress FindPublic()
|
||||
{
|
||||
if (_Public != null)
|
||||
{
|
||||
return _Public;
|
||||
}
|
||||
|
||||
var data = String.Empty;
|
||||
|
||||
var request = WebRequest.Create("https://api.ipify.org");
|
||||
|
||||
using (var response = request.GetResponse())
|
||||
{
|
||||
var r = response.GetResponseStream();
|
||||
|
||||
if (r != null)
|
||||
{
|
||||
using (var stream = new StreamReader(r))
|
||||
{
|
||||
data = stream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var m = _AddressPattern.Match(data);
|
||||
|
||||
return (_Public = m.Success ? IPAddress.Parse(m.Value) : null);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPAddress> FindInternal(this IPAddress address)
|
||||
{
|
||||
if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Select(a => a.GetIPProperties())
|
||||
.SelectMany(p => p.UnicastAddresses.Where(u => address.AddressFamily == u.Address.AddressFamily))
|
||||
.Select(uni => uni.Address);
|
||||
}
|
||||
|
||||
return address.ToEnumerable();
|
||||
}
|
||||
|
||||
public static bool IsPrivateNetwork(this IPAddress address)
|
||||
{
|
||||
// 10.0.0.0/8
|
||||
// 172.16.0.0/12
|
||||
// 192.168.0.0/16
|
||||
// 169.254.0.0/16
|
||||
// 100.64.0.0/10 RFC 6598
|
||||
|
||||
if (address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("192.168.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("10.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("172.16-31.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("169.254.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.IPMatch("100.64-127.*", address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
423
Scripts/SubSystem/VitaNex/Core/Extensions/System/NumericExt.cs
Normal file
423
Scripts/SubSystem/VitaNex/Core/Extensions/System/NumericExt.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class NumericExtUtility
|
||||
{
|
||||
private static string GetOrdinalSuffix(double value)
|
||||
{
|
||||
var ones = (int)(value % 10);
|
||||
var tens = (int)Math.Floor(value / 10.0) % 10;
|
||||
|
||||
string suff;
|
||||
|
||||
if (tens == 1)
|
||||
{
|
||||
suff = "th";
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ones)
|
||||
{
|
||||
case 1:
|
||||
suff = "st";
|
||||
break;
|
||||
case 2:
|
||||
suff = "nd";
|
||||
break;
|
||||
case 3:
|
||||
suff = "rd";
|
||||
break;
|
||||
default:
|
||||
suff = "th";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return suff;
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this decimal value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix((double)value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this double value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this float value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this sbyte value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this byte value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this short value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this ushort value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this int value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this uint value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this long value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static string ToOrdinalString(this ulong value, string format = "#,0")
|
||||
{
|
||||
return value.ToString(format) + GetOrdinalSuffix(value);
|
||||
}
|
||||
|
||||
public static decimal Overflow(this decimal value, decimal min, decimal max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static double Overflow(this double value, double min, double max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float Overflow(this float value, float min, float max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static sbyte Overflow(this sbyte value, sbyte min, sbyte max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (sbyte)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (sbyte)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static byte Overflow(this byte value, byte min, byte max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (byte)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (byte)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static short Overflow(this short value, short min, short max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (short)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (short)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ushort Overflow(this ushort value, ushort min, ushort max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = (ushort)(max - (min - value));
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = (ushort)(min + (value - max));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int Overflow(this int value, int min, int max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static uint Overflow(this uint value, uint min, uint max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static long Overflow(this long value, long min, long max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ulong Overflow(this ulong value, ulong min, ulong max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
var swapMin = Math.Min(min, max);
|
||||
var swapMax = Math.Max(min, max);
|
||||
|
||||
min = swapMin;
|
||||
max = swapMax;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
while (value < min)
|
||||
{
|
||||
value = max - (min - value);
|
||||
}
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
while (value > max)
|
||||
{
|
||||
value = min + (value - max);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
401
Scripts/SubSystem/VitaNex/Core/Extensions/System/ObjectExt.cs
Normal file
401
Scripts/SubSystem/VitaNex/Core/Extensions/System/ObjectExt.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Reflection;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class ObjectExtUtility
|
||||
{
|
||||
private const BindingFlags _CommonFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
||||
|
||||
private static readonly Delegate[] _EmptyDelegates = new Delegate[0];
|
||||
|
||||
public static Delegate[] GetEventDelegates(this object obj, string eventName)
|
||||
{
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var ei = t.GetEvent(eventName, f);
|
||||
|
||||
if (ei == null)
|
||||
{
|
||||
return _EmptyDelegates;
|
||||
}
|
||||
|
||||
var efi = t.GetField(ei.Name, f | BindingFlags.GetField);
|
||||
|
||||
if (efi == null)
|
||||
{
|
||||
efi = t.GetField("EVENT_" + ei.Name.ToUpper(), f | BindingFlags.GetField);
|
||||
}
|
||||
|
||||
if (efi == null)
|
||||
{
|
||||
return _EmptyDelegates;
|
||||
}
|
||||
|
||||
var efv = (Delegate)efi.GetValue(obj is Type ? null : obj);
|
||||
|
||||
return efv.GetInvocationList();
|
||||
}
|
||||
|
||||
public static MethodInfo[] GetEventMethods(this object obj, string eventName)
|
||||
{
|
||||
return GetEventDelegates(obj, eventName).Select(e => e.Method).ToArray();
|
||||
}
|
||||
|
||||
public static bool GetFieldValue(this object obj, string name, out object value)
|
||||
{
|
||||
return GetFieldValue<object>(obj, name, out value);
|
||||
}
|
||||
|
||||
public static bool GetFieldValue<T>(this object obj, string name, out T value)
|
||||
{
|
||||
value = default(T);
|
||||
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetField(name, f);
|
||||
|
||||
try
|
||||
{
|
||||
value = (T)o.GetValue(obj is Type ? null : obj);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SetFieldValue(this object obj, string name, object value)
|
||||
{
|
||||
return SetFieldValue<object>(obj, name, value);
|
||||
}
|
||||
|
||||
public static bool SetFieldValue<T>(this object obj, string name, T value)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetField(name, f);
|
||||
|
||||
try
|
||||
{
|
||||
o.SetValue(obj is Type ? null : obj, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetPropertyValue(this object obj, string name, out object value)
|
||||
{
|
||||
return GetPropertyValue<object>(obj, name, out value);
|
||||
}
|
||||
|
||||
public static bool GetPropertyValue<T>(this object obj, string name, out T value)
|
||||
{
|
||||
value = default(T);
|
||||
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetProperty(name, f, null, typeof(T), Type.EmptyTypes, null);
|
||||
|
||||
try
|
||||
{
|
||||
value = (T)o.GetValue(obj is Type ? null : obj, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SetPropertyValue(this object obj, string name, object value)
|
||||
{
|
||||
return SetPropertyValue<object>(obj, name, value);
|
||||
}
|
||||
|
||||
public static bool SetPropertyValue<T>(this object obj, string name, T value)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var o = t.GetProperty(name, f, null, typeof(T), Type.EmptyTypes, null);
|
||||
|
||||
try
|
||||
{
|
||||
o.SetValue(obj is Type ? null : obj, value, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static object InvokeMethod(this object obj, string name, params object[] args)
|
||||
{
|
||||
if (obj == null || String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var t = obj as Type ?? obj.GetType();
|
||||
|
||||
var f = _CommonFlags;
|
||||
|
||||
if (t.IsSealed && t.IsAbstract)
|
||||
{
|
||||
f &= ~BindingFlags.Instance;
|
||||
}
|
||||
|
||||
var a = args != null ? Type.GetTypeArray(args) : Type.EmptyTypes;
|
||||
|
||||
var o = t.GetMethod(name, f, null, a, null);
|
||||
|
||||
try
|
||||
{
|
||||
if (o.ReturnType == typeof(void))
|
||||
{
|
||||
return o.Invoke(obj is Type ? null : obj, args) ?? true;
|
||||
}
|
||||
|
||||
return o.Invoke(obj is Type ? null : obj, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
public static T InvokeMethod<T>(this object obj, string name, params object[] args)
|
||||
{
|
||||
if (InvokeMethod(obj, name, args) is T o)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
|
||||
#if NET48_OR_GREATER
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int GetTypeHashCode(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var type = obj.GetType();
|
||||
|
||||
return type.GetValueHashCode();
|
||||
}
|
||||
|
||||
public static string GetTypeName(this object obj, bool raw)
|
||||
{
|
||||
Type type;
|
||||
|
||||
if (obj is Type t)
|
||||
{
|
||||
type = t;
|
||||
}
|
||||
else if (obj is ITypeSelectProperty ts)
|
||||
{
|
||||
type = ts.ExpectedType;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = obj.GetType();
|
||||
}
|
||||
|
||||
if (raw)
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
return type.ResolveName();
|
||||
}
|
||||
|
||||
public static bool TypeEquals<T>(this object obj)
|
||||
{
|
||||
return TypeEquals<T>(obj, true);
|
||||
}
|
||||
|
||||
public static bool TypeEquals<T>(this object obj, bool child)
|
||||
{
|
||||
return TypeEquals(obj, typeof(T), child);
|
||||
}
|
||||
|
||||
public static bool TypeEquals(this object obj, object other)
|
||||
{
|
||||
return TypeEquals(obj, other, true);
|
||||
}
|
||||
|
||||
public static bool TypeEquals(this object obj, object other, bool child)
|
||||
{
|
||||
if (obj == null || other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(obj, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Type l, r;
|
||||
|
||||
if (obj is Type tl)
|
||||
{
|
||||
l = tl;
|
||||
}
|
||||
else if (obj is ITypeSelectProperty tsl)
|
||||
{
|
||||
l = tsl.InternalType;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = obj.GetType();
|
||||
}
|
||||
|
||||
if (other is Type tr)
|
||||
{
|
||||
r = tr;
|
||||
}
|
||||
else if (other is ITypeSelectProperty tsr)
|
||||
{
|
||||
r = tsr.InternalType;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = other as Type ?? other.GetType();
|
||||
}
|
||||
|
||||
if (child)
|
||||
{
|
||||
return l.IsEqualOrChildOf(r);
|
||||
}
|
||||
|
||||
return l.IsEqual(r);
|
||||
}
|
||||
|
||||
public static int CompareNull<T>(this T obj, T other)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
CompareNull(obj, other, ref result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool CompareNull<T>(this T obj, T other, ref int result)
|
||||
{
|
||||
if (obj == null && other == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
++result;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (other == null)
|
||||
{
|
||||
--result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static FieldList<T> GetFields<T>(this T obj, BindingFlags flags = BindingFlags.Default, Func<FieldInfo, bool> filter = null)
|
||||
{
|
||||
return new FieldList<T>(obj, flags, filter);
|
||||
}
|
||||
|
||||
public static PropertyList<T> GetProperties<T>(this T obj, BindingFlags flags = BindingFlags.Default, Func<PropertyInfo, bool> filter = null)
|
||||
{
|
||||
return new PropertyList<T>(obj, flags, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
1252
Scripts/SubSystem/VitaNex/Core/Extensions/System/StringExt.cs
Normal file
1252
Scripts/SubSystem/VitaNex/Core/Extensions/System/StringExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
448
Scripts/SubSystem/VitaNex/Core/Extensions/System/TypeExt.cs
Normal file
448
Scripts/SubSystem/VitaNex/Core/Extensions/System/TypeExt.cs
Normal file
@@ -0,0 +1,448 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.Crypto;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class TypeExtUtility
|
||||
{
|
||||
private static readonly Dictionary<Type, List<Type>> _ChildrenCache;
|
||||
private static readonly Dictionary<Type, List<Type>> _ConstructableChildrenCache;
|
||||
|
||||
private static readonly Dictionary<Type, int> _ValueHashCache;
|
||||
|
||||
static TypeExtUtility()
|
||||
{
|
||||
_ChildrenCache = new Dictionary<Type, List<Type>>(0x100);
|
||||
_ConstructableChildrenCache = new Dictionary<Type, List<Type>>(0x100);
|
||||
|
||||
_ValueHashCache = new Dictionary<Type, int>(0x400);
|
||||
}
|
||||
|
||||
private static string FormatName(string value)
|
||||
{
|
||||
var i = value.IndexOf('`');
|
||||
|
||||
return (i > 0 ? value.Substring(0, i) : value).SpaceWords();
|
||||
}
|
||||
|
||||
public static string ResolveName(this Type t)
|
||||
{
|
||||
return FormatName(t.Name);
|
||||
}
|
||||
|
||||
public static int GetValueHashCode(this Type t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_ValueHashCache.TryGetValue(t, out var hash) || hash == 0)
|
||||
{
|
||||
using (var c = new CryptoHashCode(CryptoHashType.MD5, t.FullName))
|
||||
{
|
||||
_ValueHashCache[t] = hash = c.ValueHash;
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static Type[] GetTypeCache(this Assembly asm)
|
||||
{
|
||||
return ScriptCompiler.GetTypeCache(asm).Types;
|
||||
}
|
||||
|
||||
public static Type[] GetHierarchy(this Type t)
|
||||
{
|
||||
return GetHierarchy(t, false);
|
||||
}
|
||||
|
||||
public static Type[] GetHierarchy(this Type t, bool self)
|
||||
{
|
||||
return EnumerateHierarchy(t, self).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> EnumerateHierarchy(this Type t)
|
||||
{
|
||||
return EnumerateHierarchy(t, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> EnumerateHierarchy(this Type t, bool self)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
yield return t;
|
||||
}
|
||||
|
||||
while (t.BaseType != null)
|
||||
{
|
||||
yield return t = t.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type FindParent<T>(this Type type)
|
||||
{
|
||||
var ot = typeof(T);
|
||||
|
||||
return EnumerateHierarchy(type, false).FirstOrDefault(pt => pt == ot);
|
||||
}
|
||||
|
||||
public static bool TryFindParent<T>(this Type type, out Type parent)
|
||||
{
|
||||
return (parent = FindParent<T>(type)) != null;
|
||||
}
|
||||
|
||||
public static Type FindParent<T>(this Type type, Func<Type, bool> predicate)
|
||||
{
|
||||
var ot = typeof(T);
|
||||
|
||||
return EnumerateHierarchy(type, false).Where(t => t == ot).FirstOrDefault(predicate);
|
||||
}
|
||||
|
||||
public static bool TryFindParent<T>(this Type type, Func<Type, bool> predicate, out Type parent)
|
||||
{
|
||||
return (parent = FindParent<T>(type, predicate)) != null;
|
||||
}
|
||||
|
||||
public static Type FindParent(this Type type, Func<Type, bool> predicate)
|
||||
{
|
||||
return EnumerateHierarchy(type, false).FirstOrDefault(predicate);
|
||||
}
|
||||
|
||||
public static bool TryFindParent(this Type type, Func<Type, bool> predicate, out Type parent)
|
||||
{
|
||||
return (parent = FindParent(type, predicate)) != null;
|
||||
}
|
||||
|
||||
public static bool GetCustomAttributes<TAttribute>(this Type t, bool inherit, out TAttribute[] attrs)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
attrs = GetCustomAttributes<TAttribute>(t, inherit);
|
||||
return attrs != null && attrs.Length > 0;
|
||||
}
|
||||
|
||||
public static TAttribute[] GetCustomAttributes<TAttribute>(this Type t, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return t != null
|
||||
? t.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().ToArray()
|
||||
: new TAttribute[0];
|
||||
}
|
||||
|
||||
public static bool HasCustomAttribute<TAttribute>(this Type t, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
var attrs = GetCustomAttributes<TAttribute>(t, inherit);
|
||||
|
||||
return attrs != null && attrs.Length > 0;
|
||||
}
|
||||
|
||||
public static int CompareTo(this Type t, Type other)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
if (t.CompareNull(other, ref result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var lp = t.BaseType;
|
||||
|
||||
while (lp != null)
|
||||
{
|
||||
if (lp == other)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lp = lp.BaseType;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName)
|
||||
{
|
||||
return IsEqual(a, bName, true);
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName, bool ignoreCase)
|
||||
{
|
||||
return IsEqual(a, bName, ignoreCase, bName.ContainsAny('.', '+'));
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, string bName, bool ignoreCase, bool fullName)
|
||||
{
|
||||
var b = Type.GetType(bName) ??
|
||||
(fullName ? ScriptCompiler.FindTypeByFullName(bName) : ScriptCompiler.FindTypeByName(bName));
|
||||
|
||||
return IsEqual(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqual(this Type a, Type b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public static bool IsEqual<TObj>(this Type t)
|
||||
{
|
||||
return IsEqual(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName)
|
||||
{
|
||||
return IsEqualOrChildOf(a, bName, true);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName, bool ignoreCase)
|
||||
{
|
||||
return IsEqualOrChildOf(a, bName, ignoreCase, bName.ContainsAny('.', '+'));
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, string bName, bool ignoreCase, bool fullName)
|
||||
{
|
||||
var b = Type.GetType(bName) ??
|
||||
(fullName ? ScriptCompiler.FindTypeByFullName(bName) : ScriptCompiler.FindTypeByName(bName));
|
||||
|
||||
return IsEqualOrChildOf(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf(this Type a, Type b)
|
||||
{
|
||||
return IsEqual(a, b) || IsChildOf(a, b);
|
||||
}
|
||||
|
||||
public static bool IsEqualOrChildOf<TObj>(this Type t)
|
||||
{
|
||||
return IsEqualOrChildOf(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsChildOf(this Type a, Type b)
|
||||
{
|
||||
return a != null && b != null && a != b && !a.IsInterface && !a.IsEnum &&
|
||||
(b.IsInterface ? HasInterface(a, b) : b.IsAssignableFrom(a));
|
||||
}
|
||||
|
||||
public static bool IsChildOf<TObj>(this Type t)
|
||||
{
|
||||
return IsChildOf(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool HasInterface(this Type t, string i)
|
||||
{
|
||||
var iType = Type.GetType(i, false) ??
|
||||
(i.IndexOf('.') < 0 ? ScriptCompiler.FindTypeByName(i) : ScriptCompiler.FindTypeByFullName(i));
|
||||
|
||||
return iType != null && iType.IsInterface && HasInterface(t, iType);
|
||||
}
|
||||
|
||||
public static bool HasInterface<TObj>(this Type t)
|
||||
{
|
||||
return HasInterface(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool HasInterface(this Type t, Type i)
|
||||
{
|
||||
return t != null && i != null && i.IsInterface && t.GetInterface(i.FullName) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructable(this Type a)
|
||||
{
|
||||
return IsConstructable(a, Type.EmptyTypes);
|
||||
}
|
||||
|
||||
public static bool IsConstructable(this Type a, Type[] argTypes)
|
||||
{
|
||||
if (a == null || a.IsAbstract || a.IsInterface || a.IsEnum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructor(argTypes) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom(this Type a, Type b)
|
||||
{
|
||||
if (a == null || b == null || a.IsAbstract || !IsChildOf(a, b))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Length > 0;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom<TObj>(this Type t)
|
||||
{
|
||||
return IsConstructableFrom(t, typeof(TObj));
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom(this Type a, Type b, Type[] argTypes)
|
||||
{
|
||||
if (a == null || b == null || a.IsAbstract || !IsChildOf(a, b))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.GetConstructor(argTypes) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructableFrom<TObj>(this Type t, Type[] argTypes)
|
||||
{
|
||||
return IsConstructableFrom(t, typeof(TObj), argTypes);
|
||||
}
|
||||
|
||||
public static Type[] GetChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
return FindChildren(type, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
|
||||
var types = _ChildrenCache.GetValue(type);
|
||||
|
||||
if (types == null)
|
||||
{
|
||||
var asm = ScriptCompiler.Assemblies.With(Core.Assembly, Assembly.GetCallingAssembly()).ToList();
|
||||
|
||||
asm.Prune();
|
||||
|
||||
types = asm.Select(GetTypeCache).SelectMany(o => o.Where(t => !IsEqual(t, type) && IsChildOf(t, type))).ToList();
|
||||
|
||||
asm.Free(true);
|
||||
|
||||
if (types.Count > 0 && types.Count <= 0x100)
|
||||
{
|
||||
_ChildrenCache[type] = types;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ChildrenCache.Count >= 0x100)
|
||||
{
|
||||
_ChildrenCache.Pop().Value.Free(true);
|
||||
}
|
||||
|
||||
return predicate != null ? types.Where(predicate) : types.AsEnumerable();
|
||||
}
|
||||
|
||||
public static Type[] GetConstructableChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
return FindConstructableChildren(type, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindConstructableChildren(this Type type, Func<Type, bool> predicate = null)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
|
||||
var types = _ConstructableChildrenCache.GetValue(type);
|
||||
|
||||
if (types == null)
|
||||
{
|
||||
types = FindChildren(type).Where(t => IsConstructableFrom(t, type)).ToList();
|
||||
|
||||
if (types.Count > 0 && types.Count <= 0x100)
|
||||
{
|
||||
_ConstructableChildrenCache[type] = types;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ConstructableChildrenCache.Count >= 0x100)
|
||||
{
|
||||
_ConstructableChildrenCache.Pop().Value.Free(true);
|
||||
}
|
||||
|
||||
return predicate != null ? types.Where(predicate) : types.AsEnumerable();
|
||||
}
|
||||
|
||||
public static TObj CreateInstance<TObj>(this Type t, params object[] args)
|
||||
{
|
||||
if (t == null || t.IsAbstract || t.IsInterface || t.IsEnum)
|
||||
{
|
||||
return default(TObj);
|
||||
}
|
||||
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
return (TObj)Activator.CreateInstance(t, true);
|
||||
}
|
||||
|
||||
return (TObj)Activator.CreateInstance(t, args);
|
||||
}
|
||||
|
||||
public static TObj CreateInstanceSafe<TObj>(this Type t, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CreateInstance<TObj>(t, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e = new TypeConstructException(t, new StackTrace(1, true), e);
|
||||
|
||||
e.ToConsole(true, true);
|
||||
|
||||
return default(TObj);
|
||||
}
|
||||
}
|
||||
|
||||
public static object CreateInstanceUnsafe(this Type t, params object[] args)
|
||||
{
|
||||
return CreateInstance<object>(t, args);
|
||||
}
|
||||
|
||||
public static object CreateInstance(this Type t, params object[] args)
|
||||
{
|
||||
return CreateInstanceSafe<object>(t, args);
|
||||
}
|
||||
}
|
||||
|
||||
public class TypeConstructException : Exception
|
||||
{
|
||||
private readonly string _Trace;
|
||||
|
||||
public override string StackTrace => _Trace;
|
||||
|
||||
public TypeConstructException(Type type, StackTrace trace, Exception inner)
|
||||
: base("Type Construction Failed: " + type.FullName, inner)
|
||||
{
|
||||
_Trace = trace.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "\n\n" + _Trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/SubSystem/VitaNex/Core/Extensions/System/UriExt.cs
Normal file
32
Scripts/SubSystem/VitaNex/Core/Extensions/System/UriExt.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VitaNex.Web;
|
||||
#endregion
|
||||
|
||||
namespace System
|
||||
{
|
||||
public static class UriExtUtility
|
||||
{
|
||||
public static IEnumerable<KeyValuePair<string, string>> DecodeQueryString(this Uri uri)
|
||||
{
|
||||
return WebAPI.DecodeQuery(uri.Query);
|
||||
}
|
||||
|
||||
public static Uri EncodeQueryString(this Uri uri, IEnumerable<KeyValuePair<string, string>> queries)
|
||||
{
|
||||
return new Uri(uri.GetLeftPart(UriPartial.Path) + WebAPI.EncodeQuery(queries));
|
||||
}
|
||||
}
|
||||
}
|
||||
479
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/ArtExt.cs
Normal file
479
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/ArtExt.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class ArtExtUtility
|
||||
{
|
||||
public const int TileWxH = 44, TileHalfWxH = TileWxH / 2;
|
||||
|
||||
public static readonly Size TileSize = new Size(TileWxH, TileWxH);
|
||||
|
||||
#if ServUOX
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return ArtData.GetStatic(index);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, int hue, bool onlyHueGrayPixels)
|
||||
{
|
||||
return ArtData.GetStatic(index, hue, onlyHueGrayPixels);
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
ArtData.Measure(img, out xMin, out yMin, out xMax, out yMax);
|
||||
}
|
||||
|
||||
#region Ultima SDK Signatures
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
patched = false;
|
||||
|
||||
if (checkMaxID)
|
||||
index &= TileData.MaxItemValue;
|
||||
|
||||
return GetStatic(index);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#elif ServUO
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return GetStatic(index, out _, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
return Art.GetStatic(index, out patched, checkMaxID);
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
Art.Measure(img, out xMin, out yMin, out xMax, out yMax);
|
||||
}
|
||||
#else
|
||||
public static Bitmap GetStatic(int index)
|
||||
{
|
||||
return GetStatic(index, out _, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, bool checkMaxID)
|
||||
{
|
||||
return GetStatic(index, out _, checkMaxID);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched)
|
||||
{
|
||||
return GetStatic(index, out patched, true);
|
||||
}
|
||||
|
||||
public static Bitmap GetStatic(int index, out bool patched, bool checkMaxID)
|
||||
{
|
||||
var param = new object[] { index, false, checkMaxID };
|
||||
|
||||
var img = Bootstrap.Invoke<Bitmap>("Art", "GetStatic", param);
|
||||
|
||||
patched = (bool)param[1];
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
public static void Measure(Bitmap img, out int xMin, out int yMin, out int xMax, out int yMax)
|
||||
{
|
||||
var param = new object[] { img, 0, 0, 0, 0 };
|
||||
|
||||
Bootstrap.Invoke("Art", "Measure", param);
|
||||
|
||||
xMin = (int)param[1];
|
||||
yMin = (int)param[2];
|
||||
xMax = (int)param[3];
|
||||
yMax = (int)param[4];
|
||||
}
|
||||
#endif
|
||||
public static Rectangle2D GetStaticBounds(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return new Rectangle2D(0, 0, TileWxH, TileWxH);
|
||||
}
|
||||
|
||||
Measure(img, out var xMin, out var yMin, out var xMax, out var yMax);
|
||||
|
||||
return new Rectangle2D(new Point2D(xMin, yMin), new Point2D(xMax, yMax));
|
||||
}
|
||||
|
||||
public static Rectangle2D GetStaticBounds(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return new Rectangle2D(0, 0, TileWxH, TileWxH);
|
||||
}
|
||||
|
||||
return GetStaticBounds(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
return GetImageOffset(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(int id)
|
||||
{
|
||||
var p = Point.Empty;
|
||||
var b = GetImageSize(id);
|
||||
|
||||
if (b.Width > TileWxH)
|
||||
{
|
||||
p.X -= (b.Width - TileWxH) / 2;
|
||||
}
|
||||
else if (b.Width < TileWxH)
|
||||
{
|
||||
p.X += (TileWxH - b.Width) / 2;
|
||||
}
|
||||
|
||||
if (b.Height > TileWxH)
|
||||
{
|
||||
p.Y -= b.Height - TileWxH;
|
||||
}
|
||||
else if (b.Height < TileWxH)
|
||||
{
|
||||
p.Y += TileWxH - b.Height;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
return img.Width;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageWidth(m);
|
||||
}
|
||||
|
||||
return GetImageWidth(item.ItemID);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
return img.Height;
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileWxH;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageHeight(m);
|
||||
}
|
||||
|
||||
return GetImageHeight(item.ItemID);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(int id)
|
||||
{
|
||||
var img = GetStatic(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return TileSize;
|
||||
}
|
||||
|
||||
return new Size(img.Width, img.Height);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return TileSize;
|
||||
}
|
||||
|
||||
if (item is BaseMulti m)
|
||||
{
|
||||
return GetImageSize(m);
|
||||
}
|
||||
|
||||
return GetImageSize(item.ItemID);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
return GetImageOffset(m.Components);
|
||||
}
|
||||
|
||||
public static Point GetImageOffset(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Point.Empty;
|
||||
}
|
||||
|
||||
Point o, p = Point.Empty;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
p.X = Math.Min(p.X, o.X);
|
||||
p.Y = Math.Min(p.Y, o.Y);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetImageWidth(m.Components);
|
||||
}
|
||||
|
||||
public static int GetImageWidth(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point o;
|
||||
int x1 = 0, x2 = 0, w;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
w = GetImageWidth(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
|
||||
x1 = Math.Min(x1, o.X);
|
||||
x2 = Math.Max(x2, o.X + w);
|
||||
}
|
||||
|
||||
return Math.Max(0, x2 - x1);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetImageHeight(m.Components);
|
||||
}
|
||||
|
||||
public static int GetImageHeight(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point o;
|
||||
int y1 = 0, y2 = 0, h;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
h = GetImageHeight(t.m_ItemID);
|
||||
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
y1 = Math.Min(y1, o.Y);
|
||||
y2 = Math.Max(y2, o.Y + h);
|
||||
}
|
||||
|
||||
return Math.Max(0, y2 - y1);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
return GetImageSize(m.Components);
|
||||
}
|
||||
|
||||
public static Size GetImageSize(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
Point o;
|
||||
Size s;
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
foreach (var t in OrderByRender(mcl))
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
s = GetImageSize(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
x1 = Math.Min(x1, o.X);
|
||||
y1 = Math.Min(y1, o.Y);
|
||||
|
||||
x2 = Math.Max(x2, o.X + s.Width);
|
||||
y2 = Math.Max(y2, o.Y + s.Height);
|
||||
}
|
||||
|
||||
return new Size(Math.Max(0, x2 - x1), Math.Max(0, y2 - y1));
|
||||
}
|
||||
|
||||
public static IEnumerable<MultiTileEntry> OrderByRender(this BaseMulti m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Enumerable.Empty<MultiTileEntry>();
|
||||
}
|
||||
|
||||
return OrderByRender(m.Components);
|
||||
}
|
||||
|
||||
public static IEnumerable<MultiTileEntry> OrderByRender(this Server.MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var e in mcl.List //
|
||||
.OrderBy(o => ((o.m_OffsetX * mcl.Height) + o.m_OffsetY) * 2)
|
||||
.ThenBy(zt => zt.m_OffsetZ)
|
||||
.ThenByDescending(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Surface)) != 0)
|
||||
.ThenByDescending(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Wall)) != 0)
|
||||
.ThenBy(zt => (Convert.ToUInt64(zt.m_Flags) & Convert.ToUInt64(Server.TileFlag.Roof)) != 0)
|
||||
.ThenBy(zt => Server.TileData.ItemTable[zt.m_ItemID].CalcHeight))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnumerateByRender(this BaseMulti m, Action<Point, MultiTileEntry> action)
|
||||
{
|
||||
if (m != null && action != null)
|
||||
{
|
||||
EnumerateByRender(m.Components, action);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnumerateByRender(this Server.MultiComponentList mcl, Action<Point, MultiTileEntry> action)
|
||||
{
|
||||
if (mcl == null || action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Point o;
|
||||
|
||||
foreach (var t in mcl.OrderByRender())
|
||||
{
|
||||
o = GetImageOffset(t.m_ItemID);
|
||||
|
||||
o.X += (t.m_OffsetX * TileHalfWxH) - (t.m_OffsetY * TileHalfWxH);
|
||||
o.Y += (t.m_OffsetY * TileHalfWxH) + (t.m_OffsetX * TileHalfWxH);
|
||||
o.Y -= t.m_OffsetZ * 4;
|
||||
|
||||
action(o, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/Bootstrap.cs
Normal file
153
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/Bootstrap.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class Bootstrap
|
||||
{
|
||||
#if ServUO && !ServUOX
|
||||
[CallPriority(1)]
|
||||
public static void Configure()
|
||||
{
|
||||
foreach (var path in Core.DataDirectories)
|
||||
{
|
||||
Files.SetMulPath(path);
|
||||
}
|
||||
}
|
||||
#else
|
||||
private static readonly Dictionary<string, Type> _Modules = new Dictionary<string, Type>();
|
||||
|
||||
public static Assembly UltimaSDK { get; private set; }
|
||||
|
||||
public static bool Loaded { get; private set; }
|
||||
public static bool Warned { get; private set; }
|
||||
|
||||
static Bootstrap()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
private static void Load()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UltimaSDK = Assembly.LoadFrom("Ultima.dll");
|
||||
|
||||
Loaded = true;
|
||||
Warned = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UltimaSDK = null;
|
||||
|
||||
VitaNexCore.ToConsole("Could not load Ultima.dll");
|
||||
|
||||
if (!Warned)
|
||||
{
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
Warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Loaded)
|
||||
{
|
||||
foreach (var path in Core.DataDirectories)
|
||||
{
|
||||
Invoke("Files", "SetMulPath", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Type GetModule(string name)
|
||||
{
|
||||
Load();
|
||||
|
||||
if (!Loaded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!_Modules.TryGetValue(name, out var type))
|
||||
{
|
||||
_Modules[name] = type = UltimaSDK.GetType($"Ultima.{name}");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole($"Could not find Ultima.{name}:");
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static T Invoke<T>(string module, string method, params object[] args)
|
||||
{
|
||||
if (Invoke(module, method, args) is T o)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
|
||||
#if NET48_OR_GREATER
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static object Invoke(string module, string method, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = GetModule(module).InvokeMethod(method, args);
|
||||
|
||||
if (result is Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole($"Could not invoke Ultima.{module}.{method}:");
|
||||
VitaNexCore.ToConsole(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
109
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/GumpsExt.cs
Normal file
109
Scripts/SubSystem/VitaNex/Core/Extensions/Ultima/GumpsExt.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
#endregion
|
||||
|
||||
namespace Ultima
|
||||
{
|
||||
public static class GumpsExtUtility
|
||||
{
|
||||
#if ServUOX
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return Server.GumpData.GetGump(index);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, int hue, bool onlyHueGrayPixels)
|
||||
{
|
||||
return Server.GumpData.GetGump(index, hue, onlyHueGrayPixels);
|
||||
}
|
||||
|
||||
#region Ultima SDK Signatures
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
patched = false;
|
||||
|
||||
return GetGump(index);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#elif ServUO
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return GetGump(index, out _);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
return Gumps.GetGump(index, out patched);
|
||||
}
|
||||
#else
|
||||
public static Bitmap GetGump(int index)
|
||||
{
|
||||
return GetGump(index, out _);
|
||||
}
|
||||
|
||||
public static Bitmap GetGump(int index, out bool patched)
|
||||
{
|
||||
var param = new object[] { index, false };
|
||||
|
||||
var img = Bootstrap.Invoke<Bitmap>("Gumps", "GetGump", param);
|
||||
|
||||
patched = (bool)param[1];
|
||||
|
||||
return img;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Size GetImageSize(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return new Size(0, 0);
|
||||
}
|
||||
|
||||
return new Size(img.Width, img.Height);
|
||||
}
|
||||
|
||||
public static int GetImageWidth(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return img.Width;
|
||||
}
|
||||
|
||||
public static int GetImageHeight(int id)
|
||||
{
|
||||
var img = GetGump(id);
|
||||
|
||||
if (img == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return img.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Scripts/SubSystem/VitaNex/Core/Filters/BaseFilter.cs
Normal file
81
Scripts/SubSystem/VitaNex/Core/Filters/BaseFilter.cs
Normal 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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
239
Scripts/SubSystem/VitaNex/Core/Filters/FilterGump.cs
Normal file
239
Scripts/SubSystem/VitaNex/Core/Filters/FilterGump.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Scripts/SubSystem/VitaNex/Core/Filters/FilterGumpEntry.cs
Normal file
30
Scripts/SubSystem/VitaNex/Core/Filters/FilterGumpEntry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Scripts/SubSystem/VitaNex/Core/Filters/FilterOption.cs
Normal file
67
Scripts/SubSystem/VitaNex/Core/Filters/FilterOption.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Scripts/SubSystem/VitaNex/Core/Filters/FilterOptions.cs
Normal file
68
Scripts/SubSystem/VitaNex/Core/Filters/FilterOptions.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
159
Scripts/SubSystem/VitaNex/Core/Filters/Filters.cs
Normal file
159
Scripts/SubSystem/VitaNex/Core/Filters/Filters.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Scripts/SubSystem/VitaNex/Core/Filters/IFilter.cs
Normal file
41
Scripts/SubSystem/VitaNex/Core/Filters/IFilter.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
618
Scripts/SubSystem/VitaNex/Core/Geography/Coords.cs
Normal file
618
Scripts/SubSystem/VitaNex/Core/Geography/Coords.cs
Normal 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
|
||||
}
|
||||
}
|
||||
354
Scripts/SubSystem/VitaNex/Core/Geography/MapPoint.cs
Normal file
354
Scripts/SubSystem/VitaNex/Core/Geography/MapPoint.cs
Normal 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
|
||||
}
|
||||
}
|
||||
341
Scripts/SubSystem/VitaNex/Core/Geometry/Angle.cs
Normal file
341
Scripts/SubSystem/VitaNex/Core/Geometry/Angle.cs
Normal 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
|
||||
}
|
||||
}
|
||||
338
Scripts/SubSystem/VitaNex/Core/Geometry/Block3D.cs
Normal file
338
Scripts/SubSystem/VitaNex/Core/Geometry/Block3D.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction4.cs
Normal file
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction4.cs
Normal 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
|
||||
}
|
||||
}
|
||||
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction45.cs
Normal file
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction45.cs
Normal 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
|
||||
}
|
||||
}
|
||||
339
Scripts/SubSystem/VitaNex/Core/Geometry/Line2D.cs
Normal file
339
Scripts/SubSystem/VitaNex/Core/Geometry/Line2D.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cube3D.cs
Normal file
113
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cube3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
148
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cylinder3D.cs
Normal file
148
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cylinder3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Disc3D.cs
Normal file
114
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Disc3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Plane3D.cs
Normal file
110
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Plane3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Ring3D.cs
Normal file
121
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Ring3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
276
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Shape3D.cs
Normal file
276
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Shape3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Sphere3D.cs
Normal file
136
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Sphere3D.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
315
Scripts/SubSystem/VitaNex/Core/Geometry/Triangle2D.cs
Normal file
315
Scripts/SubSystem/VitaNex/Core/Geometry/Triangle2D.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
469
Scripts/SubSystem/VitaNex/Core/Geometry/Wireframe.cs
Normal file
469
Scripts/SubSystem/VitaNex/Core/Geometry/Wireframe.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
139
Scripts/SubSystem/VitaNex/Core/IO/ConfigFileInfo.cs
Normal file
139
Scripts/SubSystem/VitaNex/Core/IO/ConfigFileInfo.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
131
Scripts/SubSystem/VitaNex/Core/IO/DataStores/BinaryDataStore.cs
Normal file
131
Scripts/SubSystem/VitaNex/Core/IO/DataStores/BinaryDataStore.cs
Normal 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)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
490
Scripts/SubSystem/VitaNex/Core/IO/DataStores/DataStore.cs
Normal file
490
Scripts/SubSystem/VitaNex/Core/IO/DataStores/DataStore.cs
Normal 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)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
89
Scripts/SubSystem/VitaNex/Core/IO/DataStores/XmlDataStore.cs
Normal file
89
Scripts/SubSystem/VitaNex/Core/IO/DataStores/XmlDataStore.cs
Normal 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)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
873
Scripts/SubSystem/VitaNex/Core/IO/FileMime.cs
Normal file
873
Scripts/SubSystem/VitaNex/Core/IO/FileMime.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
292
Scripts/SubSystem/VitaNex/Core/IO/IOUtility.cs
Normal file
292
Scripts/SubSystem/VitaNex/Core/IO/IOUtility.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Scripts/SubSystem/VitaNex/Core/IO/VirtualAsset.cs
Normal file
261
Scripts/SubSystem/VitaNex/Core/IO/VirtualAsset.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Scripts/SubSystem/VitaNex/Core/IO/VirtualDirectory.cs
Normal file
137
Scripts/SubSystem/VitaNex/Core/IO/VirtualDirectory.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user