Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
517
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Clilocs.cs
Normal file
517
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Clilocs.cs
Normal file
@@ -0,0 +1,517 @@
|
||||
#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 System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
using Server;
|
||||
using Server.Commands;
|
||||
|
||||
using VitaNex.Collections;
|
||||
using VitaNex.IO;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public static partial class Clilocs
|
||||
{
|
||||
private static readonly Dictionary<Type, int> _TypeCache = new Dictionary<Type, int>(0x1000);
|
||||
|
||||
private static readonly ObjectProperty _LabelNumberProp = new ObjectProperty("LabelNumber");
|
||||
|
||||
private static readonly ClilocLNG[] _Languages = default(ClilocLNG).EnumerateValues<ClilocLNG>().Not(o => o == ClilocLNG.NULL).ToArray();
|
||||
|
||||
public static readonly Regex VarPattern = new Regex(@"~(?<index>\d+)(?<sep>_*)(?<desc>\w*)~", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
|
||||
public static readonly Regex NumPattern = new Regex(@"#(?<index>\d+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
|
||||
|
||||
public static ClilocLNG DefaultLanguage { get; set; } = ClilocLNG.ENU;
|
||||
|
||||
public static CoreServiceOptions CSOptions { get; private set; }
|
||||
|
||||
public static Dictionary<ClilocLNG, ClilocTable> Tables { get; private set; }
|
||||
|
||||
private static void ExportCommand(CommandEventArgs e)
|
||||
{
|
||||
if (e.Mobile?.Deleted != false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Mobile.SendMessage(0x55, "Export requested...");
|
||||
|
||||
if (e.Arguments?.Length > 0 && !String.IsNullOrWhiteSpace(e.Arguments[0]))
|
||||
{
|
||||
if (Enum.TryParse(e.Arguments[0], true, out ClilocLNG lng) && lng != ClilocLNG.NULL)
|
||||
{
|
||||
VitaNexCore.TryCatch(() =>
|
||||
{
|
||||
var file = Export(lng);
|
||||
|
||||
if (file != null && file.Exists && file.Length > 0)
|
||||
{
|
||||
e.Mobile.SendMessage(0x55, $"{lng} clilocs have been exported to: {file.FullName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage(0x22, $"Could not export clilocs for {lng}");
|
||||
}
|
||||
},
|
||||
ex =>
|
||||
{
|
||||
e.Mobile.SendMessage(0x22, "A fatal exception occurred, check the console for details.");
|
||||
|
||||
CSOptions.ToConsole(ex);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
e.Mobile.SendMessage($"Usage: {CommandSystem.Prefix}{e.Command} <{String.Join(" | ", _Languages)}>");
|
||||
}
|
||||
|
||||
public static FileInfo Export(ClilocLNG lng)
|
||||
{
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = DefaultLanguage;
|
||||
}
|
||||
|
||||
var list = new XmlDataStore<int, ClilocData>(VitaNexCore.DataDirectory + "/Exported Clilocs/", lng.ToString());
|
||||
var table = Tables[lng];
|
||||
|
||||
list.OnSerialize = doc =>
|
||||
{
|
||||
XmlNode node;
|
||||
XmlCDataSection cdata;
|
||||
ClilocInfo info;
|
||||
|
||||
XmlNode root = doc.CreateElement("clilocs");
|
||||
|
||||
var attr = doc.CreateAttribute("len");
|
||||
|
||||
attr.Value = table.Count.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (root.Attributes != null)
|
||||
{
|
||||
root.Attributes.Append(attr);
|
||||
}
|
||||
|
||||
attr = doc.CreateAttribute("lng");
|
||||
attr.Value = table.Language.ToString();
|
||||
|
||||
if (root.Attributes != null)
|
||||
{
|
||||
root.Attributes.Append(attr);
|
||||
}
|
||||
|
||||
foreach (var d in table)
|
||||
{
|
||||
if (d.Length <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
info = d.Lookup(table.InputFile, true);
|
||||
|
||||
if (String.IsNullOrWhiteSpace(info?.Text))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node = doc.CreateElement("cliloc");
|
||||
|
||||
attr = doc.CreateAttribute("idx");
|
||||
attr.Value = d.Index.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (node.Attributes != null)
|
||||
{
|
||||
node.Attributes.Append(attr);
|
||||
}
|
||||
|
||||
attr = doc.CreateAttribute("len");
|
||||
attr.Value = d.Length.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (node.Attributes != null)
|
||||
{
|
||||
node.Attributes.Append(attr);
|
||||
}
|
||||
|
||||
cdata = doc.CreateCDataSection(info.Text);
|
||||
node.AppendChild(cdata);
|
||||
|
||||
root.AppendChild(node);
|
||||
}
|
||||
|
||||
doc.AppendChild(root);
|
||||
table.Clear();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
list.Export();
|
||||
list.Clear();
|
||||
|
||||
return list.Document;
|
||||
}
|
||||
|
||||
public static ClilocInfo Lookup(this ClilocLNG lng, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = DefaultLanguage;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_TypeCache.TryGetValue(type, out var index))
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Lookup(lng, index);
|
||||
}
|
||||
|
||||
if (!_LabelNumberProp.IsSupported(typeof(int), type))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var o = type.CreateInstanceSafe<object>();
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
index = _LabelNumberProp.GetValue(o, -1); // LabelNumber_get()
|
||||
|
||||
o.InvokeMethod("Delete");
|
||||
}
|
||||
else
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
|
||||
_TypeCache[type] = index;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
return Lookup(lng, index);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClilocInfo Lookup(this ClilocLNG lng, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = DefaultLanguage;
|
||||
}
|
||||
|
||||
if (Tables.TryGetValue(lng, out var table) && !table.IsNullOrWhiteSpace(index))
|
||||
{
|
||||
return table[index];
|
||||
}
|
||||
|
||||
if (lng != ClilocLNG.ENU)
|
||||
{
|
||||
return Lookup(ClilocLNG.ENU, index);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetRawString(this ClilocLNG lng, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = DefaultLanguage;
|
||||
}
|
||||
|
||||
if (Tables.TryGetValue(lng, out var table) && !table.IsNullOrWhiteSpace(index))
|
||||
{
|
||||
return table[index]?.Text ?? String.Empty;
|
||||
}
|
||||
|
||||
if (lng != ClilocLNG.ENU)
|
||||
{
|
||||
return GetRawString(ClilocLNG.ENU, index);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static string GetString(this ClilocLNG lng, int index, StringBuilder args)
|
||||
{
|
||||
return Lookup(lng, index)?.ToString(args) ?? String.Empty;
|
||||
}
|
||||
|
||||
public static string GetString(this ClilocLNG lng, int index, string args)
|
||||
{
|
||||
return Lookup(lng, index)?.ToString(args) ?? String.Empty;
|
||||
}
|
||||
|
||||
public static string GetString(this ClilocLNG lng, int index, params object[] args)
|
||||
{
|
||||
return Lookup(lng, index)?.ToString(args) ?? String.Empty;
|
||||
}
|
||||
|
||||
public static string GetString(this ClilocLNG lng, Type type)
|
||||
{
|
||||
return Lookup(lng, type)?.ToString() ?? String.Empty;
|
||||
}
|
||||
|
||||
public static string GetString(this TextDefinition text)
|
||||
{
|
||||
return GetString(text, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string GetString(this TextDefinition text, Mobile m)
|
||||
{
|
||||
return GetString(text, GetLanguage(m));
|
||||
}
|
||||
|
||||
public static string GetString(this TextDefinition text, ClilocLNG lng)
|
||||
{
|
||||
if (ReferenceEquals(text, null))
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
return text.Number > 0 ? GetString(lng, text.Number) : (text.String ?? String.Empty);
|
||||
}
|
||||
|
||||
public static bool IsNullOrEmpty(this TextDefinition text)
|
||||
{
|
||||
if (ReferenceEquals(text, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return text.Number <= 0 && String.IsNullOrEmpty(text.String) && String.IsNullOrEmpty(GetString(text));
|
||||
}
|
||||
|
||||
public static bool IsNullOrWhiteSpace(this TextDefinition text)
|
||||
{
|
||||
if (ReferenceEquals(text, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return text.Number <= 0 && String.IsNullOrWhiteSpace(text.String) && String.IsNullOrWhiteSpace(GetString(text));
|
||||
}
|
||||
|
||||
private static IEnumerable<T> Enumerate<T>(ObjectPropertyList list, ClilocLNG lng, bool lookup, Func<int, string, T> selector)
|
||||
{
|
||||
if (list?.Entity?.Deleted != false || selector == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = DefaultLanguage;
|
||||
}
|
||||
|
||||
ObjectPool.Acquire(out StringBuilder param);
|
||||
|
||||
var data = list.GetBuffer();
|
||||
|
||||
var index = 15;
|
||||
|
||||
while (index + 4 < data.Length)
|
||||
{
|
||||
var num = data[index++] << 24 | data[index++] << 16 | data[index++] << 8 | data[index++];
|
||||
|
||||
if (index + 2 > data.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var paramLength = data[index++] << 8 | data[index++];
|
||||
|
||||
if (paramLength > 0)
|
||||
{
|
||||
var terminate = index + paramLength;
|
||||
|
||||
if (terminate >= data.Length)
|
||||
{
|
||||
terminate = data.Length - 1;
|
||||
}
|
||||
|
||||
while (index + 2 <= terminate + 1)
|
||||
{
|
||||
if ((data[index++] | data[index++] << 8) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
param.Append(Encoding.Unicode.GetChars(data, index - 2, 2));
|
||||
}
|
||||
}
|
||||
|
||||
yield return selector(num, lookup ? GetString(lng, num, param) : String.Empty);
|
||||
|
||||
param.Clear();
|
||||
}
|
||||
|
||||
ObjectPool.Free(ref param);
|
||||
}
|
||||
|
||||
public static IEnumerable<int> EnumerateNumbers(this ObjectPropertyList list)
|
||||
{
|
||||
return Enumerate(list, DefaultLanguage, false, (id, text) => id);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateLines(this ObjectPropertyList list)
|
||||
{
|
||||
return EnumerateLines(list, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateLines(this ObjectPropertyList list, Mobile m)
|
||||
{
|
||||
return EnumerateLines(list, GetLanguage(m));
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateLines(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return Enumerate(list, lng, true, (id, text) => text);
|
||||
}
|
||||
|
||||
public static IEnumerable<TextDefinition> EnumerateEntries(this ObjectPropertyList list)
|
||||
{
|
||||
return EnumerateEntries(list, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static IEnumerable<TextDefinition> EnumerateEntries(this ObjectPropertyList list, Mobile m)
|
||||
{
|
||||
return EnumerateEntries(list, GetLanguage(m));
|
||||
}
|
||||
|
||||
public static IEnumerable<TextDefinition> EnumerateEntries(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return Enumerate(list, lng, true, (id, text) => new TextDefinition(id, text));
|
||||
}
|
||||
|
||||
public static string[] DecodePropertyList(this ObjectPropertyList list)
|
||||
{
|
||||
return DecodePropertyList(list, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string[] DecodePropertyList(this ObjectPropertyList list, Mobile m)
|
||||
{
|
||||
return DecodePropertyList(list, GetLanguage(m));
|
||||
}
|
||||
|
||||
public static string[] DecodePropertyList(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return EnumerateLines(list, lng).ToArray();
|
||||
}
|
||||
|
||||
public static string DecodePropertyListHeader(this ObjectPropertyList list)
|
||||
{
|
||||
return DecodePropertyListHeader(list, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string DecodePropertyListHeader(this ObjectPropertyList list, Mobile v)
|
||||
{
|
||||
return DecodePropertyListHeader(list, GetLanguage(v));
|
||||
}
|
||||
|
||||
public static string DecodePropertyListHeader(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return EnumerateLines(list, lng).FirstOrDefault() ?? String.Empty;
|
||||
}
|
||||
|
||||
public static string[] GetAllLines(this ObjectPropertyList list)
|
||||
{
|
||||
return DecodePropertyList(list);
|
||||
}
|
||||
|
||||
public static string[] GetAllLines(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return DecodePropertyList(list, lng);
|
||||
}
|
||||
|
||||
public static string GetHeader(this ObjectPropertyList list)
|
||||
{
|
||||
return DecodePropertyListHeader(list);
|
||||
}
|
||||
|
||||
public static string GetHeader(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return DecodePropertyListHeader(list, lng);
|
||||
}
|
||||
|
||||
public static string[] GetBody(this ObjectPropertyList list)
|
||||
{
|
||||
return GetBody(list, DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string[] GetBody(this ObjectPropertyList list, ClilocLNG lng)
|
||||
{
|
||||
return EnumerateLines(list, lng).Skip(1).ToArray();
|
||||
}
|
||||
|
||||
public static bool Contains(this ObjectPropertyList list, int num)
|
||||
{
|
||||
return IndexOf(list, num) != -1;
|
||||
}
|
||||
|
||||
public static int IndexOf(this ObjectPropertyList list, int num)
|
||||
{
|
||||
return EnumerateNumbers(list).IndexOf(num);
|
||||
}
|
||||
|
||||
public static ClilocLNG GetLanguage(this Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return ClilocLNG.NULL;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse(m.Language, out ClilocLNG lng))
|
||||
{
|
||||
lng = ClilocLNG.ENU;
|
||||
}
|
||||
|
||||
return lng;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#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 System.Threading.Tasks;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
[CoreService("Clilocs", "1.0.0.0", TaskPriority.High)]
|
||||
public static partial class Clilocs
|
||||
{
|
||||
static Clilocs()
|
||||
{
|
||||
CSOptions = new CoreServiceOptions(typeof(Clilocs));
|
||||
|
||||
Tables = new Dictionary<ClilocLNG, ClilocTable>
|
||||
{
|
||||
{ClilocLNG.ENU, new ClilocTable()},
|
||||
{ClilocLNG.DEU, new ClilocTable()},
|
||||
{ClilocLNG.ESP, new ClilocTable()},
|
||||
{ClilocLNG.FRA, new ClilocTable()},
|
||||
{ClilocLNG.JPN, new ClilocTable()},
|
||||
{ClilocLNG.KOR, new ClilocTable()},
|
||||
{ClilocLNG.CHT, new ClilocTable()}
|
||||
};
|
||||
}
|
||||
|
||||
private static void CSConfig()
|
||||
{
|
||||
CommandUtility.Register("ExportCliloc", AccessLevel.Administrator, ExportCommand);
|
||||
|
||||
var tables = new List<ClilocTable>(Tables.Values);
|
||||
|
||||
//bool noFind = false;
|
||||
|
||||
Core.DataDirectories.TakeWhile(path => !tables.TrueForAll(t => t.Loaded))
|
||||
.Where(path => !String.IsNullOrWhiteSpace(path))
|
||||
.ForEach(
|
||||
path => Parallel.ForEach(
|
||||
Tables,
|
||||
kvp =>
|
||||
{
|
||||
if (kvp.Value.Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var file = "Cliloc." + kvp.Key.ToString().ToLower();
|
||||
var stub = IOUtility.GetSafeFilePath(path + "/" + file, true);
|
||||
|
||||
if (!File.Exists(stub))
|
||||
{
|
||||
//CSOptions.ToConsole("WARNING: {0} not found!", file);
|
||||
//noFind = true;
|
||||
return;
|
||||
}
|
||||
|
||||
kvp.Value.Load(new FileInfo(stub));
|
||||
}));
|
||||
|
||||
/*if (noFind)
|
||||
{
|
||||
CSOptions.ToConsole(
|
||||
"WARNING: One or more required cliloc files could not be loaded, any features that rely on this service will not work as expected and/or may cause a fatal exception!");
|
||||
}*/
|
||||
|
||||
tables.Free(true);
|
||||
}
|
||||
|
||||
private static void CSInvoke()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public sealed class ClilocData
|
||||
{
|
||||
private ClilocInfo _Info;
|
||||
|
||||
public ClilocLNG Language { get; private set; }
|
||||
|
||||
public int Index { get; private set; }
|
||||
public long Offset { get; private set; }
|
||||
public long Length { get; private set; }
|
||||
|
||||
public ClilocData(ClilocLNG lng, int index, long offset, long length)
|
||||
{
|
||||
Language = lng;
|
||||
Index = index;
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_Info = null;
|
||||
}
|
||||
|
||||
public void Load(GenericReader bin)
|
||||
{
|
||||
bin.Seek(Offset, SeekOrigin.Begin);
|
||||
|
||||
var data = new byte[Length];
|
||||
|
||||
for (long i = 0; i < data.Length; i++)
|
||||
{
|
||||
data[i] = bin.ReadByte();
|
||||
}
|
||||
|
||||
_Info = new ClilocInfo(Language, Index, Encoding.UTF8.GetString(data));
|
||||
}
|
||||
|
||||
public ClilocInfo Lookup(FileInfo file, bool forceUpdate = false)
|
||||
{
|
||||
if (_Info == null || forceUpdate)
|
||||
{
|
||||
VitaNexCore.TryCatch(f => f.Deserialize(Load), file, Clilocs.CSOptions.ToConsole);
|
||||
}
|
||||
|
||||
return _Info;
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Objects/Info.cs
Normal file
153
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Objects/Info.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public sealed class ClilocInfo : IDisposable
|
||||
{
|
||||
private volatile object[] _Buffer;
|
||||
|
||||
public ClilocLNG Language { get; private set; }
|
||||
|
||||
public int Index { get; private set; }
|
||||
public int Count { get; private set; }
|
||||
|
||||
public string Text { get; private set; }
|
||||
public string Format { get; private set; }
|
||||
|
||||
public bool HasArgs { get; private set; }
|
||||
|
||||
public ClilocInfo(ClilocLNG lng, int index, string text)
|
||||
{
|
||||
Language = lng;
|
||||
Index = index;
|
||||
|
||||
Text = text ?? String.Empty;
|
||||
|
||||
Format = Clilocs.VarPattern.Replace(Text, e => $"{{{Count++}}}");
|
||||
|
||||
HasArgs = Count > 0;
|
||||
}
|
||||
|
||||
private string Compile(object[] args)
|
||||
{
|
||||
if (!HasArgs)
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
if (args == null)
|
||||
{
|
||||
args = Array.Empty<object>();
|
||||
}
|
||||
|
||||
if (_Buffer == null)
|
||||
{
|
||||
_Buffer = new object[Count];
|
||||
}
|
||||
|
||||
var sep = Count > 1 ? "\t" : null;
|
||||
|
||||
var max = Math.Max(args.Length, _Buffer.Length);
|
||||
var lim = _Buffer.Length - 1;
|
||||
|
||||
for (var i = 0; i < max; i++)
|
||||
{
|
||||
if (i >= _Buffer.Length)
|
||||
{
|
||||
_Buffer[lim] = $"{_Buffer[lim]} {args[i]}";
|
||||
}
|
||||
else if (i < args.Length)
|
||||
{
|
||||
if (i < lim)
|
||||
{
|
||||
_Buffer[i] = $"{args[i]}{sep}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_Buffer[i] = args[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < lim)
|
||||
{
|
||||
_Buffer[i] = sep;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Buffer[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = String.Format(Format, _Buffer);
|
||||
|
||||
Array.Clear(_Buffer, 0, _Buffer.Length);
|
||||
|
||||
return Clilocs.NumPattern.Replace(result, match =>
|
||||
{
|
||||
if (Int32.TryParse(match.Groups["index"].Value, out var sid))
|
||||
{
|
||||
return Clilocs.GetRawString(Language, sid);
|
||||
}
|
||||
|
||||
return match.Value;
|
||||
});
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
public string ToString(StringBuilder args)
|
||||
{
|
||||
return ToString(args?.ToString());
|
||||
}
|
||||
|
||||
public string ToString(string args)
|
||||
{
|
||||
return ToString(args?.Split('\t'));
|
||||
}
|
||||
|
||||
public string ToString(params object[] args)
|
||||
{
|
||||
return Compile(args);
|
||||
}
|
||||
|
||||
public TextDefinition ToDefinition()
|
||||
{
|
||||
return new TextDefinition(Index, Text);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_Buffer = null;
|
||||
|
||||
Text = null;
|
||||
Format = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public enum ClilocLNG
|
||||
{
|
||||
NULL,
|
||||
ENU,
|
||||
DEU,
|
||||
ESP,
|
||||
FRA,
|
||||
JPN,
|
||||
KOR,
|
||||
CHT
|
||||
}
|
||||
|
||||
public static class ClilocLNGExt
|
||||
{
|
||||
public static string ToFullString(this ClilocLNG lng)
|
||||
{
|
||||
if (lng == ClilocLNG.NULL)
|
||||
{
|
||||
lng = Clilocs.DefaultLanguage;
|
||||
}
|
||||
|
||||
switch (lng)
|
||||
{
|
||||
case ClilocLNG.ENU:
|
||||
return "English";
|
||||
case ClilocLNG.DEU:
|
||||
return "German";
|
||||
case ClilocLNG.ESP:
|
||||
return "Spanish";
|
||||
case ClilocLNG.FRA:
|
||||
return "French";
|
||||
case ClilocLNG.JPN:
|
||||
return "Japanese";
|
||||
case ClilocLNG.KOR:
|
||||
return "Korean";
|
||||
case ClilocLNG.CHT:
|
||||
return "Chinese";
|
||||
}
|
||||
|
||||
return lng.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
189
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Objects/Table.cs
Normal file
189
Scripts/SubSystem/VitaNex/Core/Services/Clilocs/Objects/Table.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
#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.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public sealed class ClilocTable : IEnumerable<ClilocData>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<int, ClilocData> _Table = new Dictionary<int, ClilocData>();
|
||||
|
||||
public int Count => _Table.Count;
|
||||
|
||||
public ClilocLNG Language { get; private set; }
|
||||
public FileInfo InputFile { get; private set; }
|
||||
|
||||
public bool Loaded { get; private set; }
|
||||
|
||||
public ClilocInfo this[int index] => Lookup(index);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _Table.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<ClilocData> GetEnumerator()
|
||||
{
|
||||
return _Table.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var d in _Table.Values)
|
||||
{
|
||||
d.Clear();
|
||||
}
|
||||
|
||||
_Table.Clear();
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
if (!Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Language = ClilocLNG.NULL;
|
||||
|
||||
InputFile = null;
|
||||
|
||||
Clear();
|
||||
|
||||
Loaded = false;
|
||||
}
|
||||
|
||||
public void Load(FileInfo file)
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
if (Insensitive.Equals(file?.FullName, InputFile?.FullName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
VitaNexCore.TryCatch(f =>
|
||||
{
|
||||
if (!Enum.TryParse(f.Extension.TrimStart('.'), true, out ClilocLNG lng))
|
||||
{
|
||||
throw new FileLoadException($"Could not detect language for: {f.FullName}");
|
||||
}
|
||||
|
||||
Language = lng;
|
||||
InputFile = f;
|
||||
|
||||
InputFile.Deserialize(reader =>
|
||||
{
|
||||
var size = reader.Seek(0, SeekOrigin.End);
|
||||
|
||||
reader.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
reader.ReadInt();
|
||||
reader.ReadShort();
|
||||
|
||||
while (reader.Seek(0, SeekOrigin.Current) < size)
|
||||
{
|
||||
var index = reader.ReadInt();
|
||||
|
||||
reader.ReadByte();
|
||||
|
||||
int length = reader.ReadShort();
|
||||
var offset = reader.Seek(0, SeekOrigin.Current);
|
||||
|
||||
reader.Seek(length, SeekOrigin.Current);
|
||||
|
||||
_Table[index] = new ClilocData(Language, index, offset, length);
|
||||
}
|
||||
});
|
||||
|
||||
Loaded = true;
|
||||
}, file, Clilocs.CSOptions.ToConsole);
|
||||
}
|
||||
|
||||
public bool Contains(int index)
|
||||
{
|
||||
return _Table.ContainsKey(index);
|
||||
}
|
||||
|
||||
public bool IsNullOrWhiteSpace(int index)
|
||||
{
|
||||
if (!_Table.TryGetValue(index, out var data) || data == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var info = data.Lookup(InputFile);
|
||||
|
||||
if (info == null || String.IsNullOrWhiteSpace(info.Text))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ClilocInfo Update(int index)
|
||||
{
|
||||
if (!_Table.TryGetValue(index, out var data) || data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return data.Lookup(InputFile, true);
|
||||
}
|
||||
|
||||
public ClilocInfo Lookup(int index)
|
||||
{
|
||||
if (!_Table.TryGetValue(index, out var data) || data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return data.Lookup(InputFile);
|
||||
}
|
||||
|
||||
public void LookupAll()
|
||||
{
|
||||
VitaNexCore.TryCatch(() =>
|
||||
{
|
||||
InputFile.Deserialize(reader =>
|
||||
{
|
||||
foreach (var d in _Table.Values)
|
||||
{
|
||||
VitaNexCore.TryCatch(d.Load, reader, Clilocs.CSOptions.ToConsole);
|
||||
}
|
||||
});
|
||||
}, Clilocs.CSOptions.ToConsole);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Language == ClilocLNG.NULL ? "Not Loaded" : $"Cliloc.{Language}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
/// <summary>
|
||||
/// Jenkins Lookup 3 non-cryptographic HashAlgorithm implementation.
|
||||
/// Reference: https://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
/// </summary>
|
||||
[ComVisible(true)]
|
||||
public abstract class Jenkins3 : HashAlgorithm
|
||||
{
|
||||
private static readonly string[] _Names = { "J3", "Jenkins3", "Jenkins-3", "VitaNex.Crypto.Jenkins3" };
|
||||
|
||||
static Jenkins3()
|
||||
{
|
||||
CryptoConfig.AddAlgorithm(typeof(Jenkins3CryptoServiceProvider), _Names);
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static new Jenkins3 Create()
|
||||
{
|
||||
return Create("VitaNex.Crypto.Jenkins3");
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static new Jenkins3 Create(string algName)
|
||||
{
|
||||
return (Jenkins3)CryptoConfig.CreateFromName(algName);
|
||||
}
|
||||
|
||||
protected Jenkins3()
|
||||
{
|
||||
HashSizeValue = 64;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Jenkins Lookup 3 non-cryptographic HashAlgorithm implementation.
|
||||
/// Reference: https://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
/// </summary>
|
||||
public sealed class Jenkins3CryptoServiceProvider : Jenkins3
|
||||
{
|
||||
public const uint DeadBeef = 0xDEADBEEF;
|
||||
|
||||
private string _Seed;
|
||||
private uint _X0, _X1, _X2, _X3, _X4, _X5;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_Seed = String.Empty;
|
||||
_X0 = _X1 = _X2 = _X3 = _X4 = _X5 = 0;
|
||||
}
|
||||
|
||||
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
||||
{
|
||||
if (ibStart == 0 && cbSize == array.Length)
|
||||
{
|
||||
_Seed += BitConverter.ToString(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Seed += BitConverter.ToString(array, ibStart, cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
_X0 = _X1 = _X2 = DeadBeef + (uint)_Seed.Length;
|
||||
_X3 = _X4 = 0;
|
||||
|
||||
int pos;
|
||||
|
||||
for (pos = 0; pos + 12 < _Seed.Length; pos += 12)
|
||||
{
|
||||
_X1 = (uint)((_Seed[pos + 7] << 24) | (_Seed[pos + 6] << 16) | (_Seed[pos + 5] << 8) | _Seed[pos + 4]) + _X1;
|
||||
_X2 = (uint)((_Seed[pos + 11] << 24) | (_Seed[pos + 10] << 16) | (_Seed[pos + 9] << 8) | _Seed[pos + 8]) + _X2;
|
||||
_X3 = (uint)((_Seed[pos + 3] << 24) | (_Seed[pos + 2] << 16) | (_Seed[pos + 1] << 8) | _Seed[pos]) - _X2;
|
||||
|
||||
_X3 = (_X3 + _X0) ^ (_X2 >> 28) ^ (_X2 << 4);
|
||||
_X2 += _X1;
|
||||
_X1 = (_X1 - _X3) ^ (_X3 >> 26) ^ (_X3 << 6);
|
||||
_X3 += _X2;
|
||||
_X2 = (_X2 - _X1) ^ (_X1 >> 24) ^ (_X1 << 8);
|
||||
_X1 += _X3;
|
||||
_X0 = (_X3 - _X2) ^ (_X2 >> 16) ^ (_X2 << 16);
|
||||
_X2 += _X1;
|
||||
_X1 = (_X1 - _X0) ^ (_X0 >> 13) ^ (_X0 << 19);
|
||||
_X0 += _X2;
|
||||
_X2 = (_X2 - _X1) ^ (_X1 >> 28) ^ (_X1 << 4);
|
||||
_X1 += _X0;
|
||||
}
|
||||
|
||||
var rem = _Seed.Length - pos;
|
||||
|
||||
if (rem <= 0)
|
||||
{
|
||||
return BitConverter.GetBytes(((ulong)_X2 << 32) | _X4);
|
||||
}
|
||||
|
||||
switch (rem)
|
||||
{
|
||||
case 12:
|
||||
_X2 += (uint)_Seed[pos + 11] << 24;
|
||||
goto case 11;
|
||||
case 11:
|
||||
_X2 += (uint)_Seed[pos + 10] << 16;
|
||||
goto case 10;
|
||||
case 10:
|
||||
_X2 += (uint)_Seed[pos + 9] << 8;
|
||||
goto case 9;
|
||||
case 9:
|
||||
_X2 += _Seed[pos + 8];
|
||||
goto case 8;
|
||||
case 8:
|
||||
_X1 += (uint)_Seed[pos + 7] << 24;
|
||||
goto case 7;
|
||||
case 7:
|
||||
_X1 += (uint)_Seed[pos + 6] << 16;
|
||||
goto case 6;
|
||||
case 6:
|
||||
_X1 += (uint)_Seed[pos + 5] << 8;
|
||||
goto case 5;
|
||||
case 5:
|
||||
_X1 += _Seed[pos + 4];
|
||||
goto case 4;
|
||||
case 4:
|
||||
_X0 += (uint)_Seed[pos + 3] << 24;
|
||||
goto case 3;
|
||||
case 3:
|
||||
_X0 += (uint)_Seed[pos + 2] << 16;
|
||||
goto case 2;
|
||||
case 2:
|
||||
_X0 += (uint)_Seed[pos + 1] << 8;
|
||||
goto case 1;
|
||||
case 1:
|
||||
_X0 += _Seed[pos];
|
||||
break;
|
||||
}
|
||||
|
||||
_X2 = (_X2 ^ _X1) - ((_X1 >> 18) ^ (_X1 << 14));
|
||||
_X5 = (_X2 ^ _X0) - ((_X2 >> 21) ^ (_X2 << 11));
|
||||
_X1 = (_X1 ^ _X5) - ((_X5 >> 7) ^ (_X5 << 25));
|
||||
_X2 = (_X2 ^ _X1) - ((_X1 >> 16) ^ (_X1 << 16));
|
||||
_X3 = (_X2 ^ _X5) - ((_X2 >> 28) ^ (_X2 << 4));
|
||||
_X1 = (_X1 ^ _X3) - ((_X3 >> 18) ^ (_X3 << 14));
|
||||
_X4 = (_X2 ^ _X1) - ((_X1 >> 8) ^ (_X1 << 24));
|
||||
|
||||
return BitConverter.GetBytes(((ulong)_X1 << 32) | _X4);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Scripts/SubSystem/VitaNex/Core/Services/Crypto/Crypto.cs
Normal file
52
Scripts/SubSystem/VitaNex/Core/Services/Crypto/Crypto.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
#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.Security.Cryptography;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public static partial class CryptoService
|
||||
{
|
||||
public static CryptoHashType[] HashTypes { get; private set; }
|
||||
|
||||
public static Dictionary<int, CryptoHashCodeProvider> Providers { get; private set; }
|
||||
|
||||
public static void RegisterProvider(CryptoHashType type, HashAlgorithm hal)
|
||||
{
|
||||
Providers[(int)type] = new CryptoHashCodeProvider((int)type, hal);
|
||||
}
|
||||
|
||||
public static void RegisterProvider(int type, HashAlgorithm hal)
|
||||
{
|
||||
Providers[type] = new CryptoHashCodeProvider(type, hal);
|
||||
}
|
||||
|
||||
public static CryptoHashCodeProvider GetProvider(CryptoHashType type)
|
||||
{
|
||||
return Providers.GetValue((int)type);
|
||||
}
|
||||
|
||||
public static CryptoHashCodeProvider GetProvider(int type)
|
||||
{
|
||||
return Providers.GetValue(type);
|
||||
}
|
||||
|
||||
public static bool IsExtended(int type)
|
||||
{
|
||||
return HashTypes.Cast<int>().All(t => t != type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
[CoreService("Crypto", "3.0.0.1", TaskPriority.Highest)]
|
||||
public static partial class CryptoService
|
||||
{
|
||||
static CryptoService()
|
||||
{
|
||||
HashTypes = ((CryptoHashType)0).GetValues<CryptoHashType>();
|
||||
|
||||
Providers = HashTypes.Select(h => new CryptoHashCodeProvider((int)h, HashAlgorithm.Create(h.ToString())))
|
||||
.Where(p => p.Provider != null)
|
||||
.ToDictionary(p => p.ProviderID, p => p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public interface ICryptoProvider : IDisposable
|
||||
{
|
||||
bool IsDisposed { get; }
|
||||
|
||||
int ProviderID { get; }
|
||||
HashAlgorithm Provider { get; }
|
||||
|
||||
string Seed { get; }
|
||||
byte[] Buffer { get; }
|
||||
|
||||
string Generate(string seed);
|
||||
}
|
||||
|
||||
public interface ICryptoMutator : ICryptoProvider
|
||||
{
|
||||
string Transform(string seed);
|
||||
string Mutate(string code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public static class CryptoGenerator
|
||||
{
|
||||
public static string GenString(CryptoHashType type, string seed)
|
||||
{
|
||||
var p = CryptoService.GetProvider(type);
|
||||
|
||||
return p != null ? p.Generate(seed) : String.Empty;
|
||||
}
|
||||
|
||||
public static string GenString(int type, string seed)
|
||||
{
|
||||
var p = CryptoService.GetProvider(type);
|
||||
|
||||
return p != null ? p.Generate(seed) : String.Empty;
|
||||
}
|
||||
|
||||
public static CryptoHashCode GenHashCode(CryptoHashType type, string seed)
|
||||
{
|
||||
return new CryptoHashCode((int)type, seed);
|
||||
}
|
||||
|
||||
public static CryptoHashCode GenHashCode(int type, string seed)
|
||||
{
|
||||
return new CryptoHashCode(type, seed);
|
||||
}
|
||||
|
||||
public static CryptoHashCodeTable GenTable(string seed)
|
||||
{
|
||||
return new CryptoHashCodeTable(seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#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 System.Text;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public class CryptoHashCode : IEquatable<CryptoHashCode>, IComparable<CryptoHashCode>, IEnumerable<char>, IDisposable
|
||||
{
|
||||
private int _ValueHash = -1;
|
||||
|
||||
public int ValueHash => GetValueHash();
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public bool IsExtended => CryptoService.IsExtended(ProviderID);
|
||||
|
||||
public int ProviderID { get; protected set; }
|
||||
|
||||
public virtual string Value { get; private set; }
|
||||
|
||||
public int Length => Value.Length;
|
||||
|
||||
public char this[int index] => Value[index];
|
||||
|
||||
public CryptoHashCode(CryptoHashType type, string seed)
|
||||
: this((int)type, seed)
|
||||
{ }
|
||||
|
||||
public CryptoHashCode(int providerID, string seed)
|
||||
{
|
||||
ProviderID = providerID;
|
||||
|
||||
Value = CryptoGenerator.GenString(ProviderID, seed ?? String.Empty);
|
||||
}
|
||||
|
||||
public CryptoHashCode(GenericReader reader)
|
||||
{
|
||||
Deserialize(reader);
|
||||
}
|
||||
|
||||
~CryptoHashCode()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<char> GetEnumerator()
|
||||
{
|
||||
return Value.GetEnumerator();
|
||||
}
|
||||
|
||||
public virtual int CompareTo(CryptoHashCode code)
|
||||
{
|
||||
return !ReferenceEquals(code, null) ? Insensitive.Compare(Value, code.Value) : -1;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is CryptoHashCode && Equals((CryptoHashCode)obj);
|
||||
}
|
||||
|
||||
public bool Equals(CryptoHashCode other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && ValueHash == other.ValueHash;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked(((ProviderID + 1) * 397) ^ ValueHash);
|
||||
}
|
||||
|
||||
public int GetValueHash()
|
||||
{
|
||||
if (_ValueHash > -1)
|
||||
{
|
||||
return _ValueHash;
|
||||
}
|
||||
|
||||
var hash = Value.Aggregate(Value.Length, (h, c) => unchecked((h * 397) ^ c));
|
||||
|
||||
// It may be negative, so ensure it is positive, normally this wouldn't be the case but negative integers for
|
||||
// almost unique id's should be positive for things like database keys.
|
||||
// Note this increases chance of unique collisions by 50%, though still extremely unlikely;
|
||||
// 1 : 2,147,483,647
|
||||
return _ValueHash = Math.Abs(hash);
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
Value = null;
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
var version = writer.SetVersion(2);
|
||||
|
||||
writer.Write(ProviderID);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
writer.Write(Value);
|
||||
writer.Write(_ValueHash);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Deserialize(GenericReader reader)
|
||||
{
|
||||
var version = reader.GetVersion();
|
||||
|
||||
ProviderID = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
Value = reader.ReadString();
|
||||
_ValueHash = reader.ReadInt();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
var seed = reader.ReadBool()
|
||||
? StringCompression.Unpack(reader.ReadBytes())
|
||||
: Encoding.UTF32.GetString(reader.ReadBytes());
|
||||
|
||||
Value = CryptoGenerator.GenString(ProviderID, seed ?? String.Empty);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
var seed = reader.ReadString();
|
||||
|
||||
Value = CryptoGenerator.GenString(ProviderID, seed ?? String.Empty);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(CryptoHashCode l, CryptoHashCode r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
|
||||
}
|
||||
|
||||
public static bool operator !=(CryptoHashCode l, CryptoHashCode r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public sealed class CryptoHashCodeProvider : ICryptoProvider
|
||||
{
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public int ProviderID { get; private set; }
|
||||
public HashAlgorithm Provider { get; private set; }
|
||||
|
||||
public string Seed { get; private set; }
|
||||
public byte[] Buffer { get; private set; }
|
||||
|
||||
public CryptoHashCodeProvider(int id, HashAlgorithm hal)
|
||||
{
|
||||
ProviderID = id;
|
||||
Provider = hal;
|
||||
}
|
||||
|
||||
~CryptoHashCodeProvider()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ProviderID;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is CryptoHashCodeProvider && Equals((CryptoHashCodeProvider)obj);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}:{1}", ProviderID, Provider != null ? Provider.GetType().FullName : "NULL");
|
||||
}
|
||||
|
||||
public string Generate(string seed)
|
||||
{
|
||||
seed = seed ?? String.Empty;
|
||||
|
||||
if (Buffer == null || Seed != seed)
|
||||
{
|
||||
Seed = seed;
|
||||
|
||||
Buffer = Encoding.UTF32.GetBytes(Seed);
|
||||
Buffer = Provider.ComputeHash(Buffer);
|
||||
}
|
||||
|
||||
return BitConverter.ToString(Buffer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (Provider != null)
|
||||
{
|
||||
VitaNexCore.TryCatch(Provider.Clear);
|
||||
}
|
||||
|
||||
Provider = null;
|
||||
Seed = null;
|
||||
Buffer = null;
|
||||
}
|
||||
|
||||
public static bool operator ==(CryptoHashCodeProvider l, CryptoHashCodeProvider r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
|
||||
}
|
||||
|
||||
public static bool operator !=(CryptoHashCodeProvider l, CryptoHashCodeProvider r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#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.Crypto
|
||||
{
|
||||
public class CryptoHashCodeTable : List<CryptoHashCode>, IEquatable<CryptoHashCodeTable>, IDisposable
|
||||
{
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public CryptoHashCodeTable(string seed)
|
||||
{
|
||||
AddRange(CryptoService.Providers.Keys.Select(type => CryptoGenerator.GenHashCode(type, seed)));
|
||||
}
|
||||
|
||||
~CryptoHashCodeTable()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
this.Free(true);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.GetContentsHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is CryptoHashCodeTable && Equals((CryptoHashCodeTable)obj);
|
||||
}
|
||||
|
||||
public virtual bool Equals(CryptoHashCodeTable table)
|
||||
{
|
||||
return !ReferenceEquals(table, null) && (ReferenceEquals(table, this) || this.ContentsEqual(table));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join("+", this);
|
||||
}
|
||||
|
||||
public static bool operator ==(CryptoHashCodeTable l, CryptoHashCodeTable r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
|
||||
}
|
||||
|
||||
public static bool operator !=(CryptoHashCodeTable l, CryptoHashCodeTable r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Crypto
|
||||
{
|
||||
public enum CryptoHashType
|
||||
{
|
||||
MD5 = 0,
|
||||
SHA1 = 1,
|
||||
SHA256 = 2,
|
||||
SHA384 = 3,
|
||||
SHA512 = 4,
|
||||
RIPEMD160 = 5,
|
||||
Jenkins3 = 6
|
||||
}
|
||||
}
|
||||
466
Scripts/SubSystem/VitaNex/Core/Services/Notify/Notify.cs
Normal file
466
Scripts/SubSystem/VitaNex/Core/Services/Notify/Notify.cs
Normal file
@@ -0,0 +1,466 @@
|
||||
#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 System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Server;
|
||||
using Server.Commands;
|
||||
using Server.Network;
|
||||
|
||||
using VitaNex.IO;
|
||||
using VitaNex.Text;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public static partial class Notify
|
||||
{
|
||||
public const AccessLevel Access = AccessLevel.Administrator;
|
||||
|
||||
public static CoreServiceOptions CSOptions { get; private set; }
|
||||
|
||||
public static Type[] GumpTypes { get; private set; }
|
||||
|
||||
public static Dictionary<Type, Type[]> NestedTypes { get; private set; }
|
||||
|
||||
public static Dictionary<Type, Type> SettingsMap { get; private set; }
|
||||
|
||||
public static BinaryDataStore<Type, NotifySettings> Settings { get; private set; }
|
||||
|
||||
public static event Action<NotifyGump> OnGlobalMessage;
|
||||
public static event Action<NotifyGump> OnLocalMessage;
|
||||
|
||||
public static event Action<string> OnBroadcast;
|
||||
|
||||
[Usage("Notify <text | html | bbc>"), Description(
|
||||
"Send a global notification gump to all online clients, " + //
|
||||
"containing a message parsed from HTML, BBS or plain text.")]
|
||||
private static void HandleNotify(CommandEventArgs e)
|
||||
{
|
||||
if (e.Mobile.AccessLevel >= AccessLevel.Seer && !String.IsNullOrWhiteSpace(e.ArgString) && ValidateCommand(e))
|
||||
{
|
||||
Broadcast(e.Mobile, e.ArgString);
|
||||
return;
|
||||
}
|
||||
|
||||
new NotifySettingsGump(e.Mobile).Send();
|
||||
}
|
||||
|
||||
[Usage("NotifyAC <text | html | bbc>"), Description(
|
||||
"Send a global notification gump to all online clients, " + //
|
||||
"containing a message parsed from HTML, BBS or plain text, " + //
|
||||
"which auto-closes after 10 seconds.")]
|
||||
private static void HandleNotifyAC(CommandEventArgs e)
|
||||
{
|
||||
if (ValidateCommand(e))
|
||||
{
|
||||
Broadcast(e.Mobile, e.ArgString, true);
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("NotifyNA <text | html | bbc>"), Description(
|
||||
"Send a global notification gump to all online clients, " + //
|
||||
"containing a message parsed from HTML, BBS or plain text, " + //
|
||||
"which has no animation delay.")]
|
||||
private static void HandleNotifyNA(CommandEventArgs e)
|
||||
{
|
||||
if (ValidateCommand(e))
|
||||
{
|
||||
Broadcast(e.Mobile, e.ArgString, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("NotifyACNA <text | html | bbc>"), Description(
|
||||
"Send a global notification gump to all online clients, " + //
|
||||
"containing a message parsed from HTML, BBS or plain text, " + //
|
||||
"which auto-closes after 10 seconds and has no animation delay.")]
|
||||
private static void HandleNotifyACNA(CommandEventArgs e)
|
||||
{
|
||||
if (ValidateCommand(e))
|
||||
{
|
||||
Broadcast(e.Mobile, e.ArgString, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ValidateCommand(CommandEventArgs e)
|
||||
{
|
||||
if (e == null || e.Mobile == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(e.ArgString) ||
|
||||
String.IsNullOrWhiteSpace(Regex.Replace(e.ArgString, @"<[^>]*>", String.Empty)))
|
||||
{
|
||||
e.Mobile.SendMessage(0x22, "Html/BBC message must be at least 1 character and not all white-space after parsing.");
|
||||
e.Mobile.SendMessage(0x22, "Usage: {0}{1} <text | html | bbc>", CommandSystem.Prefix, e.Command);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static NotifySettings EnsureSettings<TGump>()
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
return EnsureSettings(typeof(TGump));
|
||||
}
|
||||
|
||||
public static NotifySettings EnsureSettings(Type t)
|
||||
{
|
||||
if (t == null || !t.IsEqualOrChildOf<NotifyGump>())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (SettingsMap.TryGetValue(t, out var st) && st != null)
|
||||
{
|
||||
var o = Settings.GetValue(st);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
const BindingFlags f = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic;
|
||||
|
||||
var m = t.GetMethod("InitSettings", f);
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
foreach (var p in t.EnumerateHierarchy())
|
||||
{
|
||||
m = p.GetMethod("InitSettings", f);
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
st = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (st == null)
|
||||
{
|
||||
st = t;
|
||||
}
|
||||
|
||||
var init = false;
|
||||
|
||||
if (!Settings.TryGetValue(st, out var settings) || settings == null)
|
||||
{
|
||||
Settings[st] = settings = new NotifySettings(st);
|
||||
init = true;
|
||||
}
|
||||
|
||||
SettingsMap[t] = st;
|
||||
|
||||
if (init && m != null)
|
||||
{
|
||||
m.Invoke(null, new object[] { settings });
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static bool IsAutoClose<TGump>(Mobile pm)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
return IsAutoClose(typeof(TGump), pm);
|
||||
}
|
||||
|
||||
public static bool IsAutoClose(Type t, Mobile pm)
|
||||
{
|
||||
var settings = EnsureSettings(t);
|
||||
|
||||
return settings != null && settings.IsAutoClose(pm);
|
||||
}
|
||||
|
||||
public static bool IsIgnored<TGump>(Mobile pm)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
return IsIgnored(typeof(TGump), pm);
|
||||
}
|
||||
|
||||
public static bool IsIgnored(Type t, Mobile pm)
|
||||
{
|
||||
var settings = EnsureSettings(t);
|
||||
|
||||
return settings != null && settings.IsIgnored(pm);
|
||||
}
|
||||
|
||||
public static bool IsAnimated<TGump>(Mobile pm)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
return IsAnimated(typeof(TGump), pm);
|
||||
}
|
||||
|
||||
public static bool IsAnimated(Type t, Mobile pm)
|
||||
{
|
||||
var settings = EnsureSettings(t);
|
||||
|
||||
return settings == null || settings.IsAnimated(pm);
|
||||
}
|
||||
|
||||
public static bool IsTextOnly<TGump>(Mobile pm)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
return IsTextOnly(typeof(TGump), pm);
|
||||
}
|
||||
|
||||
public static bool IsTextOnly(Type t, Mobile pm)
|
||||
{
|
||||
var settings = EnsureSettings(t);
|
||||
|
||||
return settings != null && settings.IsTextOnly(pm);
|
||||
}
|
||||
|
||||
public static void AlterTime<TGump>(Mobile pm, ref double value)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
AlterTime(typeof(TGump), pm, ref value);
|
||||
}
|
||||
|
||||
public static void AlterTime(Type t, Mobile pm, ref double value)
|
||||
{
|
||||
var settings = EnsureSettings(t);
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
settings.AlterTime(pm, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Broadcast(
|
||||
Mobile m,
|
||||
string message,
|
||||
bool autoClose = false,
|
||||
bool animate = true,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
{
|
||||
if (m != null && !m.Deleted)
|
||||
{
|
||||
message = String.Format("[{0}] {1}:\n{2}", DateTime.Now.ToSimpleString("t@h:m@"), m.RawName, message);
|
||||
}
|
||||
|
||||
Broadcast(message, autoClose, animate ? 1.0 : 0.0, 10.0, null, null, null, level);
|
||||
}
|
||||
|
||||
public static void Broadcast(
|
||||
string html,
|
||||
bool autoClose = true,
|
||||
double delay = 1.0,
|
||||
double pause = 5.0,
|
||||
Color? color = null,
|
||||
Action<WorldNotifyGump> beforeSend = null,
|
||||
Action<WorldNotifyGump> afterSend = null,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
{
|
||||
Broadcast<WorldNotifyGump>(html, autoClose, delay, pause, color, beforeSend, afterSend, level);
|
||||
}
|
||||
|
||||
public static void Broadcast<TGump>(
|
||||
string html,
|
||||
bool autoClose = true,
|
||||
double delay = 1.0,
|
||||
double pause = 5.0,
|
||||
Color? color = null,
|
||||
Action<TGump> beforeSend = null,
|
||||
Action<TGump> afterSend = null,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
var c = NetState.Instances.Count;
|
||||
|
||||
while (--c >= 0)
|
||||
{
|
||||
if (!NetState.Instances.InBounds(c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ns = NetState.Instances[c];
|
||||
|
||||
if (ns != null && ns.Running && ns.Mobile != null && ns.Mobile.AccessLevel >= level)
|
||||
{
|
||||
VitaNexCore.TryCatch(
|
||||
m => Send(false, m, html, autoClose, delay, pause, color, beforeSend, afterSend, level),
|
||||
ns.Mobile);
|
||||
}
|
||||
}
|
||||
|
||||
if (level < AccessLevel.Counselor && OnBroadcast != null)
|
||||
{
|
||||
OnBroadcast(html.ParseBBCode());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Send(
|
||||
Mobile m,
|
||||
string html,
|
||||
bool autoClose = true,
|
||||
double delay = 1.0,
|
||||
double pause = 3.0,
|
||||
Color? color = null,
|
||||
Action<NotifyGump> beforeSend = null,
|
||||
Action<NotifyGump> afterSend = null,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
{
|
||||
Send(true, m, html, autoClose, delay, pause, color, beforeSend, afterSend, level);
|
||||
}
|
||||
|
||||
public static void Send<TGump>(
|
||||
Mobile m,
|
||||
string html,
|
||||
bool autoClose = true,
|
||||
double delay = 1.0,
|
||||
double pause = 3.0,
|
||||
Color? color = null,
|
||||
Action<TGump> beforeSend = null,
|
||||
Action<TGump> afterSend = null,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
Send(true, m, html, autoClose, delay, pause, color, beforeSend, afterSend, level);
|
||||
}
|
||||
|
||||
private static void Send<TGump>(
|
||||
bool local,
|
||||
Mobile m,
|
||||
string html,
|
||||
bool autoClose = true,
|
||||
double delay = 1.0,
|
||||
double pause = 3.0,
|
||||
Color? color = null,
|
||||
Action<TGump> beforeSend = null,
|
||||
Action<TGump> afterSend = null,
|
||||
AccessLevel level = AccessLevel.Player)
|
||||
where TGump : NotifyGump
|
||||
{
|
||||
if (!m.IsOnline() || m.AccessLevel < level)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var t = typeof(TGump);
|
||||
|
||||
if (t.IsAbstract || m.HasGump(t))
|
||||
{
|
||||
if (!NestedTypes.TryGetValue(t, out var subs) || subs == null)
|
||||
{
|
||||
NestedTypes[t] = subs = t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic) //
|
||||
.Where(st => st.IsChildOf<NotifyGump>())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var sub = subs.FirstOrDefault(st => !m.HasGump(st));
|
||||
|
||||
if (sub != null)
|
||||
{
|
||||
t = sub;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsIgnored(t, m))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.IsAbstract && !IsTextOnly(t, m))
|
||||
{
|
||||
if (!autoClose && IsAutoClose(t, m))
|
||||
{
|
||||
autoClose = true;
|
||||
}
|
||||
|
||||
if (delay > 0.0 && !IsAnimated(t, m))
|
||||
{
|
||||
delay = 0.0;
|
||||
}
|
||||
|
||||
if (delay > 0.0)
|
||||
{
|
||||
AlterTime(t, m, ref delay);
|
||||
}
|
||||
|
||||
if (pause > 3.0)
|
||||
{
|
||||
AlterTime(t, m, ref pause);
|
||||
|
||||
pause = Math.Max(3.0, pause);
|
||||
}
|
||||
|
||||
var ng = t.CreateInstanceSafe<TGump>(m, html);
|
||||
|
||||
if (ng != null)
|
||||
{
|
||||
ng.AutoClose = autoClose;
|
||||
ng.AnimDuration = TimeSpan.FromSeconds(Math.Max(0, delay));
|
||||
ng.PauseDuration = TimeSpan.FromSeconds(Math.Max(0, pause));
|
||||
ng.HtmlColor = color ?? Color.White;
|
||||
|
||||
if (ng.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (local && OnLocalMessage != null)
|
||||
{
|
||||
OnLocalMessage(ng);
|
||||
}
|
||||
else if (!local && OnGlobalMessage != null)
|
||||
{
|
||||
OnGlobalMessage(ng);
|
||||
}
|
||||
|
||||
if (beforeSend != null)
|
||||
{
|
||||
beforeSend(ng);
|
||||
}
|
||||
|
||||
if (ng.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ng.Send();
|
||||
|
||||
if (ng.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (afterSend != null)
|
||||
{
|
||||
afterSend(ng);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
html = html.StripHtmlBreaks(true);
|
||||
html = html.Replace("\n", " ");
|
||||
html = html.StripHtml(false);
|
||||
html = html.StripTabs();
|
||||
html = html.StripCRLF();
|
||||
|
||||
m.SendMessage(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Scripts/SubSystem/VitaNex/Core/Services/Notify/Notify_Init.cs
Normal file
114
Scripts/SubSystem/VitaNex/Core/Services/Notify/Notify_Init.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 System.Collections.Generic;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
[CoreService("Notify", "3.0.0.0", TaskPriority.Highest)]
|
||||
public static partial class Notify
|
||||
{
|
||||
static Notify()
|
||||
{
|
||||
CSOptions = new CoreServiceOptions(typeof(Notify));
|
||||
|
||||
GumpTypes = typeof(NotifyGump).GetChildren(t => !t.IsNested);
|
||||
|
||||
NestedTypes = new Dictionary<Type, Type[]>();
|
||||
|
||||
SettingsMap = new Dictionary<Type, Type>();
|
||||
|
||||
Settings = new BinaryDataStore<Type, NotifySettings>(VitaNexCore.SavesDirectory + "/Notify", "Settings")
|
||||
{
|
||||
Async = true,
|
||||
OnSerialize = Serialize,
|
||||
OnDeserialize = Deserialize
|
||||
};
|
||||
}
|
||||
|
||||
private static void CSConfig()
|
||||
{
|
||||
foreach (var t in GumpTypes)
|
||||
{
|
||||
EnsureSettings(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CSInvoke()
|
||||
{
|
||||
CommandUtility.Register("Notify", AccessLevel.Player, HandleNotify);
|
||||
CommandUtility.Register("NotifyAC", AccessLevel.Seer, HandleNotifyAC);
|
||||
CommandUtility.Register("NotifyNA", AccessLevel.Seer, HandleNotifyNA);
|
||||
CommandUtility.Register("NotifyACNA", AccessLevel.Seer, HandleNotifyACNA);
|
||||
}
|
||||
|
||||
private static void CSLoad()
|
||||
{
|
||||
Settings.Import();
|
||||
|
||||
Settings.RemoveRange(o => !GumpTypes.Contains(o.Key) || o.Value == null);
|
||||
}
|
||||
|
||||
private static void CSSave()
|
||||
{
|
||||
Settings.Export();
|
||||
}
|
||||
|
||||
private static bool Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.WriteBlockDictionary(
|
||||
Settings,
|
||||
(w, k, v) =>
|
||||
{
|
||||
w.WriteType(k);
|
||||
v.Serialize(w);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Deserialize(GenericReader reader)
|
||||
{
|
||||
reader.GetVersion();
|
||||
|
||||
reader.ReadBlockDictionary(
|
||||
r =>
|
||||
{
|
||||
var k = r.ReadType();
|
||||
var v = EnsureSettings(k);
|
||||
|
||||
if (v != null)
|
||||
{
|
||||
v.Deserialize(r);
|
||||
|
||||
if (v.Type == null)
|
||||
{
|
||||
v.Type = k;
|
||||
}
|
||||
}
|
||||
|
||||
return new KeyValuePair<Type, NotifySettings>(k, v);
|
||||
},
|
||||
Settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
[Flags]
|
||||
public enum NotifyFlags : ulong
|
||||
{
|
||||
None = 0x0,
|
||||
|
||||
AutoClose = 0x1,
|
||||
Ignore = 0x2,
|
||||
TextOnly = 0x4,
|
||||
Animate = 0x8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
#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.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public sealed class NotifySettings : PropertyObject
|
||||
{
|
||||
public Dictionary<IAccount, NotifySettingsState> States { get; private set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public Dictionary<IAccount, NotifySettingsState>.KeyCollection Keys
|
||||
{
|
||||
get => States.Keys;
|
||||
private set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public Dictionary<IAccount, NotifySettingsState>.ValueCollection Values
|
||||
{
|
||||
get => States.Values;
|
||||
private set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(Notify.Access, true)]
|
||||
public Type Type { get; set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public string Desc { get; set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public AccessLevel Access { get; set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool CanIgnore { get; set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool CanAutoClose { get; set; }
|
||||
|
||||
public NotifySettings(Type t)
|
||||
{
|
||||
Type = t;
|
||||
Name = t.Name;
|
||||
|
||||
Desc = String.Empty;
|
||||
Access = AccessLevel.Player;
|
||||
|
||||
CanIgnore = true;
|
||||
CanAutoClose = true;
|
||||
|
||||
States = new Dictionary<IAccount, NotifySettingsState>();
|
||||
}
|
||||
|
||||
public NotifySettings(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
States.Clear();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
States.Clear();
|
||||
}
|
||||
|
||||
public bool IsAutoClose(Mobile m)
|
||||
{
|
||||
return CanAutoClose && m != null && m.Account != null && States.ContainsKey(m.Account) && States[m.Account].AutoClose;
|
||||
}
|
||||
|
||||
public bool IsIgnored(Mobile m)
|
||||
{
|
||||
return CanIgnore && m != null && m.Account != null && States.ContainsKey(m.Account) && States[m.Account].Ignore;
|
||||
}
|
||||
|
||||
public bool IsTextOnly(Mobile m)
|
||||
{
|
||||
return m != null && m.Account != null && States.ContainsKey(m.Account) && States[m.Account].TextOnly;
|
||||
}
|
||||
|
||||
public bool IsAnimated(Mobile m)
|
||||
{
|
||||
return m == null || m.Account == null || !States.ContainsKey(m.Account) || States[m.Account].Animate;
|
||||
}
|
||||
|
||||
public void AlterTime(Mobile m, ref double value)
|
||||
{
|
||||
if (m == null || m.Account == null || !States.ContainsKey(m.Account) || value <= 0.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var speed = Math.Max(0, Math.Min(200, (int)States[m.Account].Speed));
|
||||
|
||||
if (speed > 100)
|
||||
{
|
||||
value -= value * ((speed - 100) / 100.0);
|
||||
}
|
||||
else if (speed < 100)
|
||||
{
|
||||
value += value * ((100 - speed) / 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
public NotifySettingsState EnsureState(IAccount a)
|
||||
{
|
||||
var s = States.GetValue(a);
|
||||
|
||||
if (s == null || s.Settings != this)
|
||||
{
|
||||
States[a] = s = new NotifySettingsState(this, a);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var name = Name.Replace("Notify", String.Empty).Replace("Gump", String.Empty);
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = "Notifications";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.WriteType(Type);
|
||||
writer.Write(Name);
|
||||
writer.Write(Desc);
|
||||
|
||||
writer.Write(CanIgnore);
|
||||
writer.Write(CanAutoClose);
|
||||
|
||||
writer.WriteBlockDictionary(States, (w, k, v) => v.Serialize(w));
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
Type = reader.ReadType();
|
||||
Name = reader.ReadString();
|
||||
Desc = reader.ReadString();
|
||||
|
||||
CanIgnore = reader.ReadBool();
|
||||
CanAutoClose = reader.ReadBool();
|
||||
|
||||
States = reader.ReadBlockDictionary(
|
||||
r =>
|
||||
{
|
||||
var state = new NotifySettingsState(this, r);
|
||||
|
||||
return new KeyValuePair<IAccount, NotifySettingsState>(state.Owner, state);
|
||||
},
|
||||
States);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server;
|
||||
using Server.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public sealed class NotifySettingsState : SettingsObject<NotifyFlags>
|
||||
{
|
||||
[CommandProperty(Notify.Access)]
|
||||
public NotifySettings Settings { get; private set; }
|
||||
|
||||
[CommandProperty(Notify.Access, true)]
|
||||
public IAccount Owner { get; private set; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public override NotifyFlags Flags { get => base.Flags; set => base.Flags = value; }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool AutoClose
|
||||
{
|
||||
get => GetFlag(NotifyFlags.AutoClose);
|
||||
set => SetFlag(NotifyFlags.AutoClose, value);
|
||||
}
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool Ignore { get => GetFlag(NotifyFlags.Ignore); set => SetFlag(NotifyFlags.Ignore, value); }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool TextOnly { get => GetFlag(NotifyFlags.TextOnly); set => SetFlag(NotifyFlags.TextOnly, value); }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public bool Animate { get => GetFlag(NotifyFlags.Animate); set => SetFlag(NotifyFlags.Animate, value); }
|
||||
|
||||
[CommandProperty(Notify.Access)]
|
||||
public byte Speed { get; set; }
|
||||
|
||||
public NotifySettingsState(NotifySettings settings, IAccount owner)
|
||||
{
|
||||
Settings = settings;
|
||||
Owner = owner;
|
||||
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
public NotifySettingsState(NotifySettings settings, GenericReader reader)
|
||||
: base(reader)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
public void SetDefaults()
|
||||
{
|
||||
AutoClose = false;
|
||||
Ignore = false;
|
||||
TextOnly = false;
|
||||
Animate = true;
|
||||
|
||||
Speed = 100;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Owner != null)
|
||||
{
|
||||
if (Settings != null)
|
||||
{
|
||||
return Owner + ": " + Settings;
|
||||
}
|
||||
|
||||
return Owner.ToString();
|
||||
}
|
||||
|
||||
if (Settings != null)
|
||||
{
|
||||
return Settings.ToString();
|
||||
}
|
||||
|
||||
return base.ToString();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(Owner);
|
||||
|
||||
writer.Write(Speed);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
Owner = reader.ReadAccount();
|
||||
|
||||
Speed = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
551
Scripts/SubSystem/VitaNex/Core/Services/Notify/UI/NotifyGump.cs
Normal file
551
Scripts/SubSystem/VitaNex/Core/Services/Notify/UI/NotifyGump.cs
Normal file
@@ -0,0 +1,551 @@
|
||||
#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;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
using VitaNex.Text;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public abstract class NotifyGump : SuperGump
|
||||
{
|
||||
private static void InitSettings(NotifySettings o)
|
||||
{
|
||||
o.Name = "Misc Notifications";
|
||||
o.Desc = "Any notifications that do not fall into a more specific category.";
|
||||
}
|
||||
|
||||
public static event Action<NotifyGump> OnNotify;
|
||||
|
||||
public static TimeSpan DefaultAnimDuration = TimeSpan.FromMilliseconds(500.0);
|
||||
public static TimeSpan DefaultPauseDuration = TimeSpan.FromSeconds(5.0);
|
||||
|
||||
public static Size SizeMin = new Size(100, 60);
|
||||
public static Size SizeMax = new Size(400, 200);
|
||||
|
||||
public enum AnimState
|
||||
{
|
||||
Show,
|
||||
Hide,
|
||||
Pause
|
||||
}
|
||||
|
||||
public TimeSpan AnimDuration { get; set; }
|
||||
public TimeSpan PauseDuration { get; set; }
|
||||
|
||||
public string Html { get; set; }
|
||||
public Color HtmlColor { get; set; }
|
||||
public int HtmlIndent { get; set; }
|
||||
|
||||
public int BorderID { get; set; }
|
||||
public int BorderSize { get; set; }
|
||||
public bool BorderAlpha { get; set; }
|
||||
|
||||
public int BackgroundID { get; set; }
|
||||
public bool BackgroundAlpha { get; set; }
|
||||
|
||||
public int WidthMax { get; set; }
|
||||
public int HeightMax { get; set; }
|
||||
|
||||
public bool AutoClose { get; set; }
|
||||
|
||||
public int Frame { get; private set; }
|
||||
public AnimState State { get; private set; }
|
||||
|
||||
public int FrameCount => (int)Math.Ceiling(Math.Max(100.0, AnimDuration.TotalMilliseconds) / 100.0);
|
||||
public int FrameHeight { get; private set; }
|
||||
public int FrameWidth { get; private set; }
|
||||
|
||||
public Size HtmlSize { get; private set; }
|
||||
public Size OptionsSize { get; private set; }
|
||||
|
||||
public List<NotifyGumpOption> Options { get; private set; }
|
||||
|
||||
public int OptionsCols { get; private set; }
|
||||
public int OptionsRows { get; private set; }
|
||||
|
||||
public override bool InitPolling => true;
|
||||
|
||||
public NotifyGump(Mobile user, string html)
|
||||
: this(user, html, null)
|
||||
{ }
|
||||
|
||||
public NotifyGump(Mobile user, string html, IEnumerable<NotifyGumpOption> options)
|
||||
: base(user, null, 0, 140)
|
||||
{
|
||||
Options = options.Ensure().ToList();
|
||||
|
||||
AnimDuration = DefaultAnimDuration;
|
||||
PauseDuration = DefaultPauseDuration;
|
||||
|
||||
Html = html ?? String.Empty;
|
||||
HtmlColor = Color.White;
|
||||
HtmlIndent = 10;
|
||||
|
||||
BorderSize = 4;
|
||||
BorderID = 9204;
|
||||
BorderAlpha = false;
|
||||
|
||||
BackgroundID = 2624;
|
||||
BackgroundAlpha = true;
|
||||
|
||||
AutoClose = true;
|
||||
|
||||
Frame = 0;
|
||||
State = AnimState.Pause;
|
||||
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
|
||||
CloseSound = -1;
|
||||
|
||||
ForceRecompile = true;
|
||||
AutoRefreshRate = TimeSpan.FromMilliseconds(100.0);
|
||||
AutoRefresh = true;
|
||||
|
||||
WidthMax = 250;
|
||||
HeightMax = 100;
|
||||
|
||||
InitOptions();
|
||||
}
|
||||
|
||||
protected virtual void InitOptions()
|
||||
{ }
|
||||
|
||||
public void AddOption(TextDefinition label, Action<GumpButton> callback)
|
||||
{
|
||||
AddOption(label, callback, Color.Empty);
|
||||
}
|
||||
|
||||
public void AddOption(TextDefinition label, Action<GumpButton> callback, Color color)
|
||||
{
|
||||
AddOption(label, callback, color, Color.Empty);
|
||||
}
|
||||
|
||||
public void AddOption(TextDefinition label, Action<GumpButton> callback, Color color, Color fill)
|
||||
{
|
||||
AddOption(label, callback, color, fill, Color.Empty);
|
||||
}
|
||||
|
||||
public void AddOption(TextDefinition label, Action<GumpButton> callback, Color color, Color fill, Color border)
|
||||
{
|
||||
if (color.IsEmpty)
|
||||
{
|
||||
color = HtmlColor;
|
||||
}
|
||||
|
||||
var opt = Options.Find(o => o.Label.Equals(label));
|
||||
|
||||
if (opt != null)
|
||||
{
|
||||
opt.Callback = callback;
|
||||
opt.LabelColor = color;
|
||||
opt.FillColor = fill;
|
||||
opt.BorderColor = border;
|
||||
}
|
||||
else
|
||||
{
|
||||
Options.Add(new NotifyGumpOption(label, callback, color, fill, border));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Size GetSizeMin()
|
||||
{
|
||||
return SizeMin;
|
||||
}
|
||||
|
||||
protected virtual Size GetSizeMax()
|
||||
{
|
||||
return SizeMax;
|
||||
}
|
||||
|
||||
protected override void Compile()
|
||||
{
|
||||
base.Compile();
|
||||
|
||||
var sMin = GetSizeMin();
|
||||
var sMax = GetSizeMax();
|
||||
|
||||
WidthMax = Math.Max(sMin.Width, Math.Min(sMax.Width, WidthMax));
|
||||
HeightMax = Math.Max(sMin.Height, Math.Min(sMax.Height, HeightMax));
|
||||
|
||||
HtmlIndent = Math.Max(0, HtmlIndent);
|
||||
BorderSize = Math.Max(0, BorderSize);
|
||||
|
||||
var wm = WidthMax - (BorderSize * 2);
|
||||
|
||||
var text = Html.ParseBBCode(HtmlColor).StripHtmlBreaks(true).StripHtml();
|
||||
|
||||
var font = UOFont.Unicode[1];
|
||||
|
||||
var s = font.GetSize(text);
|
||||
|
||||
s.Width += 4;
|
||||
s.Height += 4;
|
||||
|
||||
if (s.Width > wm)
|
||||
{
|
||||
s.Height += (int)Math.Ceiling((s.Width - wm) / (double)wm) * (font.LineHeight + font.LineSpacing);
|
||||
s.Width = wm;
|
||||
}
|
||||
|
||||
if (!Initialized)
|
||||
{
|
||||
s.Height = Math.Max(sMin.Height, Math.Min(HeightMax, Math.Min(sMax.Height, s.Height)));
|
||||
}
|
||||
else
|
||||
{
|
||||
s.Height = Math.Max(sMin.Height, Math.Min(sMax.Height, Math.Min(sMax.Height, s.Height)));
|
||||
}
|
||||
|
||||
HtmlSize = s;
|
||||
|
||||
if (Options.Count > 1)
|
||||
{
|
||||
OptionsCols = wm / Math.Max(30, Math.Min(wm, Options.Max(o => o.Width)));
|
||||
OptionsRows = (int)Math.Ceiling(Options.Count / (double)OptionsCols);
|
||||
}
|
||||
else if (Options.Count > 0)
|
||||
{
|
||||
OptionsCols = OptionsRows = 1;
|
||||
}
|
||||
|
||||
s.Width = wm;
|
||||
s.Height = (OptionsRows * 20) + 4;
|
||||
|
||||
OptionsSize = s;
|
||||
|
||||
HeightMax = (BorderSize * 2) + HtmlSize.Height + OptionsSize.Height;
|
||||
|
||||
var f = Frame / (double)FrameCount;
|
||||
|
||||
FrameWidth = (int)Math.Ceiling(WidthMax * f);
|
||||
FrameHeight = (int)Math.Ceiling(HeightMax * f);
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
layout.Add(
|
||||
"frame",
|
||||
() =>
|
||||
{
|
||||
if (BorderSize > 0 && BorderID >= 0)
|
||||
{
|
||||
AddImageTiled(0, 0, FrameWidth, FrameHeight, BorderID);
|
||||
|
||||
if (BorderAlpha)
|
||||
{
|
||||
AddAlphaRegion(0, 0, FrameWidth, FrameHeight);
|
||||
}
|
||||
}
|
||||
|
||||
var fw = FrameWidth - (BorderSize * 2);
|
||||
var fh = FrameHeight - (BorderSize * 2);
|
||||
|
||||
if (fw * fh > 0 && BackgroundID > 0)
|
||||
{
|
||||
AddImageTiled(BorderSize, BorderSize, fw, fh, BackgroundID);
|
||||
|
||||
if (BackgroundAlpha)
|
||||
{
|
||||
AddAlphaRegion(BorderSize, BorderSize, fw, fh);
|
||||
}
|
||||
}
|
||||
|
||||
if (Frame < FrameCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddButton(FrameWidth - BorderSize, (FrameHeight / 2) - 8, 22153, 22155, OnSettings);
|
||||
|
||||
var x = BorderSize + 2 + HtmlIndent;
|
||||
var y = BorderSize + 2;
|
||||
var w = fw - (4 + HtmlIndent);
|
||||
var h = fh - (4 + OptionsSize.Height);
|
||||
|
||||
var html = Html.ParseBBCode(HtmlColor).WrapUOHtmlColor(HtmlColor, false);
|
||||
|
||||
AddHtml(x, y, w, h, html, false, (HtmlSize.Height - 4) > h);
|
||||
});
|
||||
|
||||
if (Frame >= FrameCount && Options.Count > 0)
|
||||
{
|
||||
var x = BorderSize + 2;
|
||||
var y = BorderSize + HtmlSize.Height + 2;
|
||||
var w = OptionsSize.Width - 4;
|
||||
var h = OptionsSize.Height - 4;
|
||||
|
||||
CompileOptionsLayout(layout, x, y, w, h, w / OptionsCols);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CompileOptionsLayout(SuperGumpLayout layout, int x, int y, int w, int h, int bw)
|
||||
{
|
||||
if (Frame < FrameCount || Options.Count == 0 || OptionsCols * OptionsRows <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
layout.Add("opts", () => AddRectangle(x, y, w, h, Color.Black, true));
|
||||
|
||||
var oi = 0;
|
||||
var ox = x;
|
||||
var oy = y;
|
||||
|
||||
foreach (var ob in Options)
|
||||
{
|
||||
CompileOptionLayout(layout, oi, ox, oy, bw, 20, ob);
|
||||
|
||||
if (++oi % OptionsCols == 0)
|
||||
{
|
||||
ox = x;
|
||||
oy += 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
ox += bw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CompileOptionLayout(
|
||||
SuperGumpLayout layout,
|
||||
int index,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
NotifyGumpOption option)
|
||||
{
|
||||
layout.Add(
|
||||
"opts/" + index,
|
||||
() =>
|
||||
{
|
||||
AddHtmlButton(
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
b =>
|
||||
{
|
||||
if (option.Callback != null)
|
||||
{
|
||||
option.Callback(b);
|
||||
}
|
||||
|
||||
Refresh();
|
||||
},
|
||||
option.GetString(User),
|
||||
option.LabelColor,
|
||||
option.FillColor,
|
||||
option.BorderColor,
|
||||
1);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void OnSettings(GumpButton b)
|
||||
{
|
||||
Refresh();
|
||||
|
||||
new NotifySettingsGump(User).Send();
|
||||
}
|
||||
|
||||
protected override bool CanAutoRefresh()
|
||||
{
|
||||
return State == AnimState.Pause && Frame > 0 ? AutoClose && base.CanAutoRefresh() : base.CanAutoRefresh();
|
||||
}
|
||||
|
||||
protected override void OnAutoRefresh()
|
||||
{
|
||||
base.OnAutoRefresh();
|
||||
|
||||
AnimateList();
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case AnimState.Show:
|
||||
{
|
||||
if (Frame++ >= FrameCount)
|
||||
{
|
||||
AutoRefreshRate = PauseDuration;
|
||||
State = AnimState.Pause;
|
||||
Frame = FrameCount;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AnimState.Hide:
|
||||
{
|
||||
if (Frame-- <= 0)
|
||||
{
|
||||
AutoRefreshRate = TimeSpan.FromMilliseconds(100.0);
|
||||
State = AnimState.Pause;
|
||||
Frame = 0;
|
||||
Close(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AnimState.Pause:
|
||||
{
|
||||
AutoRefreshRate = TimeSpan.FromMilliseconds(100.0);
|
||||
State = Frame <= 0 ? AnimState.Show : AutoClose ? AnimState.Hide : AnimState.Pause;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnBeforeSend()
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
if (Notify.IsIgnored(GetType(), User))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Notify.IsAnimated(GetType(), User))
|
||||
{
|
||||
AnimDuration = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
if (OnNotify != null)
|
||||
{
|
||||
OnNotify(this);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnBeforeSend();
|
||||
}
|
||||
|
||||
public override void Close(bool all)
|
||||
{
|
||||
if (all)
|
||||
{
|
||||
base.Close(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoRefreshRate = TimeSpan.FromMilliseconds(100.0);
|
||||
AutoClose = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void AnimateList()
|
||||
{
|
||||
VitaNexCore.TryCatch(
|
||||
() =>
|
||||
{
|
||||
var p = this;
|
||||
|
||||
foreach (var g in EnumerateInstances<NotifyGump>(User, true)
|
||||
.Where(g => g != this && g.IsOpen && !g.IsDisposed && g.Y >= p.Y)
|
||||
.OrderBy(g => g.Y))
|
||||
{
|
||||
g.Y = p.Y + p.FrameHeight;
|
||||
|
||||
p = g;
|
||||
|
||||
if (g.State != AnimState.Pause)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lr = g.LastAutoRefresh;
|
||||
|
||||
g.Refresh(true);
|
||||
g.LastAutoRefresh = lr;
|
||||
}
|
||||
},
|
||||
e => e.ToConsole());
|
||||
}
|
||||
|
||||
private class Sub0 : NotifyGump
|
||||
{
|
||||
public Sub0(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub1 : NotifyGump
|
||||
{
|
||||
public Sub1(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub2 : NotifyGump
|
||||
{
|
||||
public Sub2(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub3 : NotifyGump
|
||||
{
|
||||
public Sub3(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub4 : NotifyGump
|
||||
{
|
||||
public Sub4(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub5 : NotifyGump
|
||||
{
|
||||
public Sub5(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub6 : NotifyGump
|
||||
{
|
||||
public Sub6(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub7 : NotifyGump
|
||||
{
|
||||
public Sub7(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub8 : NotifyGump
|
||||
{
|
||||
public Sub8(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub9 : NotifyGump
|
||||
{
|
||||
public Sub9(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.Text;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public class NotifyGumpOption
|
||||
{
|
||||
public char? Prefix { get; set; }
|
||||
|
||||
public TextDefinition Label { get; set; }
|
||||
public Action<GumpButton> Callback { get; set; }
|
||||
|
||||
public Color LabelColor { get; set; }
|
||||
public Color FillColor { get; set; }
|
||||
public Color BorderColor { get; set; }
|
||||
|
||||
public int Width => 10 + UOFont.GetUnicodeWidth(1, GetString());
|
||||
|
||||
public NotifyGumpOption(TextDefinition label, Action<GumpButton> callback)
|
||||
: this(label, callback, Color.Empty)
|
||||
{ }
|
||||
|
||||
public NotifyGumpOption(TextDefinition label, Action<GumpButton> callback, Color color)
|
||||
: this(label, callback, color, Color.Empty)
|
||||
{ }
|
||||
|
||||
public NotifyGumpOption(TextDefinition label, Action<GumpButton> callback, Color color, Color fill)
|
||||
: this(label, callback, color, fill, Color.Empty)
|
||||
{ }
|
||||
|
||||
public NotifyGumpOption(TextDefinition label, Action<GumpButton> callback, Color color, Color fill, Color border)
|
||||
{
|
||||
Prefix = UniGlyph.TriRightFill;
|
||||
|
||||
Label = label;
|
||||
Callback = callback;
|
||||
|
||||
LabelColor = color;
|
||||
FillColor = fill;
|
||||
BorderColor = border;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetString();
|
||||
}
|
||||
|
||||
public string GetString()
|
||||
{
|
||||
return GetString(null);
|
||||
}
|
||||
|
||||
public string GetString(Mobile viewer)
|
||||
{
|
||||
if (Prefix.HasValue)
|
||||
{
|
||||
return Prefix.Value + " " + Label.GetString(viewer);
|
||||
}
|
||||
|
||||
return Label.GetString(viewer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,600 @@
|
||||
#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.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Commands.Generic;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public class NotifySettingsGump : SuperGumpList<NotifySettings>
|
||||
{
|
||||
public NotifySettingsGump(Mobile user)
|
||||
: base(user)
|
||||
{
|
||||
EntriesPerPage = 5;
|
||||
}
|
||||
|
||||
protected override void CompileList(List<NotifySettings> list)
|
||||
{
|
||||
list.Clear();
|
||||
list.AddRange(Notify.Settings.Values.Where(o => User.AccessLevel >= o.Access).OrderByNatural());
|
||||
|
||||
base.CompileList(list);
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
const int width = 400, height = 600;
|
||||
|
||||
var sup = SupportsUltimaStore;
|
||||
var pad = sup ? 15 : 10;
|
||||
var bgID = sup ? 40000 : 9270;
|
||||
|
||||
layout.Add("bg", () => AddBackground(0, 0, width, height, bgID));
|
||||
|
||||
layout.Add(
|
||||
"title",
|
||||
() =>
|
||||
{
|
||||
var title = "Notification Settings";
|
||||
|
||||
title = title.WrapUOHtmlBig();
|
||||
title = title.WrapUOHtmlCenter();
|
||||
title = title.WrapUOHtmlColor(Color.Gold, false);
|
||||
|
||||
AddHtml(pad, pad, width - (pad * 2), 40, title, false, false);
|
||||
});
|
||||
|
||||
layout.Add(
|
||||
"opts",
|
||||
() =>
|
||||
{
|
||||
var xx = pad;
|
||||
var yy = pad + 30;
|
||||
var ww = width - (pad * 2);
|
||||
var hh = height - ((pad * 2) + 60);
|
||||
|
||||
var r = GetListRange();
|
||||
var o = AddAccordion(xx, yy, ww, hh, r.Values, CompileEntryLayout);
|
||||
|
||||
if (o == null || o.Item1 == null)
|
||||
{
|
||||
if (o != null)
|
||||
{
|
||||
CompileEmptyLayout(xx, yy + o.Item2, ww, hh - o.Item2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CompileEmptyLayout(xx, yy, ww, hh);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
layout.Add(
|
||||
"pages",
|
||||
() =>
|
||||
{
|
||||
var xx = pad;
|
||||
var yy = (height - 25) - pad;
|
||||
var ww = width - (pad * 2);
|
||||
|
||||
if (HasPrevPage)
|
||||
{
|
||||
if (sup)
|
||||
{
|
||||
AddButton(xx, yy, 40016, 40026, PreviousPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddButton(xx, yy, 9766, 9767, PreviousPage);
|
||||
}
|
||||
}
|
||||
|
||||
xx += 35;
|
||||
ww -= 70;
|
||||
|
||||
var page = String.Format("Page {0:#,0} / {1:#,0}", Page + 1, PageCount);
|
||||
|
||||
page = page.WrapUOHtmlCenter();
|
||||
page = page.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(xx, yy + 2, ww, 40, page, false, false);
|
||||
|
||||
xx += ww;
|
||||
|
||||
if (HasNextPage)
|
||||
{
|
||||
if (sup)
|
||||
{
|
||||
AddButton(xx, yy, 40017, 40027, NextPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddButton(xx, yy, 9762, 9763, NextPage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void CompileEntryLayout(int x, int y, int w, int h, NotifySettings o)
|
||||
{
|
||||
var sup = SupportsUltimaStore;
|
||||
var pad = sup ? 15 : 10;
|
||||
var off = sup ? 35 : 10;
|
||||
var bgID = sup ? 40000 : 9270;
|
||||
var btnNormal = sup ? 40017 : 9762;
|
||||
var btnSelected = sup ? 40027 : 9763;
|
||||
var chkNormal = sup ? 40014 : 9722;
|
||||
var chkSelected = sup ? 40015 : 9723;
|
||||
|
||||
var s = o.EnsureState(User.Account);
|
||||
|
||||
string label;
|
||||
|
||||
if (User.AccessLevel >= Notify.Access)
|
||||
{
|
||||
AddButton(
|
||||
x,
|
||||
y,
|
||||
btnNormal,
|
||||
btnSelected,
|
||||
b =>
|
||||
{
|
||||
Refresh();
|
||||
|
||||
if (User.AccessLevel >= Notify.Access)
|
||||
{
|
||||
User.SendGump(new PropertiesGump(User, o));
|
||||
}
|
||||
});
|
||||
|
||||
label = Notify.Access.ToString().ToUpper();
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + 35, y + 2, w - 35, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
}
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (o.CanIgnore)
|
||||
{
|
||||
AddCheck(x, y, chkNormal, chkSelected, s.Ignore, (c, v) => s.Ignore = v);
|
||||
|
||||
label = "IGNORE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddImage(x, y, chkNormal, 900);
|
||||
|
||||
label = "IGNORE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.Gray, false);
|
||||
}
|
||||
|
||||
AddHtml(x + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
if (o.CanAutoClose)
|
||||
{
|
||||
AddCheck(x + (w / 2), y, chkNormal, chkSelected, s.AutoClose, (c, v) => s.AutoClose = v);
|
||||
|
||||
label = "AUTO CLOSE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddImage(x + (w / 2), y, chkNormal, 900);
|
||||
|
||||
label = "AUTO CLOSE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.Gray, false);
|
||||
}
|
||||
|
||||
AddHtml(x + (w / 2) + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddCheck(x, y, chkNormal, chkSelected, s.Animate, (c, v) => s.Animate = v);
|
||||
|
||||
label = "ANIMATE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
AddCheck(x + (w / 2), y, chkNormal, chkSelected, s.TextOnly, (c, v) => s.TextOnly = v);
|
||||
|
||||
label = "TEXT ONLY";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + (w / 2) + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var track = (w / 2) - 60;
|
||||
|
||||
AddScrollbarH(
|
||||
x,
|
||||
y + 4,
|
||||
200,
|
||||
s.Speed,
|
||||
p =>
|
||||
{
|
||||
s.Speed = (byte)Math.Max(0, s.Speed - 10);
|
||||
|
||||
Refresh(true);
|
||||
},
|
||||
n =>
|
||||
{
|
||||
s.Speed = (byte)Math.Min(200, s.Speed + 10);
|
||||
|
||||
Refresh(true);
|
||||
},
|
||||
new Rectangle(30, 0, track, 13),
|
||||
new Rectangle(0, 0, 28, 13),
|
||||
new Rectangle(track + 32, 0, 28, 13));
|
||||
|
||||
label = String.Format("{0}% SPEED", Math.Max((byte)1, s.Speed));
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + track + 70, y + 2, w - (track + 60), 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(o.Desc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
x -= pad;
|
||||
w += pad * 2;
|
||||
|
||||
AddImage(x, y, bgID);
|
||||
AddImageTiled(x + off, y, w - (off * 2), off, bgID + 1);
|
||||
AddImage(x + off + (w - (off * 2)), y, bgID + 2);
|
||||
|
||||
x += pad;
|
||||
w -= pad * 2;
|
||||
y += pad;
|
||||
h -= pad;
|
||||
|
||||
label = "Description";
|
||||
label = label.WrapUOHtmlBig();
|
||||
label = label.WrapUOHtmlCenter();
|
||||
label = label.WrapUOHtmlColor(Color.Gold, false);
|
||||
|
||||
AddHtml(x, y, w, 40, label, false, false);
|
||||
|
||||
x += 5;
|
||||
w -= 5;
|
||||
y += 20;
|
||||
h -= 10;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
label = o.Desc;
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x, y, w, h, label, false, true);
|
||||
}
|
||||
|
||||
protected virtual void CompileEmptyLayout(int x, int y, int w, int h)
|
||||
{
|
||||
var sup = SupportsUltimaStore;
|
||||
var pad = sup ? 15 : 10;
|
||||
var off = sup ? 35 : 10;
|
||||
var bgID = sup ? 40000 : 9270;
|
||||
var btnNormal = sup ? 40017 : 9762;
|
||||
var btnSelected = sup ? 40027 : 9763;
|
||||
var chkNormal = sup ? 40014 : 9722;
|
||||
var chkSelected = sup ? 40015 : 9723;
|
||||
|
||||
x -= pad;
|
||||
w += pad * 2;
|
||||
|
||||
AddImage(x, y, bgID);
|
||||
AddImageTiled(x + off, y, w - (off * 2), off, bgID + 1);
|
||||
AddImage(x + off + (w - (off * 2)), y, bgID + 2);
|
||||
|
||||
x += pad;
|
||||
w -= pad * 2;
|
||||
y += pad;
|
||||
h -= pad;
|
||||
|
||||
var label = "All Notifications";
|
||||
label = label.WrapUOHtmlBig();
|
||||
label = label.WrapUOHtmlCenter();
|
||||
label = label.WrapUOHtmlColor(Color.Gold, false);
|
||||
|
||||
AddHtml(x, y + 2, w, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (User.AccessLevel >= Notify.Access)
|
||||
{
|
||||
AddButton(
|
||||
x,
|
||||
y,
|
||||
btnNormal,
|
||||
btnSelected,
|
||||
b =>
|
||||
{
|
||||
Refresh();
|
||||
|
||||
if (User.AccessLevel >= Notify.Access)
|
||||
{
|
||||
var cols = new[] { "Object" };
|
||||
var list = new ArrayList(List);
|
||||
|
||||
User.SendGump(new InterfaceGump(User, cols, list, 0, null));
|
||||
}
|
||||
});
|
||||
|
||||
label = Notify.Access.ToString().ToUpper();
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + 35, y + 2, w - 35, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
}
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var states = List.Select(o => o.EnsureState(User.Account));
|
||||
|
||||
var vals = new int[5, 2];
|
||||
|
||||
foreach (var o in states)
|
||||
{
|
||||
if (o.Settings.CanIgnore)
|
||||
{
|
||||
if (o.Ignore)
|
||||
{
|
||||
++vals[0, 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
++vals[0, 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (o.Settings.CanAutoClose)
|
||||
{
|
||||
if (o.AutoClose)
|
||||
{
|
||||
++vals[1, 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
++vals[1, 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (o.Animate)
|
||||
{
|
||||
++vals[2, 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
++vals[2, 1];
|
||||
}
|
||||
|
||||
if (o.TextOnly)
|
||||
{
|
||||
++vals[3, 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
++vals[3, 1];
|
||||
}
|
||||
|
||||
vals[4, 0] += o.Speed;
|
||||
++vals[4, 1];
|
||||
}
|
||||
|
||||
var ignore = vals[0, 0] >= vals[0, 1];
|
||||
|
||||
AddButton(
|
||||
x,
|
||||
y,
|
||||
ignore ? chkSelected : chkNormal,
|
||||
ignore ? chkNormal : chkSelected,
|
||||
b =>
|
||||
{
|
||||
foreach (var s in List.Where(o => o.CanIgnore).Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.Ignore = !ignore;
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
});
|
||||
|
||||
label = "IGNORE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
var autoClose = vals[1, 0] >= vals[1, 1];
|
||||
|
||||
AddButton(
|
||||
x + (w / 2),
|
||||
y,
|
||||
autoClose ? chkSelected : chkNormal,
|
||||
autoClose ? chkNormal : chkSelected,
|
||||
b =>
|
||||
{
|
||||
foreach (var s in List.Where(o => o.CanAutoClose).Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.AutoClose = !autoClose;
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
});
|
||||
|
||||
label = "AUTO CLOSE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + (w / 2) + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var animate = vals[2, 0] >= vals[2, 1];
|
||||
|
||||
AddButton(
|
||||
x,
|
||||
y,
|
||||
animate ? chkSelected : chkNormal,
|
||||
animate ? chkNormal : chkSelected,
|
||||
b =>
|
||||
{
|
||||
foreach (var s in List.Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.Animate = !animate;
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
});
|
||||
|
||||
label = "ANIMATE";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
var textOnly = vals[3, 0] >= vals[4, 1];
|
||||
|
||||
AddButton(
|
||||
x + (w / 2),
|
||||
y,
|
||||
textOnly ? chkSelected : chkNormal,
|
||||
textOnly ? chkNormal : chkSelected,
|
||||
b =>
|
||||
{
|
||||
foreach (var s in List.Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.TextOnly = !textOnly;
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
});
|
||||
|
||||
label = "TEXT ONLY";
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + (w / 2) + 30, y + 2, (w / 2) - 30, 40, label, false, false);
|
||||
|
||||
y += 30;
|
||||
h -= 30;
|
||||
|
||||
if (w * h <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var track = (w / 2) - 60;
|
||||
|
||||
var speed = vals[4, 0] / Math.Max(1, vals[4, 1]);
|
||||
|
||||
AddScrollbarH(
|
||||
x,
|
||||
y + 4,
|
||||
200,
|
||||
speed,
|
||||
p =>
|
||||
{
|
||||
foreach (var s in List.Where(o => o.CanIgnore).Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.Speed = (byte)Math.Max(0, speed - 10);
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
},
|
||||
n =>
|
||||
{
|
||||
foreach (var s in List.Where(o => o.CanIgnore).Select(o => o.EnsureState(User.Account)))
|
||||
{
|
||||
s.Speed = (byte)Math.Min(200, speed + 10);
|
||||
}
|
||||
|
||||
Refresh(true);
|
||||
},
|
||||
new Rectangle(30, 0, track, 13),
|
||||
new Rectangle(0, 0, 28, 13),
|
||||
new Rectangle(track + 32, 0, 28, 13));
|
||||
|
||||
label = String.Format("{0}% SPEED", Math.Max(1, speed));
|
||||
label = label.WrapUOHtmlBold();
|
||||
label = label.WrapUOHtmlColor(Color.PaleGoldenrod, false);
|
||||
|
||||
AddHtml(x + track + 70, y + 2, w - (track + 60), 40, label, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using Server;
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Notify
|
||||
{
|
||||
public abstract class WorldNotifyGump : NotifyGump
|
||||
{
|
||||
private static void InitSettings(NotifySettings o)
|
||||
{
|
||||
o.CanIgnore = true;
|
||||
o.Desc = "General broadcasts from the staff and server.";
|
||||
}
|
||||
|
||||
public WorldNotifyGump(Mobile user, string html)
|
||||
: this(user, html, false)
|
||||
{ }
|
||||
|
||||
public WorldNotifyGump(Mobile user, string html, bool autoClose)
|
||||
: base(user, html)
|
||||
{
|
||||
AnimDuration = TimeSpan.FromSeconds(1.0);
|
||||
PauseDuration = TimeSpan.FromSeconds(10.0);
|
||||
HtmlColor = Color.Yellow;
|
||||
AutoClose = autoClose;
|
||||
}
|
||||
|
||||
private class Sub0 : WorldNotifyGump
|
||||
{
|
||||
public Sub0(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub0(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub1 : WorldNotifyGump
|
||||
{
|
||||
public Sub1(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub1(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub2 : WorldNotifyGump
|
||||
{
|
||||
public Sub2(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub2(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub3 : WorldNotifyGump
|
||||
{
|
||||
public Sub3(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub3(PlayerMobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub4 : WorldNotifyGump
|
||||
{
|
||||
public Sub4(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub4(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub5 : WorldNotifyGump
|
||||
{
|
||||
public Sub5(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub5(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub6 : WorldNotifyGump
|
||||
{
|
||||
public Sub6(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub6(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub7 : WorldNotifyGump
|
||||
{
|
||||
public Sub7(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub7(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub8 : WorldNotifyGump
|
||||
{
|
||||
public Sub8(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub8(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class Sub9 : WorldNotifyGump
|
||||
{
|
||||
public Sub9(Mobile user, string html)
|
||||
: base(user, html)
|
||||
{ }
|
||||
|
||||
public Sub9(Mobile user, string html, bool autoClose)
|
||||
: base(user, html, autoClose)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
270
Scripts/SubSystem/VitaNex/Core/Services/Notoriety/Notoriety.cs
Normal file
270
Scripts/SubSystem/VitaNex/Core/Services/Notoriety/Notoriety.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
#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;
|
||||
using Server.Misc;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public delegate T NotorietyHandler<out T>(Mobile x, Mobile y, out bool handled);
|
||||
|
||||
public class NotorietyEntry<T>
|
||||
{
|
||||
public int Priority { get; set; }
|
||||
public NotorietyHandler<T> Handler { get; set; }
|
||||
|
||||
public NotorietyEntry(int priority, NotorietyHandler<T> handler)
|
||||
{
|
||||
Priority = priority;
|
||||
Handler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
[CoreService("Notoriety", "1.0.0.0", TaskPriority.High)]
|
||||
public static class NotoUtility
|
||||
{
|
||||
public const int Bubble = -1;
|
||||
|
||||
private static NotorietyHandler _NotorietyParent;
|
||||
private static AllowBeneficialHandler _BeneficialParent;
|
||||
private static AllowHarmfulHandler _HarmfulParent;
|
||||
|
||||
public static NotorietyHandler NotorietyParent => _NotorietyParent ?? (_NotorietyParent = Notoriety.Handler);
|
||||
|
||||
public static AllowBeneficialHandler BeneficialParent => _BeneficialParent ?? (_BeneficialParent = NotorietyHandlers.Mobile_AllowBeneficial);
|
||||
|
||||
public static AllowHarmfulHandler HarmfulParent => _HarmfulParent ?? (_HarmfulParent = NotorietyHandlers.Mobile_AllowHarmful);
|
||||
|
||||
private static readonly List<NotorietyEntry<int>> _NameHandlers = new List<NotorietyEntry<int>>();
|
||||
private static readonly List<NotorietyEntry<bool>> _BeneficialHandlers = new List<NotorietyEntry<bool>>();
|
||||
private static readonly List<NotorietyEntry<bool>> _HarmfulHandlers = new List<NotorietyEntry<bool>>();
|
||||
|
||||
public static List<NotorietyEntry<int>> NameHandlers => _NameHandlers;
|
||||
public static List<NotorietyEntry<bool>> BeneficialHandlers => _BeneficialHandlers;
|
||||
public static List<NotorietyEntry<bool>> HarmfulHandlers => _HarmfulHandlers;
|
||||
|
||||
private static void CSInvoke()
|
||||
{
|
||||
if (_NotorietyParent == null && Notoriety.Handler != MobileNotoriety)
|
||||
{
|
||||
_NotorietyParent = Notoriety.Handler ?? NotorietyHandlers.MobileNotoriety;
|
||||
}
|
||||
|
||||
if (_BeneficialParent == null && Mobile.AllowBeneficialHandler != AllowBeneficial)
|
||||
{
|
||||
_BeneficialParent = Mobile.AllowBeneficialHandler ?? NotorietyHandlers.Mobile_AllowBeneficial;
|
||||
}
|
||||
|
||||
if (_HarmfulParent == null && Mobile.AllowHarmfulHandler != AllowHarmful)
|
||||
{
|
||||
_HarmfulParent = Mobile.AllowHarmfulHandler ?? NotorietyHandlers.Mobile_AllowHarmful;
|
||||
}
|
||||
|
||||
Notoriety.Handler = MobileNotoriety;
|
||||
Mobile.AllowBeneficialHandler = AllowBeneficial;
|
||||
Mobile.AllowHarmfulHandler = AllowHarmful;
|
||||
}
|
||||
|
||||
public static void CSDispose()
|
||||
{
|
||||
Notoriety.Handler = _NotorietyParent ?? NotorietyHandlers.MobileNotoriety;
|
||||
Mobile.AllowBeneficialHandler = _BeneficialParent ?? NotorietyHandlers.Mobile_AllowBeneficial;
|
||||
Mobile.AllowHarmfulHandler = _HarmfulParent ?? NotorietyHandlers.Mobile_AllowHarmful;
|
||||
|
||||
_NotorietyParent = null;
|
||||
_BeneficialParent = null;
|
||||
_HarmfulParent = null;
|
||||
}
|
||||
|
||||
public static void RegisterNameHandler(NotorietyHandler<int> handler, int priority = 0)
|
||||
{
|
||||
UnregisterNameHandler(handler);
|
||||
_NameHandlers.Add(new NotorietyEntry<int>(priority, handler));
|
||||
}
|
||||
|
||||
public static void UnregisterNameHandler(NotorietyHandler<int> handler)
|
||||
{
|
||||
_NameHandlers.RemoveAll(e => e.Handler == handler);
|
||||
}
|
||||
|
||||
public static void RegisterBeneficialHandler(NotorietyHandler<bool> handler, int priority = 0)
|
||||
{
|
||||
UnregisterBeneficialHandler(handler);
|
||||
_BeneficialHandlers.Add(new NotorietyEntry<bool>(priority, handler));
|
||||
}
|
||||
|
||||
public static void UnregisterBeneficialHandler(NotorietyHandler<bool> handler)
|
||||
{
|
||||
_BeneficialHandlers.RemoveAll(e => e.Handler == handler);
|
||||
}
|
||||
|
||||
public static void RegisterHarmfulHandler(NotorietyHandler<bool> handler, int priority = 0)
|
||||
{
|
||||
UnregisterHarmfulHandler(handler);
|
||||
_HarmfulHandlers.Add(new NotorietyEntry<bool>(priority, handler));
|
||||
}
|
||||
|
||||
public static void UnregisterHarmfulHandler(NotorietyHandler<bool> handler)
|
||||
{
|
||||
_HarmfulHandlers.RemoveAll(e => e.Handler == handler);
|
||||
}
|
||||
|
||||
public static bool AllowBeneficial(Mobile a, Mobile b)
|
||||
{
|
||||
if (_BeneficialParent == null)
|
||||
{
|
||||
_BeneficialParent = NotorietyHandlers.Mobile_AllowBeneficial;
|
||||
}
|
||||
|
||||
if (a == null || a.Deleted || b == null || b.Deleted)
|
||||
{
|
||||
return _BeneficialParent(a, b);
|
||||
}
|
||||
|
||||
foreach (var handler in _BeneficialHandlers.Where(e => e.Handler != null)
|
||||
.OrderByDescending(e => e.Priority)
|
||||
.Select(e => e.Handler))
|
||||
{
|
||||
var result = handler(a, b, out var handled);
|
||||
|
||||
if (handled)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return _BeneficialParent(a, b);
|
||||
}
|
||||
|
||||
#if ServUO
|
||||
public static bool AllowHarmful(Mobile a, IDamageable b)
|
||||
{
|
||||
if (b is Mobile)
|
||||
{
|
||||
return AllowHarmful(a, (Mobile)b);
|
||||
}
|
||||
|
||||
if (_HarmfulParent == null)
|
||||
{
|
||||
_HarmfulParent = NotorietyHandlers.Mobile_AllowHarmful;
|
||||
}
|
||||
|
||||
return _HarmfulParent(a, b);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool AllowHarmful(Mobile a, Mobile b)
|
||||
{
|
||||
if (_HarmfulParent == null)
|
||||
{
|
||||
_HarmfulParent = NotorietyHandlers.Mobile_AllowHarmful;
|
||||
}
|
||||
|
||||
if (a == null || a.Deleted || b == null || b.Deleted)
|
||||
{
|
||||
return _HarmfulParent(a, b);
|
||||
}
|
||||
|
||||
foreach (var handler in _HarmfulHandlers.Where(e => e.Handler != null)
|
||||
.OrderByDescending(e => e.Priority)
|
||||
.Select(e => e.Handler))
|
||||
{
|
||||
var result = handler(a, b, out var handled);
|
||||
|
||||
if (handled)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return _HarmfulParent(a, b);
|
||||
}
|
||||
|
||||
#if ServUO
|
||||
public static int MobileNotoriety(Mobile a, IDamageable b)
|
||||
{
|
||||
if (b is Mobile)
|
||||
{
|
||||
return MobileNotoriety(a, (Mobile)b);
|
||||
}
|
||||
|
||||
if (_NotorietyParent == null)
|
||||
{
|
||||
_NotorietyParent = NotorietyHandlers.MobileNotoriety;
|
||||
}
|
||||
|
||||
return _NotorietyParent(a, b);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static int MobileNotoriety(Mobile a, Mobile b)
|
||||
{
|
||||
if (_NotorietyParent == null)
|
||||
{
|
||||
_NotorietyParent = NotorietyHandlers.MobileNotoriety;
|
||||
}
|
||||
|
||||
if (a == null || a.Deleted || b == null || b.Deleted)
|
||||
{
|
||||
return _NotorietyParent(a, b);
|
||||
}
|
||||
|
||||
foreach (var handler in _NameHandlers.Where(e => e.Handler != null)
|
||||
.OrderByDescending(e => e.Priority)
|
||||
.Select(e => e.Handler))
|
||||
{
|
||||
var result = handler(a, b, out var handled);
|
||||
|
||||
if (handled)
|
||||
{
|
||||
if (result <= Bubble)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return _NotorietyParent(a, b);
|
||||
}
|
||||
|
||||
public static bool Resolve<T1, T2>(Mobile a, Mobile b, out T1 x, out T2 y)
|
||||
where T1 : Mobile
|
||||
where T2 : Mobile
|
||||
{
|
||||
x = null;
|
||||
y = null;
|
||||
|
||||
if (a == null || a.Deleted || b == null || b.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a.IsControlled(out x))
|
||||
{
|
||||
x = a as T1;
|
||||
}
|
||||
|
||||
if (!b.IsControlled(out y))
|
||||
{
|
||||
y = b as T2;
|
||||
}
|
||||
|
||||
return x != null && y != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#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
|
||||
{
|
||||
public class PlayerNamesOptions : CoreServiceOptions
|
||||
{
|
||||
private bool _IgnoreCase;
|
||||
|
||||
[CommandProperty(PlayerNames.Access)]
|
||||
public virtual bool IgnoreCase
|
||||
{
|
||||
get => _IgnoreCase;
|
||||
set
|
||||
{
|
||||
if (_IgnoreCase && !value)
|
||||
{
|
||||
PlayerNames.Registry.Comparer.Impl = EqualityComparer<string>.Default;
|
||||
}
|
||||
else if (!_IgnoreCase && value)
|
||||
{
|
||||
PlayerNames.Registry.Comparer.Impl = StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_IgnoreCase = value;
|
||||
|
||||
if (PlayerNames.Registry.Count > 0)
|
||||
{
|
||||
PlayerNames.Clear();
|
||||
PlayerNames.Index();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(PlayerNames.Access)]
|
||||
public virtual bool IndexOnStart { get; set; }
|
||||
|
||||
[CommandProperty(PlayerNames.Access)]
|
||||
public virtual bool NameSharing { get; set; }
|
||||
|
||||
public PlayerNamesOptions()
|
||||
: base(typeof(PlayerNames))
|
||||
{
|
||||
IndexOnStart = false;
|
||||
NameSharing = true;
|
||||
IgnoreCase = false;
|
||||
}
|
||||
|
||||
public PlayerNamesOptions(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
|
||||
IndexOnStart = false;
|
||||
NameSharing = true;
|
||||
IgnoreCase = false;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
IndexOnStart = false;
|
||||
NameSharing = true;
|
||||
IgnoreCase = false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
var version = writer.SetVersion(2);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 2:
|
||||
writer.Write(IgnoreCase);
|
||||
goto case 1;
|
||||
case 1:
|
||||
writer.Write(NameSharing);
|
||||
goto case 0;
|
||||
case 0:
|
||||
writer.Write(IndexOnStart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.GetVersion();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 2:
|
||||
IgnoreCase = reader.ReadBool();
|
||||
goto case 1;
|
||||
case 1:
|
||||
NameSharing = reader.ReadBool();
|
||||
goto case 0;
|
||||
case 0:
|
||||
IndexOnStart = reader.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#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;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public static partial class PlayerNames
|
||||
{
|
||||
public const AccessLevel Access = AccessLevel.Administrator;
|
||||
|
||||
public static PlayerNamesOptions CSOptions { get; private set; }
|
||||
|
||||
public static BinaryDataStore<string, List<PlayerMobile>> Registry { get; private set; }
|
||||
|
||||
public static event Action<PlayerMobile> OnRegistered;
|
||||
|
||||
private static void InvokeRegistered(PlayerMobile pm)
|
||||
{
|
||||
if (OnRegistered != null)
|
||||
{
|
||||
OnRegistered(pm);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRegistered(PlayerMobile pm)
|
||||
{
|
||||
return pm != null && !String.IsNullOrWhiteSpace(FindRegisteredName(pm));
|
||||
}
|
||||
|
||||
public static void Register(PlayerMobile pm)
|
||||
{
|
||||
if (pm == null || pm.Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rName = FindRegisteredName(pm);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(rName) && rName != pm.RawName)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(pm.RawName))
|
||||
{
|
||||
pm.RawName = rName;
|
||||
return;
|
||||
}
|
||||
|
||||
Registry[rName].Remove(pm);
|
||||
Registry[rName].TrimExcess();
|
||||
|
||||
if (Registry[rName].Count == 0)
|
||||
{
|
||||
Registry.Remove(rName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Registry.ContainsKey(pm.RawName))
|
||||
{
|
||||
Registry.Add(
|
||||
pm.RawName,
|
||||
new List<PlayerMobile>
|
||||
{
|
||||
pm
|
||||
});
|
||||
InvokeRegistered(pm);
|
||||
}
|
||||
else if (!Registry[pm.RawName].Contains(pm))
|
||||
{
|
||||
Registry[pm.RawName].Add(pm);
|
||||
InvokeRegistered(pm);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ValidateSharedName(PlayerMobile m)
|
||||
{
|
||||
if (m != null && !CSOptions.NameSharing &&
|
||||
FindPlayers(m.RawName, p => p != m && p.CreationTime < m.CreationTime).Any())
|
||||
{
|
||||
new ForcePlayerRenameDialog(m).Send();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasNameChanged(PlayerMobile pm)
|
||||
{
|
||||
return pm != null && !pm.Deleted && pm.RawName != FindRegisteredName(pm);
|
||||
}
|
||||
|
||||
public static string FindRegisteredName(PlayerMobile pm)
|
||||
{
|
||||
if (pm == null || pm.Deleted)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
var val = Registry.Values.IndexOf(list => list.Contains(pm));
|
||||
|
||||
if (Registry.InBounds(val))
|
||||
{
|
||||
return Registry.GetKeyAt(val);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static IEnumerable<PlayerMobile> FindPlayers(string name)
|
||||
{
|
||||
return FindPlayers(name, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<PlayerMobile> FindPlayers(string name, Func<PlayerMobile, bool> match)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var players = Registry.GetValue(name);
|
||||
|
||||
if (players == null || players.Count == 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var m in (match == null ? players : players.Where(match)))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#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;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
[CoreService("Player Name Register", "1.0.0.0", TaskPriority.Low)]
|
||||
public static partial class PlayerNames
|
||||
{
|
||||
static PlayerNames()
|
||||
{
|
||||
CSOptions = new PlayerNamesOptions();
|
||||
|
||||
Registry = new BinaryDataStore<string, List<PlayerMobile>>(VitaNexCore.SavesDirectory + "/PlayerNames", "Registry")
|
||||
{
|
||||
OnSerialize = Serialize,
|
||||
OnDeserialize = Deserialize,
|
||||
Async = true
|
||||
};
|
||||
}
|
||||
|
||||
private static void CSConfig()
|
||||
{
|
||||
EventSink.CharacterCreated += e => Register(e.Mobile as PlayerMobile);
|
||||
|
||||
EventSink.Login += e =>
|
||||
{
|
||||
Register(e.Mobile as PlayerMobile);
|
||||
ValidateSharedName(e.Mobile as PlayerMobile);
|
||||
};
|
||||
|
||||
EventSink.Logout += e => Register(e.Mobile as PlayerMobile);
|
||||
EventSink.PlayerDeath += e => Register(e.Mobile as PlayerMobile);
|
||||
|
||||
CommandUtility.Register(
|
||||
"PlayerNames",
|
||||
Access,
|
||||
e =>
|
||||
{
|
||||
if (e.Arguments != null && e.Arguments.Length > 0 && Insensitive.Equals(e.Arguments[0], "index"))
|
||||
{
|
||||
e.Mobile.SendMessage("Indexing player names, please wait...");
|
||||
|
||||
Index();
|
||||
|
||||
e.Mobile.SendMessage(
|
||||
"Player name indexing complete, there are {0:#,0} registered names by {1:#,0} players.",
|
||||
Registry.Count,
|
||||
Registry.Values.Aggregate(0, (c, list) => c + list.Count));
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendGump(new PropertiesGump(e.Mobile, CSOptions));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
Registry.Clear();
|
||||
}
|
||||
|
||||
public static void Index()
|
||||
{
|
||||
CSOptions.ToConsole("Indexing...");
|
||||
World.Broadcast(0x55, true, "Indexing player names...");
|
||||
|
||||
World.Mobiles.Values.AsParallel().OfType<PlayerMobile>().ForEach(Register);
|
||||
|
||||
World.Broadcast(0x55, true, "Indexing complete.");
|
||||
CSOptions.ToConsole("Indexing complete.");
|
||||
|
||||
CSOptions.ToConsole(
|
||||
"{0:#,0} registered names by {1:#,0} players.",
|
||||
Registry.Count,
|
||||
Registry.Values.Aggregate(0, (c, list) => c + list.Count));
|
||||
}
|
||||
|
||||
private static void CSInvoke()
|
||||
{
|
||||
if (CSOptions.IndexOnStart)
|
||||
{
|
||||
Index();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CSSave()
|
||||
{
|
||||
Registry.Export();
|
||||
}
|
||||
|
||||
private static void CSLoad()
|
||||
{
|
||||
Registry.Import();
|
||||
}
|
||||
|
||||
private static bool Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteBlockDictionary(
|
||||
Registry,
|
||||
(w, name, players) =>
|
||||
{
|
||||
w.Write(name);
|
||||
w.WriteMobileList(players, true);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Deserialize(GenericReader reader)
|
||||
{
|
||||
reader.ReadBlockDictionary(
|
||||
r =>
|
||||
{
|
||||
var name = r.ReadString();
|
||||
var players = r.ReadStrongMobileList<PlayerMobile>();
|
||||
return new KeyValuePair<string, List<PlayerMobile>>(name, players);
|
||||
},
|
||||
Registry);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex
|
||||
{
|
||||
public class ForcePlayerRenameDialog : InputDialogGump
|
||||
{
|
||||
public ForcePlayerRenameDialog(Mobile user, string input = null)
|
||||
: base(user, input: input, limit: 16)
|
||||
{
|
||||
CanClose = false;
|
||||
CanDispose = false;
|
||||
|
||||
BlockMovement = true;
|
||||
BlockSpeech = true;
|
||||
|
||||
Html = "It appears that another character is already using the name \"" + //
|
||||
InputText.WrapUOHtmlColor(Color.LawnGreen, HtmlColor) + "\"!\n\n" + //
|
||||
"Please enter a new name for your character...";
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
layout.Remove("button/body/cancel");
|
||||
}
|
||||
|
||||
protected override void OnAccept(GumpButton button)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(InputText) || !NameVerification.Validate(
|
||||
InputText,
|
||||
2,
|
||||
20,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
1,
|
||||
NameVerification.SpaceDashPeriodQuote))
|
||||
{
|
||||
Html = ("The name \"" + InputText + "\" is invalid.\n\n").WrapUOHtmlColor(Color.OrangeRed, HtmlColor) +
|
||||
"It appears that another character is already using the name \"" + //
|
||||
User.RawName.WrapUOHtmlColor(Color.LawnGreen, HtmlColor) + "\"!\n\n" + //
|
||||
"Please enter a new name for your character...";
|
||||
|
||||
InputText = NameList.RandomName(User.Female ? "female" : "male");
|
||||
|
||||
Refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (InputText == User.RawName || PlayerNames.FindPlayers(
|
||||
InputText,
|
||||
p => p != User && p.GameTime > ((PlayerMobile)User).GameTime)
|
||||
.Any())
|
||||
{
|
||||
Html = "It appears that another character is already using the name \"" + //
|
||||
InputText.WrapUOHtmlColor(Color.LawnGreen, HtmlColor) + "\"!\n\n" + //
|
||||
"Please enter a new name for your character...";
|
||||
|
||||
InputText = NameList.RandomName(User.Female ? "female" : "male");
|
||||
|
||||
Refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
User.RawName = InputText;
|
||||
|
||||
PlayerNames.Register((PlayerMobile)User);
|
||||
|
||||
base.OnAccept(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#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 Server;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleDataStore : BinaryDataStore<string, Schedule>
|
||||
{
|
||||
public ScheduleDataStore(string root, string doc)
|
||||
: base(root, doc)
|
||||
{ }
|
||||
|
||||
public ScheduleDataStore(DirectoryInfo root, string doc)
|
||||
: base(root, doc)
|
||||
{ }
|
||||
|
||||
protected override void Serialize(GenericWriter writer)
|
||||
{
|
||||
var version = writer.SetVersion(0);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
writer.WriteDictionary(
|
||||
this,
|
||||
(k, v) =>
|
||||
{
|
||||
writer.Write(k);
|
||||
writer.WriteType(
|
||||
v,
|
||||
t =>
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
v.Serialize(writer);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Deserialize(GenericReader reader)
|
||||
{
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
reader.ReadDictionary(
|
||||
() =>
|
||||
{
|
||||
var key = reader.ReadString();
|
||||
var val = reader.ReadTypeCreate<Schedule>(reader);
|
||||
return new KeyValuePair<string, Schedule>(key, val);
|
||||
},
|
||||
this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
[Flags]
|
||||
public enum ScheduleDays : short
|
||||
{
|
||||
None = 0x000,
|
||||
Sunday = 0x001,
|
||||
Monday = 0x002,
|
||||
Tuesday = 0x004,
|
||||
Wednesday = 0x008,
|
||||
Thursday = 0x010,
|
||||
Friday = 0x020,
|
||||
Saturday = 0x040,
|
||||
|
||||
All = Int16.MaxValue
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
#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;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
[PropertyObject]
|
||||
public class ScheduleInfo : ICloneable
|
||||
{
|
||||
private static readonly TimeSpan _OneDay = TimeSpan.FromDays(1.0);
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public ScheduleMonths Months { get; set; }
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public ScheduleDays Days { get; set; }
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public ScheduleTimes Times { get; set; }
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public bool Local { get; set; }
|
||||
|
||||
public ScheduleInfo(
|
||||
ScheduleMonths months = ScheduleMonths.All,
|
||||
ScheduleDays days = ScheduleDays.All,
|
||||
ScheduleTimes times = null)
|
||||
{
|
||||
Months = months;
|
||||
Days = days;
|
||||
Times = times ?? new ScheduleTimes();
|
||||
}
|
||||
|
||||
public ScheduleInfo(GenericReader reader)
|
||||
{
|
||||
Deserialize(reader);
|
||||
}
|
||||
|
||||
object ICloneable.Clone()
|
||||
{
|
||||
return Clone();
|
||||
}
|
||||
|
||||
public virtual ScheduleInfo Clone()
|
||||
{
|
||||
return new ScheduleInfo(Months, Days, Times.Clone());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Schedule Info";
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
Months = ScheduleMonths.None;
|
||||
Days = ScheduleDays.None;
|
||||
|
||||
Times.Clear();
|
||||
}
|
||||
|
||||
public virtual bool HasMonth(ScheduleMonths month)
|
||||
{
|
||||
return Months.HasFlag(month);
|
||||
}
|
||||
|
||||
public virtual bool HasDay(ScheduleDays day)
|
||||
{
|
||||
return Days.HasFlag(day);
|
||||
}
|
||||
|
||||
public virtual bool HasTime(TimeSpan time)
|
||||
{
|
||||
Validate(ref time);
|
||||
|
||||
return Times.Contains(time);
|
||||
}
|
||||
|
||||
public virtual void Validate(ref TimeSpan time)
|
||||
{
|
||||
time = new TimeSpan(0, time.Hours, time.Minutes, 0, 0);
|
||||
}
|
||||
|
||||
public virtual void Validate(ref DateTime dt, out TimeSpan time)
|
||||
{
|
||||
Validate(ref dt);
|
||||
|
||||
time = new TimeSpan(0, dt.TimeOfDay.Hours, dt.TimeOfDay.Minutes, 0, 0);
|
||||
}
|
||||
|
||||
public virtual void Validate(ref DateTime dt)
|
||||
{
|
||||
if (!Local && !dt.Kind.HasFlag(DateTimeKind.Utc))
|
||||
{
|
||||
dt = dt.ToUniversalTime();
|
||||
}
|
||||
else if (Local && !dt.Kind.HasFlag(DateTimeKind.Local))
|
||||
{
|
||||
dt = dt.ToLocalTime();
|
||||
}
|
||||
|
||||
dt = new DateTime(dt.Year, dt.Month, dt.Day, dt.TimeOfDay.Hours, dt.TimeOfDay.Minutes, 0, 0, dt.Kind);
|
||||
}
|
||||
|
||||
public virtual DateTime? FindBefore(DateTime dt)
|
||||
{
|
||||
if (Months == ScheduleMonths.None || Days == ScheduleDays.None || Times.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Validate(ref dt, out var ts);
|
||||
|
||||
try
|
||||
{
|
||||
var past = false;
|
||||
|
||||
for (var year = dt.Year; year >= dt.Year - 1; year--)
|
||||
{
|
||||
for (var month = past ? 12 : dt.Month; month >= 1; month--)
|
||||
{
|
||||
if (!HasMonth(Schedules.ConvertMonth(month)))
|
||||
{
|
||||
past = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var start = new DateTime(year, month, past ? DateTime.DaysInMonth(year, month) : dt.Day, 0, 0, 0, dt.Kind);
|
||||
var end = new DateTime(year, month, 1, 0, 0, 0, dt.Kind);
|
||||
|
||||
for (var date = start; date >= end; date -= _OneDay)
|
||||
{
|
||||
if (!HasDay(Schedules.ConvertDay(date.DayOfWeek)))
|
||||
{
|
||||
past = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var time in Times.Where(t => past || t < ts).OrderByDescending(t => t.Ticks))
|
||||
{
|
||||
return new DateTime(year, month, date.Day, time.Hours, time.Minutes, 0, dt.Kind);
|
||||
}
|
||||
|
||||
past = true;
|
||||
}
|
||||
}
|
||||
|
||||
past = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual DateTime? FindAfter(DateTime dt)
|
||||
{
|
||||
if (Months == ScheduleMonths.None || Days == ScheduleDays.None || Times.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Validate(ref dt, out var ts);
|
||||
|
||||
try
|
||||
{
|
||||
var future = false;
|
||||
|
||||
for (var year = dt.Year; year <= dt.Year + 1; year++)
|
||||
{
|
||||
for (var month = future ? 1 : dt.Month; month <= 12; month++)
|
||||
{
|
||||
if (!HasMonth(Schedules.ConvertMonth(month)))
|
||||
{
|
||||
future = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var start = new DateTime(year, month, future ? 1 : dt.Day, 0, 0, 0, dt.Kind);
|
||||
var end = new DateTime(year, month, DateTime.DaysInMonth(year, month), 0, 0, 0, dt.Kind);
|
||||
|
||||
for (var date = start; date <= end; date += _OneDay)
|
||||
{
|
||||
if (!HasDay(Schedules.ConvertDay(date.DayOfWeek)))
|
||||
{
|
||||
future = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var time in Times.Where(t => future || t > ts).OrderBy(t => t.Ticks))
|
||||
{
|
||||
return new DateTime(year, month, date.Day, time.Hours, time.Minutes, 0, dt.Kind);
|
||||
}
|
||||
|
||||
future = true;
|
||||
}
|
||||
}
|
||||
|
||||
future = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VitaNexCore.ToConsole(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
var version = writer.SetVersion(1);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
writer.Write(Local);
|
||||
goto case 0;
|
||||
case 0:
|
||||
{
|
||||
writer.WriteFlag(Months);
|
||||
writer.WriteFlag(Days);
|
||||
writer.WriteType(Times, t => Times.Serialize(writer));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Deserialize(GenericReader reader)
|
||||
{
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
Local = reader.ReadBool();
|
||||
goto case 0;
|
||||
case 0:
|
||||
{
|
||||
Months = reader.ReadFlag<ScheduleMonths>();
|
||||
Days = reader.ReadFlag<ScheduleDays>();
|
||||
Times = reader.ReadTypeCreate<ScheduleTimes>(reader) ?? new ScheduleTimes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
[Flags]
|
||||
public enum ScheduleMonths : short
|
||||
{
|
||||
None = 0x000,
|
||||
January = 0x001,
|
||||
February = 0x002,
|
||||
March = 0x004,
|
||||
April = 0x008,
|
||||
May = 0x010,
|
||||
June = 0x020,
|
||||
July = 0x040,
|
||||
August = 0x080,
|
||||
September = 0x100,
|
||||
October = 0x200,
|
||||
November = 0x400,
|
||||
December = 0x800,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
#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.Text;
|
||||
|
||||
using Server;
|
||||
|
||||
using VitaNex.Crypto;
|
||||
using VitaNex.SuperGumps;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
[PropertyObject]
|
||||
public class Schedule : Timer, ICloneable
|
||||
{
|
||||
public static List<Schedule> Instances { get; private set; }
|
||||
|
||||
static Schedule()
|
||||
{
|
||||
Instances = new List<Schedule>(0x20);
|
||||
}
|
||||
|
||||
private ScheduleInfo _Info;
|
||||
|
||||
private TimerPriority _DefaultPriority;
|
||||
|
||||
private bool _Enabled;
|
||||
private string _Name;
|
||||
|
||||
private DateTime? _LastGlobalTick;
|
||||
private DateTime? _CurrentGlobalTick;
|
||||
private DateTime? _NextGlobalTick;
|
||||
|
||||
[CommandProperty(Schedules.Access, true)]
|
||||
public CryptoHashCode UID { get; private set; }
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual string Name { get => _Name ?? (_Name = String.Empty); set => _Name = value ?? String.Empty; }
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual bool Enabled
|
||||
{
|
||||
get => _Enabled;
|
||||
set
|
||||
{
|
||||
if (!_Enabled && value)
|
||||
{
|
||||
_Enabled = true;
|
||||
|
||||
InvalidateNextTick();
|
||||
|
||||
Priority = ComputePriority(Interval = TimeSpan.FromSeconds(1.0));
|
||||
|
||||
if (OnEnabled != null)
|
||||
{
|
||||
OnEnabled(this);
|
||||
}
|
||||
}
|
||||
else if (_Enabled && !value)
|
||||
{
|
||||
_Enabled = false;
|
||||
|
||||
InvalidateNextTick();
|
||||
|
||||
Priority = ComputePriority(Interval = TimeSpan.FromMinutes(1.0));
|
||||
|
||||
if (OnDisabled != null)
|
||||
{
|
||||
OnDisabled(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual ScheduleInfo Info
|
||||
{
|
||||
get => _Info ?? (_Info = new ScheduleInfo());
|
||||
set
|
||||
{
|
||||
_Info = value ?? new ScheduleInfo();
|
||||
|
||||
InvalidateNextTick();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual DateTime? LastGlobalTick => _LastGlobalTick;
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual DateTime? CurrentGlobalTick => _CurrentGlobalTick;
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public virtual DateTime? NextGlobalTick => _NextGlobalTick;
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public TimeSpan WaitGlobalTick
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_NextGlobalTick != null)
|
||||
{
|
||||
return TimeSpan.FromTicks(Math.Max(0, (_NextGlobalTick.Value - Now).Ticks));
|
||||
}
|
||||
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public bool IsRegistered => Schedules.IsRegistered(this);
|
||||
|
||||
[CommandProperty(Schedules.Access)]
|
||||
public bool IsLocal
|
||||
{
|
||||
get => _Info.Local;
|
||||
set
|
||||
{
|
||||
_Info.Local = value;
|
||||
|
||||
InvalidateNextTick();
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime Now => IsLocal ? DateTime.Now : DateTime.UtcNow;
|
||||
|
||||
public event Action<Schedule> OnGlobalTick;
|
||||
public event Action<Schedule> OnEnabled;
|
||||
public event Action<Schedule> OnDisabled;
|
||||
|
||||
public Schedule(
|
||||
string name,
|
||||
bool enabled,
|
||||
ScheduleMonths months = ScheduleMonths.None,
|
||||
ScheduleDays days = ScheduleDays.None,
|
||||
ScheduleTimes times = null,
|
||||
params Action<Schedule>[] onTick)
|
||||
: this(name, enabled, new ScheduleInfo(months, days, times), onTick)
|
||||
{ }
|
||||
|
||||
public Schedule(string name, bool enabled, ScheduleInfo info, params Action<Schedule>[] onTick)
|
||||
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
|
||||
{
|
||||
UID = new CryptoHashCode(CryptoHashType.MD5, TimeStamp.Now + "+" + Utility.RandomDouble());
|
||||
|
||||
_Enabled = enabled;
|
||||
_Name = name ?? String.Empty;
|
||||
_Info = info ?? new ScheduleInfo();
|
||||
|
||||
Instances.Add(this);
|
||||
|
||||
UpdateTicks(Now);
|
||||
|
||||
if (onTick != null)
|
||||
{
|
||||
foreach (var a in onTick)
|
||||
{
|
||||
OnGlobalTick += a;
|
||||
}
|
||||
}
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
public Schedule(GenericReader reader)
|
||||
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
|
||||
{
|
||||
Instances.Add(this);
|
||||
|
||||
Deserialize(reader);
|
||||
}
|
||||
|
||||
~Schedule()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
object ICloneable.Clone()
|
||||
{
|
||||
return Clone();
|
||||
}
|
||||
|
||||
public virtual Schedule Clone()
|
||||
{
|
||||
return new Schedule(Name, Enabled, Info.Clone());
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
_LastGlobalTick = null;
|
||||
_CurrentGlobalTick = null;
|
||||
_NextGlobalTick = null;
|
||||
|
||||
OnGlobalTick = null;
|
||||
OnEnabled = null;
|
||||
OnDisabled = null;
|
||||
|
||||
Instances.Remove(this);
|
||||
}
|
||||
|
||||
public void Register()
|
||||
{
|
||||
if (!IsRegistered)
|
||||
{
|
||||
Schedules.Register(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
if (IsRegistered)
|
||||
{
|
||||
Schedules.Unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTicks(DateTime dt)
|
||||
{
|
||||
_LastGlobalTick = dt;
|
||||
|
||||
InvalidateNextTick(dt);
|
||||
}
|
||||
|
||||
public void InvalidateNextTick()
|
||||
{
|
||||
InvalidateNextTick(Now);
|
||||
}
|
||||
|
||||
public void InvalidateNextTick(DateTime dt)
|
||||
{
|
||||
if (!_Enabled)
|
||||
{
|
||||
_NextGlobalTick = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_NextGlobalTick = _Info.FindAfter(dt);
|
||||
|
||||
if (_NextGlobalTick != null && _NextGlobalTick < Now)
|
||||
{
|
||||
InvalidateNextTick(_NextGlobalTick.Value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
base.OnTick();
|
||||
|
||||
if (!_Enabled)
|
||||
{
|
||||
_LastGlobalTick = null;
|
||||
_CurrentGlobalTick = null;
|
||||
_NextGlobalTick = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var now = Now;
|
||||
|
||||
if (_NextGlobalTick == null)
|
||||
{
|
||||
InvalidateNextTick(now);
|
||||
}
|
||||
|
||||
if (_NextGlobalTick == null || now < _NextGlobalTick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_CurrentGlobalTick = now;
|
||||
|
||||
InvalidateNextTick(now);
|
||||
|
||||
if (OnGlobalTick != null)
|
||||
{
|
||||
OnGlobalTick(this);
|
||||
}
|
||||
|
||||
_LastGlobalTick = now;
|
||||
_CurrentGlobalTick = null;
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
var version = writer.SetVersion(3);
|
||||
|
||||
if (version > 2)
|
||||
{
|
||||
UID.Serialize(writer);
|
||||
}
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
if (version < 2)
|
||||
{
|
||||
writer.WriteType(_Info, t => _Info.Serialize(writer));
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBlock(w => w.WriteType(_Info, t => _Info.Serialize(w)));
|
||||
}
|
||||
|
||||
writer.Write(_Enabled);
|
||||
writer.Write(_Name);
|
||||
writer.WriteFlag(_DefaultPriority);
|
||||
|
||||
if (_LastGlobalTick != null)
|
||||
{
|
||||
writer.Write(true);
|
||||
writer.Write(_LastGlobalTick.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(false);
|
||||
}
|
||||
|
||||
if (_NextGlobalTick != null)
|
||||
{
|
||||
writer.Write(true);
|
||||
writer.Write(_NextGlobalTick.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(false);
|
||||
}
|
||||
|
||||
writer.Write(Delay);
|
||||
writer.Write(Interval);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (version > 0)
|
||||
{
|
||||
writer.Write(Running);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Deserialize(GenericReader reader)
|
||||
{
|
||||
var version = reader.GetVersion();
|
||||
|
||||
if (version > 2)
|
||||
{
|
||||
UID = new CryptoHashCode(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
UID = new CryptoHashCode(CryptoHashType.MD5, TimeStamp.Now + "+" + Utility.RandomDouble());
|
||||
}
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
if (version < 2)
|
||||
{
|
||||
_Info = reader.ReadTypeCreate<ScheduleInfo>(reader) ?? new ScheduleInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
_Info = reader.ReadBlock(r => r.ReadTypeCreate<ScheduleInfo>(r)) ?? new ScheduleInfo();
|
||||
}
|
||||
|
||||
_Enabled = reader.ReadBool();
|
||||
_Name = reader.ReadString();
|
||||
_DefaultPriority = reader.ReadFlag<TimerPriority>();
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
_LastGlobalTick = reader.ReadDateTime();
|
||||
}
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
_NextGlobalTick = reader.ReadDateTime();
|
||||
}
|
||||
|
||||
Delay = reader.ReadTimeSpan();
|
||||
Interval = reader.ReadTimeSpan();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
InvalidateNextTick();
|
||||
|
||||
if (version > 0)
|
||||
{
|
||||
Running = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return UID.ValueHash;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _Name;
|
||||
}
|
||||
|
||||
public virtual string ToHtmlString(bool big = true)
|
||||
{
|
||||
var now = Now;
|
||||
var html = new StringBuilder();
|
||||
|
||||
html.AppendLine("Current Date: {0}", now.ToSimpleString("D, M d y"));
|
||||
html.AppendLine("Current Time: {0}", now.ToSimpleString("t@h:m@ X"));
|
||||
html.AppendLine();
|
||||
html.AppendLine("Schedule Overview:");
|
||||
html.AppendLine();
|
||||
|
||||
if (!_Enabled)
|
||||
{
|
||||
html.AppendLine("Schedule is currently disabled.".WrapUOHtmlColor(Color.IndianRed));
|
||||
|
||||
return html.ToString();
|
||||
}
|
||||
|
||||
var print = false;
|
||||
|
||||
var months = String.Join(", ", _Info.Months.EnumerateValues<string>(true).Not("None".Equals));
|
||||
var days = String.Join(", ", _Info.Days.EnumerateValues<string>(true).Not("None".Equals));
|
||||
|
||||
var times = _Info.Times.ToString(6);
|
||||
|
||||
if (months == "None" || String.IsNullOrWhiteSpace(months))
|
||||
{
|
||||
html.AppendLine("Schedule requires at least one Month to be set.".WrapUOHtmlColor(Color.IndianRed));
|
||||
}
|
||||
else if (days == "None" || String.IsNullOrWhiteSpace(days))
|
||||
{
|
||||
html.AppendLine("Schedule requires at least one Day to be set.".WrapUOHtmlColor(Color.IndianRed));
|
||||
}
|
||||
else if (times == "None" || String.IsNullOrWhiteSpace(times))
|
||||
{
|
||||
html.AppendLine("Schedule requires at least one Time to be set.".WrapUOHtmlColor(Color.IndianRed));
|
||||
}
|
||||
else
|
||||
{
|
||||
print = true;
|
||||
}
|
||||
|
||||
if (print)
|
||||
{
|
||||
html.Append(String.Empty.WrapUOHtmlColor(Color.Cyan, false));
|
||||
|
||||
html.AppendLine("Schedule is set to perform an action:");
|
||||
html.AppendLine();
|
||||
html.AppendLine("<B>In...</B>");
|
||||
html.AppendLine(months);
|
||||
html.AppendLine();
|
||||
html.AppendLine("<B>On...</B>");
|
||||
html.AppendLine(days);
|
||||
html.AppendLine();
|
||||
html.AppendLine("<B>At...</B>");
|
||||
html.AppendLine(times);
|
||||
|
||||
html.Append(String.Empty.WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false));
|
||||
|
||||
if (_NextGlobalTick != null)
|
||||
{
|
||||
var today = _NextGlobalTick.Value.Day == now.Day;
|
||||
|
||||
var t = _NextGlobalTick.Value.ToSimpleString("t@h:m@ X");
|
||||
var d = today ? "today" : ("on " + _NextGlobalTick.Value.ToSimpleString("D, M d y"));
|
||||
var o = WaitGlobalTick.ToSimpleString(@"!<d\d ><h\h ><m\m >s\s");
|
||||
|
||||
html.AppendLine();
|
||||
html.AppendLine("The next tick will be at {0} {1}, in {2}.", t, d, o);
|
||||
}
|
||||
}
|
||||
|
||||
var value = big ? String.Format("<big>{0}</big>", html) : html.ToString();
|
||||
|
||||
return value.WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
#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;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleTimes : IEnumerable<TimeSpan>, ICloneable
|
||||
{
|
||||
private static readonly ScheduleTimes _None;
|
||||
private static readonly ScheduleTimes _Noon;
|
||||
private static readonly ScheduleTimes _Midnight;
|
||||
private static readonly ScheduleTimes _EveryHour;
|
||||
private static readonly ScheduleTimes _EveryHalfHour;
|
||||
private static readonly ScheduleTimes _EveryQuarterHour;
|
||||
private static readonly ScheduleTimes _EveryTenMinutes;
|
||||
private static readonly ScheduleTimes _EveryFiveMinutes;
|
||||
private static readonly ScheduleTimes _EveryMinute;
|
||||
private static readonly ScheduleTimes _FourTwenty;
|
||||
|
||||
public static ScheduleTimes None => new ScheduleTimes(_None);
|
||||
public static ScheduleTimes Noon => new ScheduleTimes(_Noon);
|
||||
public static ScheduleTimes Midnight => new ScheduleTimes(_Midnight);
|
||||
public static ScheduleTimes EveryHour => new ScheduleTimes(_EveryHour);
|
||||
public static ScheduleTimes EveryHalfHour => new ScheduleTimes(_EveryHalfHour);
|
||||
public static ScheduleTimes EveryQuarterHour => new ScheduleTimes(_EveryQuarterHour);
|
||||
public static ScheduleTimes EveryTenMinutes => new ScheduleTimes(_EveryTenMinutes);
|
||||
public static ScheduleTimes EveryFiveMinutes => new ScheduleTimes(_EveryFiveMinutes);
|
||||
public static ScheduleTimes EveryMinute => new ScheduleTimes(_EveryMinute);
|
||||
public static ScheduleTimes FourTwenty => new ScheduleTimes(_FourTwenty);
|
||||
|
||||
static ScheduleTimes()
|
||||
{
|
||||
_None = new ScheduleTimes();
|
||||
_Noon = new ScheduleTimes(TimeSpan.FromHours(12));
|
||||
_Midnight = new ScheduleTimes(TimeSpan.Zero);
|
||||
_EveryHour = new ScheduleTimes();
|
||||
_EveryHalfHour = new ScheduleTimes();
|
||||
_EveryQuarterHour = new ScheduleTimes();
|
||||
_EveryTenMinutes = new ScheduleTimes();
|
||||
_EveryFiveMinutes = new ScheduleTimes();
|
||||
_EveryMinute = new ScheduleTimes();
|
||||
|
||||
for (var hours = 0; hours < 24; hours++)
|
||||
{
|
||||
_EveryHour.Add(new TimeSpan(hours, 0, 0));
|
||||
|
||||
for (var minutes = 0; minutes < 60; minutes++)
|
||||
{
|
||||
_EveryMinute.Add(new TimeSpan(hours, minutes, 0));
|
||||
|
||||
if (minutes % 5 == 0)
|
||||
{
|
||||
_EveryFiveMinutes.Add(new TimeSpan(hours, minutes, 0));
|
||||
}
|
||||
|
||||
if (minutes % 10 == 0)
|
||||
{
|
||||
_EveryTenMinutes.Add(new TimeSpan(hours, minutes, 0));
|
||||
}
|
||||
|
||||
if (minutes % 15 == 0)
|
||||
{
|
||||
_EveryQuarterHour.Add(new TimeSpan(hours, minutes, 0));
|
||||
}
|
||||
|
||||
if (minutes % 30 == 0)
|
||||
{
|
||||
_EveryHalfHour.Add(new TimeSpan(hours, minutes, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_FourTwenty = new ScheduleTimes(new TimeSpan(4, 20, 0), new TimeSpan(16, 20, 0));
|
||||
}
|
||||
|
||||
private static void Validate(ref TimeSpan time)
|
||||
{
|
||||
time = new TimeSpan(0, time.Hours, time.Minutes, 0, 0);
|
||||
}
|
||||
|
||||
private List<TimeSpan> _List = new List<TimeSpan>();
|
||||
|
||||
public int Count => _List.Count;
|
||||
|
||||
public TimeSpan? this[int index]
|
||||
{
|
||||
get => index < 0 || index >= _List.Count ? default(TimeSpan?) : _List[index];
|
||||
set
|
||||
{
|
||||
if (index < 0 || index >= _List.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
_List.RemoveAt(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
_List[index] = (TimeSpan)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ScheduleTimes(ScheduleTimes times)
|
||||
{
|
||||
Add(times);
|
||||
}
|
||||
|
||||
public ScheduleTimes(IEnumerable<TimeSpan> times)
|
||||
{
|
||||
Add(times);
|
||||
}
|
||||
|
||||
public ScheduleTimes(params TimeSpan[] times)
|
||||
{
|
||||
Add(times);
|
||||
}
|
||||
|
||||
public ScheduleTimes(GenericReader reader)
|
||||
{
|
||||
Deserialize(reader);
|
||||
}
|
||||
|
||||
object ICloneable.Clone()
|
||||
{
|
||||
return Clone();
|
||||
}
|
||||
|
||||
public virtual ScheduleTimes Clone()
|
||||
{
|
||||
return new ScheduleTimes(this);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _List.GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<TimeSpan> GetEnumerator()
|
||||
{
|
||||
return _List.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Contains(TimeSpan time, bool validate = true)
|
||||
{
|
||||
if (validate)
|
||||
{
|
||||
Validate(ref time);
|
||||
}
|
||||
|
||||
return _List.Contains(time);
|
||||
}
|
||||
|
||||
public void Add(ScheduleTimes times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalAdd(time);
|
||||
}
|
||||
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
public void Add(IEnumerable<TimeSpan> times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalAdd(time);
|
||||
}
|
||||
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
public void Add(params TimeSpan[] times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalAdd(time);
|
||||
}
|
||||
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
private void InternalAdd(TimeSpan time)
|
||||
{
|
||||
Validate(ref time);
|
||||
|
||||
if (Contains(time, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_List.Add(time);
|
||||
}
|
||||
|
||||
public void Remove(ScheduleTimes times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalRemove(time);
|
||||
}
|
||||
|
||||
_List.TrimExcess();
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
public void Remove(IEnumerable<TimeSpan> times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalRemove(time);
|
||||
}
|
||||
|
||||
_List.TrimExcess();
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
public void Remove(params TimeSpan[] times)
|
||||
{
|
||||
foreach (var time in times)
|
||||
{
|
||||
InternalRemove(time);
|
||||
}
|
||||
|
||||
_List.TrimExcess();
|
||||
_List.Sort();
|
||||
}
|
||||
|
||||
private void InternalRemove(TimeSpan time)
|
||||
{
|
||||
Validate(ref time);
|
||||
|
||||
if (!Contains(time, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_List.Remove(time);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_List.Clear();
|
||||
_List.TrimExcess();
|
||||
}
|
||||
|
||||
public TimeSpan[] ToArray()
|
||||
{
|
||||
return _List.ToArray();
|
||||
}
|
||||
|
||||
public string ToString(int cols)
|
||||
{
|
||||
if (!_List.IsNullOrEmpty())
|
||||
{
|
||||
return _List.Select(t => t.ToSimpleString("h:m")).ToWrappedString(", ", cols);
|
||||
}
|
||||
|
||||
return "None";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(0);
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
var version = writer.SetVersion(0);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
writer.WriteList(_List, (w, t) => w.Write(t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Deserialize(GenericReader reader)
|
||||
{
|
||||
var version = reader.GetVersion();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
_List = reader.ReadList(r => r.ReadTimeSpan());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
244
Scripts/SubSystem/VitaNex/Core/Services/Schedules/Schedules.cs
Normal file
244
Scripts/SubSystem/VitaNex/Core/Services/Schedules/Schedules.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
#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.Schedules
|
||||
{
|
||||
public static partial class Schedules
|
||||
{
|
||||
public const AccessLevel Access = AccessLevel.Administrator;
|
||||
|
||||
public static List<Schedule> Registry { get; private set; }
|
||||
|
||||
public static Schedule CreateSchedule(
|
||||
string name,
|
||||
bool enabled = true,
|
||||
bool register = true,
|
||||
ScheduleMonths months = ScheduleMonths.None,
|
||||
ScheduleDays days = ScheduleDays.None,
|
||||
ScheduleTimes times = null,
|
||||
Action<Schedule> handler = null)
|
||||
{
|
||||
return CreateSchedule<Schedule>(name, enabled, register, new ScheduleInfo(months, days, times), handler);
|
||||
}
|
||||
|
||||
public static Schedule CreateSchedule(
|
||||
string name,
|
||||
bool enabled = true,
|
||||
bool register = true,
|
||||
ScheduleInfo info = null,
|
||||
Action<Schedule> handler = null)
|
||||
{
|
||||
return CreateSchedule<Schedule>(name, enabled, register, info, handler);
|
||||
}
|
||||
|
||||
public static TSchedule CreateSchedule<TSchedule>(
|
||||
string name,
|
||||
bool enabled = true,
|
||||
bool register = true,
|
||||
ScheduleMonths months = ScheduleMonths.None,
|
||||
ScheduleDays days = ScheduleDays.None,
|
||||
ScheduleTimes times = null,
|
||||
Action<Schedule> handler = null)
|
||||
where TSchedule : Schedule
|
||||
{
|
||||
return CreateSchedule<TSchedule>(name, enabled, register, new ScheduleInfo(months, days, times), handler);
|
||||
}
|
||||
|
||||
public static TSchedule CreateSchedule<TSchedule>(
|
||||
string name,
|
||||
bool enabled = true,
|
||||
bool register = true,
|
||||
ScheduleInfo info = null,
|
||||
Action<Schedule> handler = null)
|
||||
where TSchedule : Schedule
|
||||
{
|
||||
var st = VitaNexCore.TryCatchGet(() => typeof(TSchedule).CreateInstance<TSchedule>(name, enabled, info, handler));
|
||||
|
||||
if (st != null && register)
|
||||
{
|
||||
st.Register();
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
public static bool IsRegistered(Schedule schedule)
|
||||
{
|
||||
return schedule != null && Registry.Contains(schedule);
|
||||
}
|
||||
|
||||
public static void Register(Schedule schedule)
|
||||
{
|
||||
if (schedule != null)
|
||||
{
|
||||
Registry.Update(schedule);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(Schedule schedule)
|
||||
{
|
||||
if (schedule != null)
|
||||
{
|
||||
Registry.Remove(schedule);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScheduleDays ConvertDay(int day)
|
||||
{
|
||||
switch (day)
|
||||
{
|
||||
case 0:
|
||||
return ScheduleDays.None;
|
||||
case 1:
|
||||
return ScheduleDays.Sunday;
|
||||
case 2:
|
||||
return ScheduleDays.Monday;
|
||||
case 3:
|
||||
return ScheduleDays.Tuesday;
|
||||
case 4:
|
||||
return ScheduleDays.Wednesday;
|
||||
case 5:
|
||||
return ScheduleDays.Thursday;
|
||||
case 6:
|
||||
return ScheduleDays.Friday;
|
||||
case 7:
|
||||
return ScheduleDays.Saturday;
|
||||
}
|
||||
|
||||
return ScheduleDays.All;
|
||||
}
|
||||
|
||||
public static int ConvertDay(ScheduleDays day)
|
||||
{
|
||||
switch (day)
|
||||
{
|
||||
case ScheduleDays.None:
|
||||
return 0;
|
||||
case ScheduleDays.Sunday:
|
||||
return 1;
|
||||
case ScheduleDays.Monday:
|
||||
return 2;
|
||||
case ScheduleDays.Tuesday:
|
||||
return 3;
|
||||
case ScheduleDays.Wednesday:
|
||||
return 4;
|
||||
case ScheduleDays.Thursday:
|
||||
return 5;
|
||||
case ScheduleDays.Friday:
|
||||
return 6;
|
||||
case ScheduleDays.Saturday:
|
||||
return 7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static ScheduleDays ConvertDay(DayOfWeek day)
|
||||
{
|
||||
switch (day)
|
||||
{
|
||||
case DayOfWeek.Sunday:
|
||||
return ScheduleDays.Sunday;
|
||||
case DayOfWeek.Monday:
|
||||
return ScheduleDays.Monday;
|
||||
case DayOfWeek.Tuesday:
|
||||
return ScheduleDays.Tuesday;
|
||||
case DayOfWeek.Wednesday:
|
||||
return ScheduleDays.Wednesday;
|
||||
case DayOfWeek.Thursday:
|
||||
return ScheduleDays.Thursday;
|
||||
case DayOfWeek.Friday:
|
||||
return ScheduleDays.Friday;
|
||||
case DayOfWeek.Saturday:
|
||||
return ScheduleDays.Saturday;
|
||||
}
|
||||
|
||||
return ScheduleDays.None;
|
||||
}
|
||||
|
||||
public static ScheduleMonths ConvertMonth(int month)
|
||||
{
|
||||
switch (month)
|
||||
{
|
||||
case 0:
|
||||
return ScheduleMonths.None;
|
||||
case 1:
|
||||
return ScheduleMonths.January;
|
||||
case 2:
|
||||
return ScheduleMonths.February;
|
||||
case 3:
|
||||
return ScheduleMonths.March;
|
||||
case 4:
|
||||
return ScheduleMonths.April;
|
||||
case 5:
|
||||
return ScheduleMonths.May;
|
||||
case 6:
|
||||
return ScheduleMonths.June;
|
||||
case 7:
|
||||
return ScheduleMonths.July;
|
||||
case 8:
|
||||
return ScheduleMonths.August;
|
||||
case 9:
|
||||
return ScheduleMonths.September;
|
||||
case 10:
|
||||
return ScheduleMonths.October;
|
||||
case 11:
|
||||
return ScheduleMonths.November;
|
||||
case 12:
|
||||
return ScheduleMonths.December;
|
||||
}
|
||||
|
||||
return ScheduleMonths.All;
|
||||
}
|
||||
|
||||
public static int ConvertMonth(ScheduleMonths month)
|
||||
{
|
||||
switch (month)
|
||||
{
|
||||
case ScheduleMonths.None:
|
||||
return 0;
|
||||
case ScheduleMonths.January:
|
||||
return 1;
|
||||
case ScheduleMonths.February:
|
||||
return 2;
|
||||
case ScheduleMonths.March:
|
||||
return 3;
|
||||
case ScheduleMonths.April:
|
||||
return 4;
|
||||
case ScheduleMonths.May:
|
||||
return 5;
|
||||
case ScheduleMonths.June:
|
||||
return 6;
|
||||
case ScheduleMonths.July:
|
||||
return 7;
|
||||
case ScheduleMonths.August:
|
||||
return 8;
|
||||
case ScheduleMonths.September:
|
||||
return 9;
|
||||
case ScheduleMonths.October:
|
||||
return 10;
|
||||
case ScheduleMonths.November:
|
||||
return 11;
|
||||
case ScheduleMonths.December:
|
||||
return 12;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#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.Schedules
|
||||
{
|
||||
[CoreService("Schedules", "3.0.0.0", TaskPriority.High)]
|
||||
public static partial class Schedules
|
||||
{
|
||||
static Schedules()
|
||||
{
|
||||
Registry = new List<Schedule>();
|
||||
}
|
||||
|
||||
private static void CSConfig()
|
||||
{
|
||||
CommandUtility.Register("Schedules", Access, e => new ScheduleListGump(e.Mobile).Send());
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Scripts/SubSystem/VitaNex/Core/Services/Schedules/UI/DaysMenu.cs
Normal file
113
Scripts/SubSystem/VitaNex/Core/Services/Schedules/UI/DaysMenu.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;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleDaysMenuGump : MenuGump
|
||||
{
|
||||
public Schedule Schedule { get; set; }
|
||||
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public ScheduleDaysMenuGump(
|
||||
Mobile user,
|
||||
Schedule schedule,
|
||||
Gump parent = null,
|
||||
GumpButton clicked = null,
|
||||
bool useConfirm = true)
|
||||
: base(user, parent, clicked: clicked)
|
||||
{
|
||||
Schedule = schedule;
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
}
|
||||
|
||||
protected override void CompileOptions(MenuGumpOptions list)
|
||||
{
|
||||
list.AppendEntry(new ListGumpEntry("None", b => SetDay(b, ScheduleDays.None)));
|
||||
list.AppendEntry(new ListGumpEntry("All", b => SetDay(b, ScheduleDays.All)));
|
||||
list.AppendEntry(new ListGumpEntry("Monday", b => SetDay(b, ScheduleDays.Monday)));
|
||||
list.AppendEntry(new ListGumpEntry("Tuesday", b => SetDay(b, ScheduleDays.Tuesday)));
|
||||
list.AppendEntry(new ListGumpEntry("Wednesday", b => SetDay(b, ScheduleDays.Wednesday)));
|
||||
list.AppendEntry(new ListGumpEntry("Thursday", b => SetDay(b, ScheduleDays.Thursday)));
|
||||
list.AppendEntry(new ListGumpEntry("Friday", b => SetDay(b, ScheduleDays.Friday)));
|
||||
list.AppendEntry(new ListGumpEntry("Saturday", b => SetDay(b, ScheduleDays.Saturday)));
|
||||
list.AppendEntry(new ListGumpEntry("Sunday", b => SetDay(b, ScheduleDays.Sunday)));
|
||||
|
||||
base.CompileOptions(list);
|
||||
|
||||
list.Replace("Cancel", new ListGumpEntry("Done", Cancel));
|
||||
}
|
||||
|
||||
protected override int GetLabelHue(int index, int pageIndex, ListGumpEntry entry)
|
||||
{
|
||||
if (Schedule == null)
|
||||
{
|
||||
return ErrorHue;
|
||||
}
|
||||
|
||||
switch (entry.Label)
|
||||
{
|
||||
case "Monday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Monday) ? HighlightHue : ErrorHue;
|
||||
case "Tuesday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Tuesday) ? HighlightHue : ErrorHue;
|
||||
case "Wednesday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Wednesday) ? HighlightHue : ErrorHue;
|
||||
case "Thursday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Thursday) ? HighlightHue : ErrorHue;
|
||||
case "Friday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Friday) ? HighlightHue : ErrorHue;
|
||||
case "Saturday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Saturday) ? HighlightHue : ErrorHue;
|
||||
case "Sunday":
|
||||
return Schedule.Info.HasDay(ScheduleDays.Sunday) ? HighlightHue : ErrorHue;
|
||||
}
|
||||
|
||||
return base.GetLabelHue(index, pageIndex, entry);
|
||||
}
|
||||
|
||||
protected virtual void SetDay(GumpButton button, ScheduleDays day)
|
||||
{
|
||||
if (Schedule == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (day)
|
||||
{
|
||||
case ScheduleDays.None:
|
||||
Schedule.Info.Days = ScheduleDays.None;
|
||||
break;
|
||||
case ScheduleDays.All:
|
||||
Schedule.Info.Days = ScheduleDays.All;
|
||||
break;
|
||||
default:
|
||||
Schedule.Info.Days ^= day;
|
||||
break;
|
||||
}
|
||||
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleMonthsMenuGump : MenuGump
|
||||
{
|
||||
public Schedule Schedule { get; set; }
|
||||
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public ScheduleMonthsMenuGump(
|
||||
Mobile user,
|
||||
Schedule schedule,
|
||||
Gump parent = null,
|
||||
GumpButton clicked = null,
|
||||
bool useConfirm = true)
|
||||
: base(user, parent, clicked: clicked)
|
||||
{
|
||||
Schedule = schedule;
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
}
|
||||
|
||||
protected override void CompileOptions(MenuGumpOptions list)
|
||||
{
|
||||
list.AppendEntry("None", b => SetMonth(b, ScheduleMonths.None));
|
||||
list.AppendEntry("All", b => SetMonth(b, ScheduleMonths.All));
|
||||
list.AppendEntry("January", b => SetMonth(b, ScheduleMonths.January));
|
||||
list.AppendEntry("February", b => SetMonth(b, ScheduleMonths.February));
|
||||
list.AppendEntry("March", b => SetMonth(b, ScheduleMonths.March));
|
||||
list.AppendEntry("April", b => SetMonth(b, ScheduleMonths.April));
|
||||
list.AppendEntry("May", b => SetMonth(b, ScheduleMonths.May));
|
||||
list.AppendEntry("June", b => SetMonth(b, ScheduleMonths.June));
|
||||
list.AppendEntry("July", b => SetMonth(b, ScheduleMonths.July));
|
||||
list.AppendEntry("August", b => SetMonth(b, ScheduleMonths.August));
|
||||
list.AppendEntry("September", b => SetMonth(b, ScheduleMonths.September));
|
||||
list.AppendEntry("October", b => SetMonth(b, ScheduleMonths.October));
|
||||
list.AppendEntry("November", b => SetMonth(b, ScheduleMonths.November));
|
||||
list.AppendEntry("December", b => SetMonth(b, ScheduleMonths.December));
|
||||
|
||||
base.CompileOptions(list);
|
||||
|
||||
list.Replace("Cancel", "Done", Cancel);
|
||||
}
|
||||
|
||||
protected override int GetLabelHue(int index, int pageIndex, ListGumpEntry entry)
|
||||
{
|
||||
if (Schedule == null)
|
||||
{
|
||||
return ErrorHue;
|
||||
}
|
||||
|
||||
switch (entry.Label)
|
||||
{
|
||||
case "January":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.January) ? HighlightHue : ErrorHue;
|
||||
case "February":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.February) ? HighlightHue : ErrorHue;
|
||||
case "March":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.March) ? HighlightHue : ErrorHue;
|
||||
case "April":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.April) ? HighlightHue : ErrorHue;
|
||||
case "May":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.May) ? HighlightHue : ErrorHue;
|
||||
case "June":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.June) ? HighlightHue : ErrorHue;
|
||||
case "July":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.July) ? HighlightHue : ErrorHue;
|
||||
case "August":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.August) ? HighlightHue : ErrorHue;
|
||||
case "September":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.September) ? HighlightHue : ErrorHue;
|
||||
case "October":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.October) ? HighlightHue : ErrorHue;
|
||||
case "November":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.November) ? HighlightHue : ErrorHue;
|
||||
case "December":
|
||||
return Schedule.Info.HasMonth(ScheduleMonths.December) ? HighlightHue : ErrorHue;
|
||||
}
|
||||
|
||||
return base.GetLabelHue(index, pageIndex, entry);
|
||||
}
|
||||
|
||||
protected virtual void SetMonth(GumpButton button, ScheduleMonths month)
|
||||
{
|
||||
if (Schedule == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (month)
|
||||
{
|
||||
case ScheduleMonths.None:
|
||||
Schedule.Info.Months = ScheduleMonths.None;
|
||||
break;
|
||||
case ScheduleMonths.All:
|
||||
Schedule.Info.Months = ScheduleMonths.All;
|
||||
break;
|
||||
default:
|
||||
Schedule.Info.Months ^= month;
|
||||
break;
|
||||
}
|
||||
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
#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.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleListGump : ListGump<Schedule>
|
||||
{
|
||||
public static string HelpText = "Schedules: Schedules are timers that tick on specific dates at specific times.";
|
||||
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public ScheduleListGump(Mobile user, Gump parent = null, bool useConfirm = true)
|
||||
: base(user, parent, emptyText: "There are no schedules to display.", title: "Schedules")
|
||||
{
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
ForceRecompile = true;
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
|
||||
AutoRefresh = true;
|
||||
}
|
||||
|
||||
protected override string GetLabelText(int index, int pageIndex, Schedule entry)
|
||||
{
|
||||
return entry != null ? entry.Name : base.GetLabelText(index, pageIndex, null);
|
||||
}
|
||||
|
||||
protected override int GetLabelHue(int index, int pageIndex, Schedule entry)
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
if (!entry.Enabled)
|
||||
{
|
||||
return ErrorHue;
|
||||
}
|
||||
|
||||
if (!entry.Running || entry.NextGlobalTick == null)
|
||||
{
|
||||
return HighlightHue;
|
||||
}
|
||||
}
|
||||
|
||||
return base.GetLabelHue(index, pageIndex, null);
|
||||
}
|
||||
|
||||
protected override void CompileMenuOptions(MenuGumpOptions list)
|
||||
{
|
||||
list.AppendEntry(new ListGumpEntry("Help", ShowHelp));
|
||||
|
||||
base.CompileMenuOptions(list);
|
||||
}
|
||||
|
||||
protected virtual void ShowHelp(GumpButton button)
|
||||
{
|
||||
Send(new NoticeDialogGump(User, this, title: "Help", html: HelpText));
|
||||
}
|
||||
|
||||
protected override void CompileList(List<Schedule> list)
|
||||
{
|
||||
list.Clear();
|
||||
list.AddRange(Schedules.Registry);
|
||||
|
||||
base.CompileList(list);
|
||||
}
|
||||
|
||||
public override string GetSearchKeyFor(Schedule key)
|
||||
{
|
||||
return key != null ? key.Name : base.GetSearchKeyFor(null);
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
layout.Replace(
|
||||
"label/header/title",
|
||||
() => AddLabelCropped(90, 15, 185, 20, GetTitleHue(), String.IsNullOrEmpty(Title) ? DefaultTitle : Title));
|
||||
|
||||
layout.Replace(
|
||||
"label/header/subtitle",
|
||||
() =>
|
||||
{
|
||||
var loc = DateTime.Now.ToSimpleString("D t@h:m@ X");
|
||||
var utc = DateTime.UtcNow.ToSimpleString("D t@h:m@ X");
|
||||
|
||||
AddLabelCropped(275, 15, 100, 20, HighlightHue, String.Format("[{0}] [{1}]", loc, utc));
|
||||
});
|
||||
}
|
||||
|
||||
protected override void SelectEntry(GumpButton button, Schedule entry)
|
||||
{
|
||||
base.SelectEntry(button, entry);
|
||||
|
||||
if (button != null && entry != null)
|
||||
{
|
||||
Send(new ScheduleOverviewGump(User, entry, Hide(true), UseConfirmDialog));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleOverviewGump : HtmlPanelGump<Schedule>
|
||||
{
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public ScheduleOverviewGump(Mobile user, Schedule schedule, Gump parent = null, bool useConfirm = true)
|
||||
: base(user, parent, emptyText: "Schedule Unavailable", title: "Schedule Overview", selected: schedule)
|
||||
{
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
HtmlColor = Color.GreenYellow;
|
||||
ForceRecompile = true;
|
||||
AutoRefresh = true;
|
||||
}
|
||||
|
||||
protected override void Compile()
|
||||
{
|
||||
base.Compile();
|
||||
|
||||
if (Selected != null)
|
||||
{
|
||||
Html = Selected.ToHtmlString();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
layout.Replace(
|
||||
"label/header/title",
|
||||
() =>
|
||||
{
|
||||
var title = String.IsNullOrEmpty(Title) ? "Schedule Overview" : Title;
|
||||
|
||||
AddLabelCropped(90, 15, Width - 235, 20, GetTitleHue(), title);
|
||||
});
|
||||
|
||||
layout.Replace(
|
||||
"label/header/subtitle",
|
||||
() =>
|
||||
{
|
||||
var time = Selected.Now.ToSimpleString("t@h:m@ X");
|
||||
|
||||
AddLabelCropped(90 + (Width - 235), 15, 100, 20, HighlightHue, time);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void CompileMenuOptions(MenuGumpOptions list)
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
if (Selected != null && User.AccessLevel >= Schedules.Access)
|
||||
{
|
||||
if (!Selected.Enabled)
|
||||
{
|
||||
list.AppendEntry(
|
||||
"Enable",
|
||||
b =>
|
||||
{
|
||||
Selected.Enabled = true;
|
||||
Refresh(true);
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AppendEntry(
|
||||
"Disable",
|
||||
b =>
|
||||
{
|
||||
Selected.Enabled = false;
|
||||
Refresh(true);
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
|
||||
if (Selected.IsLocal)
|
||||
{
|
||||
list.AppendEntry(
|
||||
"Use Universal Time",
|
||||
b =>
|
||||
{
|
||||
Selected.IsLocal = false;
|
||||
Refresh(true);
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AppendEntry(
|
||||
"Use Local Time",
|
||||
b =>
|
||||
{
|
||||
Selected.IsLocal = true;
|
||||
Refresh(true);
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
|
||||
list.AppendEntry("Edit Months", b => Send(new ScheduleMonthsMenuGump(User, Selected, Refresh(), b)), HighlightHue);
|
||||
list.AppendEntry("Edit Days", b => Send(new ScheduleDaysMenuGump(User, Selected, Refresh(), b)), HighlightHue);
|
||||
list.AppendEntry("Edit Times", b => Send(new SheduleTimeListGump(User, Selected, Hide(true))), HighlightHue);
|
||||
|
||||
list.AppendEntry(
|
||||
"Clear Schedule",
|
||||
b =>
|
||||
{
|
||||
if (UseConfirmDialog)
|
||||
{
|
||||
new ConfirmDialogGump(User, this)
|
||||
{
|
||||
Title = "Clear Schedule?",
|
||||
Html = "The schedule will be cleared, erasing all data associated with its entries.\n" +
|
||||
"This action can not be reversed.\n\nDo you want to continue?",
|
||||
AcceptHandler = OnConfirmClearSchedule,
|
||||
CancelHandler = Refresh
|
||||
}.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnConfirmClearSchedule(b);
|
||||
}
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
|
||||
base.CompileMenuOptions(list);
|
||||
}
|
||||
|
||||
protected virtual void OnConfirmClearSchedule(GumpButton button)
|
||||
{
|
||||
if (Selected == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Selected.Info.Clear();
|
||||
Selected.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/SubSystem/VitaNex/Core/Services/Schedules/UI/TimeList.cs
Normal file
217
Scripts/SubSystem/VitaNex/Core/Services/Schedules/UI/TimeList.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
#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.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class SheduleTimeListGump : ListGump<TimeSpan>
|
||||
{
|
||||
public static string HelpText = "Schedule Times: List specific times for this schedule.\n" +
|
||||
"These times determine what time of day the schedule will tick.";
|
||||
|
||||
public Schedule Schedule { get; set; }
|
||||
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public SheduleTimeListGump(Mobile user, Schedule schedule, Gump parent = null, bool useConfirm = true)
|
||||
: base(user, parent, emptyText: "There are no times to display.", title: "Schedule Times")
|
||||
{
|
||||
Schedule = schedule;
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
ForceRecompile = true;
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
|
||||
Columns = 3;
|
||||
EntriesPerPage = 24;
|
||||
}
|
||||
|
||||
protected override void Compile()
|
||||
{
|
||||
var i = Title.IndexOf('(');
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
Title = Title.Substring(0, i);
|
||||
}
|
||||
|
||||
Title += String.Concat(' ', '(', Schedule.Now.ToSimpleString("X"), ')');
|
||||
|
||||
base.Compile();
|
||||
}
|
||||
|
||||
protected override string GetLabelText(int index, int pageIndex, TimeSpan entry)
|
||||
{
|
||||
return entry.ToSimpleString("h:m");
|
||||
}
|
||||
|
||||
protected override void CompileMenuOptions(MenuGumpOptions list)
|
||||
{
|
||||
list.AppendEntry("Delete All", OnDeleteAll, HighlightHue);
|
||||
list.AppendEntry("Add Time", OnAddTime, HighlightHue);
|
||||
list.AppendEntry("Use Preset", OnPresetsMenu, HighlightHue);
|
||||
list.AppendEntry("Help", ShowHelp);
|
||||
|
||||
base.CompileMenuOptions(list);
|
||||
}
|
||||
|
||||
protected virtual void ShowHelp(GumpButton button)
|
||||
{
|
||||
if (User != null && !User.Deleted)
|
||||
{
|
||||
Send(new NoticeDialogGump(User, this, title: "Help", html: HelpText));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDeleteAll(GumpButton button)
|
||||
{
|
||||
if (UseConfirmDialog)
|
||||
{
|
||||
new ConfirmDialogGump(User, this)
|
||||
{
|
||||
Title = "Delete All Times?",
|
||||
Html = "All times in the schedule will be deleted, erasing all data associated with them.\n" +
|
||||
"This action can not be reversed.\n\nDo you want to continue?",
|
||||
AcceptHandler = subButton =>
|
||||
{
|
||||
Schedule.Info.Times.Clear();
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
},
|
||||
CancelHandler = Refresh
|
||||
}.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
Schedule.Info.Times.Clear();
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnAddTime(GumpButton button)
|
||||
{
|
||||
var nowTime = Schedule.Now.TimeOfDay;
|
||||
|
||||
new InputDialogGump(User, this)
|
||||
{
|
||||
Title = "Add Schedule Time",
|
||||
Html = "Enter the time of day " + String.Concat('(', nowTime.ToSimpleString("X"), ')') +
|
||||
" to add to this schedule.\nFormat: HH:MM\nExample: " +
|
||||
String.Format("{0:D2}:{1:D2}", nowTime.Hours, nowTime.Minutes) +
|
||||
"\n\nYou can also load a preset list of times, but be aware that presets will " +
|
||||
"overwrite any custom entries you have created.",
|
||||
Callback = (b, text) =>
|
||||
{
|
||||
|
||||
ParseTime(text, out var hh, out var mm);
|
||||
|
||||
if (hh == -1 || mm == -1)
|
||||
{
|
||||
OnAddTime(button);
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule.Info.Times.Add(new TimeSpan(0, hh, mm, 0, 0));
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
OnAddTime(button);
|
||||
},
|
||||
CancelHandler = Refresh
|
||||
}.Send();
|
||||
}
|
||||
|
||||
protected virtual void OnPresetsMenu(GumpButton button)
|
||||
{
|
||||
var entries = new[]
|
||||
{
|
||||
new ListGumpEntry("Noon", b => UsePreset(b, ScheduleTimes.Noon), HighlightHue),
|
||||
new ListGumpEntry("Midnight", b => UsePreset(b, ScheduleTimes.Midnight), HighlightHue),
|
||||
new ListGumpEntry("Every Hour", b => UsePreset(b, ScheduleTimes.EveryHour), HighlightHue),
|
||||
new ListGumpEntry("Every 30 Minutes", b => UsePreset(b, ScheduleTimes.EveryHalfHour), HighlightHue),
|
||||
new ListGumpEntry("Every 15 Minutes", b => UsePreset(b, ScheduleTimes.EveryQuarterHour), HighlightHue),
|
||||
new ListGumpEntry("Every 10 Minutes", b => UsePreset(b, ScheduleTimes.EveryTenMinutes), HighlightHue),
|
||||
new ListGumpEntry("Every 5 Minutes", b => UsePreset(b, ScheduleTimes.EveryFiveMinutes), HighlightHue),
|
||||
new ListGumpEntry("Every Minute", b => UsePreset(b, ScheduleTimes.EveryMinute), HighlightHue),
|
||||
new ListGumpEntry("Four Twenty", b => UsePreset(b, ScheduleTimes.FourTwenty), HighlightHue)
|
||||
};
|
||||
|
||||
Send(new MenuGump(User, this, entries, button));
|
||||
}
|
||||
|
||||
protected virtual void UsePreset(GumpButton button, ScheduleTimes times)
|
||||
{
|
||||
Schedule.Info.Times.Clear();
|
||||
Schedule.Info.Times.Add(times);
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Refresh(true);
|
||||
}
|
||||
|
||||
protected virtual void ParseTime(string text, out int hh, out int mm)
|
||||
{
|
||||
var parts = text.Split(':');
|
||||
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
if (!Int32.TryParse(parts[0], out hh))
|
||||
{
|
||||
hh = -1;
|
||||
}
|
||||
|
||||
if (!Int32.TryParse(parts[1], out mm))
|
||||
{
|
||||
mm = -1;
|
||||
}
|
||||
|
||||
hh = (hh < 0) ? 0 : (hh > 23) ? 23 : hh;
|
||||
mm = (mm < 0) ? 0 : (mm > 59) ? 59 : mm;
|
||||
}
|
||||
else
|
||||
{
|
||||
hh = -1;
|
||||
mm = -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CompileList(List<TimeSpan> list)
|
||||
{
|
||||
list.Clear();
|
||||
list.AddRange(Schedule.Info.Times);
|
||||
|
||||
base.CompileList(list);
|
||||
}
|
||||
|
||||
public override string GetSearchKeyFor(TimeSpan key)
|
||||
{
|
||||
return key.ToSimpleString("h:m");
|
||||
}
|
||||
|
||||
protected override void SelectEntry(GumpButton button, TimeSpan entry)
|
||||
{
|
||||
base.SelectEntry(button, entry);
|
||||
|
||||
Send(new ScheduleTimeListEntryGump(User, Schedule, Refresh(), button, entry, UseConfirmDialog));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Schedules
|
||||
{
|
||||
public class ScheduleTimeListEntryGump : MenuGump
|
||||
{
|
||||
public Schedule Schedule { get; set; }
|
||||
|
||||
public TimeSpan Time { get; set; }
|
||||
|
||||
public bool UseConfirmDialog { get; set; }
|
||||
|
||||
public ScheduleTimeListEntryGump(
|
||||
Mobile user,
|
||||
Schedule schedule,
|
||||
Gump parent = null,
|
||||
GumpButton clicked = null,
|
||||
TimeSpan? time = null,
|
||||
bool useConfirm = true)
|
||||
: base(user, parent, clicked: clicked)
|
||||
{
|
||||
Schedule = schedule;
|
||||
Time = time ?? TimeSpan.Zero;
|
||||
UseConfirmDialog = useConfirm;
|
||||
|
||||
CanMove = false;
|
||||
CanResize = false;
|
||||
}
|
||||
|
||||
protected override void CompileOptions(MenuGumpOptions list)
|
||||
{
|
||||
base.CompileOptions(list);
|
||||
|
||||
list.PrependEntry(
|
||||
"Delete",
|
||||
button =>
|
||||
{
|
||||
if (UseConfirmDialog)
|
||||
{
|
||||
new ConfirmDialogGump(User, Refresh())
|
||||
{
|
||||
Title = "Delete Time?",
|
||||
Html = "All data associated with this time will be deleted.\n" +
|
||||
"This action can not be reversed!\nDo you want to continue?",
|
||||
AcceptHandler = OnConfirmDelete
|
||||
}.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnConfirmDelete(button);
|
||||
}
|
||||
},
|
||||
HighlightHue);
|
||||
}
|
||||
|
||||
protected virtual void OnConfirmDelete(GumpButton button)
|
||||
{
|
||||
if (Selected == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule.Info.Times.Remove(Time);
|
||||
Schedule.InvalidateNextTick();
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
[Flipable(4173, 4174)]
|
||||
public class TimeBoostToken : Item
|
||||
{
|
||||
private ITimeBoost _Boost;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, true)]
|
||||
public ITimeBoost Boost
|
||||
{
|
||||
get => _Boost ?? (_Boost = TimeBoosts.MinValue);
|
||||
private set
|
||||
{
|
||||
if (_Boost == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Boost = value ?? TimeBoosts.MinValue;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public TimeSpan Value { get => Boost.Value; set => Boost = TimeBoosts.Find(value); }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public override int Hue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (World.Saving)
|
||||
{
|
||||
return base.Hue;
|
||||
}
|
||||
|
||||
var hue = base.Hue;
|
||||
|
||||
return hue > 0 ? hue : Boost.Hue;
|
||||
}
|
||||
set => base.Hue = value;
|
||||
}
|
||||
|
||||
public override string DefaultName => Boost.Name;
|
||||
|
||||
[Constructable(AccessLevel.Administrator)]
|
||||
public TimeBoostToken()
|
||||
: this(TimeBoosts.RandomValue, 1)
|
||||
{ }
|
||||
|
||||
[Constructable(AccessLevel.Administrator)]
|
||||
public TimeBoostToken(string time)
|
||||
: this(time, 1)
|
||||
{ }
|
||||
|
||||
[Constructable(AccessLevel.Administrator)]
|
||||
public TimeBoostToken(string time, int amount)
|
||||
: this(TimeSpan.Parse(time), amount)
|
||||
{ }
|
||||
|
||||
public TimeBoostToken(TimeSpan time)
|
||||
: this(TimeBoosts.Find(time))
|
||||
{ }
|
||||
|
||||
public TimeBoostToken(TimeSpan time, int amount)
|
||||
: this(TimeBoosts.Find(time), amount)
|
||||
{ }
|
||||
|
||||
public TimeBoostToken(ITimeBoost boost)
|
||||
: this(boost, 1)
|
||||
{ }
|
||||
|
||||
public TimeBoostToken(ITimeBoost boost, int amount)
|
||||
: base(Utility.RandomList(4173, 4174))
|
||||
{
|
||||
Boost = boost;
|
||||
|
||||
Stackable = true;
|
||||
Amount = Math.Max(1, Math.Min(60000, amount));
|
||||
|
||||
LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public TimeBoostToken(Serial serial)
|
||||
: base(serial)
|
||||
{ }
|
||||
|
||||
public override bool StackWith(Mobile m, Item dropped, bool playSound)
|
||||
{
|
||||
if (!(dropped is TimeBoostToken) || ((TimeBoostToken)dropped).Boost != Boost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.StackWith(m, dropped, playSound);
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
new ExtendedOPL(list)
|
||||
{
|
||||
{"Use: Credits {0:#,0} {1} to your account".WrapUOHtmlColor(Color.LawnGreen), Amount, Boost},
|
||||
"\"Time Boosts reduce the time required to do certain things\"".WrapUOHtmlColor(Color.Gold)
|
||||
}.Apply();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile m)
|
||||
{
|
||||
if (!this.CheckDoubleClick(m, true, false, -1, true, false, false) || !(m is PlayerMobile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var user = (PlayerMobile)m;
|
||||
|
||||
if (TimeBoosts.Credit(user, Boost, Amount))
|
||||
{
|
||||
TimeBoostsUI.Update(user);
|
||||
|
||||
m.SendMessage(85, "{0:#,0} {1} has been credited to your account.", Amount, Boost);
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(Boost);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
Boost = reader.ReadTimeBoost();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public interface ITimeBoost
|
||||
{
|
||||
int RawValue { get; }
|
||||
TimeSpan Value { get; }
|
||||
|
||||
string Desc { get; }
|
||||
string Name { get; }
|
||||
int Hue { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public struct TimeBoostHours : ITimeBoost
|
||||
{
|
||||
public int RawValue { get; private set; }
|
||||
public TimeSpan Value { get; private set; }
|
||||
|
||||
public string Desc => "Hour";
|
||||
public string Name => String.Format("{0}-{1} Boost", RawValue, Desc);
|
||||
|
||||
public int Hue => 2118;
|
||||
|
||||
public TimeBoostHours(int hours)
|
||||
: this()
|
||||
{
|
||||
Value = TimeSpan.FromHours(RawValue = hours);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = RawValue;
|
||||
hash = (hash * 397) ^ Value.Days;
|
||||
hash = (hash * 397) ^ Value.Hours;
|
||||
hash = (hash * 397) ^ Value.Minutes;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator TimeBoostHours(int hours)
|
||||
{
|
||||
return new TimeBoostHours(hours);
|
||||
}
|
||||
|
||||
public static implicit operator TimeBoostHours(TimeSpan time)
|
||||
{
|
||||
return new TimeBoostHours(time.Hours);
|
||||
}
|
||||
|
||||
public static implicit operator TimeSpan(TimeBoostHours value)
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public static implicit operator int(TimeBoostHours value)
|
||||
{
|
||||
return value.RawValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public struct TimeBoostMinutes : ITimeBoost
|
||||
{
|
||||
public int RawValue { get; private set; }
|
||||
public TimeSpan Value { get; private set; }
|
||||
|
||||
public string Desc => "Minute";
|
||||
public string Name => String.Format("{0}-{1} Boost", RawValue, Desc);
|
||||
|
||||
public int Hue => 2106;
|
||||
|
||||
public TimeBoostMinutes(int minutes)
|
||||
: this()
|
||||
{
|
||||
Value = TimeSpan.FromMinutes(RawValue = minutes);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = RawValue;
|
||||
hash = (hash * 397) ^ Value.Days;
|
||||
hash = (hash * 397) ^ Value.Hours;
|
||||
hash = (hash * 397) ^ Value.Minutes;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator TimeBoostMinutes(int minutes)
|
||||
{
|
||||
return new TimeBoostMinutes(minutes);
|
||||
}
|
||||
|
||||
public static implicit operator TimeBoostMinutes(TimeSpan time)
|
||||
{
|
||||
return new TimeBoostMinutes(time.Minutes);
|
||||
}
|
||||
|
||||
public static implicit operator TimeSpan(TimeBoostMinutes value)
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public static implicit operator int(TimeBoostMinutes value)
|
||||
{
|
||||
return value.RawValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
#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.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public sealed class TimeBoostProfile : PropertyObject, IEnumerable<KeyValuePair<ITimeBoost, int>>
|
||||
{
|
||||
public IAccount Owner { get; private set; }
|
||||
|
||||
private Dictionary<ITimeBoost, int> _Boosts = new Dictionary<ITimeBoost, int>();
|
||||
|
||||
public int this[ITimeBoost key] { get => _Boosts.GetValue(key); set => _Boosts.Update(key, value); }
|
||||
|
||||
public TimeSpan TotalTime => TimeSpan.FromTicks(_Boosts.Sum(kv => kv.Key.Value.Ticks * kv.Value));
|
||||
|
||||
public TimeBoostProfile(IAccount owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public TimeBoostProfile(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
_Boosts.Clear();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Boosts.Clear();
|
||||
}
|
||||
|
||||
#region Credit
|
||||
public bool CanCredit(ITimeBoost b, int amount)
|
||||
{
|
||||
return b != null && amount >= 0 && (long)this[b] + amount <= Int32.MaxValue;
|
||||
}
|
||||
|
||||
public bool Credit(ITimeBoost b, int amount)
|
||||
{
|
||||
if (CanCredit(b, amount))
|
||||
{
|
||||
this[b] += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CreditHours(int value)
|
||||
{
|
||||
return Credit(value, 0);
|
||||
}
|
||||
|
||||
public bool CreditMinutes(int value)
|
||||
{
|
||||
return Credit(0, value);
|
||||
}
|
||||
|
||||
public bool Credit(int hours, int minutes)
|
||||
{
|
||||
return Credit(hours, minutes, false) && Credit(hours, minutes, true);
|
||||
}
|
||||
|
||||
private bool Credit(int hours, int minutes, bool update)
|
||||
{
|
||||
return Credit(hours, minutes, update, out _, out _);
|
||||
}
|
||||
|
||||
private bool Credit(int hours, int minutes, bool update, out int totalHours, out int totalMinutes)
|
||||
{
|
||||
totalHours = totalMinutes = 0;
|
||||
|
||||
return (hours == 0 || Credit(hours, 0, update, out totalHours)) && (minutes == 0 || Credit(minutes, 1, update, out totalMinutes));
|
||||
}
|
||||
|
||||
private bool Credit(int time, byte index, bool update, out int totalTime)
|
||||
{
|
||||
totalTime = 0;
|
||||
|
||||
if (!TimeBoosts.Times.InBounds(index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ITimeBoost k;
|
||||
int v, t = time;
|
||||
|
||||
var i = TimeBoosts.Times[index].Length;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
k = TimeBoosts.Times[index][i];
|
||||
v = k.RawValue;
|
||||
|
||||
if (time >= v && this[k] < Int32.MaxValue)
|
||||
{
|
||||
time -= v;
|
||||
totalTime += v;
|
||||
|
||||
if (update)
|
||||
{
|
||||
++this[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalTime >= t;
|
||||
}
|
||||
#endregion Credit
|
||||
|
||||
#region Consume
|
||||
public bool CanConsume(ITimeBoost b, int amount)
|
||||
{
|
||||
return b != null && amount >= 0 && this[b] >= amount;
|
||||
}
|
||||
|
||||
public bool Consume(ITimeBoost b, int amount)
|
||||
{
|
||||
if (CanConsume(b, amount))
|
||||
{
|
||||
this[b] -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ConsumeHours(int value)
|
||||
{
|
||||
return Consume(value, 0);
|
||||
}
|
||||
|
||||
public bool ConsumeMinutes(int value)
|
||||
{
|
||||
return Consume(0, value);
|
||||
}
|
||||
|
||||
public bool Consume(int hours, int minutes)
|
||||
{
|
||||
return Consume(hours, minutes, false) && Consume(hours, minutes, true);
|
||||
}
|
||||
|
||||
private bool Consume(int hours, int minutes, bool update)
|
||||
{
|
||||
return Consume(hours, minutes, update, out _, out _);
|
||||
}
|
||||
|
||||
private bool Consume(int hours, int minutes, bool update, out int totalHours, out int totalMinutes)
|
||||
{
|
||||
totalHours = totalMinutes = 0;
|
||||
|
||||
return (hours == 0 || Consume(hours, 0, update, out totalHours)) && (minutes == 0 || Consume(minutes, 1, update, out totalMinutes));
|
||||
}
|
||||
|
||||
private bool Consume(int time, byte index, bool update, out int totalTime)
|
||||
{
|
||||
totalTime = 0;
|
||||
|
||||
if (!TimeBoosts.Times.InBounds(index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ITimeBoost k;
|
||||
int v, t = time;
|
||||
|
||||
var i = TimeBoosts.Times[index].Length;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
k = TimeBoosts.Times[index][i];
|
||||
v = k.RawValue;
|
||||
|
||||
if (time >= v && this[k] > 0)
|
||||
{
|
||||
time -= v;
|
||||
totalTime += v;
|
||||
|
||||
if (update)
|
||||
{
|
||||
--this[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalTime >= t;
|
||||
}
|
||||
#endregion Consume
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<ITimeBoost, int>> GetEnumerator()
|
||||
{
|
||||
return _Boosts.GetEnumerator();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(Owner);
|
||||
|
||||
writer.WriteDictionary(_Boosts, (w, k, v) =>
|
||||
{
|
||||
w.Write(k);
|
||||
w.Write(v);
|
||||
});
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
Owner = reader.ReadAccount();
|
||||
|
||||
_Boosts = reader.ReadDictionary(r =>
|
||||
{
|
||||
var k = r.ReadTimeBoost();
|
||||
var v = r.ReadInt();
|
||||
|
||||
return new KeyValuePair<ITimeBoost, int>(k, v);
|
||||
},
|
||||
_Boosts);
|
||||
|
||||
_Boosts.RemoveValueRange(v => v <= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Scripts/SubSystem/VitaNex/Core/Services/TimeBoosts/TimeBoosts.cs
Normal file
261
Scripts/SubSystem/VitaNex/Core/Services/TimeBoosts/TimeBoosts.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.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Accounting;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public static partial class TimeBoosts
|
||||
{
|
||||
public static TimeBoostHours[] Hours { get; private set; }
|
||||
public static TimeBoostMinutes[] Minutes { get; private set; }
|
||||
|
||||
public static ITimeBoost[][] Times { get; private set; }
|
||||
public static ITimeBoost[] AllTimes { get; private set; }
|
||||
|
||||
public static ITimeBoost RandomHours => Hours.GetRandom();
|
||||
public static ITimeBoost RandomMinutes => Minutes.GetRandom();
|
||||
|
||||
public static ITimeBoost RandomValue => AllTimes.GetRandom();
|
||||
|
||||
public static ITimeBoost MinValue => AllTimes.Lowest(b => b.Value);
|
||||
public static ITimeBoost MaxValue => AllTimes.Highest(b => b.Value);
|
||||
|
||||
public static BinaryDataStore<IAccount, TimeBoostProfile> Profiles { get; private set; }
|
||||
|
||||
public static TimeBoostProfile FindProfile(PlayerMobile m)
|
||||
{
|
||||
if (m == null || m.Account == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return FindProfile(m.Account);
|
||||
}
|
||||
|
||||
public static TimeBoostProfile FindProfile(IAccount a)
|
||||
{
|
||||
return Profiles.GetValue(a);
|
||||
}
|
||||
|
||||
public static TimeBoostProfile EnsureProfile(PlayerMobile m)
|
||||
{
|
||||
if (m == null || m.Account == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return EnsureProfile(m.Account);
|
||||
}
|
||||
|
||||
public static TimeBoostProfile EnsureProfile(IAccount a)
|
||||
{
|
||||
TimeBoostProfile profile = null;
|
||||
|
||||
Profiles.Update(a, p => profile = p ?? new TimeBoostProfile(a));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
public static IEnumerable<KeyValuePair<ITimeBoost, int>> FindBoosts(PlayerMobile m)
|
||||
{
|
||||
if (m == null || m.Account == null)
|
||||
{
|
||||
return Enumerable.Empty<KeyValuePair<ITimeBoost, int>>();
|
||||
}
|
||||
|
||||
return FindBoosts(m.Account);
|
||||
}
|
||||
|
||||
public static IEnumerable<KeyValuePair<ITimeBoost, int>> FindBoosts(IAccount a)
|
||||
{
|
||||
return FindProfile(a) ?? Enumerable.Empty<KeyValuePair<ITimeBoost, int>>();
|
||||
}
|
||||
|
||||
#region Credit
|
||||
public static bool CanCredit(PlayerMobile m, ITimeBoost b, int amount)
|
||||
{
|
||||
return m != null && CanCredit(m.Account, b, amount);
|
||||
}
|
||||
|
||||
public static bool Credit(PlayerMobile m, ITimeBoost b, int amount)
|
||||
{
|
||||
return m != null && Credit(m.Account, b, amount);
|
||||
}
|
||||
|
||||
public static bool CreditHours(PlayerMobile m, int value)
|
||||
{
|
||||
return m != null && CreditHours(m.Account, value);
|
||||
}
|
||||
|
||||
public static bool CreditMinutes(PlayerMobile m, int value)
|
||||
{
|
||||
return m != null && CreditMinutes(m.Account, value);
|
||||
}
|
||||
|
||||
public static bool Credit(PlayerMobile m, int hours, int minutes)
|
||||
{
|
||||
return m != null && Credit(m.Account, hours, minutes);
|
||||
}
|
||||
|
||||
public static bool CanCredit(IAccount a, ITimeBoost b, int amount)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.CanCredit(b, amount);
|
||||
}
|
||||
|
||||
public static bool Credit(IAccount a, ITimeBoost b, int amount)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.Credit(b, amount);
|
||||
}
|
||||
|
||||
public static bool CreditHours(IAccount a, int value)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.CreditHours(value);
|
||||
}
|
||||
|
||||
public static bool CreditMinutes(IAccount a, int value)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.CreditMinutes(value);
|
||||
}
|
||||
|
||||
public static bool Credit(IAccount a, int hours, int minutes)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.Credit(hours, minutes);
|
||||
}
|
||||
#endregion Credit
|
||||
|
||||
#region Consume
|
||||
public static bool CanConsume(PlayerMobile m, ITimeBoost b, int amount)
|
||||
{
|
||||
return m != null && CanConsume(m.Account, b, amount);
|
||||
}
|
||||
|
||||
public static bool Consume(PlayerMobile m, ITimeBoost b, int amount)
|
||||
{
|
||||
return m != null && Consume(m.Account, b, amount);
|
||||
}
|
||||
|
||||
public static bool ConsumeHours(PlayerMobile m, int value)
|
||||
{
|
||||
return m != null && ConsumeHours(m.Account, value);
|
||||
}
|
||||
|
||||
public static bool ConsumeMinutes(PlayerMobile m, int value)
|
||||
{
|
||||
return m != null && ConsumeMinutes(m.Account, value);
|
||||
}
|
||||
|
||||
public static bool Consume(PlayerMobile m, int hours, int minutes)
|
||||
{
|
||||
return m != null && Consume(m.Account, hours, minutes);
|
||||
}
|
||||
|
||||
public static bool CanConsume(IAccount a, ITimeBoost b, int amount)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.CanConsume(b, amount);
|
||||
}
|
||||
|
||||
public static bool Consume(IAccount a, ITimeBoost b, int amount)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.Consume(b, amount);
|
||||
}
|
||||
|
||||
public static bool ConsumeHours(IAccount a, int value)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.ConsumeHours(value);
|
||||
}
|
||||
|
||||
public static bool ConsumeMinutes(IAccount a, int value)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.ConsumeMinutes(value);
|
||||
}
|
||||
|
||||
public static bool Consume(IAccount a, int hours, int minutes)
|
||||
{
|
||||
var p = EnsureProfile(a);
|
||||
|
||||
return p != null && p.Consume(hours, minutes);
|
||||
}
|
||||
#endregion Consume
|
||||
|
||||
public static ITimeBoost Find(TimeSpan time)
|
||||
{
|
||||
var index = AllTimes.Length;
|
||||
|
||||
while (--index >= 0)
|
||||
{
|
||||
var b = AllTimes[index];
|
||||
|
||||
if (time >= b.Value)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Write(this GenericWriter writer, ITimeBoost boost)
|
||||
{
|
||||
writer.SetVersion(0);
|
||||
|
||||
if (boost != null)
|
||||
{
|
||||
writer.Write(true);
|
||||
writer.Write(boost.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static ITimeBoost ReadTimeBoost(this GenericReader reader)
|
||||
{
|
||||
reader.GetVersion();
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
return Find(reader.ReadTimeSpan());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#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;
|
||||
using Server.Accounting;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
[CoreService("Time Boosts", "1.0.0.0", TaskPriority.High)]
|
||||
public static partial class TimeBoosts
|
||||
{
|
||||
public static CoreServiceOptions CSOptions { get; private set; }
|
||||
|
||||
static TimeBoosts()
|
||||
{
|
||||
Hours = new TimeBoostHours[] { 1, 3, 6, 12 };
|
||||
Minutes = new TimeBoostMinutes[] { 1, 3, 5, 15, 30 };
|
||||
|
||||
Times = new[] { Hours.CastToArray<ITimeBoost>(), Minutes.CastToArray<ITimeBoost>() };
|
||||
|
||||
AllTimes = Times.SelectMany(t => t).OrderBy(b => b.Value).ToArray();
|
||||
|
||||
CSOptions = new CoreServiceOptions(typeof(TimeBoosts));
|
||||
|
||||
Profiles = new BinaryDataStore<IAccount, TimeBoostProfile>(VitaNexCore.SavesDirectory + "/TimeBoosts", "Profiles")
|
||||
{
|
||||
Async = true,
|
||||
OnSerialize = Serialize,
|
||||
OnDeserialize = Deserialize
|
||||
};
|
||||
}
|
||||
|
||||
private static void CSSave()
|
||||
{
|
||||
Profiles.Export();
|
||||
}
|
||||
|
||||
private static void CSLoad()
|
||||
{
|
||||
Profiles.Import();
|
||||
}
|
||||
|
||||
private static bool Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.WriteBlockDictionary(Profiles, (w, k, v) =>
|
||||
{
|
||||
w.Write(k);
|
||||
v.Serialize(w);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Deserialize(GenericReader reader)
|
||||
{
|
||||
reader.GetVersion();
|
||||
|
||||
reader.ReadBlockDictionary(r =>
|
||||
{
|
||||
var k = r.ReadAccount();
|
||||
var v = new TimeBoostProfile(r);
|
||||
|
||||
return new KeyValuePair<IAccount, TimeBoostProfile>(k, v);
|
||||
},
|
||||
Profiles);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,551 @@
|
||||
#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 System.Text;
|
||||
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
using VitaNex.SuperGumps.UI;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.TimeBoosts
|
||||
{
|
||||
public class TimeBoostsUI : SuperGumpList<ITimeBoost>
|
||||
{
|
||||
public static string DefaultTitle = "Time Boosts";
|
||||
public static string DefaultSubTitle = String.Empty;
|
||||
public static string DefaultEmptyText = "No available Time Boosts.";
|
||||
public static string DefaultSummaryText = "Time Left";
|
||||
public static string DefaultHelpText = "Tip: Click an available time boost to update the time remaining!";
|
||||
|
||||
public static Color DefaultTitleColor = Color.PaleGoldenrod;
|
||||
public static Color DefaultSubTitleColor = Color.Goldenrod;
|
||||
public static Color DefaultEmptyTextColor = Color.SaddleBrown;
|
||||
public static Color DefaultBoostTextColor = Color.Yellow;
|
||||
public static Color DefaultBoostCountColor = Color.LawnGreen;
|
||||
public static Color DefaultSummaryTextColor = Color.Goldenrod;
|
||||
public static Color DefaultHelpTextColor = Color.Gold;
|
||||
|
||||
public static void Update(PlayerMobile user)
|
||||
{
|
||||
foreach (var info in EnumerateInstances<TimeBoostsUI>(user, true).Where(g => g != null && !g.IsDisposed && g.IsOpen))
|
||||
info.Refresh(true);
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string SubTitle { get; set; }
|
||||
public string EmptyText { get; set; }
|
||||
public string SummaryText { get; set; }
|
||||
public string HelpText { get; set; }
|
||||
|
||||
public Color TitleColor { get; set; }
|
||||
public Color SubTitleColor { get; set; }
|
||||
public Color EmptyTextColor { get; set; }
|
||||
public Color BoostTextColor { get; set; }
|
||||
public Color BoostCountColor { get; set; }
|
||||
public Color SummaryTextColor { get; set; }
|
||||
public Color HelpTextColor { get; set; }
|
||||
|
||||
public TimeBoostProfile Profile { get; set; }
|
||||
|
||||
public bool ApplyAutoAllowed { get; set; }
|
||||
public bool ApplyAutoPreview { get; set; }
|
||||
|
||||
public Func<ITimeBoost, bool> CanApply { get; set; }
|
||||
public Action<ITimeBoost> BoostUsed { get; set; }
|
||||
|
||||
public Func<TimeSpan> GetTime { get; set; }
|
||||
public Action<TimeSpan> SetTime { get; set; }
|
||||
|
||||
public TimeSpan? OldTime { get; private set; }
|
||||
|
||||
public TimeSpan? Time { get => GetTime?.Invoke(); set => SetTime?.Invoke(value ?? TimeSpan.Zero); }
|
||||
|
||||
public TimeBoostsUI(Mobile user, Gump parent = null, TimeBoostProfile profile = null, Func<ITimeBoost, bool> canApply = null, Action<ITimeBoost> boostUsed = null, Func<TimeSpan> getTime = null, Action<TimeSpan> setTime = null)
|
||||
: base(user, parent)
|
||||
{
|
||||
Profile = profile;
|
||||
|
||||
CanApply = canApply;
|
||||
BoostUsed = boostUsed;
|
||||
|
||||
GetTime = getTime;
|
||||
SetTime = setTime;
|
||||
|
||||
Title = DefaultTitle;
|
||||
SubTitle = DefaultSubTitle;
|
||||
EmptyText = DefaultEmptyText;
|
||||
SummaryText = DefaultSummaryText;
|
||||
HelpText = DefaultHelpText;
|
||||
|
||||
TitleColor = DefaultTitleColor;
|
||||
SubTitleColor = DefaultSubTitleColor;
|
||||
EmptyTextColor = DefaultEmptyTextColor;
|
||||
BoostTextColor = DefaultBoostTextColor;
|
||||
BoostCountColor = DefaultBoostCountColor;
|
||||
SummaryTextColor = DefaultSummaryTextColor;
|
||||
HelpTextColor = DefaultHelpTextColor;
|
||||
|
||||
ApplyAutoAllowed = true;
|
||||
|
||||
EntriesPerPage = 4;
|
||||
|
||||
Sorted = true;
|
||||
|
||||
CanClose = true;
|
||||
CanDispose = true;
|
||||
CanMove = true;
|
||||
CanResize = false;
|
||||
|
||||
AutoRefreshRate = TimeSpan.FromMinutes(1.0);
|
||||
AutoRefresh = true;
|
||||
|
||||
ForceRecompile = true;
|
||||
}
|
||||
|
||||
protected override void Compile()
|
||||
{
|
||||
if (Profile == null && User != null)
|
||||
Profile = TimeBoosts.EnsureProfile(User.Account);
|
||||
|
||||
if (!ApplyAutoAllowed)
|
||||
ApplyAutoPreview = false;
|
||||
|
||||
base.Compile();
|
||||
}
|
||||
|
||||
protected override void CompileList(List<ITimeBoost> list)
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
var boosts = TimeBoosts.AllTimes.Where(b => Profile == null || Profile[b] > 0);
|
||||
|
||||
if (ApplyAutoAllowed && ApplyAutoPreview)
|
||||
{
|
||||
var time = Time?.Ticks ?? 0;
|
||||
|
||||
if (time > 0)
|
||||
{
|
||||
foreach (var boost in boosts.OrderByDescending(b => b.Value.Ticks))
|
||||
{
|
||||
if (boost.Value.Ticks > time)
|
||||
break;
|
||||
|
||||
var take = Math.Min(Profile[boost], (int)(time / boost.Value.Ticks));
|
||||
|
||||
if (take <= 0)
|
||||
break;
|
||||
|
||||
time -= take * boost.Value.Ticks;
|
||||
|
||||
list.Add(new BoostPreview(boost, take));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
list.AddRange(boosts);
|
||||
|
||||
base.CompileList(list);
|
||||
}
|
||||
|
||||
protected override void CompileLayout(SuperGumpLayout layout)
|
||||
{
|
||||
base.CompileLayout(layout);
|
||||
|
||||
layout.Add("background", () =>
|
||||
{
|
||||
AddBackground(0, 0, 480, 225, 9270);
|
||||
AddBackground(15, 40, 450, 140, 9350);
|
||||
});
|
||||
|
||||
layout.Add("title", () =>
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(Title))
|
||||
return;
|
||||
|
||||
var text = Title;
|
||||
|
||||
text = text.ToUpper();
|
||||
text = text.WrapUOHtmlBold();
|
||||
text = text.WrapUOHtmlColor(TitleColor, false);
|
||||
|
||||
AddHtml(20, 15, 235, 40, text, false, false);
|
||||
});
|
||||
|
||||
layout.Add("subtitle", () =>
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(SubTitle))
|
||||
return;
|
||||
|
||||
var text = SubTitle;
|
||||
|
||||
text = text.ToUpper();
|
||||
text = text.WrapUOHtmlBold();
|
||||
text = text.WrapUOHtmlColor(SubTitleColor, false);
|
||||
text = text.WrapUOHtmlRight();
|
||||
|
||||
AddHtml(255, 15, 200, 40, text, false, false);
|
||||
});
|
||||
|
||||
layout.Add("page/prev", () =>
|
||||
{
|
||||
if (HasPrevPage)
|
||||
AddButton(7, 150, 9910, 9911, PreviousPage);
|
||||
else
|
||||
AddImage(7, 150, 9909);
|
||||
});
|
||||
|
||||
layout.Add("page/next", () =>
|
||||
{
|
||||
if (HasNextPage)
|
||||
AddButton(451, 150, 9904, 9905, NextPage);
|
||||
else
|
||||
AddImage(451, 150, 9903);
|
||||
});
|
||||
|
||||
CompileEntryLayout(layout, GetListRange());
|
||||
|
||||
layout.Add("summary", () =>
|
||||
{
|
||||
TimeSpan time;
|
||||
|
||||
if (ApplyAutoPreview)
|
||||
time = TimeSpan.FromTicks(List.OfType<BoostPreview>().Aggregate(0L, (t, b) => t + (b.Value.Ticks * b.Amount)));
|
||||
else
|
||||
time = Time ?? TimeSpan.Zero;
|
||||
|
||||
if (time < TimeSpan.Zero)
|
||||
time = TimeSpan.Zero;
|
||||
|
||||
var text = SummaryText;
|
||||
|
||||
if (ApplyAutoPreview)
|
||||
text = "Total Time";
|
||||
|
||||
text = text.ToUpper();
|
||||
text = text.WrapUOHtmlBold();
|
||||
text = text.WrapUOHtmlColor(SummaryTextColor, false);
|
||||
text = text.WrapUOHtmlCenter();
|
||||
|
||||
AddHtml(20, 192, 87, 40, text, false, false);
|
||||
AddImage(112, 185, 30223);
|
||||
|
||||
if (ApplyAutoPreview)
|
||||
AddImageTime(140, 185, time, 0x55); // 175 x 28
|
||||
else
|
||||
AddImageTime(140, 185, time, 0x33); // 175 x 28
|
||||
|
||||
AddImage(315, 185, 30223);
|
||||
});
|
||||
|
||||
layout.Add("auto", () =>
|
||||
{
|
||||
if (ApplyAutoPreview)
|
||||
AddButton(350, 187, 2124, 2123, b => ApplyAuto(false));
|
||||
else if (ApplyAutoAllowed)
|
||||
AddButton(350, 187, 2113, 2112, b => ApplyAuto(true));
|
||||
else
|
||||
AddImage(350, 187, 2113, 900);
|
||||
});
|
||||
|
||||
layout.Add("okay", () =>
|
||||
{
|
||||
if (ApplyAutoPreview)
|
||||
AddButton(410, 187, 2121, 2120, b => ApplyAuto(null));
|
||||
else
|
||||
AddButton(410, 187, 2130, 2129, Close);
|
||||
});
|
||||
|
||||
layout.Add("tip", () =>
|
||||
{
|
||||
AddBackground(0, 225, 480, 40, 9270);
|
||||
|
||||
var text = HelpText;
|
||||
|
||||
if (ApplyAutoPreview)
|
||||
text = "Automatically use boosts as displayed above.";
|
||||
|
||||
text = text.WrapUOHtmlSmall();
|
||||
text = text.WrapUOHtmlCenter();
|
||||
text = text.WrapUOHtmlColor(HelpTextColor);
|
||||
|
||||
AddHtml(20, 235, 440, 40, text, false, false);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void CompileEntryLayout(SuperGumpLayout layout, Dictionary<int, ITimeBoost> range)
|
||||
{
|
||||
if (range.Count > 0)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
foreach (var kv in range)
|
||||
{
|
||||
CompileEntryLayout(layout, range.Count, kv.Key, i, 53 + (i * 93), kv.Value);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Add("empty", () =>
|
||||
{
|
||||
var text = EmptyText;
|
||||
|
||||
text = text.WrapUOHtmlColor(EmptyTextColor, false);
|
||||
text = text.WrapUOHtmlCenter();
|
||||
|
||||
AddHtml(35, 150, 355, 40, text, false, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CompileEntryLayout(SuperGumpLayout layout, int length, int index, int pIndex, int xOffset, ITimeBoost boost)
|
||||
{
|
||||
layout.Add("boosts/" + index, () =>
|
||||
{
|
||||
BoostPreview? bp = null;
|
||||
|
||||
if (boost is BoostPreview p)
|
||||
bp = p;
|
||||
|
||||
int hue = boost.Hue, bellID = 10850;
|
||||
|
||||
var text = String.Empty;
|
||||
|
||||
if (boost.Value.Hours != 0)
|
||||
{
|
||||
bellID = 10810; //Blue Gem
|
||||
text = "Hour";
|
||||
}
|
||||
else if (boost.Value.Minutes != 0)
|
||||
{
|
||||
bellID = 10830; //Green Gem
|
||||
text = "Min";
|
||||
}
|
||||
else
|
||||
hue = 2999;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(text) && boost.RawValue != 1)
|
||||
text += "s";
|
||||
|
||||
if (hue == 2999)
|
||||
{
|
||||
AddImage(xOffset + 7, 56, bellID, hue); //Left Bell
|
||||
AddImage(xOffset + 57, 56, bellID, hue); //Right Bell
|
||||
}
|
||||
else
|
||||
{
|
||||
AddImage(xOffset + 7, 56, bellID); //Left Bell
|
||||
AddImage(xOffset + 57, 56, bellID); //Right Bell
|
||||
}
|
||||
|
||||
AddImage(xOffset, 45, 30058, hue); //Hammer
|
||||
|
||||
if (Profile != null && bp == null)
|
||||
AddButton(xOffset + 5, 65, 1417, 1417, b => SelectBoost(boost)); //Disc
|
||||
|
||||
AddImage(xOffset + 5, 65, 1417, hue); //Disc
|
||||
AddImage(xOffset + 14, 75, 5577, 2999); //Blackout
|
||||
|
||||
AddImageNumber(xOffset + 44, 99, boost.RawValue, hue, Axis.Both);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
text = text.WrapUOHtmlSmall();
|
||||
text = text.WrapUOHtmlCenter();
|
||||
text = text.WrapUOHtmlColor(BoostTextColor, false);
|
||||
|
||||
AddHtml(xOffset + 20, 110, 50, 40, text, false, false);
|
||||
}
|
||||
|
||||
if (hue == 2999)
|
||||
AddImage(xOffset, 130, 30062, hue); //Feet
|
||||
else
|
||||
{
|
||||
if (Profile != null)
|
||||
AddBackground(xOffset + 10, 143, 70, 30, 9270); //9300
|
||||
|
||||
AddImage(xOffset, 130, 30062); //Feet
|
||||
|
||||
if (Profile != null)
|
||||
{
|
||||
text = $"{(bp?.Amount ?? Profile[boost]):N0}";
|
||||
text = text.WrapUOHtmlBold();
|
||||
text = text.WrapUOHtmlCenter();
|
||||
text = text.WrapUOHtmlColor(BoostCountColor, false);
|
||||
|
||||
AddHtml(xOffset + 12, 150, 65, 40, text, false, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public virtual void ApplyAuto(bool? state)
|
||||
{
|
||||
if (!ApplyAutoAllowed || state == null)
|
||||
ApplyAutoPreview = false;
|
||||
else if (state == true)
|
||||
ApplyAutoPreview = true;
|
||||
else if (ApplyAutoPreview)
|
||||
{
|
||||
foreach (var bp in List.OfType<BoostPreview>())
|
||||
{
|
||||
var amount = bp.Amount;
|
||||
|
||||
while (--amount >= 0 && (IsOpen || Hidden))
|
||||
{
|
||||
if (ApplyBoost(bp.Boost))
|
||||
{
|
||||
OnBoostUsed(bp.Boost);
|
||||
|
||||
if (IsOpen || Hidden)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsOpen && !Hidden)
|
||||
break;
|
||||
}
|
||||
|
||||
ApplyAutoPreview = false;
|
||||
}
|
||||
|
||||
if (IsOpen || Hidden)
|
||||
Refresh(true);
|
||||
}
|
||||
|
||||
public virtual void SelectBoost(ITimeBoost boost)
|
||||
{
|
||||
if (CanApplyBoost(boost))
|
||||
ApplyBoost(boost, boost.Value.TotalHours >= 6);
|
||||
else
|
||||
Refresh(true);
|
||||
}
|
||||
|
||||
public virtual void ApplyBoost(ITimeBoost boost, bool confirm)
|
||||
{
|
||||
if (CanApplyBoost(boost))
|
||||
{
|
||||
if (confirm)
|
||||
{
|
||||
new ConfirmDialogGump(User, Hide(true))
|
||||
{
|
||||
Icon = 7057,
|
||||
Title = $"Use {boost.Name}?",
|
||||
Html = $"{Title}: {SubTitle}\n{boost.RawValue} {boost.Desc}{(boost.RawValue != 1 ? "s" : String.Empty)}.\nClick OK to apply this Time Boost.",
|
||||
AcceptHandler = b => ApplyBoost(boost, false),
|
||||
CancelHandler = b => Refresh(true)
|
||||
}.Send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApplyBoost(boost))
|
||||
OnBoostUsed(boost);
|
||||
}
|
||||
|
||||
if (IsOpen || Hidden)
|
||||
Refresh(true);
|
||||
}
|
||||
|
||||
public virtual bool ApplyBoost(ITimeBoost boost)
|
||||
{
|
||||
if (!CanApplyBoost(boost) || !Profile.Consume(boost, 1))
|
||||
return false;
|
||||
|
||||
OldTime = Time;
|
||||
Time -= boost.Value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool CanApplyBoost(ITimeBoost boost)
|
||||
{
|
||||
return GetTime != null && SetTime != null && Time > TimeSpan.Zero && boost != null && boost.RawValue > 0 &&
|
||||
Profile != null && Profile.Owner == User.Account && (CanApply == null || CanApply(boost));
|
||||
}
|
||||
|
||||
protected virtual void OnBoostUsed(ITimeBoost boost)
|
||||
{
|
||||
BoostUsed?.Invoke(boost);
|
||||
|
||||
LogBoostUsed(boost);
|
||||
}
|
||||
|
||||
protected virtual void LogBoostUsed(ITimeBoost boost)
|
||||
{
|
||||
var log = new StringBuilder();
|
||||
|
||||
log.AppendLine();
|
||||
log.AppendLine("UI: '{0}' : '{1}' : '{2}'", Title, SubTitle, SummaryText);
|
||||
log.AppendLine("User: {0}", User);
|
||||
log.AppendLine("Boost: {0}", boost);
|
||||
log.AppendLine("Get: {0}", GetTime.Trace());
|
||||
log.AppendLine("Set: {0}", SetTime.Trace());
|
||||
log.AppendLine("Time: {0} > {1}", OldTime, Time);
|
||||
log.AppendLine();
|
||||
|
||||
log.Log($"/TimeBoosts/{DateTime.Now.ToDirectoryName()}/{boost}.log");
|
||||
}
|
||||
|
||||
public override int SortCompare(ITimeBoost a, ITimeBoost b)
|
||||
{
|
||||
var res = 0;
|
||||
|
||||
if (a.CompareNull(b, ref res))
|
||||
return res;
|
||||
|
||||
if (a.Value < b.Value)
|
||||
return -1;
|
||||
|
||||
if (a.Value > b.Value)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override void OnDisposed()
|
||||
{
|
||||
base.OnDisposed();
|
||||
|
||||
Profile = null;
|
||||
}
|
||||
|
||||
protected struct BoostPreview : ITimeBoost
|
||||
{
|
||||
public readonly ITimeBoost Boost;
|
||||
public readonly int Amount;
|
||||
|
||||
public int RawValue => Boost.RawValue;
|
||||
public TimeSpan Value => Boost.Value;
|
||||
public string Desc => Boost.Desc;
|
||||
public string Name => Boost.Name;
|
||||
public int Hue => Boost.Hue;
|
||||
|
||||
public BoostPreview(ITimeBoost boost, int amount)
|
||||
{
|
||||
Boost = boost;
|
||||
Amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/Delegates.cs
Normal file
27
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/Delegates.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 System.Net;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public delegate void WebAPIContextHandler(WebAPIContext context);
|
||||
|
||||
public delegate void WebAPIClientConnected(WebAPIClient client);
|
||||
|
||||
public delegate void WebAPIClientDisconnected(WebAPIClient client);
|
||||
|
||||
public delegate void WebAPIRequestSend<in T>(HttpWebRequest req, T state);
|
||||
|
||||
public delegate void WebAPIRequestReceive<in T>(HttpWebRequest req, T state, HttpWebResponse res);
|
||||
}
|
||||
411
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/Objects/Client.cs
Normal file
411
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/Objects/Client.cs
Normal file
@@ -0,0 +1,411 @@
|
||||
#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.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public sealed class WebAPIClient : IDisposable
|
||||
{
|
||||
private static readonly char[] _Separators = { '\r', '\n' };
|
||||
private static readonly byte[] _EmptyBuffer = new byte[0];
|
||||
private static readonly KeyValueString[] _EmptyHeaders = new KeyValueString[0];
|
||||
|
||||
private static IEnumerable<KeyValueString> ParseHeaders(IEnumerable<string> headers)
|
||||
{
|
||||
int i;
|
||||
|
||||
foreach (var h in headers)
|
||||
{
|
||||
i = h.IndexOf(' ');
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
var k = h.Substring(0, i).Trim().TrimEnd(':');
|
||||
var v = h.Substring(i + 1);
|
||||
|
||||
yield return new KeyValueString(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TcpClient Client { get; private set; }
|
||||
public NetworkStream Stream { get; private set; }
|
||||
|
||||
public bool Connected => Client != null && Client.Connected;
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public WebAPIClient(TcpClient client)
|
||||
{
|
||||
Client = client;
|
||||
Stream = Client.GetStream();
|
||||
}
|
||||
|
||||
public void Encode(Encoding enc, string data, out byte[] buffer, out int length)
|
||||
{
|
||||
buffer = enc.GetBytes(data ?? String.Empty);
|
||||
length = buffer.Length;
|
||||
}
|
||||
|
||||
public void Decode(Encoding enc, byte[] buffer, int length, out string data)
|
||||
{
|
||||
if (buffer == null || buffer.Length == 0 || length <= 0)
|
||||
{
|
||||
data = String.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
data = enc.GetString(buffer, 0, length);
|
||||
}
|
||||
|
||||
public void Compress(ref byte[] buffer, ref int length)
|
||||
{
|
||||
using (var outS = new MemoryStream())
|
||||
{
|
||||
using (var ds = new DeflateStream(outS, CompressionMode.Compress, true))
|
||||
{
|
||||
ds.Write(buffer, 0, length);
|
||||
}
|
||||
|
||||
outS.Position = 0;
|
||||
|
||||
// Recycle the buffer?
|
||||
if (outS.Length <= buffer.Length)
|
||||
{
|
||||
length = outS.Read(buffer, 0, buffer.Length);
|
||||
|
||||
// Heartbleed: Nope; zero-fill the remaining buffer!
|
||||
for (var i = length; i < buffer.Length; i++)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = outS.ToArray();
|
||||
length = buffer.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Decompress(ref byte[] buffer, ref int length)
|
||||
{
|
||||
using (MemoryStream inS = new MemoryStream(buffer, 0, length), outS = new MemoryStream())
|
||||
{
|
||||
using (var ds = new DeflateStream(inS, CompressionMode.Decompress, true))
|
||||
{
|
||||
ds.CopyTo(outS);
|
||||
}
|
||||
|
||||
outS.Position = 0;
|
||||
|
||||
// Recycle the buffer?
|
||||
if (outS.Length <= buffer.Length)
|
||||
{
|
||||
length = outS.Read(buffer, 0, buffer.Length);
|
||||
|
||||
// Heartbleed: Nope; zero-fill the remaining buffer!
|
||||
for (var i = length; i < buffer.Length; i++)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = outS.ToArray();
|
||||
length = buffer.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Send(bool compress, string data, Encoding enc)
|
||||
{
|
||||
|
||||
Send(compress, data, enc, out var buffer, out var length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public void Send(bool compress, string data, Encoding enc, out byte[] buffer, out int length)
|
||||
{
|
||||
Encode(enc, data, out buffer, out length);
|
||||
Send(compress, ref buffer, ref length);
|
||||
}
|
||||
|
||||
public void Send(bool compress, ref byte[] buffer, ref int length)
|
||||
{
|
||||
if (compress)
|
||||
{
|
||||
Compress(ref buffer, ref length);
|
||||
}
|
||||
|
||||
if (buffer.Length > Client.SendBufferSize)
|
||||
{
|
||||
Client.SendBufferSize = Math.Min(1048576, buffer.Length);
|
||||
}
|
||||
|
||||
Stream.Write(buffer, 0, length);
|
||||
|
||||
WebAPI.CSOptions.ToConsole(
|
||||
"Sent {0:#,0} bytes ({1:#,0} bytes/write)",
|
||||
length,
|
||||
Math.Min(length, Client.SendBufferSize));
|
||||
}
|
||||
|
||||
private static bool Sequence(byte b, ref int seq)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
{
|
||||
if (seq % 2 == 0)
|
||||
{
|
||||
++seq;
|
||||
}
|
||||
else
|
||||
{
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
{
|
||||
if (seq % 2 == 1)
|
||||
{
|
||||
++seq;
|
||||
}
|
||||
else
|
||||
{
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
seq = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return seq > 0;
|
||||
}
|
||||
|
||||
public bool ReceiveHeaders(out KeyValueString[] headers)
|
||||
{
|
||||
headers = _EmptyHeaders;
|
||||
|
||||
var buffer = _EmptyBuffer;
|
||||
var length = 0;
|
||||
|
||||
if (Stream.CanRead)
|
||||
{
|
||||
VitaNexCore.WaitWhile(() => !Stream.DataAvailable, TimeSpan.FromMilliseconds(1000));
|
||||
|
||||
if (Stream.DataAvailable)
|
||||
{
|
||||
buffer = new byte[Client.ReceiveBufferSize];
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
int idx = 0, seq = 0;
|
||||
|
||||
while (Stream.DataAvailable)
|
||||
{
|
||||
var r = Stream.ReadByte();
|
||||
|
||||
if (r > -1)
|
||||
{
|
||||
if (++length > WebAPI.CSOptions.MaxReceiveBufferSizeBytes)
|
||||
{
|
||||
throw new InternalBufferOverflowException(
|
||||
String.Format("Received data exceeded {0:#,0} bytes", WebAPI.CSOptions.MaxReceiveBufferSizeBytes));
|
||||
}
|
||||
|
||||
var b = (byte)r;
|
||||
|
||||
buffer[idx++] = b;
|
||||
|
||||
if (Sequence(b, ref seq) && seq >= 4)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx >= buffer.Length)
|
||||
{
|
||||
ms.Write(buffer, 0, idx);
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, idx);
|
||||
}
|
||||
|
||||
buffer = ms.ToArray();
|
||||
length = buffer.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebAPI.CSOptions.ToConsole(
|
||||
"Received {0:#,0} bytes ({1:#,0} bytes/read)",
|
||||
length,
|
||||
Math.Min(length, Client.ReceiveBufferSize));
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var raw = Encoding.ASCII.GetString(buffer, 0, length);
|
||||
|
||||
if (String.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var h = raw.Split(_Separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (h.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
headers = ParseHeaders(h).ToArray();
|
||||
|
||||
return headers.Length > 0;
|
||||
}
|
||||
|
||||
public void Receive(bool decompress, Encoding enc, out string content, out byte[] buffer, out int length)
|
||||
{
|
||||
content = String.Empty;
|
||||
buffer = _EmptyBuffer;
|
||||
length = 0;
|
||||
|
||||
if (Stream.CanRead)
|
||||
{
|
||||
VitaNexCore.WaitWhile(() => !Stream.DataAvailable, TimeSpan.FromMilliseconds(1000));
|
||||
|
||||
if (Stream.DataAvailable)
|
||||
{
|
||||
buffer = new byte[Client.ReceiveBufferSize];
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
while (Stream.DataAvailable)
|
||||
{
|
||||
length = Stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (ms.Length + length > WebAPI.CSOptions.MaxReceiveBufferSizeBytes)
|
||||
{
|
||||
throw new InternalBufferOverflowException(
|
||||
String.Format("Received data exceeded {0:#,0} bytes", WebAPI.CSOptions.MaxReceiveBufferSizeBytes));
|
||||
}
|
||||
|
||||
ms.SetLength(ms.Length + length);
|
||||
ms.Write(buffer, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
buffer = ms.ToArray();
|
||||
length = buffer.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebAPI.CSOptions.ToConsole(
|
||||
"Received {0:#,0} bytes ({1:#,0} bytes/read)",
|
||||
length,
|
||||
Math.Min(length, Client.ReceiveBufferSize));
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (decompress)
|
||||
{
|
||||
Decompress(ref buffer, ref length);
|
||||
}
|
||||
|
||||
Decode(enc, buffer, length, out content);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Close(false);
|
||||
}
|
||||
|
||||
public void Close(bool disconnecting)
|
||||
{
|
||||
if (IsDisposed || !Client.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VitaNexCore.TryCatch(
|
||||
() =>
|
||||
{
|
||||
if (!disconnecting)
|
||||
{
|
||||
WebAPI.Disconnect(this);
|
||||
}
|
||||
|
||||
if (Stream != null)
|
||||
{
|
||||
using (Stream)
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
if (Client != null)
|
||||
{
|
||||
Client.Close();
|
||||
}
|
||||
},
|
||||
WebAPI.CSOptions.ToConsole);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Close(false);
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
Client = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Client == null || Client.Client == null || Client.Client.RemoteEndPoint == null)
|
||||
{
|
||||
return "?.?.?.?:?";
|
||||
}
|
||||
|
||||
return Client.Client.RemoteEndPoint.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIContext : IDisposable
|
||||
{
|
||||
public WebAPIClient Client { get; private set; }
|
||||
|
||||
public WebAPIMethod Method { get; private set; }
|
||||
public string Uri { get; private set; }
|
||||
|
||||
public WebAPIRequest Request { get; private set; }
|
||||
public WebAPIResponse Response { get; private set; }
|
||||
|
||||
public bool Authorized { get; set; }
|
||||
|
||||
public WebAPIContext(WebAPIClient client, WebAPIMethod method, string uri)
|
||||
{
|
||||
Client = client;
|
||||
|
||||
Method = method;
|
||||
Uri = uri;
|
||||
|
||||
Request = new WebAPIRequest(Client);
|
||||
Response = new WebAPIResponse(Client);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Client = null;
|
||||
|
||||
Method = WebAPIMethod.UNKNOWN;
|
||||
Uri = null;
|
||||
|
||||
Request.Dispose();
|
||||
Request = null;
|
||||
|
||||
Response.Dispose();
|
||||
Response = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIHandler
|
||||
{
|
||||
public string Uri { get; private set; }
|
||||
|
||||
public Action<WebAPIContext> Handler { get; set; }
|
||||
|
||||
public WebAPIHandler(string uri, Action<WebAPIContext> handler)
|
||||
{
|
||||
Uri = uri;
|
||||
Handler = handler;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Uri.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#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;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIHeaders : IDisposable, IEnumerable<KeyValuePair<string, string>>
|
||||
{
|
||||
private Dictionary<string, string> _Headers;
|
||||
|
||||
public string this[string header]
|
||||
{
|
||||
get => _Headers.GetValue(header);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_Headers.Remove(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Headers[header] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => _Headers.Count;
|
||||
|
||||
public WebAPIHeaders()
|
||||
{
|
||||
_Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public WebAPIHeaders(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
: this()
|
||||
{
|
||||
foreach (var kv in headers.Ensure())
|
||||
{
|
||||
this[kv.Key] = kv.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_Headers.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_Headers = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join("\r\n", _Headers.Select(kv => String.Format("{0}: {1}", kv.Key, kv.Value))) + "\r\n\r\n";
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return _Headers.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public enum WebAPIMethod
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
OPTIONS,
|
||||
GET,
|
||||
HEAD,
|
||||
POST,
|
||||
PUT,
|
||||
DELETE,
|
||||
TRACE,
|
||||
CONNECT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#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;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIQueries : IDisposable, IEnumerable<KeyValuePair<string, string>>
|
||||
{
|
||||
private Dictionary<string, string> _Queries;
|
||||
|
||||
public string this[string query]
|
||||
{
|
||||
get => _Queries.GetValue(query);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_Queries.Remove(query);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Queries[query] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => _Queries.Count;
|
||||
|
||||
public WebAPIQueries()
|
||||
{
|
||||
_Queries = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public WebAPIQueries(IEnumerable<KeyValuePair<string, string>> queries)
|
||||
: this()
|
||||
{
|
||||
foreach (var kv in queries.Ensure())
|
||||
{
|
||||
this[kv.Key] = kv.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public WebAPIQueries(string query)
|
||||
: this(WebAPI.DecodeQuery(query))
|
||||
{ }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_Queries.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_Queries = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return WebAPI.EncodeQuery(_Queries);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return _Queries.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIRequest : IDisposable
|
||||
{
|
||||
public WebAPIClient Client { get; private set; }
|
||||
|
||||
public WebAPIHeaders Headers { get; private set; }
|
||||
public WebAPIQueries Queries { get; private set; }
|
||||
|
||||
public FileMime ContentType { get; set; }
|
||||
public Encoding Encoding { get; set; }
|
||||
public string Data { get; set; }
|
||||
public int Length { get; set; }
|
||||
|
||||
public WebAPIRequest(WebAPIClient client)
|
||||
{
|
||||
Client = client;
|
||||
|
||||
Headers = new WebAPIHeaders();
|
||||
Queries = new WebAPIQueries();
|
||||
|
||||
ContentType = FileMime.Default;
|
||||
Encoding = Encoding.UTF8;
|
||||
|
||||
Data = String.Empty;
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Headers.Dispose();
|
||||
Headers = null;
|
||||
|
||||
Queries.Dispose();
|
||||
Queries = null;
|
||||
|
||||
Encoding = null;
|
||||
|
||||
Data = null;
|
||||
Length = 0;
|
||||
|
||||
Client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using VitaNex.IO;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIResponse : IDisposable
|
||||
{
|
||||
public WebAPIClient Client { get; private set; }
|
||||
public WebAPIHeaders Headers { get; private set; }
|
||||
|
||||
public HttpStatusCode Status { get; set; }
|
||||
public FileMime ContentType { get; set; }
|
||||
public Encoding Encoding { get; set; }
|
||||
public object Data { get; set; }
|
||||
|
||||
public bool Compress { get; set; }
|
||||
public bool FreeData { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
public int Cache { get; set; }
|
||||
|
||||
public WebAPIResponse(WebAPIClient client)
|
||||
{
|
||||
Client = client;
|
||||
|
||||
Headers = new WebAPIHeaders();
|
||||
|
||||
Compress = false;
|
||||
FreeData = true;
|
||||
|
||||
Cache = -1;
|
||||
FileName = String.Empty;
|
||||
Encoding = Encoding.UTF8;
|
||||
|
||||
Status = HttpStatusCode.OK;
|
||||
ContentType = FileMime.Default;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (FreeData && Data is IDisposable)
|
||||
{
|
||||
((IDisposable)Data).Dispose();
|
||||
}
|
||||
|
||||
Data = null;
|
||||
|
||||
Headers.Dispose();
|
||||
Headers = null;
|
||||
|
||||
Cache = -1;
|
||||
FileName = "public.html";
|
||||
Encoding = null;
|
||||
|
||||
Client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
public class WebAPIOptions : CoreServiceOptions
|
||||
{
|
||||
public List<string> Whitelist { get; private set; }
|
||||
public List<string> Blacklist { get; private set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public bool UseWhitelist { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public short Port { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public int MaxConnections { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public int MaxSendBufferSize { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public int MaxReceiveBufferSize { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public int MaxSendBufferSizeBytes => MaxSendBufferSize * 1024 * 1024;
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public int MaxReceiveBufferSizeBytes => MaxReceiveBufferSize * 1024 * 1024;
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public bool DirectoryIndex { get; set; }
|
||||
|
||||
[CommandProperty(WebAPI.Access)]
|
||||
public bool WebServer { get; set; }
|
||||
|
||||
public WebAPIOptions()
|
||||
: base(typeof(WebAPI))
|
||||
{
|
||||
Whitelist = new List<string>();
|
||||
Blacklist = new List<string>();
|
||||
|
||||
Port = 2595;
|
||||
MaxConnections = 500;
|
||||
MaxSendBufferSize = 32;
|
||||
MaxReceiveBufferSize = 32;
|
||||
|
||||
UseWhitelist = false;
|
||||
WebServer = true;
|
||||
DirectoryIndex = true;
|
||||
}
|
||||
|
||||
public WebAPIOptions(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
|
||||
Whitelist.Clear();
|
||||
Blacklist.Clear();
|
||||
|
||||
Port = 80;
|
||||
MaxConnections = 500;
|
||||
MaxSendBufferSize = 32;
|
||||
MaxReceiveBufferSize = 32;
|
||||
|
||||
UseWhitelist = false;
|
||||
WebServer = false;
|
||||
DirectoryIndex = false;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Whitelist.Clear();
|
||||
Blacklist.Clear();
|
||||
|
||||
Port = 80;
|
||||
MaxConnections = 500;
|
||||
MaxSendBufferSize = 32;
|
||||
MaxReceiveBufferSize = 32;
|
||||
|
||||
UseWhitelist = false;
|
||||
WebServer = false;
|
||||
DirectoryIndex = false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
var version = writer.SetVersion(4);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
writer.Write(WebServer);
|
||||
writer.Write(DirectoryIndex);
|
||||
}
|
||||
goto case 3;
|
||||
case 3:
|
||||
case 2:
|
||||
{
|
||||
writer.Write(MaxSendBufferSize);
|
||||
writer.Write(MaxReceiveBufferSize);
|
||||
}
|
||||
goto case 1;
|
||||
case 1:
|
||||
{
|
||||
writer.WriteList(Whitelist, (w, m) => w.Write(m));
|
||||
writer.WriteList(Blacklist, (w, m) => w.Write(m));
|
||||
|
||||
writer.Write(UseWhitelist);
|
||||
}
|
||||
goto case 0;
|
||||
case 0:
|
||||
{
|
||||
writer.Write(Port);
|
||||
writer.Write(MaxConnections);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.GetVersion();
|
||||
|
||||
if (version < 3)
|
||||
{
|
||||
MaxSendBufferSize = 32;
|
||||
MaxReceiveBufferSize = 32;
|
||||
}
|
||||
|
||||
if (version < 2)
|
||||
{
|
||||
Whitelist = new List<string>();
|
||||
Blacklist = new List<string>();
|
||||
}
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
WebServer = reader.ReadBool();
|
||||
DirectoryIndex = reader.ReadBool();
|
||||
}
|
||||
goto case 3;
|
||||
case 3:
|
||||
case 2:
|
||||
{
|
||||
MaxSendBufferSize = reader.ReadInt();
|
||||
MaxReceiveBufferSize = reader.ReadInt();
|
||||
}
|
||||
goto case 1;
|
||||
case 1:
|
||||
{
|
||||
Whitelist = reader.ReadList(r => r.ReadString(), Whitelist);
|
||||
Blacklist = reader.ReadList(r => r.ReadString(), Blacklist);
|
||||
|
||||
UseWhitelist = reader.ReadBool();
|
||||
}
|
||||
goto case 0;
|
||||
case 0:
|
||||
{
|
||||
Port = reader.ReadShort();
|
||||
MaxConnections = reader.ReadInt();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1371
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/WebAPI.cs
Normal file
1371
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/WebAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
100
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/WebAPI_Init.cs
Normal file
100
Scripts/SubSystem/VitaNex/Core/Services/WebAPI/WebAPI_Init.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.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
|
||||
using Server;
|
||||
using Server.Misc;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Web
|
||||
{
|
||||
[CoreService("Web API", "3.0.0.1")]
|
||||
public static partial class WebAPI
|
||||
{
|
||||
static WebAPI()
|
||||
{
|
||||
CSOptions = new WebAPIOptions();
|
||||
|
||||
Clients = new List<WebAPIClient>();
|
||||
|
||||
Handlers = new Dictionary<string, WebAPIHandler>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
_ActivityTimer = PollTimer.FromSeconds(
|
||||
60.0,
|
||||
() =>
|
||||
{
|
||||
if (!_Listening || Listener == null || Listener.Server == null || !Listener.Server.IsBound)
|
||||
{
|
||||
_Listening = false;
|
||||
ListenerUtility.ListenAsync();
|
||||
}
|
||||
|
||||
Clients.RemoveAll(c => !c.Connected);
|
||||
},
|
||||
() => Clients.Count > 0,
|
||||
false);
|
||||
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType)0x3FC0; // Tls, Tls11, Tls12, Tls13
|
||||
}
|
||||
|
||||
private static void CSConfig()
|
||||
{
|
||||
if (_ServerStarted)
|
||||
{
|
||||
ListenerUtility.ListenAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
EventSink.ServerStarted += () =>
|
||||
{
|
||||
_ServerStarted = true;
|
||||
|
||||
ListenerUtility.ListenAsync();
|
||||
};
|
||||
|
||||
var t = typeof(StatusPage);
|
||||
var f = t.GetField("Enabled", BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (f != null)
|
||||
{
|
||||
f.SetValue(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CSInvoke()
|
||||
{
|
||||
_ActivityTimer.Start();
|
||||
|
||||
Register("/", HandleRoot);
|
||||
}
|
||||
|
||||
private static void CSDisposed()
|
||||
{
|
||||
Clients.ForEachReverse(c => c.Close());
|
||||
|
||||
_ActivityTimer.Stop();
|
||||
_ActivityTimer = null;
|
||||
|
||||
if (Listener == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Listener.Stop();
|
||||
Listener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user