fix: Cleans up core code (#1187)
**Only one functional change** * Fixes a bug in LogFactory where `Warning` is being logged as `Information` Non-functional changes: * Updates/Fixes copyright headers * Removes namespace scopes for core files. View with [whitespace off](https://github.com/modernuo/ModernUO/pull/1187/files?w=1).
This commit is contained in:
parent
0138d40bda
commit
f268d5d4e2
262 changed files with 28527 additions and 28646 deletions
4
.github/workflows/build-test.yml
vendored
4
.github/workflows/build-test.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
||||||
- name: Setup .NET 6
|
- name: Setup .NET 6
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.400
|
dotnet-version: 6.0.401
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./publish.cmd Release
|
run: ./publish.cmd Release
|
||||||
- name: Test
|
- name: Test
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
- name: Setup .NET 6
|
- name: Setup .NET 6
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.400
|
dotnet-version: 6.0.401
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./publish.cmd Release
|
run: ./publish.cmd Release
|
||||||
- name: Test
|
- name: Test
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Kamron Batman</Authors>
|
<Authors>Kamron Batman</Authors>
|
||||||
<Company>ModernUO</Company>
|
<Company>ModernUO</Company>
|
||||||
<Copyright>2019-2020</Copyright>
|
<Copyright>2019-2022</Copyright>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: VendorSellPackets.cs *
|
* File: VendorSellPackets.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: AssemblyHandler.cs *
|
* File: AssemblyHandler.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -21,334 +21,333 @@ using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public static class AssemblyHandler
|
||||||
{
|
{
|
||||||
public static class AssemblyHandler
|
private static readonly Dictionary<Assembly, TypeCache> m_TypeCaches = new();
|
||||||
|
private static TypeCache m_NullCache;
|
||||||
|
public static Assembly[] Assemblies { get; set; }
|
||||||
|
|
||||||
|
internal static Assembly AssemblyResolver(object sender, ResolveEventArgs args)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Assembly, TypeCache> m_TypeCaches = new();
|
var assemblyName = new AssemblyName(args.Name);
|
||||||
private static TypeCache m_NullCache;
|
var assembly = LoadAssemblyByAssemblyName(assemblyName);
|
||||||
public static Assembly[] Assemblies { get; set; }
|
if (assembly == null)
|
||||||
|
|
||||||
internal static Assembly AssemblyResolver(object sender, ResolveEventArgs args)
|
|
||||||
{
|
{
|
||||||
var assemblyName = new AssemblyName(args.Name);
|
throw new FileNotFoundException(
|
||||||
var assembly = LoadAssemblyByAssemblyName(assemblyName);
|
$"Could not load file or assembly {assemblyName}. The system cannot find the file specified. Review the assemblyDirectories field in {ServerConfiguration.ConfigurationFilePath}",
|
||||||
if (assembly == null)
|
$"{assemblyName.Name}.dll"
|
||||||
{
|
);
|
||||||
throw new FileNotFoundException(
|
|
||||||
$"Could not load file or assembly {assemblyName}. The system cannot find the file specified. Review the assemblyDirectories field in {ServerConfiguration.ConfigurationFilePath}",
|
|
||||||
$"{assemblyName.Name}.dll"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assembly;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EnsureAssemblyDirectories()
|
return assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnsureAssemblyDirectories()
|
||||||
|
{
|
||||||
|
if (ServerConfiguration.AssemblyDirectories.Count == 0)
|
||||||
{
|
{
|
||||||
if (ServerConfiguration.AssemblyDirectories.Count == 0)
|
ServerConfiguration.AssemblyDirectories.Add("./Assemblies");
|
||||||
{
|
ServerConfiguration.Save();
|
||||||
ServerConfiguration.AssemblyDirectories.Add("./Assemblies");
|
|
||||||
ServerConfiguration.Save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Assembly LoadAssemblyByAssemblyName(AssemblyName assemblyName)
|
public static Assembly LoadAssemblyByAssemblyName(AssemblyName assemblyName)
|
||||||
|
{
|
||||||
|
if (assemblyName?.Name == null)
|
||||||
{
|
{
|
||||||
if (assemblyName?.Name == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fullName = assemblyName.FullName;
|
|
||||||
var fileName = $"{assemblyName.Name}.dll";
|
|
||||||
|
|
||||||
EnsureAssemblyDirectories();
|
|
||||||
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
|
|
||||||
|
|
||||||
foreach (var assemblyDir in assemblyDirectories)
|
|
||||||
{
|
|
||||||
var assemblyPath = PathUtility.GetFullPath(Path.Combine(assemblyDir, fileName), Core.BaseDirectory);
|
|
||||||
if (File.Exists(assemblyPath))
|
|
||||||
{
|
|
||||||
var assemblyNameCheck = AssemblyName.GetAssemblyName(assemblyPath);
|
|
||||||
if (assemblyNameCheck.FullName == fullName)
|
|
||||||
{
|
|
||||||
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Assembly LoadAssemblyByFileName(string assemblyFile)
|
var fullName = assemblyName.FullName;
|
||||||
{
|
var fileName = $"{assemblyName.Name}.dll";
|
||||||
EnsureAssemblyDirectories();
|
|
||||||
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
|
|
||||||
|
|
||||||
foreach (var assemblyDir in assemblyDirectories)
|
EnsureAssemblyDirectories();
|
||||||
|
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
|
||||||
|
|
||||||
|
foreach (var assemblyDir in assemblyDirectories)
|
||||||
|
{
|
||||||
|
var assemblyPath = PathUtility.GetFullPath(Path.Combine(assemblyDir, fileName), Core.BaseDirectory);
|
||||||
|
if (File.Exists(assemblyPath))
|
||||||
{
|
{
|
||||||
var assemblyPath = Path.Combine(assemblyDir, assemblyFile);
|
var assemblyNameCheck = AssemblyName.GetAssemblyName(assemblyPath);
|
||||||
if (File.Exists(assemblyPath))
|
if (assemblyNameCheck.FullName == fullName)
|
||||||
{
|
{
|
||||||
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
|
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assembly LoadAssemblyByFileName(string assemblyFile)
|
||||||
|
{
|
||||||
|
EnsureAssemblyDirectories();
|
||||||
|
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
|
||||||
|
|
||||||
|
foreach (var assemblyDir in assemblyDirectories)
|
||||||
|
{
|
||||||
|
var assemblyPath = Path.Combine(assemblyDir, assemblyFile);
|
||||||
|
if (File.Exists(assemblyPath))
|
||||||
|
{
|
||||||
|
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadAssemblies(string[] files)
|
||||||
|
{
|
||||||
|
var assemblies = new Assembly[files.Length];
|
||||||
|
|
||||||
|
for (var i = 0; i < files.Length; i++)
|
||||||
|
{
|
||||||
|
var assemblyFile = files[i];
|
||||||
|
var assembly = LoadAssemblyByFileName(assemblyFile);
|
||||||
|
if (assembly == null)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException(
|
||||||
|
$"Could not load file or assembly {assemblyFile}. The system cannot find the file specified. Review the assemblyDirectories field in {ServerConfiguration.ConfigurationFilePath}",
|
||||||
|
assemblyFile
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assemblies[i] = assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assemblies = assemblies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Invoke(string method)
|
||||||
|
{
|
||||||
|
var invoke = new List<MethodInfo>();
|
||||||
|
|
||||||
|
Core.Assembly.AddMethods(method, invoke);
|
||||||
|
|
||||||
|
for (var i = 0; i < Assemblies.Length; i++)
|
||||||
|
{
|
||||||
|
Assemblies[i].AddMethods(method, invoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke.Sort(new CallPriorityComparer());
|
||||||
|
|
||||||
|
for (var i = 0; i < invoke.Count; ++i)
|
||||||
|
{
|
||||||
|
invoke[i].Invoke(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddMethods(this Assembly assembly, string method, List<MethodInfo> list)
|
||||||
|
{
|
||||||
|
var types = assembly.GetTypes();
|
||||||
|
|
||||||
|
for (int i = 0; i < types.Length; i++)
|
||||||
|
{
|
||||||
|
var m = types[i].GetMethod(method, BindingFlags.Static | BindingFlags.Public);
|
||||||
|
if (m?.GetParameters().Length == 0)
|
||||||
|
{
|
||||||
|
list.Add(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static TypeCache GetTypeCache(Assembly asm)
|
||||||
|
{
|
||||||
|
if (asm == null)
|
||||||
|
{
|
||||||
|
return m_NullCache ??= new TypeCache(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_TypeCaches.TryGetValue(asm, out var c))
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_TypeCaches[asm] = new TypeCache(asm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type FindTypeByFullName(string name, bool ignoreCase = true) =>
|
||||||
|
FindTypeByName(name, true, ignoreCase);
|
||||||
|
|
||||||
|
public static Type FindTypeByName(string name, bool fullName = false, bool ignoreCase = true)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LoadAssemblies(string[] files)
|
for (var i = 0; i < Assemblies.Length; i++)
|
||||||
{
|
{
|
||||||
var assemblies = new Assembly[files.Length];
|
foreach (var type in GetTypeCache(Assemblies[i]).GetTypesByName(name, fullName, ignoreCase))
|
||||||
|
|
||||||
for (var i = 0; i < files.Length; i++)
|
|
||||||
{
|
|
||||||
var assemblyFile = files[i];
|
|
||||||
var assembly = LoadAssemblyByFileName(assemblyFile);
|
|
||||||
if (assembly == null)
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException(
|
|
||||||
$"Could not load file or assembly {assemblyFile}. The system cannot find the file specified. Review the assemblyDirectories field in {ServerConfiguration.ConfigurationFilePath}",
|
|
||||||
assemblyFile
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assemblies[i] = assembly;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assemblies = assemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Invoke(string method)
|
|
||||||
{
|
|
||||||
var invoke = new List<MethodInfo>();
|
|
||||||
|
|
||||||
Core.Assembly.AddMethods(method, invoke);
|
|
||||||
|
|
||||||
for (var i = 0; i < Assemblies.Length; i++)
|
|
||||||
{
|
|
||||||
Assemblies[i].AddMethods(method, invoke);
|
|
||||||
}
|
|
||||||
|
|
||||||
invoke.Sort(new CallPriorityComparer());
|
|
||||||
|
|
||||||
for (var i = 0; i < invoke.Count; ++i)
|
|
||||||
{
|
|
||||||
invoke[i].Invoke(null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddMethods(this Assembly assembly, string method, List<MethodInfo> list)
|
|
||||||
{
|
|
||||||
var types = assembly.GetTypes();
|
|
||||||
|
|
||||||
for (int i = 0; i < types.Length; i++)
|
|
||||||
{
|
|
||||||
var m = types[i].GetMethod(method, BindingFlags.Static | BindingFlags.Public);
|
|
||||||
if (m?.GetParameters().Length == 0)
|
|
||||||
{
|
|
||||||
list.Add(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static TypeCache GetTypeCache(Assembly asm)
|
|
||||||
{
|
|
||||||
if (asm == null)
|
|
||||||
{
|
|
||||||
return m_NullCache ??= new TypeCache(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_TypeCaches.TryGetValue(asm, out var c))
|
|
||||||
{
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_TypeCaches[asm] = new TypeCache(asm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type FindTypeByFullName(string name, bool ignoreCase = true) =>
|
|
||||||
FindTypeByName(name, true, ignoreCase);
|
|
||||||
|
|
||||||
public static Type FindTypeByName(string name, bool fullName = false, bool ignoreCase = true)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < Assemblies.Length; i++)
|
|
||||||
{
|
|
||||||
foreach (var type in GetTypeCache(Assemblies[i]).GetTypesByName(name, fullName, ignoreCase))
|
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(var type in GetTypeCache(Core.Assembly).GetTypesByName(name, fullName, ignoreCase))
|
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
foreach(var type in GetTypeCache(Core.Assembly).GetTypesByName(name, fullName, ignoreCase))
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TypeCache
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, int[]> _nameMap = new();
|
||||||
|
private readonly Dictionary<string, int[]> _nameMapInsensitive = new();
|
||||||
|
private readonly Dictionary<string, int[]> _fullNameMap = new();
|
||||||
|
private readonly Dictionary<string, int[]> _fullNameMapInsensitive = new();
|
||||||
|
|
||||||
|
public TypeCache(Assembly asm)
|
||||||
|
{
|
||||||
|
Types = asm?.GetTypes() ?? Type.EmptyTypes;
|
||||||
|
|
||||||
|
var nameMap = new Dictionary<string, HashSet<int>>();
|
||||||
|
var nameMapInsensitive = new Dictionary<string, HashSet<int>>();
|
||||||
|
var fullNameMap = new Dictionary<string, HashSet<int>>();
|
||||||
|
var fullNameMapInsensitive = new Dictionary<string, HashSet<int>>();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
void addTypeToRefs(int index, string fullTypeName)
|
||||||
|
{
|
||||||
|
var typeName = fullTypeName[(fullTypeName.LastIndexOf('.') + 1)..];
|
||||||
|
AddToRefs(index, typeName, nameMap);
|
||||||
|
AddToRefs(index, typeName.ToLower(), nameMapInsensitive);
|
||||||
|
AddToRefs(index, fullTypeName, fullNameMap);
|
||||||
|
AddToRefs(index, fullTypeName.ToLower(), fullNameMapInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
var aliasType = typeof(TypeAliasAttribute);
|
||||||
|
for (var i = 0; i < Types.Length; i++)
|
||||||
|
{
|
||||||
|
var current = Types[i];
|
||||||
|
addTypeToRefs(i, current.FullName);
|
||||||
|
if (current.GetCustomAttribute(aliasType, false) is TypeAliasAttribute alias)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < alias.Aliases.Length; j++)
|
||||||
|
{
|
||||||
|
addTypeToRefs(i, alias.Aliases[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (key, value) in nameMap)
|
||||||
|
{
|
||||||
|
_nameMap[key] = value.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (key, value) in nameMapInsensitive)
|
||||||
|
{
|
||||||
|
_nameMapInsensitive[key] = value.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (key, value) in fullNameMap)
|
||||||
|
{
|
||||||
|
_fullNameMap[key] = value.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (key, value) in fullNameMapInsensitive)
|
||||||
|
{
|
||||||
|
_fullNameMapInsensitive[key] = value.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TypeCache
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void AddToRefs(int index, string key, Dictionary<string, HashSet<int>> map)
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, int[]> _nameMap = new();
|
if (key == null)
|
||||||
private readonly Dictionary<string, int[]> _nameMapInsensitive = new();
|
|
||||||
private readonly Dictionary<string, int[]> _fullNameMap = new();
|
|
||||||
private readonly Dictionary<string, int[]> _fullNameMapInsensitive = new();
|
|
||||||
|
|
||||||
public TypeCache(Assembly asm)
|
|
||||||
{
|
{
|
||||||
Types = asm?.GetTypes() ?? Type.EmptyTypes;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nameMap = new Dictionary<string, HashSet<int>>();
|
if (map.TryGetValue(key, out var refs))
|
||||||
var nameMapInsensitive = new Dictionary<string, HashSet<int>>();
|
{
|
||||||
var fullNameMap = new Dictionary<string, HashSet<int>>();
|
refs.Add(index);
|
||||||
var fullNameMapInsensitive = new Dictionary<string, HashSet<int>>();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
refs = new HashSet<int> { index };
|
||||||
|
map.Add(key, refs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public Type[] Types { get; }
|
||||||
void addTypeToRefs(int index, string fullTypeName)
|
|
||||||
{
|
|
||||||
var typeName = fullTypeName[(fullTypeName.LastIndexOf('.') + 1)..];
|
|
||||||
AddToRefs(index, typeName, nameMap);
|
|
||||||
AddToRefs(index, typeName.ToLower(), nameMapInsensitive);
|
|
||||||
AddToRefs(index, fullTypeName, fullNameMap);
|
|
||||||
AddToRefs(index, fullTypeName.ToLower(), fullNameMapInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
var aliasType = typeof(TypeAliasAttribute);
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
for (var i = 0; i < Types.Length; i++)
|
public TypeEnumerable GetTypesByName(string name, bool full, bool ignoreCase) => new(name, this, full, ignoreCase);
|
||||||
{
|
|
||||||
var current = Types[i];
|
|
||||||
addTypeToRefs(i, current.FullName);
|
|
||||||
if (current.GetCustomAttribute(aliasType, false) is TypeAliasAttribute alias)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < alias.Aliases.Length; j++)
|
|
||||||
{
|
|
||||||
addTypeToRefs(i, alias.Aliases[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (key, value) in nameMap)
|
public ref struct TypeEnumerable
|
||||||
{
|
{
|
||||||
_nameMap[key] = value.ToArray();
|
private readonly TypeCache _cache;
|
||||||
}
|
private readonly string _name;
|
||||||
|
private readonly bool _ignoreCase;
|
||||||
|
private readonly bool _full;
|
||||||
|
|
||||||
foreach (var (key, value) in nameMapInsensitive)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
public TypeEnumerable(string name, TypeCache cache, bool full, bool ignoreCase)
|
||||||
_nameMapInsensitive[key] = value.ToArray();
|
{
|
||||||
}
|
_name = name;
|
||||||
|
_cache = cache;
|
||||||
foreach (var (key, value) in fullNameMap)
|
_ignoreCase = ignoreCase;
|
||||||
{
|
_full = full;
|
||||||
_fullNameMap[key] = value.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (key, value) in fullNameMapInsensitive)
|
|
||||||
{
|
|
||||||
_fullNameMapInsensitive[key] = value.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void AddToRefs(int index, string key, Dictionary<string, HashSet<int>> map)
|
public TypeEnumerator GetEnumerator() => new(_name, _cache, _full, _ignoreCase);
|
||||||
{
|
}
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map.TryGetValue(key, out var refs))
|
public ref struct TypeEnumerator
|
||||||
|
{
|
||||||
|
private readonly TypeCache _cache;
|
||||||
|
private readonly int[] _values;
|
||||||
|
private int _index;
|
||||||
|
private Type _current;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal TypeEnumerator(string name, TypeCache cache, bool full, bool ignoreCase)
|
||||||
|
{
|
||||||
|
_cache = cache;
|
||||||
|
|
||||||
|
if (ignoreCase)
|
||||||
{
|
{
|
||||||
refs.Add(index);
|
var map = full ? _cache._fullNameMapInsensitive : _cache._nameMapInsensitive;
|
||||||
|
_values = map.TryGetValue(name.ToLower(), out var values) ? values : Array.Empty<int>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
refs = new HashSet<int> { index };
|
var map = full ? _cache._fullNameMap : _cache._nameMap;
|
||||||
map.Add(key, refs);
|
_values = map.TryGetValue(name, out var values) ? values : Array.Empty<int>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public Type[] Types { get; }
|
_index = 0;
|
||||||
|
_current = default;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public TypeEnumerable GetTypesByName(string name, bool full, bool ignoreCase) => new(name, this, full, ignoreCase);
|
public bool MoveNext()
|
||||||
|
|
||||||
public ref struct TypeEnumerable
|
|
||||||
{
|
{
|
||||||
private readonly TypeCache _cache;
|
int[] localList = _values;
|
||||||
private readonly string _name;
|
|
||||||
private readonly bool _ignoreCase;
|
|
||||||
private readonly bool _full;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
if ((uint)_index < (uint)localList.Length)
|
||||||
public TypeEnumerable(string name, TypeCache cache, bool full, bool ignoreCase)
|
|
||||||
{
|
{
|
||||||
_name = name;
|
_current = _cache.Types[_values[_index++]];
|
||||||
_cache = cache;
|
|
||||||
_ignoreCase = ignoreCase;
|
return true;
|
||||||
_full = full;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
return false;
|
||||||
public TypeEnumerator GetEnumerator() => new(_name, _cache, _full, _ignoreCase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref struct TypeEnumerator
|
public Type Current
|
||||||
{
|
{
|
||||||
private readonly TypeCache _cache;
|
|
||||||
private readonly int[] _values;
|
|
||||||
private int _index;
|
|
||||||
private Type _current;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal TypeEnumerator(string name, TypeCache cache, bool full, bool ignoreCase)
|
get => _current;
|
||||||
{
|
|
||||||
_cache = cache;
|
|
||||||
|
|
||||||
if (ignoreCase)
|
|
||||||
{
|
|
||||||
var map = full ? _cache._fullNameMapInsensitive : _cache._nameMapInsensitive;
|
|
||||||
_values = map.TryGetValue(name.ToLower(), out var values) ? values : Array.Empty<int>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var map = full ? _cache._fullNameMap : _cache._nameMap;
|
|
||||||
_values = map.TryGetValue(name, out var values) ? values : Array.Empty<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_index = 0;
|
|
||||||
_current = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
int[] localList = _values;
|
|
||||||
|
|
||||||
if ((uint)_index < (uint)localList.Length)
|
|
||||||
{
|
|
||||||
_current = _cache.Types[_values[_index++]];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type Current
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _current;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,140 +2,139 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class HueAttribute : Attribute
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
}
|
||||||
public class HueAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||||
public class PropertyObjectAttribute : Attribute
|
public class PropertyObjectAttribute : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||||
public class NoSortAttribute : Attribute
|
public class NoSortAttribute : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public class CallPriorityAttribute : Attribute
|
public class CallPriorityAttribute : Attribute
|
||||||
{
|
{
|
||||||
public CallPriorityAttribute(int priority) => Priority = priority;
|
public CallPriorityAttribute(int priority) => Priority = priority;
|
||||||
|
|
||||||
public int Priority { get; set; }
|
public int Priority { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CallPriorityComparer : IComparer<MethodInfo>
|
public class CallPriorityComparer : IComparer<MethodInfo>
|
||||||
|
{
|
||||||
|
public int Compare(MethodInfo x, MethodInfo y)
|
||||||
{
|
{
|
||||||
public int Compare(MethodInfo x, MethodInfo y)
|
if (x == null && y == null)
|
||||||
{
|
{
|
||||||
if (x == null && y == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x == null)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xPriority = GetPriority(x);
|
|
||||||
var yPriority = GetPriority(y);
|
|
||||||
|
|
||||||
if (xPriority > yPriority)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xPriority < yPriority)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetPriority(MethodInfo mi)
|
if (x == null)
|
||||||
{
|
|
||||||
var objs = mi.GetCustomAttributes(typeof(CallPriorityAttribute), true);
|
|
||||||
|
|
||||||
if (objs.Length == 0)
|
|
||||||
{
|
|
||||||
return 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objs[0] is not CallPriorityAttribute attr)
|
|
||||||
{
|
|
||||||
return 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
return attr.Priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class TypeAliasAttribute : Attribute
|
|
||||||
{
|
|
||||||
public TypeAliasAttribute(params string[] aliases) => Aliases = aliases;
|
|
||||||
|
|
||||||
public string[] Aliases { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
|
||||||
public class ParsableAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
|
|
||||||
public class CustomEnumAttribute : Attribute
|
|
||||||
{
|
|
||||||
public CustomEnumAttribute(string[] names) => Names = names;
|
|
||||||
|
|
||||||
public string[] Names { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Constructor)]
|
|
||||||
public class ConstructibleAttribute : Attribute
|
|
||||||
{
|
|
||||||
public ConstructibleAttribute() :
|
|
||||||
this(AccessLevel.Player) // Lowest accesslevel for current functionality (Level determined by access to [add)
|
|
||||||
{
|
{
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstructibleAttribute(AccessLevel accessLevel) => AccessLevel = accessLevel;
|
if (y == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
public AccessLevel AccessLevel { get; set; }
|
var xPriority = GetPriority(x);
|
||||||
|
var yPriority = GetPriority(y);
|
||||||
|
|
||||||
|
if (xPriority > yPriority)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xPriority < yPriority)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
private int GetPriority(MethodInfo mi)
|
||||||
public class CommandPropertyAttribute : Attribute
|
|
||||||
{
|
{
|
||||||
public CommandPropertyAttribute(
|
var objs = mi.GetCustomAttributes(typeof(CallPriorityAttribute), true);
|
||||||
AccessLevel level,
|
|
||||||
bool readOnly = false,
|
if (objs.Length == 0)
|
||||||
bool canModify = false
|
|
||||||
) : this(level, level)
|
|
||||||
{
|
{
|
||||||
ReadOnly = readOnly;
|
return 50;
|
||||||
CanModify = canModify;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandPropertyAttribute(AccessLevel readLevel, AccessLevel writeLevel)
|
if (objs[0] is not CallPriorityAttribute attr)
|
||||||
{
|
{
|
||||||
ReadLevel = readLevel;
|
return 50;
|
||||||
WriteLevel = writeLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessLevel ReadLevel { get; }
|
return attr.Priority;
|
||||||
public AccessLevel WriteLevel { get; }
|
|
||||||
public bool ReadOnly { get; }
|
|
||||||
public bool CanModify { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class TypeAliasAttribute : Attribute
|
||||||
|
{
|
||||||
|
public TypeAliasAttribute(params string[] aliases) => Aliases = aliases;
|
||||||
|
|
||||||
|
public string[] Aliases { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||||
|
public class ParsableAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
|
||||||
|
public class CustomEnumAttribute : Attribute
|
||||||
|
{
|
||||||
|
public CustomEnumAttribute(string[] names) => Names = names;
|
||||||
|
|
||||||
|
public string[] Names { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Constructor)]
|
||||||
|
public class ConstructibleAttribute : Attribute
|
||||||
|
{
|
||||||
|
public ConstructibleAttribute() :
|
||||||
|
this(AccessLevel.Player) // Lowest accesslevel for current functionality (Level determined by access to [add)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstructibleAttribute(AccessLevel accessLevel) => AccessLevel = accessLevel;
|
||||||
|
|
||||||
|
public AccessLevel AccessLevel { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class CommandPropertyAttribute : Attribute
|
||||||
|
{
|
||||||
|
public CommandPropertyAttribute(
|
||||||
|
AccessLevel level,
|
||||||
|
bool readOnly = false,
|
||||||
|
bool canModify = false
|
||||||
|
) : this(level, level)
|
||||||
|
{
|
||||||
|
ReadOnly = readOnly;
|
||||||
|
CanModify = canModify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandPropertyAttribute(AccessLevel readLevel, AccessLevel writeLevel)
|
||||||
|
{
|
||||||
|
ReadLevel = readLevel;
|
||||||
|
WriteLevel = writeLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessLevel ReadLevel { get; }
|
||||||
|
public AccessLevel WriteLevel { get; }
|
||||||
|
public bool ReadOnly { get; }
|
||||||
|
public bool CanModify { get; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: CircularBuffer.cs *
|
* File: CircularBuffer.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -13,128 +13,127 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
namespace System.Buffers
|
namespace System.Buffers;
|
||||||
|
|
||||||
|
public readonly ref struct CircularBuffer<T>
|
||||||
{
|
{
|
||||||
public readonly ref struct CircularBuffer<T>
|
private readonly Span<T> _first;
|
||||||
|
private readonly Span<T> _second;
|
||||||
|
|
||||||
|
public int Length { get; }
|
||||||
|
|
||||||
|
public CircularBuffer(ArraySegment<T>[] buffers) : this(buffers[0], buffers[1])
|
||||||
{
|
{
|
||||||
private readonly Span<T> _first;
|
}
|
||||||
private readonly Span<T> _second;
|
|
||||||
|
|
||||||
public int Length { get; }
|
public CircularBuffer(Span<T> first, Span<T> second)
|
||||||
|
{
|
||||||
|
_first = first;
|
||||||
|
_second = second;
|
||||||
|
Length = first.Length + second.Length;
|
||||||
|
}
|
||||||
|
|
||||||
public CircularBuffer(ArraySegment<T>[] buffers) : this(buffers[0], buffers[1])
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
}
|
if (index < 0 || index > Length)
|
||||||
|
|
||||||
public CircularBuffer(Span<T> first, Span<T> second)
|
|
||||||
{
|
|
||||||
_first = first;
|
|
||||||
_second = second;
|
|
||||||
Length = first.Length + second.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
{
|
||||||
if (index < 0 || index > Length)
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
return index < _first.Length ? _first[index] : _second[index - _first.Length];
|
|
||||||
}
|
}
|
||||||
set
|
|
||||||
{
|
|
||||||
if (index < 0 || index > Length)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < _first.Length)
|
return index < _first.Length ? _first[index] : _second[index - _first.Length];
|
||||||
{
|
}
|
||||||
_first[index] = value;
|
set
|
||||||
}
|
{
|
||||||
else
|
if (index < 0 || index > Length)
|
||||||
{
|
{
|
||||||
_second[index - _first.Length] = value;
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index < _first.Length)
|
||||||
|
{
|
||||||
|
_first[index] = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_second[index - _first.Length] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CopyFrom(ReadOnlySpan<T> bytes)
|
public void CopyFrom(ReadOnlySpan<T> bytes)
|
||||||
|
{
|
||||||
|
var remaining = bytes.Length;
|
||||||
|
var offset = 0;
|
||||||
|
|
||||||
|
if (remaining == 0)
|
||||||
{
|
{
|
||||||
var remaining = bytes.Length;
|
return;
|
||||||
var offset = 0;
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
var buffer = i == 0 ? _first : _second;
|
||||||
|
|
||||||
|
if (buffer.Length == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sz = Math.Min(remaining, buffer.Length);
|
||||||
|
bytes.Slice(offset, sz).CopyTo(buffer);
|
||||||
|
|
||||||
|
remaining -= sz;
|
||||||
|
offset += sz;
|
||||||
|
|
||||||
if (remaining == 0)
|
if (remaining == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
var buffer = i == 0 ? _first : _second;
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sz = Math.Min(remaining, buffer.Length);
|
|
||||||
bytes.Slice(offset, sz).CopyTo(buffer);
|
|
||||||
|
|
||||||
remaining -= sz;
|
|
||||||
offset += sz;
|
|
||||||
|
|
||||||
if (remaining == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(Span<T> bytes)
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(Span<T> bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length < Length)
|
||||||
{
|
{
|
||||||
if (bytes.Length < Length)
|
throw new ArgumentOutOfRangeException(nameof(bytes));
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_first.Length > 0)
|
|
||||||
{
|
|
||||||
_first.CopyTo(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_second.Length > 0)
|
|
||||||
{
|
|
||||||
_second.CopyTo(bytes[_first.Length..]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CircularBuffer<T> Slice(int offset, int count)
|
if (_first.Length > 0)
|
||||||
{
|
{
|
||||||
var firstCount = Math.Min(count, _first.Length - offset);
|
_first.CopyTo(bytes);
|
||||||
var first = offset < _first.Length
|
|
||||||
? _first.Slice(offset, firstCount)
|
|
||||||
: Span<T>.Empty;
|
|
||||||
|
|
||||||
var secondCount = offset > _first.Length ? count : count - firstCount;
|
|
||||||
var second = secondCount > 0 ? _second.Slice(Math.Max(0, offset - _first.Length), secondCount) : Span<T>.Empty;
|
|
||||||
|
|
||||||
return new CircularBuffer<T>(first, second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Span<T> GetSpan(int index)
|
if (_second.Length > 0)
|
||||||
{
|
{
|
||||||
if (index is < 0 or > 1)
|
_second.CopyTo(bytes[_first.Length..]);
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
return index == 0 ? _first : _second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CircularBuffer<T> Slice(int offset, int count)
|
||||||
|
{
|
||||||
|
var firstCount = Math.Min(count, _first.Length - offset);
|
||||||
|
var first = offset < _first.Length
|
||||||
|
? _first.Slice(offset, firstCount)
|
||||||
|
: Span<T>.Empty;
|
||||||
|
|
||||||
|
var secondCount = offset > _first.Length ? count : count - firstCount;
|
||||||
|
var second = secondCount > 0 ? _second.Slice(Math.Max(0, offset - _first.Length), secondCount) : Span<T>.Empty;
|
||||||
|
|
||||||
|
return new CircularBuffer<T>(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span<T> GetSpan(int index)
|
||||||
|
{
|
||||||
|
if (index is < 0 or > 1)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return index == 0 ? _first : _second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: PacketReader.cs *
|
* File: PacketReader.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -21,375 +21,374 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Server.Text;
|
using Server.Text;
|
||||||
|
|
||||||
namespace Server.Network
|
namespace Server.Network;
|
||||||
|
|
||||||
|
public ref struct CircularBufferReader
|
||||||
{
|
{
|
||||||
public ref struct CircularBufferReader
|
private readonly ReadOnlySpan<byte> _first;
|
||||||
|
private readonly ReadOnlySpan<byte> _second;
|
||||||
|
|
||||||
|
public int Length { get; }
|
||||||
|
public int Position { get; private set; }
|
||||||
|
public int Remaining => Length - Position;
|
||||||
|
|
||||||
|
// Only used for debugging!
|
||||||
|
public ReadOnlySpan<byte> First => _first;
|
||||||
|
public ReadOnlySpan<byte> Second => _second;
|
||||||
|
|
||||||
|
public CircularBufferReader(ref CircularBuffer<byte> buffer) : this(buffer.GetSpan(0), buffer.GetSpan(1))
|
||||||
{
|
{
|
||||||
private readonly ReadOnlySpan<byte> _first;
|
}
|
||||||
private readonly ReadOnlySpan<byte> _second;
|
|
||||||
|
|
||||||
public int Length { get; }
|
public CircularBufferReader(ArraySegment<byte>[] buffer) : this(buffer[0], buffer[1])
|
||||||
public int Position { get; private set; }
|
{
|
||||||
public int Remaining => Length - Position;
|
}
|
||||||
|
|
||||||
// Only used for debugging!
|
public CircularBufferReader(ReadOnlySpan<byte> first, ReadOnlySpan<byte> second)
|
||||||
public ReadOnlySpan<byte> First => _first;
|
{
|
||||||
public ReadOnlySpan<byte> Second => _second;
|
_first = first;
|
||||||
|
_second = second;
|
||||||
|
Position = 0;
|
||||||
|
Length = first.Length + second.Length;
|
||||||
|
}
|
||||||
|
|
||||||
public CircularBufferReader(ref CircularBuffer<byte> buffer) : this(buffer.GetSpan(0), buffer.GetSpan(1))
|
public void Trace(NetState state)
|
||||||
|
{
|
||||||
|
// We don't have data, so nothing to trace
|
||||||
|
if (_first.Length == 0)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CircularBufferReader(ArraySegment<byte>[] buffer) : this(buffer[0], buffer[1])
|
try
|
||||||
{
|
{
|
||||||
|
using var sw = new StreamWriter("unhandled-packets.log", true);
|
||||||
|
sw.WriteLine("Client: {0}: Unhandled packet 0x{1:X2}", state, _first[0]);
|
||||||
|
sw.FormatBuffer(_first, _second, Length);
|
||||||
|
sw.WriteLine();
|
||||||
|
sw.WriteLine();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public byte ReadByte()
|
||||||
|
{
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
return _first[Position++];
|
||||||
}
|
}
|
||||||
|
|
||||||
public CircularBufferReader(ReadOnlySpan<byte> first, ReadOnlySpan<byte> second)
|
if (Position < Length)
|
||||||
{
|
{
|
||||||
_first = first;
|
return _second[Position++ - _first.Length];
|
||||||
_second = second;
|
|
||||||
Position = 0;
|
|
||||||
Length = first.Length + second.Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Trace(NetState state)
|
throw new OutOfMemoryException();
|
||||||
{
|
}
|
||||||
// We don't have data, so nothing to trace
|
|
||||||
if (_first.Length == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool ReadBoolean() => ReadByte() > 0;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public sbyte ReadSByte() => (sbyte)ReadByte();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public short ReadInt16()
|
||||||
|
{
|
||||||
|
short value;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt16BigEndian(_first[Position..], out value))
|
||||||
{
|
{
|
||||||
using var sw = new StreamWriter("unhandled-packets.log", true);
|
// Not enough space. Split the spans
|
||||||
sw.WriteLine("Client: {0}: Unhandled packet 0x{1:X2}", state, _first[0]);
|
return (short)((ReadByte() >> 8) | ReadByte());
|
||||||
sw.FormatBuffer(_first, _second, Length);
|
|
||||||
sw.WriteLine();
|
|
||||||
sw.WriteLine();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadInt16BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public byte ReadByte()
|
|
||||||
{
|
{
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
return _first[Position++];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Position < Length)
|
|
||||||
{
|
|
||||||
return _second[Position++ - _first.Length];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new OutOfMemoryException();
|
throw new OutOfMemoryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
Position += 2;
|
||||||
public bool ReadBoolean() => ReadByte() > 0;
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public sbyte ReadSByte() => (sbyte)ReadByte();
|
public ushort ReadUInt16()
|
||||||
|
{
|
||||||
|
ushort value;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
if (Position < _first.Length)
|
||||||
public short ReadInt16()
|
|
||||||
{
|
{
|
||||||
short value;
|
if (!BinaryPrimitives.TryReadUInt16BigEndian(_first[Position..], out value))
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
{
|
||||||
if (!BinaryPrimitives.TryReadInt16BigEndian(_first[Position..], out value))
|
// Not enough space. Split the spans
|
||||||
{
|
return (ushort)((ReadByte() >> 8) | ReadByte());
|
||||||
// Not enough space. Split the spans
|
|
||||||
return (short)((ReadByte() >> 8) | ReadByte());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!BinaryPrimitives.TryReadInt16BigEndian(_second[(Position - _first.Length)..], out value))
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadUInt16BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int ReadInt32()
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt32BigEndian(_first[Position..], out value))
|
||||||
|
{
|
||||||
|
// Not enough space. Split the spans
|
||||||
|
return (ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadInt32BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public uint ReadUInt32()
|
||||||
|
{
|
||||||
|
uint value;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt32BigEndian(_first[Position..], out value))
|
||||||
|
{
|
||||||
|
// Not enough space. Split the spans
|
||||||
|
return (uint)((ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadUInt32BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public long ReadInt64()
|
||||||
|
{
|
||||||
|
long value;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt64BigEndian(_first[Position..], out value))
|
||||||
|
{
|
||||||
|
// Not enough space. Split the spans
|
||||||
|
return ((long)ReadByte() >> 56) |
|
||||||
|
((long)ReadByte() >> 48) |
|
||||||
|
((long)ReadByte() >> 40) |
|
||||||
|
((long)ReadByte() >> 32) |
|
||||||
|
((long)ReadByte() >> 24) |
|
||||||
|
((long)ReadByte() >> 16) |
|
||||||
|
((long)ReadByte() >> 8) |
|
||||||
|
ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadInt64BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ulong ReadUInt64()
|
||||||
|
{
|
||||||
|
ulong value;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt64BigEndian(_first[Position..], out value))
|
||||||
|
{
|
||||||
|
// Not enough space. Split the spans
|
||||||
|
return ((ulong)ReadByte() >> 56) |
|
||||||
|
((ulong)ReadByte() >> 48) |
|
||||||
|
((ulong)ReadByte() >> 40) |
|
||||||
|
((ulong)ReadByte() >> 32) |
|
||||||
|
((ulong)ReadByte() >> 24) |
|
||||||
|
((ulong)ReadByte() >> 16) |
|
||||||
|
((ulong)ReadByte() >> 8) |
|
||||||
|
ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!BinaryPrimitives.TryReadUInt64BigEndian(_second[(Position - _first.Length)..], out value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1)
|
||||||
|
{
|
||||||
|
int byteLength = encoding.GetByteLengthForEncoding();
|
||||||
|
|
||||||
|
bool isFixedLength = fixedLength > -1;
|
||||||
|
|
||||||
|
var remaining = Remaining;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
if (isFixedLength)
|
||||||
|
{
|
||||||
|
size = fixedLength * byteLength;
|
||||||
|
if (size > Remaining)
|
||||||
{
|
{
|
||||||
throw new OutOfMemoryException();
|
throw new OutOfMemoryException();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Position += 2;
|
else
|
||||||
return value;
|
{
|
||||||
|
size = remaining - (remaining & (byteLength - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
ReadOnlySpan<byte> span;
|
||||||
public ushort ReadUInt16()
|
int index;
|
||||||
|
|
||||||
|
if (Position < _first.Length)
|
||||||
{
|
{
|
||||||
ushort value;
|
var firstLength = Math.Min(_first.Length - Position, size);
|
||||||
|
|
||||||
if (Position < _first.Length)
|
// Find terminator
|
||||||
|
index = _first.Slice(Position, firstLength).IndexOfTerminator(byteLength);
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
{
|
{
|
||||||
if (!BinaryPrimitives.TryReadUInt16BigEndian(_first[Position..], out value))
|
remaining = size - firstLength;
|
||||||
|
// We don't have a terminator, but a fixed size to the end of the first span, so stop there
|
||||||
|
if (remaining <= 0)
|
||||||
{
|
{
|
||||||
// Not enough space. Split the spans
|
index = firstLength;
|
||||||
return (ushort)((ReadByte() >> 8) | ReadByte());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!BinaryPrimitives.TryReadUInt16BigEndian(_second[(Position - _first.Length)..], out value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int ReadInt32()
|
|
||||||
{
|
|
||||||
int value;
|
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadInt32BigEndian(_first[Position..], out value))
|
|
||||||
{
|
|
||||||
// Not enough space. Split the spans
|
|
||||||
return (ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!BinaryPrimitives.TryReadInt32BigEndian(_second[(Position - _first.Length)..], out value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public uint ReadUInt32()
|
|
||||||
{
|
|
||||||
uint value;
|
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt32BigEndian(_first[Position..], out value))
|
|
||||||
{
|
|
||||||
// Not enough space. Split the spans
|
|
||||||
return (uint)((ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!BinaryPrimitives.TryReadUInt32BigEndian(_second[(Position - _first.Length)..], out value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public long ReadInt64()
|
|
||||||
{
|
|
||||||
long value;
|
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadInt64BigEndian(_first[Position..], out value))
|
|
||||||
{
|
|
||||||
// Not enough space. Split the spans
|
|
||||||
return ((long)ReadByte() >> 56) |
|
|
||||||
((long)ReadByte() >> 48) |
|
|
||||||
((long)ReadByte() >> 40) |
|
|
||||||
((long)ReadByte() >> 32) |
|
|
||||||
((long)ReadByte() >> 24) |
|
|
||||||
((long)ReadByte() >> 16) |
|
|
||||||
((long)ReadByte() >> 8) |
|
|
||||||
ReadByte();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!BinaryPrimitives.TryReadInt64BigEndian(_second[(Position - _first.Length)..], out value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ulong ReadUInt64()
|
|
||||||
{
|
|
||||||
ulong value;
|
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt64BigEndian(_first[Position..], out value))
|
|
||||||
{
|
|
||||||
// Not enough space. Split the spans
|
|
||||||
return ((ulong)ReadByte() >> 56) |
|
|
||||||
((ulong)ReadByte() >> 48) |
|
|
||||||
((ulong)ReadByte() >> 40) |
|
|
||||||
((ulong)ReadByte() >> 32) |
|
|
||||||
((ulong)ReadByte() >> 24) |
|
|
||||||
((ulong)ReadByte() >> 16) |
|
|
||||||
((ulong)ReadByte() >> 8) |
|
|
||||||
ReadByte();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!BinaryPrimitives.TryReadUInt64BigEndian(_second[(Position - _first.Length)..], out value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1)
|
|
||||||
{
|
|
||||||
int byteLength = encoding.GetByteLengthForEncoding();
|
|
||||||
|
|
||||||
bool isFixedLength = fixedLength > -1;
|
|
||||||
|
|
||||||
var remaining = Remaining;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
if (isFixedLength)
|
|
||||||
{
|
|
||||||
size = fixedLength * byteLength;
|
|
||||||
if (size > Remaining)
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = remaining - (remaining & (byteLength - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlySpan<byte> span;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
if (Position < _first.Length)
|
|
||||||
{
|
|
||||||
var firstLength = Math.Min(_first.Length - Position, size);
|
|
||||||
|
|
||||||
// Find terminator
|
|
||||||
index = _first.Slice(Position, firstLength).IndexOfTerminator(byteLength);
|
|
||||||
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
remaining = size - firstLength;
|
|
||||||
// We don't have a terminator, but a fixed size to the end of the first span, so stop there
|
|
||||||
if (remaining <= 0)
|
|
||||||
{
|
|
||||||
index = firstLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index = _second[..remaining].IndexOfTerminator(byteLength);
|
|
||||||
|
|
||||||
int secondLength = index < 0 ? remaining : index;
|
|
||||||
int length = firstLength + secondLength;
|
|
||||||
|
|
||||||
// Assume no strings should be too long for the stack
|
|
||||||
Span<byte> bytes = stackalloc byte[length];
|
|
||||||
_first[Position..].CopyTo(bytes);
|
|
||||||
_second[..secondLength].CopyTo(bytes[firstLength..]);
|
|
||||||
|
|
||||||
Position += length + (index >= 0 ? byteLength : 0);
|
|
||||||
return TextEncoding.GetString(bytes, encoding, safeString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span = _first.Slice(Position, index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = Math.Min(remaining, size);
|
|
||||||
span = _second.Slice( Position - _first.Length, size);
|
|
||||||
index = span.IndexOfTerminator(byteLength);
|
|
||||||
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
span = span[..index];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = size;
|
index = _second[..remaining].IndexOfTerminator(byteLength);
|
||||||
|
|
||||||
|
int secondLength = index < 0 ? remaining : index;
|
||||||
|
int length = firstLength + secondLength;
|
||||||
|
|
||||||
|
// Assume no strings should be too long for the stack
|
||||||
|
Span<byte> bytes = stackalloc byte[length];
|
||||||
|
_first[Position..].CopyTo(bytes);
|
||||||
|
_second[..secondLength].CopyTo(bytes[firstLength..]);
|
||||||
|
|
||||||
|
Position += length + (index >= 0 ? byteLength : 0);
|
||||||
|
return TextEncoding.GetString(bytes, encoding, safeString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Position += isFixedLength ? size : index + byteLength;
|
span = _first.Slice(Position, index);
|
||||||
return TextEncoding.GetString(span, encoding, safeString);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUniSafe(int fixedLength) => ReadString(TextEncoding.UnicodeLE, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUniSafe() => ReadString(TextEncoding.UnicodeLE, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUni(int fixedLength) => ReadString(TextEncoding.UnicodeLE, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUni() => ReadString(TextEncoding.UnicodeLE);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUniSafe(int fixedLength) => ReadString(TextEncoding.Unicode, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUniSafe() => ReadString(TextEncoding.Unicode, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUni(int fixedLength) => ReadString(TextEncoding.Unicode, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUni() => ReadString(TextEncoding.Unicode);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8Safe(int fixedLength) => ReadString(TextEncoding.UTF8, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8Safe() => ReadString(TextEncoding.UTF8, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8() => ReadString(TextEncoding.UTF8);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAsciiSafe(int fixedLength) => ReadString(Encoding.ASCII, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAsciiSafe() => ReadString(Encoding.ASCII, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAscii(int fixedLength) => ReadString(Encoding.ASCII, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAscii() => ReadString(Encoding.ASCII);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int Seek(int offset, SeekOrigin origin) =>
|
|
||||||
Position = origin switch
|
|
||||||
{
|
|
||||||
SeekOrigin.Begin => offset,
|
|
||||||
SeekOrigin.End => Length + offset,
|
|
||||||
_ => Position + offset // Current
|
|
||||||
};
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Read(Span<byte> bytes)
|
|
||||||
{
|
{
|
||||||
if (bytes.Length < Length)
|
size = Math.Min(remaining, size);
|
||||||
{
|
span = _second.Slice( Position - _first.Length, size);
|
||||||
throw new ArgumentOutOfRangeException(nameof(bytes));
|
index = span.IndexOfTerminator(byteLength);
|
||||||
}
|
|
||||||
|
|
||||||
if (_first.Length > 0 && !_first.TryCopyTo(bytes))
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
return false;
|
span = span[..index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _second.Length <= 0 || _second.TryCopyTo(bytes[_first.Length..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Position += isFixedLength ? size : index + byteLength;
|
||||||
|
return TextEncoding.GetString(span, encoding, safeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUniSafe(int fixedLength) => ReadString(TextEncoding.UnicodeLE, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUniSafe() => ReadString(TextEncoding.UnicodeLE, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUni(int fixedLength) => ReadString(TextEncoding.UnicodeLE, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUni() => ReadString(TextEncoding.UnicodeLE);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUniSafe(int fixedLength) => ReadString(TextEncoding.Unicode, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUniSafe() => ReadString(TextEncoding.Unicode, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUni(int fixedLength) => ReadString(TextEncoding.Unicode, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUni() => ReadString(TextEncoding.Unicode);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8Safe(int fixedLength) => ReadString(TextEncoding.UTF8, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8Safe() => ReadString(TextEncoding.UTF8, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8() => ReadString(TextEncoding.UTF8);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAsciiSafe(int fixedLength) => ReadString(Encoding.ASCII, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAsciiSafe() => ReadString(Encoding.ASCII, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAscii(int fixedLength) => ReadString(Encoding.ASCII, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAscii() => ReadString(Encoding.ASCII);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Seek(int offset, SeekOrigin origin) =>
|
||||||
|
Position = origin switch
|
||||||
|
{
|
||||||
|
SeekOrigin.Begin => offset,
|
||||||
|
SeekOrigin.End => Length + offset,
|
||||||
|
_ => Position + offset // Current
|
||||||
|
};
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Read(Span<byte> bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length < Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_first.Length > 0 && !_first.TryCopyTo(bytes))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _second.Length <= 0 || _second.TryCopyTo(bytes[_first.Length..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: SpanReader.cs *
|
* File: SpanReader.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -21,273 +21,272 @@ using System.Text;
|
||||||
using Server;
|
using Server;
|
||||||
using Server.Text;
|
using Server.Text;
|
||||||
|
|
||||||
namespace System.Buffers
|
namespace System.Buffers;
|
||||||
|
|
||||||
|
public ref struct SpanReader
|
||||||
{
|
{
|
||||||
public ref struct SpanReader
|
private readonly ReadOnlySpan<byte> _buffer;
|
||||||
|
|
||||||
|
public int Length { get; }
|
||||||
|
public int Position { get; private set; }
|
||||||
|
public int Remaining => Length - Position;
|
||||||
|
|
||||||
|
public SpanReader(ReadOnlySpan<byte> span)
|
||||||
{
|
{
|
||||||
private readonly ReadOnlySpan<byte> _buffer;
|
_buffer = span;
|
||||||
|
Position = 0;
|
||||||
|
Length = span.Length;
|
||||||
|
}
|
||||||
|
|
||||||
public int Length { get; }
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int Position { get; private set; }
|
public byte ReadByte()
|
||||||
public int Remaining => Length - Position;
|
{
|
||||||
|
if (Position >= Length)
|
||||||
public SpanReader(ReadOnlySpan<byte> span)
|
|
||||||
{
|
{
|
||||||
_buffer = span;
|
throw new OutOfMemoryException();
|
||||||
Position = 0;
|
|
||||||
Length = span.Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
return _buffer[Position++];
|
||||||
public byte ReadByte()
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool ReadBoolean() => ReadByte() > 0;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public sbyte ReadSByte() => (sbyte)ReadByte();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public short ReadInt16()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt16BigEndian(_buffer[Position..], out var value))
|
||||||
{
|
{
|
||||||
if (Position >= Length)
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public short ReadInt16LE()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt16LittleEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ushort ReadUInt16()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt16BigEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ushort ReadUInt16LE()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt16LittleEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int ReadInt32()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt32BigEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public uint ReadUInt32()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt32BigEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public uint ReadUInt32LE()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt32LittleEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public long ReadInt64()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadInt64BigEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ulong ReadUInt64()
|
||||||
|
{
|
||||||
|
if (!BinaryPrimitives.TryReadUInt64BigEndian(_buffer[Position..], out var value))
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1)
|
||||||
|
{
|
||||||
|
int byteLength = encoding.GetByteLengthForEncoding();
|
||||||
|
|
||||||
|
bool isFixedLength = fixedLength > -1;
|
||||||
|
|
||||||
|
var remaining = Remaining;
|
||||||
|
int size;
|
||||||
|
if (isFixedLength)
|
||||||
|
{
|
||||||
|
size = fixedLength * byteLength;
|
||||||
|
if (size > Remaining)
|
||||||
{
|
{
|
||||||
throw new OutOfMemoryException();
|
throw new OutOfMemoryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _buffer[Position++];
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool ReadBoolean() => ReadByte() > 0;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public sbyte ReadSByte() => (sbyte)ReadByte();
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public short ReadInt16()
|
|
||||||
{
|
{
|
||||||
if (!BinaryPrimitives.TryReadInt16BigEndian(_buffer[Position..], out var value))
|
// In case the remaining is not evenly divisible
|
||||||
{
|
size = remaining - (remaining & (byteLength - 1));
|
||||||
throw new OutOfMemoryException();
|
int index = _buffer.Slice(Position, size).IndexOfTerminator(byteLength);
|
||||||
}
|
size = index < 0 ? size : index;
|
||||||
|
|
||||||
Position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
var span = _buffer.Slice(Position, size);
|
||||||
public short ReadInt16LE()
|
Position += size;
|
||||||
|
return TextEncoding.GetString(span, encoding, safeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUniSafe(int fixedLength) => ReadString(TextEncoding.UnicodeLE, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUniSafe() => ReadString(TextEncoding.UnicodeLE, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUni(int fixedLength) => ReadString(TextEncoding.UnicodeLE, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadLittleUni() => ReadString(TextEncoding.UnicodeLE);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUniSafe(int fixedLength) => ReadString(TextEncoding.Unicode, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUniSafe() => ReadString(TextEncoding.Unicode, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUni(int fixedLength) => ReadString(TextEncoding.Unicode, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadBigUni() => ReadString(TextEncoding.Unicode);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8Safe(int fixedLength) => ReadString(TextEncoding.UTF8, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8Safe() => ReadString(TextEncoding.UTF8, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadUTF8() => ReadString(TextEncoding.UTF8);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAsciiSafe(int fixedLength) => ReadString(Encoding.ASCII, true, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAsciiSafe() => ReadString(Encoding.ASCII, true);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAscii(int fixedLength) => ReadString(Encoding.ASCII, false, fixedLength);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public string ReadAscii() => ReadString(Encoding.ASCII);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Seek(int offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.End || offset <= 0,
|
||||||
|
"Attempting to seek to a position beyond capacity using SeekOrigin.End"
|
||||||
|
);
|
||||||
|
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.End || offset >= -_buffer.Length,
|
||||||
|
"Attempting to seek to a negative position using SeekOrigin.End"
|
||||||
|
);
|
||||||
|
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.Begin || offset >= 0,
|
||||||
|
"Attempting to seek to a negative position using SeekOrigin.Begin"
|
||||||
|
);
|
||||||
|
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.Begin || offset <= _buffer.Length,
|
||||||
|
"Attempting to seek to a position beyond the capacity using SeekOrigin.Begin"
|
||||||
|
);
|
||||||
|
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.Current || Position + offset >= 0,
|
||||||
|
"Attempting to seek to a negative position using SeekOrigin.Current"
|
||||||
|
);
|
||||||
|
|
||||||
|
Debug.Assert(
|
||||||
|
origin != SeekOrigin.Current || Position + offset <= _buffer.Length,
|
||||||
|
"Attempting to seek to a position beyond the capacity using SeekOrigin.Current"
|
||||||
|
);
|
||||||
|
|
||||||
|
return Position = Math.Max(0, origin switch
|
||||||
{
|
{
|
||||||
if (!BinaryPrimitives.TryReadInt16LittleEndian(_buffer[Position..], out var value))
|
SeekOrigin.Current => Position + offset,
|
||||||
{
|
SeekOrigin.End => _buffer.Length + offset,
|
||||||
throw new OutOfMemoryException();
|
_ => offset // Begin
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Position += 2;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
return value;
|
public bool Read(Span<byte> bytes)
|
||||||
}
|
{
|
||||||
|
if (bytes.Length < Length)
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ushort ReadUInt16()
|
|
||||||
{
|
{
|
||||||
if (!BinaryPrimitives.TryReadUInt16BigEndian(_buffer[Position..], out var value))
|
throw new ArgumentOutOfRangeException(nameof(bytes));
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
return _buffer.TryCopyTo(bytes);
|
||||||
public ushort ReadUInt16LE()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt16LittleEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int ReadInt32()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadInt32BigEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public uint ReadUInt32()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt32BigEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public uint ReadUInt32LE()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt32LittleEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public long ReadInt64()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadInt64BigEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ulong ReadUInt64()
|
|
||||||
{
|
|
||||||
if (!BinaryPrimitives.TryReadUInt64BigEndian(_buffer[Position..], out var value))
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1)
|
|
||||||
{
|
|
||||||
int byteLength = encoding.GetByteLengthForEncoding();
|
|
||||||
|
|
||||||
bool isFixedLength = fixedLength > -1;
|
|
||||||
|
|
||||||
var remaining = Remaining;
|
|
||||||
int size;
|
|
||||||
if (isFixedLength)
|
|
||||||
{
|
|
||||||
size = fixedLength * byteLength;
|
|
||||||
if (size > Remaining)
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// In case the remaining is not evenly divisible
|
|
||||||
size = remaining - (remaining & (byteLength - 1));
|
|
||||||
int index = _buffer.Slice(Position, size).IndexOfTerminator(byteLength);
|
|
||||||
size = index < 0 ? size : index;
|
|
||||||
}
|
|
||||||
|
|
||||||
var span = _buffer.Slice(Position, size);
|
|
||||||
Position += size;
|
|
||||||
return TextEncoding.GetString(span, encoding, safeString);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUniSafe(int fixedLength) => ReadString(TextEncoding.UnicodeLE, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUniSafe() => ReadString(TextEncoding.UnicodeLE, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUni(int fixedLength) => ReadString(TextEncoding.UnicodeLE, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadLittleUni() => ReadString(TextEncoding.UnicodeLE);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUniSafe(int fixedLength) => ReadString(TextEncoding.Unicode, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUniSafe() => ReadString(TextEncoding.Unicode, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUni(int fixedLength) => ReadString(TextEncoding.Unicode, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadBigUni() => ReadString(TextEncoding.Unicode);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8Safe(int fixedLength) => ReadString(TextEncoding.UTF8, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8Safe() => ReadString(TextEncoding.UTF8, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadUTF8() => ReadString(TextEncoding.UTF8);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAsciiSafe(int fixedLength) => ReadString(Encoding.ASCII, true, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAsciiSafe() => ReadString(Encoding.ASCII, true);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAscii(int fixedLength) => ReadString(Encoding.ASCII, false, fixedLength);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string ReadAscii() => ReadString(Encoding.ASCII);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int Seek(int offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.End || offset <= 0,
|
|
||||||
"Attempting to seek to a position beyond capacity using SeekOrigin.End"
|
|
||||||
);
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.End || offset >= -_buffer.Length,
|
|
||||||
"Attempting to seek to a negative position using SeekOrigin.End"
|
|
||||||
);
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.Begin || offset >= 0,
|
|
||||||
"Attempting to seek to a negative position using SeekOrigin.Begin"
|
|
||||||
);
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.Begin || offset <= _buffer.Length,
|
|
||||||
"Attempting to seek to a position beyond the capacity using SeekOrigin.Begin"
|
|
||||||
);
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.Current || Position + offset >= 0,
|
|
||||||
"Attempting to seek to a negative position using SeekOrigin.Current"
|
|
||||||
);
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
origin != SeekOrigin.Current || Position + offset <= _buffer.Length,
|
|
||||||
"Attempting to seek to a position beyond the capacity using SeekOrigin.Current"
|
|
||||||
);
|
|
||||||
|
|
||||||
return Position = Math.Max(0, origin switch
|
|
||||||
{
|
|
||||||
SeekOrigin.Current => Position + offset,
|
|
||||||
SeekOrigin.End => _buffer.Length + offset,
|
|
||||||
_ => offset // Begin
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Read(Span<byte> bytes)
|
|
||||||
{
|
|
||||||
if (bytes.Length < Length)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buffer.TryCopyTo(bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: CityInfo.cs *
|
* File: CityInfo.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -13,71 +13,70 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public sealed class CityInfo
|
||||||
{
|
{
|
||||||
public sealed class CityInfo
|
private Point3D m_Location;
|
||||||
|
|
||||||
|
public CityInfo(string city, string building, int description, int x, int y, int z, Map m)
|
||||||
{
|
{
|
||||||
private Point3D m_Location;
|
City = city;
|
||||||
|
Building = building;
|
||||||
public CityInfo(string city, string building, int description, int x, int y, int z, Map m)
|
Description = description;
|
||||||
{
|
Location = new Point3D(x, y, z);
|
||||||
City = city;
|
Map = m;
|
||||||
Building = building;
|
|
||||||
Description = description;
|
|
||||||
Location = new Point3D(x, y, z);
|
|
||||||
Map = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CityInfo(string city, string building, int x, int y, int z, Map m) : this(city, building, 0, x, y, z, m)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public CityInfo(string city, string building, int description, int x, int y, int z) : this(
|
|
||||||
city,
|
|
||||||
building,
|
|
||||||
description,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
z,
|
|
||||||
Map.Trammel
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public CityInfo(string city, string building, int x, int y, int z) : this(city, building, 0, x, y, z, Map.Trammel)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string City { get; set; }
|
|
||||||
|
|
||||||
public string Building { get; set; }
|
|
||||||
|
|
||||||
public int Description { get; set; }
|
|
||||||
|
|
||||||
public int X
|
|
||||||
{
|
|
||||||
get => m_Location.X;
|
|
||||||
set => m_Location.X = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Y
|
|
||||||
{
|
|
||||||
get => m_Location.Y;
|
|
||||||
set => m_Location.Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Z
|
|
||||||
{
|
|
||||||
get => m_Location.Z;
|
|
||||||
set => m_Location.Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point3D Location
|
|
||||||
{
|
|
||||||
get => m_Location;
|
|
||||||
set => m_Location = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map Map { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CityInfo(string city, string building, int x, int y, int z, Map m) : this(city, building, 0, x, y, z, m)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public CityInfo(string city, string building, int description, int x, int y, int z) : this(
|
||||||
|
city,
|
||||||
|
building,
|
||||||
|
description,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
Map.Trammel
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public CityInfo(string city, string building, int x, int y, int z) : this(city, building, 0, x, y, z, Map.Trammel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string City { get; set; }
|
||||||
|
|
||||||
|
public string Building { get; set; }
|
||||||
|
|
||||||
|
public int Description { get; set; }
|
||||||
|
|
||||||
|
public int X
|
||||||
|
{
|
||||||
|
get => m_Location.X;
|
||||||
|
set => m_Location.X = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Y
|
||||||
|
{
|
||||||
|
get => m_Location.Y;
|
||||||
|
set => m_Location.Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Z
|
||||||
|
{
|
||||||
|
get => m_Location.Z;
|
||||||
|
set => m_Location.Z = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D Location
|
||||||
|
{
|
||||||
|
get => m_Location;
|
||||||
|
set => m_Location = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map Map { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ArrayEnumerator.cs *
|
* File: ArrayEnumerator.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,63 +17,62 @@ using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server.Collections
|
namespace Server.Collections;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-thread safe, non-guarded enumerator for classes that have internal arrays.
|
||||||
|
/// Recommended to copy this and use it as a nested struct.
|
||||||
|
/// Recommend adding version checking to properly guard against modification during enumeration.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public struct ArrayEnumerator<T> : IEnumerator<T>
|
||||||
{
|
{
|
||||||
/// <summary>
|
private readonly T[] _array;
|
||||||
/// Non-thread safe, non-guarded enumerator for classes that have internal arrays.
|
private int _index;
|
||||||
/// Recommended to copy this and use it as a nested struct.
|
private T? _current;
|
||||||
/// Recommend adding version checking to properly guard against modification during enumeration.
|
|
||||||
/// </summary>
|
public ArrayEnumerator(T[] array)
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public struct ArrayEnumerator<T> : IEnumerator<T>
|
|
||||||
{
|
{
|
||||||
private readonly T[] _array;
|
_array = array;
|
||||||
private int _index;
|
_index = 0;
|
||||||
private T? _current;
|
_current = default;
|
||||||
|
}
|
||||||
|
|
||||||
public ArrayEnumerator(T[] array)
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
T[] localList = _array;
|
||||||
|
|
||||||
|
if ((uint)_index < (uint)localList.Length)
|
||||||
{
|
{
|
||||||
_array = array;
|
_current = _array[_index++];
|
||||||
_index = 0;
|
return true;
|
||||||
_current = default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
return false;
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
public T? Current => _current!;
|
||||||
{
|
|
||||||
T[] localList = _array;
|
|
||||||
|
|
||||||
if ((uint)_index < (uint)localList.Length)
|
object IEnumerator.Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_index == 0 || _index == _array.Length + 1)
|
||||||
{
|
{
|
||||||
_current = _array[_index++];
|
throw new InvalidOperationException(nameof(_index));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return _current;
|
||||||
}
|
|
||||||
|
|
||||||
public T? Current => _current!;
|
|
||||||
|
|
||||||
object IEnumerator.Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_index == 0 || _index == _array.Length + 1)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(nameof(_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IEnumerator.Reset()
|
|
||||||
{
|
|
||||||
_index = 0;
|
|
||||||
_current = default;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IEnumerator.Reset()
|
||||||
|
{
|
||||||
|
_index = 0;
|
||||||
|
_current = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: CollectionHelpers.cs *
|
* File: CollectionHelpers.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,17 +16,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server.Collections
|
namespace Server.Collections;
|
||||||
|
|
||||||
|
public static class CollectionHelpers
|
||||||
{
|
{
|
||||||
public static class CollectionHelpers
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AddNotNull<T>(this ICollection<T> coll, T t) where T : class
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
if (t != null)
|
||||||
public static void AddNotNull<T>(this ICollection<T> coll, T t) where T : class
|
|
||||||
{
|
{
|
||||||
if (t != null)
|
coll.Add(t);
|
||||||
{
|
|
||||||
coll.Add(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: CollectionThrowStrings.cs *
|
* File: CollectionThrowStrings.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -6,120 +6,119 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Microsoft.Collections.Extensions
|
namespace Microsoft.Collections.Extensions;
|
||||||
|
|
||||||
|
internal static class HashHelpers
|
||||||
{
|
{
|
||||||
internal static class HashHelpers
|
|
||||||
|
// must never be written to
|
||||||
|
internal static readonly int[] SizeOneIntArray = new int[1];
|
||||||
|
|
||||||
|
// This is the maximum prime smaller than Array.MaxArrayLength
|
||||||
|
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
|
||||||
|
|
||||||
|
public const int HashPrime = 101;
|
||||||
|
|
||||||
|
// Table of prime numbers to use as hash table sizes.
|
||||||
|
// A typical resize algorithm would pick the smallest prime number in this array
|
||||||
|
// that is larger than twice the previous capacity.
|
||||||
|
// Suppose our Hashtable currently has capacity x and enough elements are added
|
||||||
|
// such that a resize needs to occur. Resizing first computes 2x then finds the
|
||||||
|
// first prime in the table greater than 2x, i.e. if primes are ordered
|
||||||
|
// p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
|
||||||
|
// Doubling is important for preserving the asymptotic complexity of the
|
||||||
|
// hashtable operations such as add. Having a prime guarantees that double
|
||||||
|
// hashing does not lead to infinite loops. IE, your hash function will be
|
||||||
|
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
|
||||||
|
// We prefer the low computation costs of higher prime numbers over the increased
|
||||||
|
// memory allocation of a fixed prime number i.e. when right sizing a HashSet.
|
||||||
|
public static readonly int[] primes = {
|
||||||
|
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
||||||
|
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
||||||
|
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
||||||
|
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
||||||
|
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 };
|
||||||
|
|
||||||
|
public static bool IsPrime(int candidate)
|
||||||
{
|
{
|
||||||
|
if ((candidate & 1) != 0)
|
||||||
// must never be written to
|
|
||||||
internal static readonly int[] SizeOneIntArray = new int[1];
|
|
||||||
|
|
||||||
// This is the maximum prime smaller than Array.MaxArrayLength
|
|
||||||
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
|
|
||||||
|
|
||||||
public const int HashPrime = 101;
|
|
||||||
|
|
||||||
// Table of prime numbers to use as hash table sizes.
|
|
||||||
// A typical resize algorithm would pick the smallest prime number in this array
|
|
||||||
// that is larger than twice the previous capacity.
|
|
||||||
// Suppose our Hashtable currently has capacity x and enough elements are added
|
|
||||||
// such that a resize needs to occur. Resizing first computes 2x then finds the
|
|
||||||
// first prime in the table greater than 2x, i.e. if primes are ordered
|
|
||||||
// p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
|
|
||||||
// Doubling is important for preserving the asymptotic complexity of the
|
|
||||||
// hashtable operations such as add. Having a prime guarantees that double
|
|
||||||
// hashing does not lead to infinite loops. IE, your hash function will be
|
|
||||||
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
|
|
||||||
// We prefer the low computation costs of higher prime numbers over the increased
|
|
||||||
// memory allocation of a fixed prime number i.e. when right sizing a HashSet.
|
|
||||||
public static readonly int[] primes = {
|
|
||||||
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
|
||||||
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
|
||||||
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
|
||||||
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
|
||||||
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 };
|
|
||||||
|
|
||||||
public static bool IsPrime(int candidate)
|
|
||||||
{
|
{
|
||||||
if ((candidate & 1) != 0)
|
int limit = (int)Math.Sqrt(candidate);
|
||||||
|
for (int divisor = 3; divisor <= limit; divisor += 2)
|
||||||
{
|
{
|
||||||
int limit = (int)Math.Sqrt(candidate);
|
if (candidate % divisor == 0)
|
||||||
for (int divisor = 3; divisor <= limit; divisor += 2)
|
|
||||||
{
|
{
|
||||||
if (candidate % divisor == 0)
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return candidate == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetPrime(int min)
|
|
||||||
{
|
|
||||||
if (min < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table.");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < primes.Length; i++)
|
|
||||||
{
|
|
||||||
int prime = primes[i];
|
|
||||||
if (prime >= min)
|
|
||||||
{
|
|
||||||
return prime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
//outside of our predefined table.
|
|
||||||
//compute the hard way.
|
|
||||||
for (int i = min | 1; i < int.MaxValue; i += 2)
|
|
||||||
{
|
|
||||||
if (IsPrime(i) && (i - 1) % HashPrime != 0)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
}
|
||||||
|
return candidate == 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns size of hashtable to grow to.
|
public static int GetPrime(int min)
|
||||||
public static int ExpandPrime(int oldSize)
|
{
|
||||||
|
if (min < 0)
|
||||||
{
|
{
|
||||||
int newSize = 2 * oldSize;
|
throw new ArgumentException("Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table.");
|
||||||
|
|
||||||
// Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow.
|
|
||||||
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
|
|
||||||
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
|
|
||||||
{
|
|
||||||
Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
|
|
||||||
return MaxPrimeArrayLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetPrime(newSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns approximate reciprocal of the divisor: ceil(2**64 / divisor).</summary>
|
for (int i = 0; i < primes.Length; i++)
|
||||||
/// <remarks>This should only be used on 64-bit.</remarks>
|
|
||||||
public static ulong GetFastModMultiplier(uint divisor) =>
|
|
||||||
ulong.MaxValue / divisor + 1;
|
|
||||||
|
|
||||||
/// <summary>Performs a mod operation using the multiplier pre-computed with <see cref="GetFastModMultiplier"/>.</summary>
|
|
||||||
/// <remarks>This should only be used on 64-bit.</remarks>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint FastMod(uint value, uint divisor, ulong multiplier)
|
|
||||||
{
|
{
|
||||||
// We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406),
|
int prime = primes[i];
|
||||||
// which allows to avoid the long multiplication if the divisor is less than 2**31.
|
if (prime >= min)
|
||||||
Debug.Assert(divisor <= int.MaxValue);
|
{
|
||||||
|
return prime;
|
||||||
// This is equivalent of (uint)Math.BigMul(multiplier * value, divisor, out _). This version
|
}
|
||||||
// is faster than BigMul currently because we only need the high bits.
|
|
||||||
uint highbits = (uint)(((((multiplier * value) >> 32) + 1) * divisor) >> 32);
|
|
||||||
|
|
||||||
Debug.Assert(highbits == value % divisor);
|
|
||||||
return highbits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//outside of our predefined table.
|
||||||
|
//compute the hard way.
|
||||||
|
for (int i = min | 1; i < int.MaxValue; i += 2)
|
||||||
|
{
|
||||||
|
if (IsPrime(i) && (i - 1) % HashPrime != 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns size of hashtable to grow to.
|
||||||
|
public static int ExpandPrime(int oldSize)
|
||||||
|
{
|
||||||
|
int newSize = 2 * oldSize;
|
||||||
|
|
||||||
|
// Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow.
|
||||||
|
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
|
||||||
|
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
|
||||||
|
{
|
||||||
|
Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
|
||||||
|
return MaxPrimeArrayLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPrime(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns approximate reciprocal of the divisor: ceil(2**64 / divisor).</summary>
|
||||||
|
/// <remarks>This should only be used on 64-bit.</remarks>
|
||||||
|
public static ulong GetFastModMultiplier(uint divisor) =>
|
||||||
|
ulong.MaxValue / divisor + 1;
|
||||||
|
|
||||||
|
/// <summary>Performs a mod operation using the multiplier pre-computed with <see cref="GetFastModMultiplier"/>.</summary>
|
||||||
|
/// <remarks>This should only be used on 64-bit.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint FastMod(uint value, uint divisor, ulong multiplier)
|
||||||
|
{
|
||||||
|
// We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406),
|
||||||
|
// which allows to avoid the long multiplication if the divisor is less than 2**31.
|
||||||
|
Debug.Assert(divisor <= int.MaxValue);
|
||||||
|
|
||||||
|
// This is equivalent of (uint)Math.BigMul(multiplier * value, divisor, out _). This version
|
||||||
|
// is faster than BigMul currently because we only need the high bits.
|
||||||
|
uint highbits = (uint)(((((multiplier * value) >> 32) + 1) * divisor) >> 32);
|
||||||
|
|
||||||
|
Debug.Assert(highbits == value % divisor);
|
||||||
|
return highbits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: PooledOrderedHashSet.cs *
|
* File: PooledOrderedHashSet.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -2,240 +2,230 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public delegate void CommandEventHandler(CommandEventArgs e);
|
||||||
|
|
||||||
|
public class CommandEventArgs
|
||||||
{
|
{
|
||||||
public delegate void CommandEventHandler(CommandEventArgs e);
|
public CommandEventArgs(Mobile mobile, string command, string argString, string[] arguments)
|
||||||
|
|
||||||
public class CommandEventArgs
|
|
||||||
{
|
{
|
||||||
public CommandEventArgs(Mobile mobile, string command, string argString, string[] arguments)
|
Mobile = mobile;
|
||||||
{
|
Command = command;
|
||||||
Mobile = mobile;
|
ArgString = argString;
|
||||||
Command = command;
|
Arguments = arguments;
|
||||||
ArgString = argString;
|
|
||||||
Arguments = arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mobile Mobile { get; }
|
|
||||||
|
|
||||||
public string Command { get; }
|
|
||||||
|
|
||||||
public string ArgString { get; }
|
|
||||||
|
|
||||||
public string[] Arguments { get; }
|
|
||||||
|
|
||||||
public int Length => Arguments.Length;
|
|
||||||
|
|
||||||
public string GetString(int index) => index < 0 || index >= Arguments.Length ? "" : Arguments[index];
|
|
||||||
|
|
||||||
public int GetInt32(int index) => index < 0 || index >= Arguments.Length ? 0 : Utility.ToInt32(Arguments[index]);
|
|
||||||
|
|
||||||
public uint GetUInt32(int index) =>
|
|
||||||
index < 0 || index >= Arguments.Length ? 0 : Utility.ToUInt32(Arguments[index]);
|
|
||||||
|
|
||||||
public bool GetBoolean(int index) => index >= 0 && index < Arguments.Length && Utility.ToBoolean(Arguments[index]);
|
|
||||||
|
|
||||||
public double GetDouble(int index) =>
|
|
||||||
index < 0 || index >= Arguments.Length ? 0.0 : Utility.ToDouble(Arguments[index]);
|
|
||||||
|
|
||||||
public TimeSpan GetTimeSpan(int index) =>
|
|
||||||
index < 0 || index >= Arguments.Length ? TimeSpan.Zero : Utility.ToTimeSpan(Arguments[index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public Mobile Mobile { get; }
|
||||||
|
|
||||||
|
public string Command { get; }
|
||||||
|
|
||||||
|
public string ArgString { get; }
|
||||||
|
|
||||||
|
public string[] Arguments { get; }
|
||||||
|
|
||||||
|
public int Length => Arguments.Length;
|
||||||
|
|
||||||
|
public string GetString(int index) => index < 0 || index >= Arguments.Length ? "" : Arguments[index];
|
||||||
|
|
||||||
|
public int GetInt32(int index) => index < 0 || index >= Arguments.Length ? 0 : Utility.ToInt32(Arguments[index]);
|
||||||
|
|
||||||
|
public uint GetUInt32(int index) =>
|
||||||
|
index < 0 || index >= Arguments.Length ? 0 : Utility.ToUInt32(Arguments[index]);
|
||||||
|
|
||||||
|
public bool GetBoolean(int index) => index >= 0 && index < Arguments.Length && Utility.ToBoolean(Arguments[index]);
|
||||||
|
|
||||||
|
public double GetDouble(int index) =>
|
||||||
|
index < 0 || index >= Arguments.Length ? 0.0 : Utility.ToDouble(Arguments[index]);
|
||||||
|
|
||||||
|
public TimeSpan GetTimeSpan(int index) =>
|
||||||
|
index < 0 || index >= Arguments.Length ? TimeSpan.Zero : Utility.ToTimeSpan(Arguments[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<CommandEventArgs> Command;
|
||||||
|
public static void InvokeCommand(CommandEventArgs e) => Command?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandEntry : IComparable<CommandEntry>
|
||||||
|
{
|
||||||
|
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)
|
||||||
{
|
{
|
||||||
public static event Action<CommandEventArgs> Command;
|
Command = command;
|
||||||
public static void InvokeCommand(CommandEventArgs e) => Command?.Invoke(e);
|
Handler = handler;
|
||||||
|
AccessLevel = accessLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CommandEntry : IComparable<CommandEntry>
|
public string Command { get; }
|
||||||
|
|
||||||
|
public CommandEventHandler Handler { get; }
|
||||||
|
|
||||||
|
public AccessLevel AccessLevel { get; }
|
||||||
|
|
||||||
|
public int CompareTo(CommandEntry e) => string.CompareOrdinal(Command, e?.Command);
|
||||||
|
|
||||||
|
public static List<CommandEntry> GetList()
|
||||||
{
|
{
|
||||||
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)
|
var commands = new List<CommandEntry>(CommandSystem.Entries.Values);
|
||||||
|
|
||||||
|
commands.Sort();
|
||||||
|
commands.Reverse();
|
||||||
|
|
||||||
|
for (var i = 0; i < commands.Count; ++i)
|
||||||
{
|
{
|
||||||
Command = command;
|
var e = commands[i];
|
||||||
Handler = handler;
|
|
||||||
AccessLevel = accessLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Command { get; }
|
for (var j = i + 1; j < commands.Count; ++j)
|
||||||
|
|
||||||
public CommandEventHandler Handler { get; }
|
|
||||||
|
|
||||||
public AccessLevel AccessLevel { get; }
|
|
||||||
|
|
||||||
public int CompareTo(CommandEntry e) => string.CompareOrdinal(Command, e?.Command);
|
|
||||||
|
|
||||||
public static List<CommandEntry> GetList()
|
|
||||||
{
|
|
||||||
var commands = new List<CommandEntry>(CommandSystem.Entries.Values);
|
|
||||||
|
|
||||||
commands.Sort();
|
|
||||||
commands.Reverse();
|
|
||||||
|
|
||||||
for (var i = 0; i < commands.Count; ++i)
|
|
||||||
{
|
{
|
||||||
var e = commands[i];
|
var c = commands[j];
|
||||||
|
|
||||||
for (var j = i + 1; j < commands.Count; ++j)
|
if (e.Handler.Method == c.Handler.Method)
|
||||||
{
|
{
|
||||||
var c = commands[j];
|
commands.RemoveAt(j);
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Handler.Method == c.Handler.Method)
|
return commands;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CommandInfo(AccessLevel AccessLevel, string Name, string[] Aliases, string Usage, string Description);
|
||||||
|
|
||||||
|
public class CommandInfoSorter : IComparer<CommandInfo>
|
||||||
|
{
|
||||||
|
public int Compare(CommandInfo a, CommandInfo b)
|
||||||
|
{
|
||||||
|
if (a == null && b == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var v = b?.AccessLevel.CompareTo(a?.AccessLevel) ?? 1;
|
||||||
|
|
||||||
|
return v != 0 ? v : string.CompareOrdinal(a?.Name, b?.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CommandSystem
|
||||||
|
{
|
||||||
|
public static string Prefix { get; set; } = "[";
|
||||||
|
|
||||||
|
public static Dictionary<string, CommandEntry> Entries { get; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static AccessLevel BadCommandIgnoreLevel { get; set; } = AccessLevel.Player;
|
||||||
|
|
||||||
|
public static string[] Split(string value)
|
||||||
|
{
|
||||||
|
var array = value.ToCharArray();
|
||||||
|
var list = new List<string>();
|
||||||
|
|
||||||
|
var start = 0;
|
||||||
|
|
||||||
|
while (start < array.Length)
|
||||||
|
{
|
||||||
|
var c = array[start];
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
++start;
|
||||||
|
var end = start;
|
||||||
|
|
||||||
|
while (end < array.Length)
|
||||||
|
{
|
||||||
|
if (array[end] != '"' || array[end - 1] == '\\')
|
||||||
{
|
{
|
||||||
commands.RemoveAt(j);
|
++end;
|
||||||
--j;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list.Add(value.Substring(start, end - start));
|
||||||
|
|
||||||
|
start = end + 2;
|
||||||
}
|
}
|
||||||
|
else if (c != ' ')
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record CommandInfo(AccessLevel AccessLevel, string Name, string[] Aliases, string Usage, string Description);
|
|
||||||
|
|
||||||
public class CommandInfoSorter : IComparer<CommandInfo>
|
|
||||||
{
|
|
||||||
public int Compare(CommandInfo a, CommandInfo b)
|
|
||||||
{
|
|
||||||
if (a == null && b == null)
|
|
||||||
{
|
{
|
||||||
return 0;
|
var end = start;
|
||||||
}
|
|
||||||
|
|
||||||
var v = b?.AccessLevel.CompareTo(a?.AccessLevel) ?? 1;
|
while (end < array.Length)
|
||||||
|
|
||||||
return v != 0 ? v : string.CompareOrdinal(a?.Name, b?.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CommandSystem
|
|
||||||
{
|
|
||||||
public static string Prefix { get; set; } = "[";
|
|
||||||
|
|
||||||
public static Dictionary<string, CommandEntry> Entries { get; } = new(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
public static AccessLevel BadCommandIgnoreLevel { get; set; } = AccessLevel.Player;
|
|
||||||
|
|
||||||
public static string[] Split(string value)
|
|
||||||
{
|
|
||||||
var array = value.ToCharArray();
|
|
||||||
var list = new List<string>();
|
|
||||||
|
|
||||||
var start = 0;
|
|
||||||
|
|
||||||
while (start < array.Length)
|
|
||||||
{
|
|
||||||
var c = array[start];
|
|
||||||
|
|
||||||
if (c == '"')
|
|
||||||
{
|
{
|
||||||
++start;
|
if (array[end] != ' ')
|
||||||
var end = start;
|
|
||||||
|
|
||||||
while (end < array.Length)
|
|
||||||
{
|
{
|
||||||
if (array[end] != '"' || array[end - 1] == '\\')
|
++end;
|
||||||
{
|
|
||||||
++end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
list.Add(value.Substring(start, end - start));
|
|
||||||
|
|
||||||
start = end + 2;
|
|
||||||
}
|
|
||||||
else if (c != ' ')
|
|
||||||
{
|
|
||||||
var end = start;
|
|
||||||
|
|
||||||
while (end < array.Length)
|
|
||||||
{
|
{
|
||||||
if (array[end] != ' ')
|
break;
|
||||||
{
|
|
||||||
++end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list.Add(value.Substring(start, end - start));
|
|
||||||
|
|
||||||
start = end + 1;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.ToArray();
|
list.Add(value.Substring(start, end - start));
|
||||||
}
|
|
||||||
|
|
||||||
public static void Register(string command, AccessLevel access, CommandEventHandler handler)
|
start = end + 1;
|
||||||
{
|
|
||||||
Entries[command] = new CommandEntry(command, handler, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Handle(Mobile from, string text, MessageType type = MessageType.Regular)
|
|
||||||
{
|
|
||||||
if (!text.StartsWithOrdinal(Prefix) && type != MessageType.Command)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type != MessageType.Command)
|
|
||||||
{
|
|
||||||
text = text[Prefix.Length..];
|
|
||||||
}
|
|
||||||
|
|
||||||
var indexOf = text.IndexOfOrdinal(' ');
|
|
||||||
|
|
||||||
string command;
|
|
||||||
string[] args;
|
|
||||||
string argString;
|
|
||||||
|
|
||||||
if (indexOf >= 0)
|
|
||||||
{
|
|
||||||
argString = text[(indexOf + 1)..];
|
|
||||||
|
|
||||||
command = text[..indexOf];
|
|
||||||
args = Split(argString);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
argString = "";
|
++start;
|
||||||
command = text.ToLower();
|
|
||||||
args = Array.Empty<string>();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Entries.TryGetValue(command, out var entry);
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
if (entry != null)
|
public static void Register(string command, AccessLevel access, CommandEventHandler handler)
|
||||||
|
{
|
||||||
|
Entries[command] = new CommandEntry(command, handler, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Handle(Mobile from, string text, MessageType type = MessageType.Regular)
|
||||||
|
{
|
||||||
|
if (!text.StartsWithOrdinal(Prefix) && type != MessageType.Command)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != MessageType.Command)
|
||||||
|
{
|
||||||
|
text = text[Prefix.Length..];
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexOf = text.IndexOfOrdinal(' ');
|
||||||
|
|
||||||
|
string command;
|
||||||
|
string[] args;
|
||||||
|
string argString;
|
||||||
|
|
||||||
|
if (indexOf >= 0)
|
||||||
|
{
|
||||||
|
argString = text[(indexOf + 1)..];
|
||||||
|
|
||||||
|
command = text[..indexOf];
|
||||||
|
args = Split(argString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argString = "";
|
||||||
|
command = text.ToLower();
|
||||||
|
args = Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Entries.TryGetValue(command, out var entry);
|
||||||
|
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
if (from.AccessLevel >= entry.AccessLevel)
|
||||||
{
|
{
|
||||||
if (from.AccessLevel >= entry.AccessLevel)
|
if (entry.Handler != null)
|
||||||
{
|
{
|
||||||
if (entry.Handler != null)
|
var e = new CommandEventArgs(from, command, argString, args);
|
||||||
{
|
entry.Handler(e);
|
||||||
var e = new CommandEventArgs(from, command, argString, args);
|
EventSink.InvokeCommand(e);
|
||||||
entry.Handler(e);
|
|
||||||
EventSink.InvokeCommand(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
from.SendMessage("You do not have access to that command.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -245,10 +235,19 @@ namespace Server
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
from.SendMessage("That is not a valid command.");
|
from.SendMessage("You do not have access to that command.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
from.SendMessage("That is not a valid command.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: DescendingComparer.cs *
|
* File: DescendingComparer.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,9 +16,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
{
|
|
||||||
public class DescendingComparer<T> : IComparer<T> where T : IComparable<T> {
|
public class DescendingComparer<T> : IComparer<T> where T : IComparable<T> {
|
||||||
public int Compare(T x, T y) => y?.CompareTo(x) ?? 1;
|
public int Compare(T x, T y) => y?.CompareTo(x) ?? 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: LocationComparer.cs *
|
* File: LocationComparer.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,42 +15,41 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class LocationComparer : IComparer<IPoint3D>
|
||||||
{
|
{
|
||||||
public class LocationComparer : IComparer<IPoint3D>
|
private static LocationComparer m_Instance;
|
||||||
|
|
||||||
|
public LocationComparer(IPoint3D relativeTo) => RelativeTo = relativeTo;
|
||||||
|
|
||||||
|
public IPoint3D RelativeTo { get; set; }
|
||||||
|
|
||||||
|
public int Compare(IPoint3D x, IPoint3D y) => GetDistance(x) - GetDistance(y);
|
||||||
|
|
||||||
|
public static LocationComparer GetInstance(IPoint3D relativeTo)
|
||||||
{
|
{
|
||||||
private static LocationComparer m_Instance;
|
if (m_Instance == null)
|
||||||
|
|
||||||
public LocationComparer(IPoint3D relativeTo) => RelativeTo = relativeTo;
|
|
||||||
|
|
||||||
public IPoint3D RelativeTo { get; set; }
|
|
||||||
|
|
||||||
public int Compare(IPoint3D x, IPoint3D y) => GetDistance(x) - GetDistance(y);
|
|
||||||
|
|
||||||
public static LocationComparer GetInstance(IPoint3D relativeTo)
|
|
||||||
{
|
{
|
||||||
if (m_Instance == null)
|
m_Instance = new LocationComparer(relativeTo);
|
||||||
{
|
}
|
||||||
m_Instance = new LocationComparer(relativeTo);
|
else
|
||||||
}
|
{
|
||||||
else
|
m_Instance.RelativeTo = relativeTo;
|
||||||
{
|
|
||||||
m_Instance.RelativeTo = relativeTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetDistance(IPoint3D p)
|
return m_Instance;
|
||||||
{
|
}
|
||||||
var x = RelativeTo.X - p.X;
|
|
||||||
var y = RelativeTo.Y - p.Y;
|
|
||||||
var z = RelativeTo.Z - p.Z;
|
|
||||||
|
|
||||||
x *= 11;
|
private int GetDistance(IPoint3D p)
|
||||||
y *= 11;
|
{
|
||||||
|
var x = RelativeTo.X - p.X;
|
||||||
|
var y = RelativeTo.Y - p.Y;
|
||||||
|
var z = RelativeTo.Z - p.Z;
|
||||||
|
|
||||||
return x * x + y * y + z * z;
|
x *= 11;
|
||||||
}
|
y *= 11;
|
||||||
|
|
||||||
|
return x * x + y * y + z * z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ServerConfiguration.cs *
|
* File: ServerConfiguration.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ServerSettings.cs *
|
* File: ServerSettings.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,23 +17,22 @@ using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class ServerSettings
|
||||||
{
|
{
|
||||||
public class ServerSettings
|
[JsonPropertyName("assemblyDirectories")]
|
||||||
{
|
public List<string> AssemblyDirectories { get; set; } = new();
|
||||||
[JsonPropertyName("assemblyDirectories")]
|
|
||||||
public List<string> AssemblyDirectories { get; set; } = new();
|
|
||||||
|
|
||||||
[JsonPropertyName("dataDirectories")]
|
[JsonPropertyName("dataDirectories")]
|
||||||
public HashSet<string> DataDirectories { get; set; } = new();
|
public HashSet<string> DataDirectories { get; set; } = new();
|
||||||
|
|
||||||
[JsonPropertyName("listeners")]
|
[JsonPropertyName("listeners")]
|
||||||
public List<IPEndPoint> Listeners { get; set; } = new();
|
public List<IPEndPoint> Listeners { get; set; } = new();
|
||||||
|
|
||||||
[JsonPropertyName("expansion")]
|
[JsonPropertyName("expansion")]
|
||||||
public Expansion? Expansion { get; set; }
|
public Expansion? Expansion { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("settings")]
|
[JsonPropertyName("settings")]
|
||||||
public SortedDictionary<string, string> Settings { get; set; } = new();
|
public SortedDictionary<string, string> Settings { get; set; } = new();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,82 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server.ContextMenus
|
namespace Server.ContextMenus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list
|
||||||
|
/// of
|
||||||
|
/// <see cref="ContextMenuEntry">entries</see> that the menu is composed of.
|
||||||
|
/// <seealso cref="ContextMenuEntry" />
|
||||||
|
/// </summary>
|
||||||
|
public class ContextMenu
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list
|
/// Instantiates a new ContextMenu instance.
|
||||||
/// of
|
|
||||||
/// <see cref="ContextMenuEntry">entries</see> that the menu is composed of.
|
|
||||||
/// <seealso cref="ContextMenuEntry" />
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ContextMenu
|
/// <param name="from">
|
||||||
|
/// The <see cref="Mobile" /> who opened this ContextMenu.
|
||||||
|
/// <seealso cref="From" />
|
||||||
|
/// </param>
|
||||||
|
/// <param name="target">
|
||||||
|
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||||
|
/// <seealso cref="Target" />
|
||||||
|
/// </param>
|
||||||
|
public ContextMenu(Mobile from, IEntity target)
|
||||||
{
|
{
|
||||||
/// <summary>
|
From = from;
|
||||||
/// Instantiates a new ContextMenu instance.
|
Target = target;
|
||||||
/// </summary>
|
|
||||||
/// <param name="from">
|
var list = new List<ContextMenuEntry>();
|
||||||
/// The <see cref="Mobile" /> who opened this ContextMenu.
|
|
||||||
/// <seealso cref="From" />
|
if (target is Mobile mobile)
|
||||||
/// </param>
|
|
||||||
/// <param name="target">
|
|
||||||
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
|
||||||
/// <seealso cref="Target" />
|
|
||||||
/// </param>
|
|
||||||
public ContextMenu(Mobile from, IEntity target)
|
|
||||||
{
|
{
|
||||||
From = from;
|
mobile.GetContextMenuEntries(from, list);
|
||||||
Target = target;
|
}
|
||||||
|
else if (target is Item item)
|
||||||
var list = new List<ContextMenuEntry>();
|
{
|
||||||
|
item.GetContextMenuEntries(from, list);
|
||||||
if (target is Mobile mobile)
|
|
||||||
{
|
|
||||||
mobile.GetContextMenuEntries(from, list);
|
|
||||||
}
|
|
||||||
else if (target is Item item)
|
|
||||||
{
|
|
||||||
item.GetContextMenuEntries(from, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
Entries = list.ToArray();
|
|
||||||
|
|
||||||
for (var i = 0; i < Entries.Length; ++i)
|
|
||||||
{
|
|
||||||
Entries[i].Owner = this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
Entries = list.ToArray();
|
||||||
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
|
|
||||||
/// </summary>
|
|
||||||
public Mobile From { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
for (var i = 0; i < Entries.Length; ++i)
|
||||||
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
|
||||||
/// </summary>
|
|
||||||
public IEntity Target { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
|
|
||||||
/// </summary>
|
|
||||||
public ContextMenuEntry[] Entries { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns true if this ContextMenu requires packet version 2.
|
|
||||||
/// </summary>
|
|
||||||
public bool RequiresNewPacket
|
|
||||||
{
|
{
|
||||||
get
|
Entries[i].Owner = this;
|
||||||
{
|
}
|
||||||
for (var i = 0; i < Entries.Length; ++i)
|
}
|
||||||
{
|
|
||||||
var number = Entries[i].Number;
|
|
||||||
if (number is < 3000000 or > 3032767)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
|
||||||
|
/// </summary>
|
||||||
|
public Mobile From { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity Target { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
|
||||||
|
/// </summary>
|
||||||
|
public ContextMenuEntry[] Entries { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if this ContextMenu requires packet version 2.
|
||||||
|
/// </summary>
|
||||||
|
public bool RequiresNewPacket
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Entries.Length; ++i)
|
||||||
|
{
|
||||||
|
var number = Entries[i].Number;
|
||||||
|
if (number is < 3000000 or > 3032767)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,82 @@
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.ContextMenus
|
namespace Server.ContextMenus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
|
||||||
|
/// <seealso cref="ContextMenu" />
|
||||||
|
/// </summary>
|
||||||
|
public class ContextMenuEntry
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
|
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (
|
||||||
/// <seealso cref="ContextMenu" />
|
/// <paramref name="number" />)
|
||||||
|
/// and <see cref="Range">maximum range</see> (<paramref name="range" />).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ContextMenuEntry
|
/// <param name="number">
|
||||||
|
/// The localization number containing the name of this entry.
|
||||||
|
/// <seealso cref="Number" />
|
||||||
|
/// </param>
|
||||||
|
/// <param name="range">
|
||||||
|
/// The maximum range at which this entry can be used.
|
||||||
|
/// <seealso cref="Range" />
|
||||||
|
/// </param>
|
||||||
|
public ContextMenuEntry(int number, int range = -1)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (number <= 0x7FFF) // Legacy code support
|
||||||
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (
|
|
||||||
/// <paramref name="number" />)
|
|
||||||
/// and <see cref="Range">maximum range</see> (<paramref name="range" />).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="number">
|
|
||||||
/// The localization number containing the name of this entry.
|
|
||||||
/// <seealso cref="Number" />
|
|
||||||
/// </param>
|
|
||||||
/// <param name="range">
|
|
||||||
/// The maximum range at which this entry can be used.
|
|
||||||
/// <seealso cref="Range" />
|
|
||||||
/// </param>
|
|
||||||
public ContextMenuEntry(int number, int range = -1)
|
|
||||||
{
|
{
|
||||||
if (number <= 0x7FFF) // Legacy code support
|
Number = 3000000 + number;
|
||||||
{
|
}
|
||||||
Number = 3000000 + number;
|
else
|
||||||
}
|
{
|
||||||
else
|
Number = number;
|
||||||
{
|
|
||||||
Number = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
Range = range;
|
|
||||||
Enabled = true;
|
|
||||||
Color = 0xFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
Range = range;
|
||||||
/// Gets or sets additional <see cref="CMEFlags">flags</see> used in client communication.
|
Enabled = true;
|
||||||
/// </summary>
|
Color = 0xFFFF;
|
||||||
public CMEFlags Flags { get; set; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ContextMenu" /> that owns this entry.
|
/// Gets or sets additional <see cref="CMEFlags">flags</see> used in client communication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ContextMenu Owner { get; set; }
|
public CMEFlags Flags { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the localization number containing the name of this entry.
|
/// Gets or sets the <see cref="ContextMenu" /> that owns this entry.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Number { get; set; }
|
public ContextMenu Owner { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the maximum range at which this entry may be used, in tiles. A value of -1 signifies no maximum range.
|
/// Gets or sets the localization number containing the name of this entry.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Range { get; set; }
|
public int Number { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color for this entry. Format is A1-R5-G5-B5.
|
/// Gets or sets the maximum range at which this entry may be used, in tiles. A value of -1 signifies no maximum range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Color { get; set; }
|
public int Range { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether this entry is enabled. When false, the entry will appear in a gray hue and <see cref="OnClick" />
|
/// Gets or sets the color for this entry. Format is A1-R5-G5-B5.
|
||||||
/// will never be invoked.
|
/// </summary>
|
||||||
/// </summary>
|
public int Color { get; set; }
|
||||||
public bool Enabled { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating if non local use of this entry is permitted.
|
/// Gets or sets whether this entry is enabled. When false, the entry will appear in a gray hue and <see cref="OnClick" />
|
||||||
/// </summary>
|
/// will never be invoked.
|
||||||
public virtual bool NonLocalUse => false;
|
/// </summary>
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overridable. Virtual event invoked when the entry is clicked.
|
/// Gets a value indicating if non local use of this entry is permitted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void OnClick()
|
public virtual bool NonLocalUse => false;
|
||||||
{
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Overridable. Virtual event invoked when the entry is clicked.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnClick()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
namespace Server.ContextMenus
|
namespace Server.ContextMenus;
|
||||||
|
|
||||||
|
public class OpenBackpackEntry : ContextMenuEntry
|
||||||
{
|
{
|
||||||
public class OpenBackpackEntry : ContextMenuEntry
|
private readonly Mobile m_Mobile;
|
||||||
|
|
||||||
|
public OpenBackpackEntry(Mobile m) : base(6145) => m_Mobile = m;
|
||||||
|
|
||||||
|
public override void OnClick()
|
||||||
{
|
{
|
||||||
private readonly Mobile m_Mobile;
|
m_Mobile.Use(m_Mobile.Backpack);
|
||||||
|
|
||||||
public OpenBackpackEntry(Mobile m) : base(6145) => m_Mobile = m;
|
|
||||||
|
|
||||||
public override void OnClick()
|
|
||||||
{
|
|
||||||
m_Mobile.Use(m_Mobile.Backpack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
namespace Server.ContextMenus
|
namespace Server.ContextMenus;
|
||||||
|
|
||||||
|
public class PaperdollEntry : ContextMenuEntry
|
||||||
{
|
{
|
||||||
public class PaperdollEntry : ContextMenuEntry
|
private readonly Mobile m_Mobile;
|
||||||
|
|
||||||
|
public PaperdollEntry(Mobile m) : base(6123, 18) => m_Mobile = m;
|
||||||
|
|
||||||
|
public override void OnClick()
|
||||||
{
|
{
|
||||||
private readonly Mobile m_Mobile;
|
if (m_Mobile.CanPaperdollBeOpenedBy(Owner.From))
|
||||||
|
|
||||||
public PaperdollEntry(Mobile m) : base(6123, 18) => m_Mobile = m;
|
|
||||||
|
|
||||||
public override void OnClick()
|
|
||||||
{
|
{
|
||||||
if (m_Mobile.CanPaperdollBeOpenedBy(Owner.From))
|
m_Mobile.DisplayPaperdollTo(Owner.From);
|
||||||
{
|
|
||||||
m_Mobile.DisplayPaperdollTo(Owner.From);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,78 +3,77 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Server.Diagnostics
|
namespace Server.Diagnostics;
|
||||||
|
|
||||||
|
public abstract class BaseProfile
|
||||||
{
|
{
|
||||||
public abstract class BaseProfile
|
private readonly Stopwatch _stopwatch;
|
||||||
|
|
||||||
|
protected BaseProfile(string name)
|
||||||
{
|
{
|
||||||
private readonly Stopwatch _stopwatch;
|
Name = name;
|
||||||
|
|
||||||
protected BaseProfile(string name)
|
_stopwatch = new Stopwatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public long Count { get; private set; }
|
||||||
|
|
||||||
|
public TimeSpan AverageTime => TimeSpan.FromTicks(TotalTime.Ticks / Math.Max(Count, 1));
|
||||||
|
|
||||||
|
public TimeSpan PeakTime { get; private set; }
|
||||||
|
|
||||||
|
public TimeSpan TotalTime { get; private set; }
|
||||||
|
|
||||||
|
public static void WriteAll<T>(TextWriter op, IEnumerable<T> profiles) where T : BaseProfile
|
||||||
|
{
|
||||||
|
var list = new List<T>(profiles);
|
||||||
|
|
||||||
|
list.Sort((a, b) => -a.TotalTime.CompareTo(b.TotalTime));
|
||||||
|
|
||||||
|
foreach (var prof in list)
|
||||||
{
|
{
|
||||||
Name = name;
|
prof.WriteTo(op);
|
||||||
|
op.WriteLine();
|
||||||
_stopwatch = new Stopwatch();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public virtual void Start()
|
||||||
|
{
|
||||||
public long Count { get; private set; }
|
if (_stopwatch.IsRunning)
|
||||||
|
|
||||||
public TimeSpan AverageTime => TimeSpan.FromTicks(TotalTime.Ticks / Math.Max(Count, 1));
|
|
||||||
|
|
||||||
public TimeSpan PeakTime { get; private set; }
|
|
||||||
|
|
||||||
public TimeSpan TotalTime { get; private set; }
|
|
||||||
|
|
||||||
public static void WriteAll<T>(TextWriter op, IEnumerable<T> profiles) where T : BaseProfile
|
|
||||||
{
|
{
|
||||||
var list = new List<T>(profiles);
|
|
||||||
|
|
||||||
list.Sort((a, b) => -a.TotalTime.CompareTo(b.TotalTime));
|
|
||||||
|
|
||||||
foreach (var prof in list)
|
|
||||||
{
|
|
||||||
prof.WriteTo(op);
|
|
||||||
op.WriteLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Start()
|
|
||||||
{
|
|
||||||
if (_stopwatch.IsRunning)
|
|
||||||
{
|
|
||||||
_stopwatch.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
_stopwatch.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Finish()
|
|
||||||
{
|
|
||||||
var elapsed = _stopwatch.Elapsed;
|
|
||||||
|
|
||||||
TotalTime += elapsed;
|
|
||||||
|
|
||||||
if (elapsed > PeakTime)
|
|
||||||
{
|
|
||||||
PeakTime = elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
Count++;
|
|
||||||
|
|
||||||
_stopwatch.Reset();
|
_stopwatch.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void WriteTo(TextWriter op)
|
_stopwatch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Finish()
|
||||||
|
{
|
||||||
|
var elapsed = _stopwatch.Elapsed;
|
||||||
|
|
||||||
|
TotalTime += elapsed;
|
||||||
|
|
||||||
|
if (elapsed > PeakTime)
|
||||||
{
|
{
|
||||||
op.Write(
|
PeakTime = elapsed;
|
||||||
"{0,-100} {1,12:N0} {2,12:F5} {3,-12:F5} {4,12:F5}",
|
|
||||||
Name,
|
|
||||||
Count,
|
|
||||||
AverageTime.TotalSeconds,
|
|
||||||
PeakTime.TotalSeconds,
|
|
||||||
TotalTime.TotalSeconds
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Count++;
|
||||||
|
|
||||||
|
_stopwatch.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void WriteTo(TextWriter op)
|
||||||
|
{
|
||||||
|
op.Write(
|
||||||
|
"{0,-100} {1,12:N0} {2,12:F5} {3,-12:F5} {4,12:F5}",
|
||||||
|
Name,
|
||||||
|
Count,
|
||||||
|
AverageTime.TotalSeconds,
|
||||||
|
PeakTime.TotalSeconds,
|
||||||
|
TotalTime.TotalSeconds
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,30 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server.Diagnostics
|
namespace Server.Diagnostics;
|
||||||
|
|
||||||
|
public class GumpProfile : BaseProfile
|
||||||
{
|
{
|
||||||
public class GumpProfile : BaseProfile
|
private static readonly Dictionary<Type, GumpProfile> _profiles = new();
|
||||||
|
|
||||||
|
public GumpProfile(Type type) : base(type.FullName)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Type, GumpProfile> _profiles = new();
|
}
|
||||||
|
|
||||||
public GumpProfile(Type type) : base(type.FullName)
|
public static IEnumerable<GumpProfile> Profiles => _profiles.Values;
|
||||||
|
|
||||||
|
public static GumpProfile Acquire(Type type)
|
||||||
|
{
|
||||||
|
if (!Core.Profiling)
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<GumpProfile> Profiles => _profiles.Values;
|
if (!_profiles.TryGetValue(type, out var prof))
|
||||||
|
|
||||||
public static GumpProfile Acquire(Type type)
|
|
||||||
{
|
{
|
||||||
if (!Core.Profiling)
|
_profiles.Add(type, prof = new GumpProfile(type));
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_profiles.TryGetValue(type, out var prof))
|
|
||||||
{
|
|
||||||
_profiles.Add(type, prof = new GumpProfile(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return prof;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return prof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,89 +4,88 @@ using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Server.Diagnostics
|
namespace Server.Diagnostics;
|
||||||
|
|
||||||
|
public abstract class BasePacketProfile : BaseProfile
|
||||||
{
|
{
|
||||||
public abstract class BasePacketProfile : BaseProfile
|
protected BasePacketProfile(string name) : base(name)
|
||||||
{
|
{
|
||||||
protected BasePacketProfile(string name) : base(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public long TotalLength { get; private set; }
|
|
||||||
|
|
||||||
public double AverageLength => (double)TotalLength / Math.Max(Count, 1);
|
|
||||||
|
|
||||||
public void Finish(long length)
|
|
||||||
{
|
|
||||||
Finish();
|
|
||||||
|
|
||||||
TotalLength += length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTo(TextWriter op)
|
|
||||||
{
|
|
||||||
base.WriteTo(op);
|
|
||||||
|
|
||||||
op.Write("\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PacketSendProfile : BasePacketProfile
|
public long TotalLength { get; private set; }
|
||||||
|
|
||||||
|
public double AverageLength => (double)TotalLength / Math.Max(Count, 1);
|
||||||
|
|
||||||
|
public void Finish(long length)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<int, PacketSendProfile> _profiles = new();
|
Finish();
|
||||||
|
|
||||||
private long _created;
|
TotalLength += length;
|
||||||
|
|
||||||
public PacketSendProfile(int packetId) : base($"0x{packetId:X2}")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<PacketSendProfile> Profiles => _profiles.Values;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
|
||||||
public static PacketSendProfile Acquire(int packetId)
|
|
||||||
{
|
|
||||||
if (!_profiles.TryGetValue(packetId, out var prof))
|
|
||||||
{
|
|
||||||
_profiles.Add(packetId, prof = new PacketSendProfile(packetId));
|
|
||||||
}
|
|
||||||
|
|
||||||
return prof;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Increment()
|
|
||||||
{
|
|
||||||
Interlocked.Increment(ref _created);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTo(TextWriter op)
|
|
||||||
{
|
|
||||||
base.WriteTo(op);
|
|
||||||
|
|
||||||
op.Write("\t{0,12:N0}", _created);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PacketReceiveProfile : BasePacketProfile
|
public override void WriteTo(TextWriter op)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<int, PacketReceiveProfile>
|
base.WriteTo(op);
|
||||||
_profiles = new();
|
|
||||||
|
|
||||||
public PacketReceiveProfile(int packetId) : base($"0x{packetId:X2}")
|
op.Write("\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength);
|
||||||
{
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<PacketReceiveProfile> Profiles => _profiles.Values;
|
public class PacketSendProfile : BasePacketProfile
|
||||||
|
{
|
||||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
private static readonly Dictionary<int, PacketSendProfile> _profiles = new();
|
||||||
public static PacketReceiveProfile Acquire(int packetId)
|
|
||||||
{
|
private long _created;
|
||||||
if (!_profiles.TryGetValue(packetId, out var prof))
|
|
||||||
{
|
public PacketSendProfile(int packetId) : base($"0x{packetId:X2}")
|
||||||
_profiles.Add(packetId, prof = new PacketReceiveProfile(packetId));
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
return prof;
|
public static IEnumerable<PacketSendProfile> Profiles => _profiles.Values;
|
||||||
}
|
|
||||||
|
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
|
public static PacketSendProfile Acquire(int packetId)
|
||||||
|
{
|
||||||
|
if (!_profiles.TryGetValue(packetId, out var prof))
|
||||||
|
{
|
||||||
|
_profiles.Add(packetId, prof = new PacketSendProfile(packetId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return prof;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Increment()
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref _created);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteTo(TextWriter op)
|
||||||
|
{
|
||||||
|
base.WriteTo(op);
|
||||||
|
|
||||||
|
op.Write("\t{0,12:N0}", _created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PacketReceiveProfile : BasePacketProfile
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<int, PacketReceiveProfile>
|
||||||
|
_profiles = new();
|
||||||
|
|
||||||
|
public PacketReceiveProfile(int packetId) : base($"0x{packetId:X2}")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PacketReceiveProfile> Profiles => _profiles.Values;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
|
public static PacketReceiveProfile Acquire(int packetId)
|
||||||
|
{
|
||||||
|
if (!_profiles.TryGetValue(packetId, out var prof))
|
||||||
|
{
|
||||||
|
_profiles.Add(packetId, prof = new PacketReceiveProfile(packetId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return prof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,31 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server.Diagnostics
|
namespace Server.Diagnostics;
|
||||||
|
|
||||||
|
public class TargetProfile : BaseProfile
|
||||||
{
|
{
|
||||||
public class TargetProfile : BaseProfile
|
private static readonly Dictionary<Type, TargetProfile> _profiles = new();
|
||||||
|
|
||||||
|
public TargetProfile(Type type)
|
||||||
|
: base(type.FullName)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Type, TargetProfile> _profiles = new();
|
}
|
||||||
|
|
||||||
public TargetProfile(Type type)
|
public static IEnumerable<TargetProfile> Profiles => _profiles.Values;
|
||||||
: base(type.FullName)
|
|
||||||
|
public static TargetProfile Acquire(Type type)
|
||||||
|
{
|
||||||
|
if (!Core.Profiling)
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<TargetProfile> Profiles => _profiles.Values;
|
if (!_profiles.TryGetValue(type, out var prof))
|
||||||
|
|
||||||
public static TargetProfile Acquire(Type type)
|
|
||||||
{
|
{
|
||||||
if (!Core.Profiling)
|
_profiles.Add(type, prof = new TargetProfile(type));
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_profiles.TryGetValue(type, out var prof))
|
|
||||||
{
|
|
||||||
_profiles.Add(type, prof = new TargetProfile(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return prof;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return prof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,44 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Server.Diagnostics
|
namespace Server.Diagnostics;
|
||||||
|
|
||||||
|
public class TimerProfile : BaseProfile
|
||||||
{
|
{
|
||||||
public class TimerProfile : BaseProfile
|
private static readonly Dictionary<string, TimerProfile> _profiles = new();
|
||||||
|
|
||||||
|
public TimerProfile(string name)
|
||||||
|
: base(name)
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, TimerProfile> _profiles = new();
|
}
|
||||||
|
|
||||||
public TimerProfile(string name)
|
public static IEnumerable<TimerProfile> Profiles => _profiles.Values;
|
||||||
: base(name)
|
|
||||||
|
public long Created { get; set; }
|
||||||
|
|
||||||
|
public long Started { get; set; }
|
||||||
|
|
||||||
|
public long Stopped { get; set; }
|
||||||
|
|
||||||
|
public static TimerProfile Acquire(string name)
|
||||||
|
{
|
||||||
|
if (!Core.Profiling)
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<TimerProfile> Profiles => _profiles.Values;
|
if (!_profiles.TryGetValue(name, out var prof))
|
||||||
|
|
||||||
public long Created { get; set; }
|
|
||||||
|
|
||||||
public long Started { get; set; }
|
|
||||||
|
|
||||||
public long Stopped { get; set; }
|
|
||||||
|
|
||||||
public static TimerProfile Acquire(string name)
|
|
||||||
{
|
{
|
||||||
if (!Core.Profiling)
|
_profiles.Add(name, prof = new TimerProfile(name));
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_profiles.TryGetValue(name, out var prof))
|
|
||||||
{
|
|
||||||
_profiles.Add(name, prof = new TimerProfile(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return prof;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteTo(TextWriter op)
|
return prof;
|
||||||
{
|
}
|
||||||
base.WriteTo(op);
|
|
||||||
|
|
||||||
op.Write("\t{0,12:N0} {1,12:N0} {2,-12:N0}", Created, Started, Stopped);
|
public override void WriteTo(TextWriter op)
|
||||||
}
|
{
|
||||||
|
base.WriteTo(op);
|
||||||
|
|
||||||
|
op.Write("\t{0,12:N0} {1,12:N0} {2,-12:N0}", Created, Started, Stopped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Effects.cs *
|
* File: Effects.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,262 +16,304 @@
|
||||||
using System;
|
using System;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public enum EffectType
|
||||||
{
|
{
|
||||||
public enum EffectType
|
Moving,
|
||||||
|
Lightning,
|
||||||
|
FixedXYZ,
|
||||||
|
FixedFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ScreenEffectType
|
||||||
|
{
|
||||||
|
FadeOut = 0x00,
|
||||||
|
FadeIn = 0x01,
|
||||||
|
LightFlash = 0x02,
|
||||||
|
FadeInOut = 0x03,
|
||||||
|
DarkFlash = 0x04
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EffectLayer
|
||||||
|
{
|
||||||
|
Head = 0,
|
||||||
|
RightHand = 1,
|
||||||
|
LeftHand = 2,
|
||||||
|
Waist = 3,
|
||||||
|
LeftFoot = 4,
|
||||||
|
RightFoot = 5,
|
||||||
|
CenterFeet = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ParticleSupportType
|
||||||
|
{
|
||||||
|
Full,
|
||||||
|
Detect,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Effects
|
||||||
|
{
|
||||||
|
public static ParticleSupportType ParticleSupportType { get; set; } = ParticleSupportType.Detect;
|
||||||
|
|
||||||
|
public static bool SendParticlesTo(NetState state) =>
|
||||||
|
ParticleSupportType == ParticleSupportType.Full ||
|
||||||
|
ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient;
|
||||||
|
|
||||||
|
public static void PlaySound(IEntity e, int soundID) => PlaySound(e.Location, e.Map, soundID);
|
||||||
|
|
||||||
|
public static void PlaySound(Point3D p, Map map, int soundID)
|
||||||
{
|
{
|
||||||
Moving,
|
if (soundID <= -1)
|
||||||
Lightning,
|
|
||||||
FixedXYZ,
|
|
||||||
FixedFrom
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ScreenEffectType
|
|
||||||
{
|
|
||||||
FadeOut = 0x00,
|
|
||||||
FadeIn = 0x01,
|
|
||||||
LightFlash = 0x02,
|
|
||||||
FadeInOut = 0x03,
|
|
||||||
DarkFlash = 0x04
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EffectLayer
|
|
||||||
{
|
|
||||||
Head = 0,
|
|
||||||
RightHand = 1,
|
|
||||||
LeftHand = 2,
|
|
||||||
Waist = 3,
|
|
||||||
LeftFoot = 4,
|
|
||||||
RightFoot = 5,
|
|
||||||
CenterFeet = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ParticleSupportType
|
|
||||||
{
|
|
||||||
Full,
|
|
||||||
Detect,
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Effects
|
|
||||||
{
|
|
||||||
public static ParticleSupportType ParticleSupportType { get; set; } = ParticleSupportType.Detect;
|
|
||||||
|
|
||||||
public static bool SendParticlesTo(NetState state) =>
|
|
||||||
ParticleSupportType == ParticleSupportType.Full ||
|
|
||||||
ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient;
|
|
||||||
|
|
||||||
public static void PlaySound(IEntity e, int soundID) => PlaySound(e.Location, e.Map, soundID);
|
|
||||||
|
|
||||||
public static void PlaySound(Point3D p, Map map, int soundID)
|
|
||||||
{
|
{
|
||||||
if (soundID <= -1)
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map != null)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength].InitializePacket();
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(new Point3D(p));
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
|
||||||
{
|
|
||||||
state.Mobile.ProcessDelta();
|
|
||||||
OutgoingEffectPackets.CreateSoundEffect(buffer, soundID, p);
|
|
||||||
state.Send(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendBoltEffect(IEntity e, bool sound = true, int hue = 0)
|
if (map != null)
|
||||||
{
|
{
|
||||||
var map = e.Map;
|
Span<byte> buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength].InitializePacket();
|
||||||
|
|
||||||
if (map == null)
|
var eable = map.GetClientsInRange(new Point3D(p));
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.ProcessDelta();
|
|
||||||
|
|
||||||
Span<byte> preEffect = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
|
||||||
Span<byte> boltEffect = stackalloc byte[OutgoingEffectPackets.BoltEffectLength].InitializePacket();
|
|
||||||
Span<byte> soundEffect = sound ? stackalloc byte[OutgoingEffectPackets.SoundPacketLength].InitializePacket() : null;
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(e.Location);
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
|
||||||
{
|
|
||||||
if (state.Mobile.CanSee(e))
|
|
||||||
{
|
|
||||||
if (SendParticlesTo(state))
|
|
||||||
{
|
|
||||||
OutgoingEffectPackets.CreateTargetParticleEffect(
|
|
||||||
preEffect,
|
|
||||||
e, 0, 10, 5, 0, 0, 5031, 3, 0
|
|
||||||
);
|
|
||||||
state.Send(preEffect);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutgoingEffectPackets.CreateBoltEffect(boltEffect, e, hue);
|
|
||||||
state.Send(boltEffect);
|
|
||||||
|
|
||||||
if (sound)
|
|
||||||
{
|
|
||||||
OutgoingEffectPackets.CreateSoundEffect(soundEffect, 0x29, e);
|
|
||||||
state.Send(soundEffect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendLocationEffect(
|
|
||||||
IEntity e, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0
|
|
||||||
) => SendLocationEffect(e.Location, e.Map, itemID, duration, speed, hue, renderMode);
|
|
||||||
|
|
||||||
public static void SendLocationEffect(
|
|
||||||
Point3D p, Map map, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket();
|
|
||||||
OutgoingEffectPackets.CreateLocationHuedEffect(
|
|
||||||
effect,
|
|
||||||
p, itemID, speed, duration, hue, renderMode
|
|
||||||
);
|
|
||||||
|
|
||||||
SendPacket(p, map, effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect)
|
|
||||||
{
|
|
||||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect, int unknown)
|
|
||||||
{
|
|
||||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, unknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendLocationParticles(
|
|
||||||
IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var map = e.Map;
|
|
||||||
|
|
||||||
if (map == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
|
||||||
|
|
||||||
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(e.Location);
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
foreach (var state in eable)
|
||||||
{
|
{
|
||||||
state.Mobile.ProcessDelta();
|
state.Mobile.ProcessDelta();
|
||||||
|
OutgoingEffectPackets.CreateSoundEffect(buffer, soundID, p);
|
||||||
if (SendParticlesTo(state))
|
state.Send(buffer);
|
||||||
{
|
|
||||||
OutgoingEffectPackets.CreateLocationParticleEffect(
|
|
||||||
particles,
|
|
||||||
e, itemID, speed, duration, hue, renderMode, effect, unknown
|
|
||||||
);
|
|
||||||
state.Send(particles);
|
|
||||||
}
|
|
||||||
else if (itemID != 0)
|
|
||||||
{
|
|
||||||
OutgoingEffectPackets.CreateLocationHuedEffect(
|
|
||||||
regular,
|
|
||||||
e.Location, itemID, speed, duration, hue, renderMode
|
|
||||||
);
|
|
||||||
state.Send(regular);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eable.Free();
|
eable.Free();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue = 0, int renderMode = 0)
|
public static void SendBoltEffect(IEntity e, bool sound = true, int hue = 0)
|
||||||
|
{
|
||||||
|
var map = e.Map;
|
||||||
|
|
||||||
|
if (map == null)
|
||||||
{
|
{
|
||||||
(target as Mobile)?.ProcessDelta();
|
return;
|
||||||
|
|
||||||
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket();
|
|
||||||
OutgoingEffectPackets.CreateTargetHuedEffect(
|
|
||||||
effect,
|
|
||||||
target, itemID, speed, duration, hue, renderMode
|
|
||||||
);
|
|
||||||
|
|
||||||
SendPacket(target.Location, target.Map, effect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendTargetParticles(
|
e.ProcessDelta();
|
||||||
IEntity target, int itemID, int speed, int duration, int effect,
|
|
||||||
EffectLayer layer
|
Span<byte> preEffect = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
||||||
)
|
Span<byte> boltEffect = stackalloc byte[OutgoingEffectPackets.BoltEffectLength].InitializePacket();
|
||||||
|
Span<byte> soundEffect = sound ? stackalloc byte[OutgoingEffectPackets.SoundPacketLength].InitializePacket() : null;
|
||||||
|
|
||||||
|
var eable = map.GetClientsInRange(e.Location);
|
||||||
|
|
||||||
|
foreach (var state in eable)
|
||||||
{
|
{
|
||||||
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer);
|
if (state.Mobile.CanSee(e))
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendTargetParticles(
|
|
||||||
IEntity target, int itemID, int speed, int duration, int hue, int renderMode,
|
|
||||||
int effect, EffectLayer layer, int unknown = 0
|
|
||||||
)
|
|
||||||
{
|
|
||||||
(target as Mobile)?.ProcessDelta();
|
|
||||||
|
|
||||||
var map = target.Map;
|
|
||||||
|
|
||||||
if (map == null)
|
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
|
||||||
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(target.Location);
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
|
||||||
{
|
|
||||||
state.Mobile.ProcessDelta();
|
|
||||||
|
|
||||||
if (SendParticlesTo(state))
|
if (SendParticlesTo(state))
|
||||||
{
|
{
|
||||||
OutgoingEffectPackets.CreateTargetParticleEffect(
|
OutgoingEffectPackets.CreateTargetParticleEffect(
|
||||||
particles,
|
preEffect,
|
||||||
target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown
|
e, 0, 10, 5, 0, 0, 5031, 3, 0
|
||||||
);
|
);
|
||||||
state.Send(particles);
|
state.Send(preEffect);
|
||||||
}
|
}
|
||||||
else if (itemID != 0)
|
|
||||||
|
OutgoingEffectPackets.CreateBoltEffect(boltEffect, e, hue);
|
||||||
|
state.Send(boltEffect);
|
||||||
|
|
||||||
|
if (sound)
|
||||||
{
|
{
|
||||||
OutgoingEffectPackets.CreateTargetHuedEffect(regular, target, itemID, speed, duration, hue, renderMode);
|
OutgoingEffectPackets.CreateSoundEffect(soundEffect, 0x29, e);
|
||||||
state.Send(regular);
|
state.Send(soundEffect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
eable.Free();
|
||||||
Map map, int itemID, Point3D from, Point3D to, int speed, int duration,
|
}
|
||||||
bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
|
||||||
) => SendMovingEffect(
|
public static void SendLocationEffect(
|
||||||
|
IEntity e, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0
|
||||||
|
) => SendLocationEffect(e.Location, e.Map, itemID, duration, speed, hue, renderMode);
|
||||||
|
|
||||||
|
public static void SendLocationEffect(
|
||||||
|
Point3D p, Map map, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket();
|
||||||
|
OutgoingEffectPackets.CreateLocationHuedEffect(
|
||||||
|
effect,
|
||||||
|
p, itemID, speed, duration, hue, renderMode
|
||||||
|
);
|
||||||
|
|
||||||
|
SendPacket(p, map, effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect)
|
||||||
|
{
|
||||||
|
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect, int unknown)
|
||||||
|
{
|
||||||
|
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendLocationParticles(
|
||||||
|
IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var map = e.Map;
|
||||||
|
|
||||||
|
if (map == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
||||||
|
|
||||||
|
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
||||||
|
|
||||||
|
var eable = map.GetClientsInRange(e.Location);
|
||||||
|
|
||||||
|
foreach (var state in eable)
|
||||||
|
{
|
||||||
|
state.Mobile.ProcessDelta();
|
||||||
|
|
||||||
|
if (SendParticlesTo(state))
|
||||||
|
{
|
||||||
|
OutgoingEffectPackets.CreateLocationParticleEffect(
|
||||||
|
particles,
|
||||||
|
e, itemID, speed, duration, hue, renderMode, effect, unknown
|
||||||
|
);
|
||||||
|
state.Send(particles);
|
||||||
|
}
|
||||||
|
else if (itemID != 0)
|
||||||
|
{
|
||||||
|
OutgoingEffectPackets.CreateLocationHuedEffect(
|
||||||
|
regular,
|
||||||
|
e.Location, itemID, speed, duration, hue, renderMode
|
||||||
|
);
|
||||||
|
state.Send(regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue = 0, int renderMode = 0)
|
||||||
|
{
|
||||||
|
(target as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket();
|
||||||
|
OutgoingEffectPackets.CreateTargetHuedEffect(
|
||||||
|
effect,
|
||||||
|
target, itemID, speed, duration, hue, renderMode
|
||||||
|
);
|
||||||
|
|
||||||
|
SendPacket(target.Location, target.Map, effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendTargetParticles(
|
||||||
|
IEntity target, int itemID, int speed, int duration, int effect,
|
||||||
|
EffectLayer layer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendTargetParticles(
|
||||||
|
IEntity target, int itemID, int speed, int duration, int hue, int renderMode,
|
||||||
|
int effect, EffectLayer layer, int unknown = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
(target as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
var map = target.Map;
|
||||||
|
|
||||||
|
if (map == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
||||||
|
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
||||||
|
|
||||||
|
var eable = map.GetClientsInRange(target.Location);
|
||||||
|
|
||||||
|
foreach (var state in eable)
|
||||||
|
{
|
||||||
|
state.Mobile.ProcessDelta();
|
||||||
|
|
||||||
|
if (SendParticlesTo(state))
|
||||||
|
{
|
||||||
|
OutgoingEffectPackets.CreateTargetParticleEffect(
|
||||||
|
particles,
|
||||||
|
target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown
|
||||||
|
);
|
||||||
|
state.Send(particles);
|
||||||
|
}
|
||||||
|
else if (itemID != 0)
|
||||||
|
{
|
||||||
|
OutgoingEffectPackets.CreateTargetHuedEffect(regular, target, itemID, speed, duration, hue, renderMode);
|
||||||
|
state.Send(regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMovingEffect(
|
||||||
|
Map map, int itemID, Point3D from, Point3D to, int speed, int duration,
|
||||||
|
bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
|
) => SendMovingEffect(
|
||||||
|
Serial.Zero,
|
||||||
|
Serial.Zero,
|
||||||
|
from,
|
||||||
|
map,
|
||||||
|
itemID,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
speed,
|
||||||
|
duration,
|
||||||
|
fixedDirection,
|
||||||
|
explodes,
|
||||||
|
hue,
|
||||||
|
renderMode
|
||||||
|
);
|
||||||
|
|
||||||
|
public static void SendMovingEffect(
|
||||||
|
Point3D origin, Map map, int itemID, Point3D from, Point3D to, int speed, int duration,
|
||||||
|
bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
|
) => SendMovingEffect(
|
||||||
|
Serial.Zero,
|
||||||
|
Serial.Zero,
|
||||||
|
origin,
|
||||||
|
map,
|
||||||
|
itemID,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
speed,
|
||||||
|
duration,
|
||||||
|
fixedDirection,
|
||||||
|
explodes,
|
||||||
|
hue,
|
||||||
|
renderMode
|
||||||
|
);
|
||||||
|
|
||||||
|
public static void SendMovingEffect(
|
||||||
|
IEntity from, Point3D to, int itemID,
|
||||||
|
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
(from as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
SendMovingEffect(
|
||||||
|
from.Serial,
|
||||||
Serial.Zero,
|
Serial.Zero,
|
||||||
Serial.Zero,
|
from.Location,
|
||||||
from,
|
from.Map,
|
||||||
map,
|
|
||||||
itemID,
|
itemID,
|
||||||
from,
|
from.Location,
|
||||||
to,
|
to,
|
||||||
speed,
|
speed,
|
||||||
duration,
|
duration,
|
||||||
|
|
@ -280,18 +322,49 @@ namespace Server
|
||||||
hue,
|
hue,
|
||||||
renderMode
|
renderMode
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
public static void SendMovingEffect(
|
||||||
Point3D origin, Map map, int itemID, Point3D from, Point3D to, int speed, int duration,
|
IEntity from, IEntity to, int itemID,
|
||||||
bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
) => SendMovingEffect(
|
)
|
||||||
Serial.Zero,
|
{
|
||||||
Serial.Zero,
|
(from as Mobile)?.ProcessDelta();
|
||||||
|
(to as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
SendMovingEffect(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
from.Location,
|
||||||
|
from.Map,
|
||||||
|
itemID,
|
||||||
|
from.Location,
|
||||||
|
to.Location,
|
||||||
|
speed,
|
||||||
|
duration,
|
||||||
|
fixedDirection,
|
||||||
|
explodes,
|
||||||
|
hue,
|
||||||
|
renderMode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMovingEffect(
|
||||||
|
IEntity from, IEntity to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation,
|
||||||
|
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
(from as Mobile)?.ProcessDelta();
|
||||||
|
(to as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
SendMovingEffect(
|
||||||
|
from.Serial,
|
||||||
|
to.Serial,
|
||||||
origin,
|
origin,
|
||||||
map,
|
map,
|
||||||
itemID,
|
itemID,
|
||||||
from,
|
fromLocation,
|
||||||
to,
|
toLocation,
|
||||||
speed,
|
speed,
|
||||||
duration,
|
duration,
|
||||||
fixedDirection,
|
fixedDirection,
|
||||||
|
|
@ -299,205 +372,131 @@ namespace Server
|
||||||
hue,
|
hue,
|
||||||
renderMode
|
renderMode
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
public static void SendMovingEffect(
|
||||||
IEntity from, Point3D to, int itemID,
|
Serial from, Serial to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation,
|
||||||
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength];
|
||||||
|
OutgoingEffectPackets.CreateMovingHuedEffect(
|
||||||
|
effect,
|
||||||
|
from, to, itemID, fromLocation, toLocation, speed, duration, fixedDirection,
|
||||||
|
explodes, hue, renderMode
|
||||||
|
);
|
||||||
|
|
||||||
|
SendPacket(origin, map, effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMovingParticles(
|
||||||
|
IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||||
|
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SendMovingParticles(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
itemID,
|
||||||
|
speed,
|
||||||
|
duration,
|
||||||
|
fixedDirection,
|
||||||
|
explodes,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
effect,
|
||||||
|
explodeEffect,
|
||||||
|
explodeSound,
|
||||||
|
unknown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMovingParticles(
|
||||||
|
IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||||
|
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||||
|
int unknown
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SendMovingParticles(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
itemID,
|
||||||
|
speed,
|
||||||
|
duration,
|
||||||
|
fixedDirection,
|
||||||
|
explodes,
|
||||||
|
hue,
|
||||||
|
renderMode,
|
||||||
|
effect,
|
||||||
|
explodeEffect,
|
||||||
|
explodeSound,
|
||||||
|
(EffectLayer)255,
|
||||||
|
unknown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMovingParticles(
|
||||||
|
IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||||
|
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||||
|
EffectLayer layer, int unknown
|
||||||
|
)
|
||||||
|
{
|
||||||
|
(from as Mobile)?.ProcessDelta();
|
||||||
|
(to as Mobile)?.ProcessDelta();
|
||||||
|
|
||||||
|
var map = from.Map;
|
||||||
|
|
||||||
|
if (map == null)
|
||||||
{
|
{
|
||||||
(from as Mobile)?.ProcessDelta();
|
return;
|
||||||
|
|
||||||
SendMovingEffect(
|
|
||||||
from.Serial,
|
|
||||||
Serial.Zero,
|
|
||||||
from.Location,
|
|
||||||
from.Map,
|
|
||||||
itemID,
|
|
||||||
from.Location,
|
|
||||||
to,
|
|
||||||
speed,
|
|
||||||
duration,
|
|
||||||
fixedDirection,
|
|
||||||
explodes,
|
|
||||||
hue,
|
|
||||||
renderMode
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
||||||
IEntity from, IEntity to, int itemID,
|
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
||||||
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
|
||||||
)
|
var eable = map.GetClientsInRange(from.Location);
|
||||||
|
|
||||||
|
foreach (var state in eable)
|
||||||
{
|
{
|
||||||
(from as Mobile)?.ProcessDelta();
|
state.Mobile.ProcessDelta();
|
||||||
(to as Mobile)?.ProcessDelta();
|
|
||||||
|
|
||||||
SendMovingEffect(
|
if (SendParticlesTo(state))
|
||||||
from,
|
|
||||||
to,
|
|
||||||
from.Location,
|
|
||||||
from.Map,
|
|
||||||
itemID,
|
|
||||||
from.Location,
|
|
||||||
to.Location,
|
|
||||||
speed,
|
|
||||||
duration,
|
|
||||||
fixedDirection,
|
|
||||||
explodes,
|
|
||||||
hue,
|
|
||||||
renderMode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
|
||||||
IEntity from, IEntity to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation,
|
|
||||||
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
|
||||||
)
|
|
||||||
{
|
|
||||||
(from as Mobile)?.ProcessDelta();
|
|
||||||
(to as Mobile)?.ProcessDelta();
|
|
||||||
|
|
||||||
SendMovingEffect(
|
|
||||||
from.Serial,
|
|
||||||
to.Serial,
|
|
||||||
origin,
|
|
||||||
map,
|
|
||||||
itemID,
|
|
||||||
fromLocation,
|
|
||||||
toLocation,
|
|
||||||
speed,
|
|
||||||
duration,
|
|
||||||
fixedDirection,
|
|
||||||
explodes,
|
|
||||||
hue,
|
|
||||||
renderMode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMovingEffect(
|
|
||||||
Serial from, Serial to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation,
|
|
||||||
int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Span<byte> effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength];
|
|
||||||
OutgoingEffectPackets.CreateMovingHuedEffect(
|
|
||||||
effect,
|
|
||||||
from, to, itemID, fromLocation, toLocation, speed, duration, fixedDirection,
|
|
||||||
explodes, hue, renderMode
|
|
||||||
);
|
|
||||||
|
|
||||||
SendPacket(origin, map, effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMovingParticles(
|
|
||||||
IEntity from, IEntity to, int itemID, int speed, int duration,
|
|
||||||
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown = 0
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SendMovingParticles(
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
itemID,
|
|
||||||
speed,
|
|
||||||
duration,
|
|
||||||
fixedDirection,
|
|
||||||
explodes,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
effect,
|
|
||||||
explodeEffect,
|
|
||||||
explodeSound,
|
|
||||||
unknown
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMovingParticles(
|
|
||||||
IEntity from, IEntity to, int itemID, int speed, int duration,
|
|
||||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
|
||||||
int unknown
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SendMovingParticles(
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
itemID,
|
|
||||||
speed,
|
|
||||||
duration,
|
|
||||||
fixedDirection,
|
|
||||||
explodes,
|
|
||||||
hue,
|
|
||||||
renderMode,
|
|
||||||
effect,
|
|
||||||
explodeEffect,
|
|
||||||
explodeSound,
|
|
||||||
(EffectLayer)255,
|
|
||||||
unknown
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMovingParticles(
|
|
||||||
IEntity from, IEntity to, int itemID, int speed, int duration,
|
|
||||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
|
||||||
EffectLayer layer, int unknown
|
|
||||||
)
|
|
||||||
{
|
|
||||||
(from as Mobile)?.ProcessDelta();
|
|
||||||
(to as Mobile)?.ProcessDelta();
|
|
||||||
|
|
||||||
var map = from.Map;
|
|
||||||
|
|
||||||
if (map == null)
|
|
||||||
{
|
{
|
||||||
return;
|
OutgoingEffectPackets.CreateMovingParticleEffect(
|
||||||
|
particles,
|
||||||
|
from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect,
|
||||||
|
explodeEffect, explodeSound, layer, unknown
|
||||||
|
);
|
||||||
|
state.Send(particles);
|
||||||
}
|
}
|
||||||
|
else if (itemID > 1)
|
||||||
Span<byte> particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength].InitializePacket();
|
|
||||||
Span<byte> regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength].InitializePacket() : null;
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(from.Location);
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
|
||||||
{
|
{
|
||||||
state.Mobile.ProcessDelta();
|
OutgoingEffectPackets.CreateMovingHuedEffect(
|
||||||
|
regular,
|
||||||
if (SendParticlesTo(state))
|
from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode
|
||||||
{
|
);
|
||||||
OutgoingEffectPackets.CreateMovingParticleEffect(
|
state.Send(regular);
|
||||||
particles,
|
|
||||||
from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect,
|
|
||||||
explodeEffect, explodeSound, layer, unknown
|
|
||||||
);
|
|
||||||
state.Send(particles);
|
|
||||||
}
|
|
||||||
else if (itemID > 1)
|
|
||||||
{
|
|
||||||
OutgoingEffectPackets.CreateMovingHuedEffect(
|
|
||||||
regular,
|
|
||||||
from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode
|
|
||||||
);
|
|
||||||
state.Send(regular);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendPacket(Point3D origin, Map map, Span<byte> effectBuffer)
|
eable.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendPacket(Point3D origin, Map map, Span<byte> effectBuffer)
|
||||||
|
{
|
||||||
|
if (map == null)
|
||||||
{
|
{
|
||||||
if (map == null)
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eable = map.GetClientsInRange(new Point3D(origin));
|
|
||||||
|
|
||||||
foreach (var state in eable)
|
|
||||||
{
|
|
||||||
state.Mobile.ProcessDelta();
|
|
||||||
state.Send(effectBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var eable = map.GetClientsInRange(new Point3D(origin));
|
||||||
|
|
||||||
|
foreach (var state in eable)
|
||||||
|
{
|
||||||
|
state.Mobile.ProcessDelta();
|
||||||
|
state.Send(effectBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
eable.Free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: EventLoopTasks.cs *
|
* File: EventLoopTasks.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,59 +17,58 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public sealed class EventLoopContext : SynchronizationContext
|
||||||
{
|
{
|
||||||
public sealed class EventLoopContext : SynchronizationContext
|
private readonly ConcurrentQueue<Action> _queue;
|
||||||
|
private readonly Thread _mainThread;
|
||||||
|
|
||||||
|
public EventLoopContext()
|
||||||
{
|
{
|
||||||
private readonly ConcurrentQueue<Action> _queue;
|
_queue = new ConcurrentQueue<Action>();
|
||||||
private readonly Thread _mainThread;
|
_mainThread = Thread.CurrentThread;
|
||||||
|
}
|
||||||
|
|
||||||
public EventLoopContext()
|
public override SynchronizationContext CreateCopy() => new EventLoopContext();
|
||||||
|
|
||||||
|
public void Post(Action d) => _queue.Enqueue(d);
|
||||||
|
|
||||||
|
public override void Post(SendOrPostCallback d, object state) => _queue.Enqueue(() => d(state));
|
||||||
|
|
||||||
|
public override void Send(SendOrPostCallback d, object state)
|
||||||
|
{
|
||||||
|
if (Thread.CurrentThread == _mainThread)
|
||||||
{
|
{
|
||||||
_queue = new ConcurrentQueue<Action>();
|
d(state);
|
||||||
_mainThread = Thread.CurrentThread;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SynchronizationContext CreateCopy() => new EventLoopContext();
|
AutoResetEvent evt = new AutoResetEvent(false);
|
||||||
|
|
||||||
public void Post(Action d) => _queue.Enqueue(d);
|
_queue.Enqueue(() =>
|
||||||
|
|
||||||
public override void Post(SendOrPostCallback d, object state) => _queue.Enqueue(() => d(state));
|
|
||||||
|
|
||||||
public override void Send(SendOrPostCallback d, object state)
|
|
||||||
{
|
{
|
||||||
if (Thread.CurrentThread == _mainThread)
|
d(state);
|
||||||
{
|
evt.Set();
|
||||||
d(state);
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoResetEvent evt = new AutoResetEvent(false);
|
evt.WaitOne();
|
||||||
|
}
|
||||||
|
|
||||||
_queue.Enqueue(() =>
|
public void ExecuteTasks()
|
||||||
{
|
{
|
||||||
d(state);
|
if (Thread.CurrentThread != _mainThread)
|
||||||
evt.Set();
|
{
|
||||||
});
|
throw new Exception("Called EventLoop.ExecuteTasks on incorrect thread!");
|
||||||
|
|
||||||
evt.WaitOne();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteTasks()
|
var count = _queue.Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (Thread.CurrentThread != _mainThread)
|
if (_queue.TryDequeue(out var a))
|
||||||
{
|
{
|
||||||
throw new Exception("Called EventLoop.ExecuteTasks on incorrect thread!");
|
a();
|
||||||
}
|
|
||||||
|
|
||||||
var count = _queue.Count;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (_queue.TryDequeue(out var a))
|
|
||||||
{
|
|
||||||
a();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: AccountLoginEvent.cs *
|
* File: AccountLoginEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,33 +17,32 @@ using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class AccountLoginEventArgs
|
||||||
{
|
{
|
||||||
public class AccountLoginEventArgs
|
public AccountLoginEventArgs(NetState state, string username, string password)
|
||||||
{
|
{
|
||||||
public AccountLoginEventArgs(NetState state, string username, string password)
|
State = state;
|
||||||
{
|
Username = username;
|
||||||
State = state;
|
Password = password;
|
||||||
Username = username;
|
|
||||||
Password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NetState State { get; }
|
|
||||||
|
|
||||||
public string Username { get; }
|
|
||||||
|
|
||||||
public string Password { get; }
|
|
||||||
|
|
||||||
public bool Accepted { get; set; }
|
|
||||||
|
|
||||||
public ALRReason RejectReason { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public NetState State { get; }
|
||||||
{
|
|
||||||
public static event Action<AccountLoginEventArgs> AccountLogin;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public string Username { get; }
|
||||||
public static void InvokeAccountLogin(AccountLoginEventArgs e) => AccountLogin?.Invoke(e);
|
|
||||||
}
|
public string Password { get; }
|
||||||
|
|
||||||
|
public bool Accepted { get; set; }
|
||||||
|
|
||||||
|
public ALRReason RejectReason { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<AccountLoginEventArgs> AccountLogin;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeAccountLogin(AccountLoginEventArgs e) => AccountLogin?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: AggressiveActionEvent.cs *
|
* File: AggressiveActionEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,56 +17,55 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class AggressiveActionEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public class AggressiveActionEventArgs : EventArgs
|
private static readonly Queue<AggressiveActionEventArgs> m_Pool = new();
|
||||||
|
|
||||||
|
private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal)
|
||||||
{
|
{
|
||||||
private static readonly Queue<AggressiveActionEventArgs> m_Pool = new();
|
Aggressed = aggressed;
|
||||||
|
Aggressor = aggressor;
|
||||||
private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal)
|
Criminal = criminal;
|
||||||
{
|
|
||||||
Aggressed = aggressed;
|
|
||||||
Aggressor = aggressor;
|
|
||||||
Criminal = criminal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mobile Aggressed { get; private set; }
|
|
||||||
|
|
||||||
public Mobile Aggressor { get; private set; }
|
|
||||||
|
|
||||||
public bool Criminal { get; private set; }
|
|
||||||
|
|
||||||
public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal)
|
|
||||||
{
|
|
||||||
AggressiveActionEventArgs args;
|
|
||||||
|
|
||||||
if (m_Pool.Count > 0)
|
|
||||||
{
|
|
||||||
args = m_Pool.Dequeue();
|
|
||||||
|
|
||||||
args.Aggressed = aggressed;
|
|
||||||
args.Aggressor = aggressor;
|
|
||||||
args.Criminal = criminal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args = new AggressiveActionEventArgs(aggressed, aggressor, criminal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Free()
|
|
||||||
{
|
|
||||||
m_Pool.Enqueue(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public Mobile Aggressed { get; private set; }
|
||||||
{
|
|
||||||
public static event Action<AggressiveActionEventArgs> AggressiveAction;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public Mobile Aggressor { get; private set; }
|
||||||
public static void InvokeAggressiveAction(AggressiveActionEventArgs e) => AggressiveAction?.Invoke(e);
|
|
||||||
|
public bool Criminal { get; private set; }
|
||||||
|
|
||||||
|
public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal)
|
||||||
|
{
|
||||||
|
AggressiveActionEventArgs args;
|
||||||
|
|
||||||
|
if (m_Pool.Count > 0)
|
||||||
|
{
|
||||||
|
args = m_Pool.Dequeue();
|
||||||
|
|
||||||
|
args.Aggressed = aggressed;
|
||||||
|
args.Aggressor = aggressor;
|
||||||
|
args.Criminal = criminal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args = new AggressiveActionEventArgs(aggressed, aggressor, criminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free()
|
||||||
|
{
|
||||||
|
m_Pool.Enqueue(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<AggressiveActionEventArgs> AggressiveAction;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeAggressiveAction(AggressiveActionEventArgs e) => AggressiveAction?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: CharacterCreatedEvent.cs *
|
* File: CharacterCreatedEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -18,77 +18,76 @@ using System.Runtime.CompilerServices;
|
||||||
using Server.Accounting;
|
using Server.Accounting;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class CharacterCreatedEventArgs
|
||||||
{
|
{
|
||||||
public class CharacterCreatedEventArgs
|
public CharacterCreatedEventArgs(
|
||||||
|
NetState state, IAccount a, string name, bool female, int hue, StatNameValue[] stats, CityInfo city,
|
||||||
|
SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, int beardID, int beardHue,
|
||||||
|
int profession, Race race
|
||||||
|
)
|
||||||
{
|
{
|
||||||
public CharacterCreatedEventArgs(
|
State = state;
|
||||||
NetState state, IAccount a, string name, bool female, int hue, StatNameValue[] stats, CityInfo city,
|
Account = a;
|
||||||
SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, int beardID, int beardHue,
|
Name = name;
|
||||||
int profession, Race race
|
Female = female;
|
||||||
)
|
Hue = hue;
|
||||||
{
|
Stats = stats;
|
||||||
State = state;
|
City = city;
|
||||||
Account = a;
|
Skills = skills;
|
||||||
Name = name;
|
ShirtHue = shirtHue;
|
||||||
Female = female;
|
PantsHue = pantsHue;
|
||||||
Hue = hue;
|
HairID = hairID;
|
||||||
Stats = stats;
|
HairHue = hairHue;
|
||||||
City = city;
|
BeardID = beardID;
|
||||||
Skills = skills;
|
BeardHue = beardHue;
|
||||||
ShirtHue = shirtHue;
|
Profession = profession;
|
||||||
PantsHue = pantsHue;
|
Race = race;
|
||||||
HairID = hairID;
|
|
||||||
HairHue = hairHue;
|
|
||||||
BeardID = beardID;
|
|
||||||
BeardHue = beardHue;
|
|
||||||
Profession = profession;
|
|
||||||
Race = race;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NetState State { get; }
|
|
||||||
|
|
||||||
public IAccount Account { get; }
|
|
||||||
|
|
||||||
public Mobile Mobile { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public bool Female { get; }
|
|
||||||
|
|
||||||
public int Hue { get; }
|
|
||||||
|
|
||||||
public StatNameValue[] Stats { get; }
|
|
||||||
|
|
||||||
public CityInfo City { get; }
|
|
||||||
|
|
||||||
public SkillNameValue[] Skills { get; }
|
|
||||||
|
|
||||||
public int ShirtHue { get; }
|
|
||||||
|
|
||||||
public int PantsHue { get; }
|
|
||||||
|
|
||||||
public int HairID { get; }
|
|
||||||
|
|
||||||
public int HairHue { get; }
|
|
||||||
|
|
||||||
public int BeardID { get; }
|
|
||||||
|
|
||||||
public int BeardHue { get; }
|
|
||||||
|
|
||||||
public int Profession { get; set; }
|
|
||||||
|
|
||||||
public Race Race { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct SkillNameValue(SkillName Name, int Value);
|
public NetState State { get; }
|
||||||
public readonly record struct StatNameValue(StatType Name, int Value);
|
|
||||||
|
|
||||||
public static partial class EventSink
|
public IAccount Account { get; }
|
||||||
{
|
|
||||||
public static event Action<CharacterCreatedEventArgs> CharacterCreated;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public Mobile Mobile { get; set; }
|
||||||
public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) => CharacterCreated?.Invoke(e);
|
|
||||||
}
|
public string Name { get; }
|
||||||
|
|
||||||
|
public bool Female { get; }
|
||||||
|
|
||||||
|
public int Hue { get; }
|
||||||
|
|
||||||
|
public StatNameValue[] Stats { get; }
|
||||||
|
|
||||||
|
public CityInfo City { get; }
|
||||||
|
|
||||||
|
public SkillNameValue[] Skills { get; }
|
||||||
|
|
||||||
|
public int ShirtHue { get; }
|
||||||
|
|
||||||
|
public int PantsHue { get; }
|
||||||
|
|
||||||
|
public int HairID { get; }
|
||||||
|
|
||||||
|
public int HairHue { get; }
|
||||||
|
|
||||||
|
public int BeardID { get; }
|
||||||
|
|
||||||
|
public int BeardHue { get; }
|
||||||
|
|
||||||
|
public int Profession { get; set; }
|
||||||
|
|
||||||
|
public Race Race { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly record struct SkillNameValue(SkillName Name, int Value);
|
||||||
|
public readonly record struct StatNameValue(StatType Name, int Value);
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<CharacterCreatedEventArgs> CharacterCreated;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) => CharacterCreated?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: EventSink.cs *
|
* File: EventSink.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,145 +17,144 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
{
|
{
|
||||||
public static partial class EventSink
|
public static event Action<Mobile> OpenDoorMacroUsed;
|
||||||
|
public static void InvokeOpenDoorMacroUsed(Mobile m) => OpenDoorMacroUsed?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> Login;
|
||||||
|
public static void InvokeLogin(Mobile m) => Login?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile, int> HungerChanged;
|
||||||
|
public static void InvokeHungerChanged(Mobile mobile, int oldValue) => HungerChanged?.Invoke(mobile, oldValue);
|
||||||
|
|
||||||
|
public static event Action Shutdown;
|
||||||
|
public static void InvokeShutdown() => Shutdown?.Invoke();
|
||||||
|
|
||||||
|
public static event Action<Mobile> HelpRequest;
|
||||||
|
public static void InvokeHelpRequest(Mobile m) => HelpRequest?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> DisarmRequest;
|
||||||
|
public static void InvokeDisarmRequest(Mobile m) => DisarmRequest?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> StunRequest;
|
||||||
|
public static void InvokeStunRequest(Mobile m) => StunRequest?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile, int> OpenSpellbookRequest;
|
||||||
|
public static void InvokeOpenSpellbookRequest(Mobile m, int type) => OpenSpellbookRequest?.Invoke(m, type);
|
||||||
|
|
||||||
|
public static event Action<Mobile, int, Item> CastSpellRequest;
|
||||||
|
|
||||||
|
public static void InvokeCastSpellRequest(Mobile m, int spellID, Item book) =>
|
||||||
|
CastSpellRequest?.Invoke(m, spellID, book);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Item, Mobile> BandageTargetRequest;
|
||||||
|
|
||||||
|
public static void InvokeBandageTargetRequest(Mobile m, Item bandage, Mobile target) =>
|
||||||
|
BandageTargetRequest?.Invoke(m, bandage, target);
|
||||||
|
|
||||||
|
public static event Action<Mobile, string> AnimateRequest;
|
||||||
|
public static void InvokeAnimateRequest(Mobile m, string action) => AnimateRequest?.Invoke(m, action);
|
||||||
|
|
||||||
|
public static event Action<Mobile> Logout;
|
||||||
|
public static void InvokeLogout(Mobile m) => Logout?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> Connected;
|
||||||
|
public static void InvokeConnected(Mobile m) => Connected?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> BeforeDisconnected;
|
||||||
|
public static void InvokeBeforeDisconnected(Mobile m) => BeforeDisconnected?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> Disconnected;
|
||||||
|
public static void InvokeDisconnected(Mobile m) => Disconnected?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile, string> RenameRequest;
|
||||||
|
|
||||||
|
public static void InvokeRenameRequest(Mobile from, Mobile target, string name) =>
|
||||||
|
RenameRequest?.Invoke(from, target, name);
|
||||||
|
|
||||||
|
public static event Action<Mobile> PlayerDeath;
|
||||||
|
public static void InvokePlayerDeath(Mobile m) => PlayerDeath?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile> VirtueGumpRequest;
|
||||||
|
|
||||||
|
public static void InvokeVirtueGumpRequest(Mobile beholder, Mobile beheld) =>
|
||||||
|
VirtueGumpRequest?.Invoke(beholder, beheld);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile, int> VirtueItemRequest;
|
||||||
|
|
||||||
|
public static void InvokeVirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) =>
|
||||||
|
VirtueItemRequest?.Invoke(beholder, beheld, gumpID);
|
||||||
|
|
||||||
|
public static event Action<Mobile, int> VirtueMacroRequest;
|
||||||
|
|
||||||
|
public static void InvokeVirtueMacroRequest(Mobile mobile, int virtueID) =>
|
||||||
|
VirtueMacroRequest?.Invoke(mobile, virtueID);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile> PaperdollRequest;
|
||||||
|
|
||||||
|
public static void InvokePaperdollRequest(Mobile beholder, Mobile beheld) =>
|
||||||
|
PaperdollRequest?.Invoke(beholder, beheld);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile> ProfileRequest;
|
||||||
|
public static void InvokeProfileRequest(Mobile beholder, Mobile beheld) => ProfileRequest?.Invoke(beholder, beheld);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Mobile, string> ChangeProfileRequest;
|
||||||
|
|
||||||
|
public static void InvokeChangeProfileRequest(Mobile beholder, Mobile beheld, string text) =>
|
||||||
|
ChangeProfileRequest?.Invoke(beholder, beheld, text);
|
||||||
|
|
||||||
|
public static event Action<NetState, int> DeleteRequest;
|
||||||
|
public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index);
|
||||||
|
|
||||||
|
public static event Action ServerStarted;
|
||||||
|
public static void InvokeServerStarted() => ServerStarted?.Invoke();
|
||||||
|
|
||||||
|
public static event Action<Mobile> GuildGumpRequest;
|
||||||
|
public static void InvokeGuildGumpRequest(Mobile m) => GuildGumpRequest?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<Mobile> QuestGumpRequest;
|
||||||
|
public static void InvokeQuestGumpRequest(Mobile m) => QuestGumpRequest?.Invoke(m);
|
||||||
|
|
||||||
|
public static event Action<NetState, ClientVersion> ClientVersionReceived;
|
||||||
|
|
||||||
|
public static void InvokeClientVersionReceived(NetState state, ClientVersion cv) =>
|
||||||
|
ClientVersionReceived?.Invoke(state, cv);
|
||||||
|
|
||||||
|
public static event Action<Mobile, List<Serial>> EquipMacro;
|
||||||
|
|
||||||
|
public static void InvokeEquipMacro(Mobile m, List<Serial> list)
|
||||||
{
|
{
|
||||||
public static event Action<Mobile> OpenDoorMacroUsed;
|
if (list?.Count > 0)
|
||||||
public static void InvokeOpenDoorMacroUsed(Mobile m) => OpenDoorMacroUsed?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> Login;
|
|
||||||
public static void InvokeLogin(Mobile m) => Login?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile, int> HungerChanged;
|
|
||||||
public static void InvokeHungerChanged(Mobile mobile, int oldValue) => HungerChanged?.Invoke(mobile, oldValue);
|
|
||||||
|
|
||||||
public static event Action Shutdown;
|
|
||||||
public static void InvokeShutdown() => Shutdown?.Invoke();
|
|
||||||
|
|
||||||
public static event Action<Mobile> HelpRequest;
|
|
||||||
public static void InvokeHelpRequest(Mobile m) => HelpRequest?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> DisarmRequest;
|
|
||||||
public static void InvokeDisarmRequest(Mobile m) => DisarmRequest?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> StunRequest;
|
|
||||||
public static void InvokeStunRequest(Mobile m) => StunRequest?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile, int> OpenSpellbookRequest;
|
|
||||||
public static void InvokeOpenSpellbookRequest(Mobile m, int type) => OpenSpellbookRequest?.Invoke(m, type);
|
|
||||||
|
|
||||||
public static event Action<Mobile, int, Item> CastSpellRequest;
|
|
||||||
|
|
||||||
public static void InvokeCastSpellRequest(Mobile m, int spellID, Item book) =>
|
|
||||||
CastSpellRequest?.Invoke(m, spellID, book);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Item, Mobile> BandageTargetRequest;
|
|
||||||
|
|
||||||
public static void InvokeBandageTargetRequest(Mobile m, Item bandage, Mobile target) =>
|
|
||||||
BandageTargetRequest?.Invoke(m, bandage, target);
|
|
||||||
|
|
||||||
public static event Action<Mobile, string> AnimateRequest;
|
|
||||||
public static void InvokeAnimateRequest(Mobile m, string action) => AnimateRequest?.Invoke(m, action);
|
|
||||||
|
|
||||||
public static event Action<Mobile> Logout;
|
|
||||||
public static void InvokeLogout(Mobile m) => Logout?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> Connected;
|
|
||||||
public static void InvokeConnected(Mobile m) => Connected?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> BeforeDisconnected;
|
|
||||||
public static void InvokeBeforeDisconnected(Mobile m) => BeforeDisconnected?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> Disconnected;
|
|
||||||
public static void InvokeDisconnected(Mobile m) => Disconnected?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile, string> RenameRequest;
|
|
||||||
|
|
||||||
public static void InvokeRenameRequest(Mobile from, Mobile target, string name) =>
|
|
||||||
RenameRequest?.Invoke(from, target, name);
|
|
||||||
|
|
||||||
public static event Action<Mobile> PlayerDeath;
|
|
||||||
public static void InvokePlayerDeath(Mobile m) => PlayerDeath?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile> VirtueGumpRequest;
|
|
||||||
|
|
||||||
public static void InvokeVirtueGumpRequest(Mobile beholder, Mobile beheld) =>
|
|
||||||
VirtueGumpRequest?.Invoke(beholder, beheld);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile, int> VirtueItemRequest;
|
|
||||||
|
|
||||||
public static void InvokeVirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) =>
|
|
||||||
VirtueItemRequest?.Invoke(beholder, beheld, gumpID);
|
|
||||||
|
|
||||||
public static event Action<Mobile, int> VirtueMacroRequest;
|
|
||||||
|
|
||||||
public static void InvokeVirtueMacroRequest(Mobile mobile, int virtueID) =>
|
|
||||||
VirtueMacroRequest?.Invoke(mobile, virtueID);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile> PaperdollRequest;
|
|
||||||
|
|
||||||
public static void InvokePaperdollRequest(Mobile beholder, Mobile beheld) =>
|
|
||||||
PaperdollRequest?.Invoke(beholder, beheld);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile> ProfileRequest;
|
|
||||||
public static void InvokeProfileRequest(Mobile beholder, Mobile beheld) => ProfileRequest?.Invoke(beholder, beheld);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Mobile, string> ChangeProfileRequest;
|
|
||||||
|
|
||||||
public static void InvokeChangeProfileRequest(Mobile beholder, Mobile beheld, string text) =>
|
|
||||||
ChangeProfileRequest?.Invoke(beholder, beheld, text);
|
|
||||||
|
|
||||||
public static event Action<NetState, int> DeleteRequest;
|
|
||||||
public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index);
|
|
||||||
|
|
||||||
public static event Action ServerStarted;
|
|
||||||
public static void InvokeServerStarted() => ServerStarted?.Invoke();
|
|
||||||
|
|
||||||
public static event Action<Mobile> GuildGumpRequest;
|
|
||||||
public static void InvokeGuildGumpRequest(Mobile m) => GuildGumpRequest?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<Mobile> QuestGumpRequest;
|
|
||||||
public static void InvokeQuestGumpRequest(Mobile m) => QuestGumpRequest?.Invoke(m);
|
|
||||||
|
|
||||||
public static event Action<NetState, ClientVersion> ClientVersionReceived;
|
|
||||||
|
|
||||||
public static void InvokeClientVersionReceived(NetState state, ClientVersion cv) =>
|
|
||||||
ClientVersionReceived?.Invoke(state, cv);
|
|
||||||
|
|
||||||
public static event Action<Mobile, List<Serial>> EquipMacro;
|
|
||||||
|
|
||||||
public static void InvokeEquipMacro(Mobile m, List<Serial> list)
|
|
||||||
{
|
{
|
||||||
if (list?.Count > 0)
|
EquipMacro?.Invoke(m, list);
|
||||||
{
|
|
||||||
EquipMacro?.Invoke(m, list);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static event Action<Mobile, List<Layer>> UnequipMacro;
|
|
||||||
|
|
||||||
public static void InvokeUnequipMacro(Mobile m, List<Layer> layers)
|
|
||||||
{
|
|
||||||
if (layers?.Count > 0)
|
|
||||||
{
|
|
||||||
UnequipMacro?.Invoke(m, layers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static event Action<Mobile, IEntity, int> TargetedSpell;
|
|
||||||
|
|
||||||
public static void InvokeTargetedSpell(Mobile m, IEntity target, int spellId) =>
|
|
||||||
TargetedSpell?.Invoke(m, target, spellId);
|
|
||||||
|
|
||||||
public static event Action<Mobile, IEntity, int> TargetedSkillUse;
|
|
||||||
|
|
||||||
public static void InvokeTargetedSkillUse(Mobile m, IEntity target, int skillId) =>
|
|
||||||
TargetedSkillUse?.Invoke(m, target, skillId);
|
|
||||||
|
|
||||||
public static event Action<Mobile, Item, short> TargetByResourceMacro;
|
|
||||||
|
|
||||||
public static void InvokeTargetByResourceMacro(Mobile m, Item item, short resourceType) =>
|
|
||||||
TargetByResourceMacro?.Invoke(m, item, resourceType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static event Action<Mobile, List<Layer>> UnequipMacro;
|
||||||
|
|
||||||
|
public static void InvokeUnequipMacro(Mobile m, List<Layer> layers)
|
||||||
|
{
|
||||||
|
if (layers?.Count > 0)
|
||||||
|
{
|
||||||
|
UnequipMacro?.Invoke(m, layers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static event Action<Mobile, IEntity, int> TargetedSpell;
|
||||||
|
|
||||||
|
public static void InvokeTargetedSpell(Mobile m, IEntity target, int spellId) =>
|
||||||
|
TargetedSpell?.Invoke(m, target, spellId);
|
||||||
|
|
||||||
|
public static event Action<Mobile, IEntity, int> TargetedSkillUse;
|
||||||
|
|
||||||
|
public static void InvokeTargetedSkillUse(Mobile m, IEntity target, int skillId) =>
|
||||||
|
TargetedSkillUse?.Invoke(m, target, skillId);
|
||||||
|
|
||||||
|
public static event Action<Mobile, Item, short> TargetByResourceMacro;
|
||||||
|
|
||||||
|
public static void InvokeTargetByResourceMacro(Mobile m, Item item, short resourceType) =>
|
||||||
|
TargetByResourceMacro?.Invoke(m, item, resourceType);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: FastwalkEvent.cs *
|
* File: FastwalkEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,22 +17,21 @@ using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class FastWalkEventArgs
|
||||||
{
|
{
|
||||||
public class FastWalkEventArgs
|
public FastWalkEventArgs(NetState state) => NetState = state;
|
||||||
{
|
|
||||||
public FastWalkEventArgs(NetState state) => NetState = state;
|
|
||||||
|
|
||||||
public NetState NetState { get; }
|
public NetState NetState { get; }
|
||||||
|
|
||||||
public bool Blocked { get; set; } = true;
|
public bool Blocked { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public static partial class EventSink
|
||||||
{
|
{
|
||||||
public static event Action<FastWalkEventArgs> FastWalk;
|
public static event Action<FastWalkEventArgs> FastWalk;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void InvokeFastWalk(FastWalkEventArgs e) => FastWalk?.Invoke(e);
|
public static void InvokeFastWalk(FastWalkEventArgs e) => FastWalk?.Invoke(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GameLoginEvent.cs *
|
* File: GameLoginEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,33 +17,32 @@ using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class GameLoginEventArgs
|
||||||
{
|
{
|
||||||
public class GameLoginEventArgs
|
public GameLoginEventArgs(NetState state, string un, string pw)
|
||||||
{
|
{
|
||||||
public GameLoginEventArgs(NetState state, string un, string pw)
|
State = state;
|
||||||
{
|
Username = un;
|
||||||
State = state;
|
Password = pw;
|
||||||
Username = un;
|
|
||||||
Password = pw;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NetState State { get; }
|
|
||||||
|
|
||||||
public string Username { get; }
|
|
||||||
|
|
||||||
public string Password { get; }
|
|
||||||
|
|
||||||
public bool Accepted { get; set; }
|
|
||||||
|
|
||||||
public CityInfo[] CityInfo { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public NetState State { get; }
|
||||||
{
|
|
||||||
public static event Action<GameLoginEventArgs> GameLogin;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public string Username { get; }
|
||||||
public static void InvokeGameLogin(GameLoginEventArgs e) => GameLogin?.Invoke(e);
|
|
||||||
}
|
public string Password { get; }
|
||||||
|
|
||||||
|
public bool Accepted { get; set; }
|
||||||
|
|
||||||
|
public CityInfo[] CityInfo { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<GameLoginEventArgs> GameLogin;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeGameLogin(GameLoginEventArgs e) => GameLogin?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: MovementEvent.cs *
|
* File: MovementEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,55 +17,54 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class MovementEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public class MovementEventArgs : EventArgs
|
private static readonly Queue<MovementEventArgs> m_Pool = new();
|
||||||
|
|
||||||
|
public MovementEventArgs(Mobile mobile, Direction dir)
|
||||||
{
|
{
|
||||||
private static readonly Queue<MovementEventArgs> m_Pool = new();
|
Mobile = mobile;
|
||||||
|
Direction = dir;
|
||||||
public MovementEventArgs(Mobile mobile, Direction dir)
|
|
||||||
{
|
|
||||||
Mobile = mobile;
|
|
||||||
Direction = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mobile Mobile { get; private set; }
|
|
||||||
|
|
||||||
public Direction Direction { get; private set; }
|
|
||||||
|
|
||||||
public bool Blocked { get; set; }
|
|
||||||
|
|
||||||
public static MovementEventArgs Create(Mobile mobile, Direction dir)
|
|
||||||
{
|
|
||||||
MovementEventArgs args;
|
|
||||||
|
|
||||||
if (m_Pool.Count > 0)
|
|
||||||
{
|
|
||||||
args = m_Pool.Dequeue();
|
|
||||||
|
|
||||||
args.Mobile = mobile;
|
|
||||||
args.Direction = dir;
|
|
||||||
args.Blocked = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args = new MovementEventArgs(mobile, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Free()
|
|
||||||
{
|
|
||||||
m_Pool.Enqueue(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public Mobile Mobile { get; private set; }
|
||||||
{
|
|
||||||
public static event Action<MovementEventArgs> Movement;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public Direction Direction { get; private set; }
|
||||||
public static void InvokeMovement(MovementEventArgs e) => Movement?.Invoke(e);
|
|
||||||
|
public bool Blocked { get; set; }
|
||||||
|
|
||||||
|
public static MovementEventArgs Create(Mobile mobile, Direction dir)
|
||||||
|
{
|
||||||
|
MovementEventArgs args;
|
||||||
|
|
||||||
|
if (m_Pool.Count > 0)
|
||||||
|
{
|
||||||
|
args = m_Pool.Dequeue();
|
||||||
|
|
||||||
|
args.Mobile = mobile;
|
||||||
|
args.Direction = dir;
|
||||||
|
args.Blocked = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args = new MovementEventArgs(mobile, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free()
|
||||||
|
{
|
||||||
|
m_Pool.Enqueue(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<MovementEventArgs> Movement;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeMovement(MovementEventArgs e) => Movement?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ServerCrashedEvent.cs *
|
* File: ServerCrashedEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,22 +16,21 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class ServerCrashedEventArgs
|
||||||
{
|
{
|
||||||
public class ServerCrashedEventArgs
|
public ServerCrashedEventArgs(Exception e) => Exception = e;
|
||||||
{
|
|
||||||
public ServerCrashedEventArgs(Exception e) => Exception = e;
|
|
||||||
|
|
||||||
public Exception Exception { get; }
|
public Exception Exception { get; }
|
||||||
|
|
||||||
public bool Close { get; set; }
|
public bool Close { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public static partial class EventSink
|
||||||
{
|
{
|
||||||
public static event Action<ServerCrashedEventArgs> ServerCrashed;
|
public static event Action<ServerCrashedEventArgs> ServerCrashed;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void InvokeServerCrashed(ServerCrashedEventArgs e) => ServerCrashed?.Invoke(e);
|
public static void InvokeServerCrashed(ServerCrashedEventArgs e) => ServerCrashed?.Invoke(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ServerListEvent.cs *
|
* File: ServerListEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -20,41 +20,40 @@ using System.Runtime.CompilerServices;
|
||||||
using Server.Accounting;
|
using Server.Accounting;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class ServerListEventArgs
|
||||||
{
|
{
|
||||||
public class ServerListEventArgs
|
public ServerListEventArgs(NetState state, IAccount account)
|
||||||
{
|
{
|
||||||
public ServerListEventArgs(NetState state, IAccount account)
|
State = state;
|
||||||
{
|
Account = account;
|
||||||
State = state;
|
Servers = new List<ServerInfo>();
|
||||||
Account = account;
|
|
||||||
Servers = new List<ServerInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NetState State { get; }
|
|
||||||
|
|
||||||
public IAccount Account { get; }
|
|
||||||
|
|
||||||
public bool Rejected { get; set; }
|
|
||||||
|
|
||||||
public List<ServerInfo> Servers { get; }
|
|
||||||
|
|
||||||
public void AddServer(string name, IPEndPoint address)
|
|
||||||
{
|
|
||||||
AddServer(name, 0, TimeZoneInfo.Local, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address)
|
|
||||||
{
|
|
||||||
Servers.Add(new ServerInfo(name, fullPercent, tz, address));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public NetState State { get; }
|
||||||
{
|
|
||||||
public static event Action<ServerListEventArgs> ServerList;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public IAccount Account { get; }
|
||||||
public static void InvokeServerList(ServerListEventArgs e) => ServerList?.Invoke(e);
|
|
||||||
|
public bool Rejected { get; set; }
|
||||||
|
|
||||||
|
public List<ServerInfo> Servers { get; }
|
||||||
|
|
||||||
|
public void AddServer(string name, IPEndPoint address)
|
||||||
|
{
|
||||||
|
AddServer(name, 0, TimeZoneInfo.Local, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address)
|
||||||
|
{
|
||||||
|
Servers.Add(new ServerInfo(name, fullPercent, tz, address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<ServerListEventArgs> ServerList;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeServerList(ServerListEventArgs e) => ServerList?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: SocketConnectionEvent.cs *
|
* File: SocketConnectionEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,26 +17,25 @@ using System;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class SocketConnectEventArgs
|
||||||
{
|
{
|
||||||
public class SocketConnectEventArgs
|
public SocketConnectEventArgs(Socket c)
|
||||||
{
|
{
|
||||||
public SocketConnectEventArgs(Socket c)
|
Connection = c;
|
||||||
{
|
AllowConnection = true;
|
||||||
Connection = c;
|
|
||||||
AllowConnection = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket Connection { get; }
|
|
||||||
|
|
||||||
public bool AllowConnection { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public Socket Connection { get; }
|
||||||
{
|
|
||||||
public static event Action<SocketConnectEventArgs> SocketConnect;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public bool AllowConnection { get; set; }
|
||||||
public static void InvokeSocketConnect(SocketConnectEventArgs e) => SocketConnect?.Invoke(e);
|
}
|
||||||
}
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<SocketConnectEventArgs> SocketConnect;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeSocketConnect(SocketConnectEventArgs e) => SocketConnect?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: SpeechEvent.cs *
|
* File: SpeechEvent.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,52 +17,51 @@ using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class SpeechEventArgs
|
||||||
{
|
{
|
||||||
public class SpeechEventArgs
|
public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords)
|
||||||
{
|
{
|
||||||
public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords)
|
Mobile = mobile;
|
||||||
{
|
Speech = speech;
|
||||||
Mobile = mobile;
|
Type = type;
|
||||||
Speech = speech;
|
Hue = hue;
|
||||||
Type = type;
|
Keywords = keywords;
|
||||||
Hue = hue;
|
|
||||||
Keywords = keywords;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mobile Mobile { get; }
|
|
||||||
|
|
||||||
public string Speech { get; set; }
|
|
||||||
|
|
||||||
public MessageType Type { get; }
|
|
||||||
|
|
||||||
public int Hue { get; }
|
|
||||||
|
|
||||||
public int[] Keywords { get; }
|
|
||||||
|
|
||||||
public bool Handled { get; set; }
|
|
||||||
|
|
||||||
public bool Blocked { get; set; }
|
|
||||||
|
|
||||||
public bool HasKeyword(int keyword)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < Keywords.Length; ++i)
|
|
||||||
{
|
|
||||||
if (Keywords[i] == keyword)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EventSink
|
public Mobile Mobile { get; }
|
||||||
{
|
|
||||||
public static event Action<SpeechEventArgs> Speech;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public string Speech { get; set; }
|
||||||
public static void InvokeSpeech(SpeechEventArgs e) => Speech?.Invoke(e);
|
|
||||||
|
public MessageType Type { get; }
|
||||||
|
|
||||||
|
public int Hue { get; }
|
||||||
|
|
||||||
|
public int[] Keywords { get; }
|
||||||
|
|
||||||
|
public bool Handled { get; set; }
|
||||||
|
|
||||||
|
public bool Blocked { get; set; }
|
||||||
|
|
||||||
|
public bool HasKeyword(int keyword)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Keywords.Length; ++i)
|
||||||
|
{
|
||||||
|
if (Keywords[i] == keyword)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static partial class EventSink
|
||||||
|
{
|
||||||
|
public static event Action<SpeechEventArgs> Speech;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeSpeech(SpeechEventArgs e) => Speech?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ExceptionExtensions.cs *
|
* File: ExceptionExtensions.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -18,25 +18,24 @@ using System.Diagnostics;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Server.Exceptions
|
namespace Server.Exceptions;
|
||||||
|
|
||||||
|
public static class ExceptionExtensions
|
||||||
{
|
{
|
||||||
public static class ExceptionExtensions
|
public static Exception SetStackTrace(this Exception target, StackTrace stack) => _setStackTrace(target, stack);
|
||||||
|
|
||||||
|
private static readonly Func<Exception, StackTrace, Exception> _setStackTrace = _createStackTraceMethod();
|
||||||
|
|
||||||
|
private static Func<Exception, StackTrace, Exception> _createStackTraceMethod()
|
||||||
{
|
{
|
||||||
public static Exception SetStackTrace(this Exception target, StackTrace stack) => _setStackTrace(target, stack);
|
ParameterExpression target = Expression.Parameter(typeof(Exception));
|
||||||
|
ParameterExpression stack = Expression.Parameter(typeof(StackTrace));
|
||||||
private static readonly Func<Exception, StackTrace, Exception> _setStackTrace = _createStackTraceMethod();
|
Type traceFormatType = typeof(StackTrace).GetNestedType("TraceFormat", BindingFlags.NonPublic);
|
||||||
|
MethodInfo toString = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { traceFormatType }, null);
|
||||||
private static Func<Exception, StackTrace, Exception> _createStackTraceMethod()
|
object normalTraceFormat = Enum.GetValues(traceFormatType!).GetValue(0);
|
||||||
{
|
MethodCallExpression stackTraceString = Expression.Call(stack, toString!, Expression.Constant(normalTraceFormat, traceFormatType));
|
||||||
ParameterExpression target = Expression.Parameter(typeof(Exception));
|
FieldInfo stackTraceStringField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
ParameterExpression stack = Expression.Parameter(typeof(StackTrace));
|
BinaryExpression assign = Expression.Assign(Expression.Field(target, stackTraceStringField!), stackTraceString);
|
||||||
Type traceFormatType = typeof(StackTrace).GetNestedType("TraceFormat", BindingFlags.NonPublic);
|
return Expression.Lambda<Func<Exception, StackTrace, Exception>>(Expression.Block(assign, target), target, stack).Compile();
|
||||||
MethodInfo toString = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { traceFormatType }, null);
|
|
||||||
object normalTraceFormat = Enum.GetValues(traceFormatType!).GetValue(0);
|
|
||||||
MethodCallExpression stackTraceString = Expression.Call(stack, toString!, Expression.Constant(normalTraceFormat, traceFormatType));
|
|
||||||
FieldInfo stackTraceStringField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
BinaryExpression assign = Expression.Assign(Expression.Field(target, stackTraceStringField!), stackTraceString);
|
|
||||||
return Expression.Lambda<Func<Exception, StackTrace, Exception>>(Expression.Block(assign, target), target, stack).Compile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: InvalidThreadException.cs *
|
* File: InvalidThreadException.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,12 +15,11 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server.Exceptions
|
namespace Server.Exceptions;
|
||||||
|
|
||||||
|
public class InvalidThreadException : Exception
|
||||||
{
|
{
|
||||||
public class InvalidThreadException : Exception
|
public InvalidThreadException(string methodName) : base($"{methodName} executed on an invalid thread.")
|
||||||
{
|
{
|
||||||
public InvalidThreadException(string methodName) : base($"{methodName} executed on an invalid thread.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: MaxConnectionsException.cs *
|
* File: MaxConnectionsException.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,12 +15,11 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server.Exceptions
|
namespace Server.Exceptions;
|
||||||
|
|
||||||
|
public class MaxConnectionsException : Exception
|
||||||
{
|
{
|
||||||
public class MaxConnectionsException : Exception
|
public MaxConnectionsException() : base("Maximum connections exceeded")
|
||||||
{
|
{
|
||||||
public MaxConnectionsException() : base("Maximum connections exceeded")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ExpansionInfo.cs *
|
* File: ExpansionInfo.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point2D.cs *
|
* File: Point2D.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,102 +15,101 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
[Parsable]
|
||||||
|
public struct Point2D
|
||||||
|
: IPoint2D, IComparable<Point2D>, IComparable<IPoint2D>, IEquatable<object>, IEquatable<Point2D>,
|
||||||
|
IEquatable<IPoint2D>
|
||||||
{
|
{
|
||||||
[Parsable]
|
internal int m_X;
|
||||||
public struct Point2D
|
internal int m_Y;
|
||||||
: IPoint2D, IComparable<Point2D>, IComparable<IPoint2D>, IEquatable<object>, IEquatable<Point2D>,
|
|
||||||
IEquatable<IPoint2D>
|
public static readonly Point2D Zero = new(0, 0);
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int X
|
||||||
{
|
{
|
||||||
internal int m_X;
|
get => m_X;
|
||||||
internal int m_Y;
|
set => m_X = value;
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly Point2D Zero = new(0, 0);
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Y
|
||||||
|
{
|
||||||
|
get => m_Y;
|
||||||
|
set => m_Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
public Point2D(int x, int y)
|
||||||
public int X
|
{
|
||||||
{
|
m_X = x;
|
||||||
get => m_X;
|
m_Y = y;
|
||||||
set => m_X = value;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
public Point2D(Point2D p) : this(p.X, p.Y)
|
||||||
public int Y
|
{
|
||||||
{
|
}
|
||||||
get => m_Y;
|
|
||||||
set => m_Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point2D(int x, int y)
|
public override string ToString() => $"({m_X}, {m_Y})";
|
||||||
{
|
|
||||||
m_X = x;
|
|
||||||
m_Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point2D(Point2D p) : this(p.X, p.Y)
|
public static Point2D Parse(string value)
|
||||||
{
|
{
|
||||||
}
|
var start = value.IndexOfOrdinal('(');
|
||||||
|
var end = value.IndexOf(',', start + 1);
|
||||||
|
|
||||||
public override string ToString() => $"({m_X}, {m_Y})";
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||||
|
|
||||||
public static Point2D Parse(string value)
|
start = end;
|
||||||
{
|
end = value.IndexOf(')', start + 1);
|
||||||
var start = value.IndexOfOrdinal('(');
|
|
||||||
var end = value.IndexOf(',', start + 1);
|
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||||
|
|
||||||
start = end;
|
return new Point2D(x, y);
|
||||||
end = value.IndexOf(')', start + 1);
|
}
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
public bool Equals(Point2D other) => m_X == other.m_X && m_Y == other.m_Y;
|
||||||
|
|
||||||
return new Point2D(x, y);
|
public bool Equals(IPoint2D other) =>
|
||||||
}
|
m_X == other?.X && m_Y == other.Y;
|
||||||
|
|
||||||
public bool Equals(Point2D other) => m_X == other.m_X && m_Y == other.m_Y;
|
public override bool Equals(object obj) => obj is Point2D other && Equals(other);
|
||||||
|
|
||||||
public bool Equals(IPoint2D other) =>
|
public override int GetHashCode() => HashCode.Combine(m_X, m_Y);
|
||||||
m_X == other?.X && m_Y == other.Y;
|
|
||||||
|
|
||||||
public override bool Equals(object obj) => obj is Point2D other && Equals(other);
|
public static bool operator ==(Point2D l, Point2D r) => l.m_X == r.m_X && l.m_Y == r.m_Y;
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(m_X, m_Y);
|
public static bool operator !=(Point2D l, Point2D r) => l.m_X != r.m_X || l.m_Y != r.m_Y;
|
||||||
|
|
||||||
public static bool operator ==(Point2D l, Point2D r) => l.m_X == r.m_X && l.m_Y == r.m_Y;
|
public static bool operator ==(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y;
|
||||||
|
|
||||||
public static bool operator !=(Point2D l, Point2D r) => l.m_X != r.m_X || l.m_Y != r.m_Y;
|
public static bool operator !=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && (l.m_X != r.X || l.m_Y != r.Y);
|
||||||
|
|
||||||
public static bool operator ==(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y;
|
public static bool operator >(Point2D l, Point2D r) => l.m_X > r.m_X && l.m_Y > r.m_Y;
|
||||||
|
|
||||||
public static bool operator !=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && (l.m_X != r.X || l.m_Y != r.Y);
|
public static bool operator >(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X > r.X && l.m_Y > r.Y;
|
||||||
|
|
||||||
public static bool operator >(Point2D l, Point2D r) => l.m_X > r.m_X && l.m_Y > r.m_Y;
|
public static bool operator <(Point2D l, Point2D r) => l.m_X < r.m_X && l.m_Y < r.m_Y;
|
||||||
|
|
||||||
public static bool operator >(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X > r.X && l.m_Y > r.Y;
|
public static bool operator <(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X < r.X && l.m_Y < r.Y;
|
||||||
|
|
||||||
public static bool operator <(Point2D l, Point2D r) => l.m_X < r.m_X && l.m_Y < r.m_Y;
|
public static bool operator >=(Point2D l, Point2D r) => l.m_X >= r.m_X && l.m_Y >= r.m_Y;
|
||||||
|
|
||||||
public static bool operator <(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X < r.X && l.m_Y < r.Y;
|
public static bool operator >=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X >= r.X && l.m_Y >= r.Y;
|
||||||
|
|
||||||
public static bool operator >=(Point2D l, Point2D r) => l.m_X >= r.m_X && l.m_Y >= r.m_Y;
|
public static bool operator <=(Point2D l, Point2D r) => l.m_X <= r.m_X && l.m_Y <= r.m_Y;
|
||||||
|
|
||||||
public static bool operator >=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X >= r.X && l.m_Y >= r.Y;
|
public static bool operator <=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X <= r.X && l.m_Y <= r.Y;
|
||||||
|
|
||||||
public static bool operator <=(Point2D l, Point2D r) => l.m_X <= r.m_X && l.m_Y <= r.m_Y;
|
public int CompareTo(Point2D other)
|
||||||
|
{
|
||||||
|
var xComparison = m_X.CompareTo(other.m_X);
|
||||||
|
return xComparison != 0 ? xComparison : m_Y.CompareTo(other.m_Y);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool operator <=(Point2D l, IPoint2D r) => !ReferenceEquals(r, null) && l.m_X <= r.X && l.m_Y <= r.Y;
|
public int CompareTo(IPoint2D other)
|
||||||
|
{
|
||||||
public int CompareTo(Point2D other)
|
var xComparison = m_X.CompareTo(other.X);
|
||||||
{
|
return xComparison != 0 ? xComparison : m_Y.CompareTo(other.Y);
|
||||||
var xComparison = m_X.CompareTo(other.m_X);
|
|
||||||
return xComparison != 0 ? xComparison : m_Y.CompareTo(other.m_Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(IPoint2D other)
|
|
||||||
{
|
|
||||||
var xComparison = m_X.CompareTo(other.X);
|
|
||||||
return xComparison != 0 ? xComparison : m_Y.CompareTo(other.Y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point3D.cs *
|
* File: Point3D.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,153 +16,152 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
[Parsable]
|
||||||
|
public struct Point3D
|
||||||
|
: IPoint3D, IComparable<Point3D>, IComparable<IPoint3D>, IEquatable<object>, IEquatable<Point3D>,
|
||||||
|
IEquatable<IPoint3D>
|
||||||
{
|
{
|
||||||
[Parsable]
|
internal int m_X;
|
||||||
public struct Point3D
|
internal int m_Y;
|
||||||
: IPoint3D, IComparable<Point3D>, IComparable<IPoint3D>, IEquatable<object>, IEquatable<Point3D>,
|
internal int m_Z;
|
||||||
IEquatable<IPoint3D>
|
|
||||||
|
public static readonly Point3D Zero = new(0, 0, 0);
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int X
|
||||||
{
|
{
|
||||||
internal int m_X;
|
get => m_X;
|
||||||
internal int m_Y;
|
set => m_X = value;
|
||||||
internal int m_Z;
|
}
|
||||||
|
|
||||||
public static readonly Point3D Zero = new(0, 0, 0);
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Y
|
||||||
|
{
|
||||||
|
get => m_Y;
|
||||||
|
set => m_Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
public int X
|
public int Z
|
||||||
|
{
|
||||||
|
get => m_Z;
|
||||||
|
set => m_Z = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D(Point3D p) : this(p.X, p.Y, p.Z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D(Point2D p, int z) : this(p.X, p.Y, z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D(int x, int y, int z)
|
||||||
|
{
|
||||||
|
m_X = x;
|
||||||
|
m_Y = y;
|
||||||
|
m_Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"({m_X}, {m_Y}, {m_Z})";
|
||||||
|
|
||||||
|
public bool Equals(Point3D other) => m_X == other.m_X && m_Y == other.m_Y && m_Z == other.m_Z;
|
||||||
|
|
||||||
|
public bool Equals(IPoint3D other) =>
|
||||||
|
m_X == other?.X && m_Y == other.Y && m_Z == other.Z;
|
||||||
|
|
||||||
|
public override bool Equals(object obj) => obj is Point3D other && Equals(other);
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(m_X, m_Y, m_Z);
|
||||||
|
|
||||||
|
public static Point3D Parse(string value)
|
||||||
|
{
|
||||||
|
var start = value.IndexOfOrdinal('(');
|
||||||
|
var end = value.IndexOf(',', start + 1);
|
||||||
|
|
||||||
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
end = value.IndexOf(',', start + 1);
|
||||||
|
|
||||||
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
end = value.IndexOf(')', start + 1);
|
||||||
|
|
||||||
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
||||||
|
|
||||||
|
return new Point3D(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Point3D l, Point3D r) => l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator ==(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;
|
||||||
|
|
||||||
|
public static bool operator !=(Point3D l, Point3D r) => l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator !=(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && (l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z);
|
||||||
|
|
||||||
|
public static bool operator >(Point3D l, Point3D r) => l.m_X > r.m_X && l.m_Y > r.m_Y && l.m_Z > r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator >(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_X > r.X && l.m_Y > r.Y && l.m_Z > r.Z;
|
||||||
|
|
||||||
|
public static bool operator <(Point3D l, Point3D r) => l.m_X < r.m_X && l.m_Y < r.m_Y && l.m_Z > r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator <(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_X < r.X && l.m_Y < r.Y && l.m_Z > r.Z;
|
||||||
|
|
||||||
|
public static bool operator >=(Point3D l, Point3D r) => l.m_X >= r.m_X && l.m_Y >= r.m_Y && l.m_Z > r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator >=(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_X >= r.X && l.m_Y >= r.Y && l.m_Z > r.Z;
|
||||||
|
|
||||||
|
public static bool operator <=(Point3D l, Point3D r) => l.m_X <= r.m_X && l.m_Y <= r.m_Y && l.m_Z > r.m_Z;
|
||||||
|
|
||||||
|
public static bool operator <=(Point3D l, IPoint3D r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_X <= r.X && l.m_Y <= r.Y && l.m_Z > r.Z;
|
||||||
|
|
||||||
|
public int CompareTo(Point3D other)
|
||||||
|
{
|
||||||
|
var xComparison = m_X.CompareTo(other.m_X);
|
||||||
|
if (xComparison != 0)
|
||||||
{
|
{
|
||||||
get => m_X;
|
return xComparison;
|
||||||
set => m_X = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
var yComparison = m_Y.CompareTo(other.m_Y);
|
||||||
public int Y
|
if (yComparison != 0)
|
||||||
{
|
{
|
||||||
get => m_Y;
|
return yComparison;
|
||||||
set => m_Y = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
return m_Z.CompareTo(other.m_Z);
|
||||||
public int Z
|
}
|
||||||
|
|
||||||
|
public int CompareTo(IPoint3D other)
|
||||||
|
{
|
||||||
|
var xComparison = m_X.CompareTo(other.X);
|
||||||
|
if (xComparison != 0)
|
||||||
{
|
{
|
||||||
get => m_Z;
|
return xComparison;
|
||||||
set => m_Z = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
var yComparison = m_Y.CompareTo(other.Y);
|
||||||
public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z)
|
if (yComparison != 0)
|
||||||
{
|
{
|
||||||
|
return yComparison;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point3D(Point3D p) : this(p.X, p.Y, p.Z)
|
return m_Z.CompareTo(other.Z);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point3D(Point2D p, int z) : this(p.X, p.Y, z)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point3D(int x, int y, int z)
|
|
||||||
{
|
|
||||||
m_X = x;
|
|
||||||
m_Y = y;
|
|
||||||
m_Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => $"({m_X}, {m_Y}, {m_Z})";
|
|
||||||
|
|
||||||
public bool Equals(Point3D other) => m_X == other.m_X && m_Y == other.m_Y && m_Z == other.m_Z;
|
|
||||||
|
|
||||||
public bool Equals(IPoint3D other) =>
|
|
||||||
m_X == other?.X && m_Y == other.Y && m_Z == other.Z;
|
|
||||||
|
|
||||||
public override bool Equals(object obj) => obj is Point3D other && Equals(other);
|
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(m_X, m_Y, m_Z);
|
|
||||||
|
|
||||||
public static Point3D Parse(string value)
|
|
||||||
{
|
|
||||||
var start = value.IndexOfOrdinal('(');
|
|
||||||
var end = value.IndexOf(',', start + 1);
|
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
|
||||||
|
|
||||||
start = end;
|
|
||||||
end = value.IndexOf(',', start + 1);
|
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
|
||||||
|
|
||||||
start = end;
|
|
||||||
end = value.IndexOf(')', start + 1);
|
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
|
||||||
|
|
||||||
return new Point3D(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Point3D l, Point3D r) => l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator ==(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;
|
|
||||||
|
|
||||||
public static bool operator !=(Point3D l, Point3D r) => l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator !=(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && (l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z);
|
|
||||||
|
|
||||||
public static bool operator >(Point3D l, Point3D r) => l.m_X > r.m_X && l.m_Y > r.m_Y && l.m_Z > r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator >(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && l.m_X > r.X && l.m_Y > r.Y && l.m_Z > r.Z;
|
|
||||||
|
|
||||||
public static bool operator <(Point3D l, Point3D r) => l.m_X < r.m_X && l.m_Y < r.m_Y && l.m_Z > r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator <(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && l.m_X < r.X && l.m_Y < r.Y && l.m_Z > r.Z;
|
|
||||||
|
|
||||||
public static bool operator >=(Point3D l, Point3D r) => l.m_X >= r.m_X && l.m_Y >= r.m_Y && l.m_Z > r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator >=(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && l.m_X >= r.X && l.m_Y >= r.Y && l.m_Z > r.Z;
|
|
||||||
|
|
||||||
public static bool operator <=(Point3D l, Point3D r) => l.m_X <= r.m_X && l.m_Y <= r.m_Y && l.m_Z > r.m_Z;
|
|
||||||
|
|
||||||
public static bool operator <=(Point3D l, IPoint3D r) =>
|
|
||||||
!ReferenceEquals(r, null) && l.m_X <= r.X && l.m_Y <= r.Y && l.m_Z > r.Z;
|
|
||||||
|
|
||||||
public int CompareTo(Point3D other)
|
|
||||||
{
|
|
||||||
var xComparison = m_X.CompareTo(other.m_X);
|
|
||||||
if (xComparison != 0)
|
|
||||||
{
|
|
||||||
return xComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
var yComparison = m_Y.CompareTo(other.m_Y);
|
|
||||||
if (yComparison != 0)
|
|
||||||
{
|
|
||||||
return yComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Z.CompareTo(other.m_Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(IPoint3D other)
|
|
||||||
{
|
|
||||||
var xComparison = m_X.CompareTo(other.X);
|
|
||||||
if (xComparison != 0)
|
|
||||||
{
|
|
||||||
return xComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
var yComparison = m_Y.CompareTo(other.Y);
|
|
||||||
if (yComparison != 0)
|
|
||||||
{
|
|
||||||
return yComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Z.CompareTo(other.Z);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,83 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class Point3DList
|
||||||
{
|
{
|
||||||
public class Point3DList
|
private static readonly Point3D[] m_EmptyList = Array.Empty<Point3D>();
|
||||||
|
private Point3D[] m_List;
|
||||||
|
|
||||||
|
public Point3DList()
|
||||||
{
|
{
|
||||||
private static readonly Point3D[] m_EmptyList = Array.Empty<Point3D>();
|
m_List = new Point3D[8];
|
||||||
private Point3D[] m_List;
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public Point3DList()
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
public Point3D Last => m_List[Count - 1];
|
||||||
|
|
||||||
|
public Point3D this[int index] => m_List[index];
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int x, int y, int z)
|
||||||
|
{
|
||||||
|
if (Count + 1 > m_List.Length)
|
||||||
{
|
{
|
||||||
m_List = new Point3D[8];
|
var old = m_List;
|
||||||
Count = 0;
|
m_List = new Point3D[old.Length * 2];
|
||||||
}
|
|
||||||
|
|
||||||
public int Count { get; private set; }
|
for (var i = 0; i < old.Length; ++i)
|
||||||
|
|
||||||
public Point3D Last => m_List[Count - 1];
|
|
||||||
|
|
||||||
public Point3D this[int index] => m_List[index];
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
Count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(int x, int y, int z)
|
|
||||||
{
|
|
||||||
if (Count + 1 > m_List.Length)
|
|
||||||
{
|
{
|
||||||
var old = m_List;
|
m_List[i] = old[i];
|
||||||
m_List = new Point3D[old.Length * 2];
|
|
||||||
|
|
||||||
for (var i = 0; i < old.Length; ++i)
|
|
||||||
{
|
|
||||||
m_List[i] = old[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_List[Count].m_X = x;
|
|
||||||
m_List[Count].m_Y = y;
|
|
||||||
m_List[Count].m_Z = z;
|
|
||||||
++Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(Point3D p)
|
m_List[Count].m_X = x;
|
||||||
|
m_List[Count].m_Y = y;
|
||||||
|
m_List[Count].m_Z = z;
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(Point3D p)
|
||||||
|
{
|
||||||
|
if (Count + 1 > m_List.Length)
|
||||||
{
|
{
|
||||||
if (Count + 1 > m_List.Length)
|
var old = m_List;
|
||||||
|
m_List = new Point3D[old.Length * 2];
|
||||||
|
|
||||||
|
for (var i = 0; i < old.Length; ++i)
|
||||||
{
|
{
|
||||||
var old = m_List;
|
m_List[i] = old[i];
|
||||||
m_List = new Point3D[old.Length * 2];
|
|
||||||
|
|
||||||
for (var i = 0; i < old.Length; ++i)
|
|
||||||
{
|
|
||||||
m_List[i] = old[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_List[Count].m_X = p.m_X;
|
|
||||||
m_List[Count].m_Y = p.m_Y;
|
|
||||||
m_List[Count].m_Z = p.m_Z;
|
|
||||||
++Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point3D[] ToArray()
|
m_List[Count].m_X = p.m_X;
|
||||||
|
m_List[Count].m_Y = p.m_Y;
|
||||||
|
m_List[Count].m_Z = p.m_Z;
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D[] ToArray()
|
||||||
|
{
|
||||||
|
if (Count == 0)
|
||||||
{
|
{
|
||||||
if (Count == 0)
|
return m_EmptyList;
|
||||||
{
|
|
||||||
return m_EmptyList;
|
|
||||||
}
|
|
||||||
|
|
||||||
var list = new Point3D[Count];
|
|
||||||
|
|
||||||
for (var i = 0; i < Count; ++i)
|
|
||||||
{
|
|
||||||
list[i] = m_List[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Count = 0;
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var list = new Point3D[Count];
|
||||||
|
|
||||||
|
for (var i = 0; i < Count; ++i)
|
||||||
|
{
|
||||||
|
list[i] = m_List[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Count = 0;
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Rectangle2D.cs *
|
* File: Rectangle2D.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Rectangle3D.cs *
|
* File: Rectangle3D.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -13,130 +13,129 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
[NoSort]
|
||||||
|
[PropertyObject]
|
||||||
|
public struct Rectangle3D
|
||||||
{
|
{
|
||||||
[NoSort]
|
private Point3D m_Start;
|
||||||
[PropertyObject]
|
private Point3D m_End;
|
||||||
public struct Rectangle3D
|
|
||||||
|
public Rectangle3D(Point3D start, Point3D end)
|
||||||
{
|
{
|
||||||
private Point3D m_Start;
|
m_Start = start;
|
||||||
private Point3D m_End;
|
m_End = end;
|
||||||
|
|
||||||
public Rectangle3D(Point3D start, Point3D end)
|
|
||||||
{
|
|
||||||
m_Start = start;
|
|
||||||
m_End = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rectangle3D(int x, int y, int z, int width, int height, int depth)
|
|
||||||
{
|
|
||||||
m_Start = new Point3D(x, y, z);
|
|
||||||
m_End = new Point3D(x + width, y + height, z + depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public Point3D Start
|
|
||||||
{
|
|
||||||
get => m_Start;
|
|
||||||
set => m_Start = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public Point3D End
|
|
||||||
{
|
|
||||||
get => m_End;
|
|
||||||
set => m_End = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int X
|
|
||||||
{
|
|
||||||
get => m_Start.m_X;
|
|
||||||
set => m_Start.m_X = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int Y
|
|
||||||
{
|
|
||||||
get => m_Start.m_Y;
|
|
||||||
set => m_Start.m_Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int Z
|
|
||||||
{
|
|
||||||
get => m_Start.m_Z;
|
|
||||||
set => m_Start.m_Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int Width => m_End.X - m_Start.X;
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int Height => m_End.Y - m_Start.Y;
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public int Depth => m_End.Z - m_Start.Z;
|
|
||||||
|
|
||||||
public void MakeHold(Rectangle3D r)
|
|
||||||
{
|
|
||||||
if (r.m_Start.m_X < m_Start.m_X)
|
|
||||||
{
|
|
||||||
m_Start.m_X = r.m_Start.m_X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.m_Start.m_Y < m_Start.m_Y)
|
|
||||||
{
|
|
||||||
m_Start.m_Y = r.m_Start.m_Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.m_Start.m_Z < m_Start.m_Z)
|
|
||||||
{
|
|
||||||
m_Start.m_Z = r.m_Start.m_Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.m_End.m_X > m_End.m_X)
|
|
||||||
{
|
|
||||||
m_End.m_X = r.m_End.m_X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.m_End.m_Y > m_End.m_Y)
|
|
||||||
{
|
|
||||||
m_End.m_Y = r.m_End.m_Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.m_End.m_Z < m_End.m_Z)
|
|
||||||
{
|
|
||||||
m_End.m_Z = r.m_End.m_Z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(Point3D p) =>
|
|
||||||
p.m_X >= m_Start.m_X
|
|
||||||
&& p.m_X < m_End.m_X
|
|
||||||
&& p.m_Y >= m_Start.m_Y
|
|
||||||
&& p.m_Y < m_End.m_Y
|
|
||||||
&& p.m_Z >= m_Start.m_Z
|
|
||||||
&& p.m_Z < m_End.m_Z;
|
|
||||||
|
|
||||||
public bool Contains(Point2D p) =>
|
|
||||||
p.m_X >= m_Start.m_X
|
|
||||||
&& p.m_X < m_End.m_X
|
|
||||||
&& p.m_Y >= m_Start.m_Y
|
|
||||||
&& p.m_Y < m_End.m_Y;
|
|
||||||
|
|
||||||
public bool Contains(IPoint2D p) =>
|
|
||||||
p.X >= m_Start.m_X
|
|
||||||
&& p.X < m_End.m_X
|
|
||||||
&& p.Y >= m_Start.m_Y
|
|
||||||
&& p.Y < m_End.m_Y;
|
|
||||||
|
|
||||||
public bool Contains(IPoint3D p) =>
|
|
||||||
p.X >= m_Start.m_X
|
|
||||||
&& p.X < m_End.m_X
|
|
||||||
&& p.Y >= m_Start.m_Y
|
|
||||||
&& p.Y < m_End.m_Y
|
|
||||||
&& p.Z >= m_Start.m_Z
|
|
||||||
&& p.Z < m_End.m_Z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rectangle3D(int x, int y, int z, int width, int height, int depth)
|
||||||
|
{
|
||||||
|
m_Start = new Point3D(x, y, z);
|
||||||
|
m_End = new Point3D(x + width, y + height, z + depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public Point3D Start
|
||||||
|
{
|
||||||
|
get => m_Start;
|
||||||
|
set => m_Start = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public Point3D End
|
||||||
|
{
|
||||||
|
get => m_End;
|
||||||
|
set => m_End = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int X
|
||||||
|
{
|
||||||
|
get => m_Start.m_X;
|
||||||
|
set => m_Start.m_X = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Y
|
||||||
|
{
|
||||||
|
get => m_Start.m_Y;
|
||||||
|
set => m_Start.m_Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Z
|
||||||
|
{
|
||||||
|
get => m_Start.m_Z;
|
||||||
|
set => m_Start.m_Z = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Width => m_End.X - m_Start.X;
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Height => m_End.Y - m_Start.Y;
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int Depth => m_End.Z - m_Start.Z;
|
||||||
|
|
||||||
|
public void MakeHold(Rectangle3D r)
|
||||||
|
{
|
||||||
|
if (r.m_Start.m_X < m_Start.m_X)
|
||||||
|
{
|
||||||
|
m_Start.m_X = r.m_Start.m_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.m_Start.m_Y < m_Start.m_Y)
|
||||||
|
{
|
||||||
|
m_Start.m_Y = r.m_Start.m_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.m_Start.m_Z < m_Start.m_Z)
|
||||||
|
{
|
||||||
|
m_Start.m_Z = r.m_Start.m_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.m_End.m_X > m_End.m_X)
|
||||||
|
{
|
||||||
|
m_End.m_X = r.m_End.m_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.m_End.m_Y > m_End.m_Y)
|
||||||
|
{
|
||||||
|
m_End.m_Y = r.m_End.m_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.m_End.m_Z < m_End.m_Z)
|
||||||
|
{
|
||||||
|
m_End.m_Z = r.m_End.m_Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(Point3D p) =>
|
||||||
|
p.m_X >= m_Start.m_X
|
||||||
|
&& p.m_X < m_End.m_X
|
||||||
|
&& p.m_Y >= m_Start.m_Y
|
||||||
|
&& p.m_Y < m_End.m_Y
|
||||||
|
&& p.m_Z >= m_Start.m_Z
|
||||||
|
&& p.m_Z < m_End.m_Z;
|
||||||
|
|
||||||
|
public bool Contains(Point2D p) =>
|
||||||
|
p.m_X >= m_Start.m_X
|
||||||
|
&& p.m_X < m_End.m_X
|
||||||
|
&& p.m_Y >= m_Start.m_Y
|
||||||
|
&& p.m_Y < m_End.m_Y;
|
||||||
|
|
||||||
|
public bool Contains(IPoint2D p) =>
|
||||||
|
p.X >= m_Start.m_X
|
||||||
|
&& p.X < m_End.m_X
|
||||||
|
&& p.Y >= m_Start.m_Y
|
||||||
|
&& p.Y < m_End.m_Y;
|
||||||
|
|
||||||
|
public bool Contains(IPoint3D p) =>
|
||||||
|
p.X >= m_Start.m_X
|
||||||
|
&& p.X < m_End.m_X
|
||||||
|
&& p.Y >= m_Start.m_Y
|
||||||
|
&& p.Y < m_End.m_Y
|
||||||
|
&& p.Z >= m_Start.m_Z
|
||||||
|
&& p.Z < m_End.m_Z;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: WorldLocation.cs *
|
* File: WorldLocation.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,153 +16,152 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
[Parsable]
|
||||||
|
public struct WorldLocation
|
||||||
|
: IPoint3D, IComparable<WorldLocation>, IEquatable<object>, IEquatable<WorldLocation>, IEquatable<IEntity>
|
||||||
{
|
{
|
||||||
[Parsable]
|
internal Point3D m_Loc;
|
||||||
public struct WorldLocation
|
internal Map m_Map;
|
||||||
: IPoint3D, IComparable<WorldLocation>, IEquatable<object>, IEquatable<WorldLocation>, IEquatable<IEntity>
|
|
||||||
|
public static readonly WorldLocation Zero = new(0, 0, 0, Map.Internal);
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public Point3D Location
|
||||||
{
|
{
|
||||||
internal Point3D m_Loc;
|
get => m_Loc;
|
||||||
internal Map m_Map;
|
set => m_Loc = value;
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly WorldLocation Zero = new(0, 0, 0, Map.Internal);
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public int X
|
||||||
|
{
|
||||||
|
get => m_Loc.m_X;
|
||||||
|
set => m_Loc.m_X = value;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
public Point3D Location
|
public int Y
|
||||||
{
|
{
|
||||||
get => m_Loc;
|
get => m_Loc.m_Y;
|
||||||
set => m_Loc = value;
|
set => m_Loc.m_Y = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
public int X
|
public int Z
|
||||||
{
|
{
|
||||||
get => m_Loc.m_X;
|
get => m_Loc.m_Z;
|
||||||
set => m_Loc.m_X = value;
|
set => m_Loc.m_Z = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
public int Y
|
public Map Map
|
||||||
{
|
{
|
||||||
get => m_Loc.m_Y;
|
get => m_Map;
|
||||||
set => m_Loc.m_Y = value;
|
set => m_Map = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
public WorldLocation(IEntity e) : this(e.Location.X, e.Location.Y, e.Location.Z, e.Map)
|
||||||
public int Z
|
{
|
||||||
{
|
}
|
||||||
get => m_Loc.m_Z;
|
|
||||||
set => m_Loc.m_Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
public WorldLocation(Point2D p, Map map) : this(p.X, p.Y, 0, map)
|
||||||
public Map Map
|
{
|
||||||
{
|
}
|
||||||
get => m_Map;
|
|
||||||
set => m_Map = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorldLocation(IEntity e) : this(e.Location.X, e.Location.Y, e.Location.Z, e.Map)
|
public WorldLocation(int x, int y, Map map) : this(x, y, 0, map)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldLocation(Point2D p, Map map) : this(p.X, p.Y, 0, map)
|
public WorldLocation(Point3D p, Map map) : this(p.X, p.Y, p.Z, map)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldLocation(int x, int y, Map map) : this(x, y, 0, map)
|
public WorldLocation(int x, int y, int z, Map map)
|
||||||
{
|
{
|
||||||
}
|
m_Loc.m_X = x;
|
||||||
|
m_Loc.m_Y = y;
|
||||||
|
m_Loc.m_Z = z;
|
||||||
|
m_Map = map;
|
||||||
|
}
|
||||||
|
|
||||||
public WorldLocation(Point3D p, Map map) : this(p.X, p.Y, p.Z, map)
|
public override string ToString() =>
|
||||||
{
|
$"({m_Loc.m_X}, {m_Loc.m_Y}, {m_Loc.m_Z}, {m_Map?.ToString() ?? "(-null-)"})";
|
||||||
}
|
|
||||||
|
|
||||||
public WorldLocation(int x, int y, int z, Map map)
|
public bool Equals(WorldLocation other) =>
|
||||||
{
|
m_Loc.Equals(other.m_Loc) && m_Map.MapID == other.m_Map.MapID;
|
||||||
m_Loc.m_X = x;
|
|
||||||
m_Loc.m_Y = y;
|
|
||||||
m_Loc.m_Z = z;
|
|
||||||
m_Map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() =>
|
public bool Equals(IEntity other) =>
|
||||||
$"({m_Loc.m_X}, {m_Loc.m_Y}, {m_Loc.m_Z}, {m_Map?.ToString() ?? "(-null-)"})";
|
!ReferenceEquals(other, null) && m_Loc == other.Location &&
|
||||||
|
m_Map.MapID == other.Map.MapID;
|
||||||
|
|
||||||
public bool Equals(WorldLocation other) =>
|
public override bool Equals(object obj) =>
|
||||||
m_Loc.Equals(other.m_Loc) && m_Map.MapID == other.m_Map.MapID;
|
obj is WorldLocation other && Equals(other);
|
||||||
|
|
||||||
public bool Equals(IEntity other) =>
|
public override int GetHashCode() => HashCode.Combine(m_Loc, m_Map);
|
||||||
!ReferenceEquals(other, null) && m_Loc == other.Location &&
|
|
||||||
m_Map.MapID == other.Map.MapID;
|
|
||||||
|
|
||||||
public override bool Equals(object obj) =>
|
public int CompareTo(WorldLocation other)
|
||||||
obj is WorldLocation other && Equals(other);
|
{
|
||||||
|
var locComparison = m_Loc.CompareTo(other.m_Loc);
|
||||||
|
return locComparison != 0 ? locComparison : Comparer<Map>.Default.Compare(m_Map, other.m_Map);
|
||||||
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(m_Loc, m_Map);
|
public static implicit operator Point3D(WorldLocation worldLocation) => worldLocation.Location;
|
||||||
|
|
||||||
public int CompareTo(WorldLocation other)
|
public static bool operator ==(WorldLocation l, WorldLocation r) =>
|
||||||
{
|
l.m_Loc == r.m_Loc && l.m_Map == r.m_Map;
|
||||||
var locComparison = m_Loc.CompareTo(other.m_Loc);
|
|
||||||
return locComparison != 0 ? locComparison : Comparer<Map>.Default.Compare(m_Map, other.m_Map);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Point3D(WorldLocation worldLocation) => worldLocation.Location;
|
public static bool operator ==(WorldLocation l, IEntity r) =>
|
||||||
|
!ReferenceEquals(r, null) && l.m_Loc == r.Location && l.m_Map == r.Map;
|
||||||
|
|
||||||
public static bool operator ==(WorldLocation l, WorldLocation r) =>
|
public static bool operator !=(WorldLocation l, WorldLocation r) => l.m_Loc != r.m_Loc && l.m_Map != r.m_Map;
|
||||||
l.m_Loc == r.m_Loc && l.m_Map == r.m_Map;
|
|
||||||
|
|
||||||
public static bool operator ==(WorldLocation l, IEntity r) =>
|
public static bool operator !=(WorldLocation l, IEntity r) =>
|
||||||
!ReferenceEquals(r, null) && l.m_Loc == r.Location && l.m_Map == r.Map;
|
!ReferenceEquals(r, null) && l.m_Loc != r.Location && l.m_Map != r.Map;
|
||||||
|
|
||||||
public static bool operator !=(WorldLocation l, WorldLocation r) => l.m_Loc != r.m_Loc && l.m_Map != r.m_Map;
|
public static bool operator >(WorldLocation l, WorldLocation r) => l.m_Loc > r.m_Loc && l.m_Map == r.m_Map;
|
||||||
|
|
||||||
public static bool operator !=(WorldLocation l, IEntity r) =>
|
public static bool operator >(WorldLocation l, IEntity r) =>
|
||||||
!ReferenceEquals(r, null) && l.m_Loc != r.Location && l.m_Map != r.Map;
|
!ReferenceEquals(r, null) && l.m_Loc > r.Location && l.m_Map == r.Map;
|
||||||
|
|
||||||
public static bool operator >(WorldLocation l, WorldLocation r) => l.m_Loc > r.m_Loc && l.m_Map == r.m_Map;
|
public static bool operator <(WorldLocation l, WorldLocation r) => l.m_Loc < r.m_Loc && l.m_Map == r.m_Map;
|
||||||
|
|
||||||
public static bool operator >(WorldLocation l, IEntity r) =>
|
public static bool operator <(WorldLocation l, IEntity r) =>
|
||||||
!ReferenceEquals(r, null) && l.m_Loc > r.Location && l.m_Map == r.Map;
|
!ReferenceEquals(r, null) && l.m_Loc < r.Location && l.m_Map == r.Map;
|
||||||
|
|
||||||
public static bool operator <(WorldLocation l, WorldLocation r) => l.m_Loc < r.m_Loc && l.m_Map == r.m_Map;
|
public static bool operator >=(WorldLocation l, WorldLocation r) => l.m_Loc >= r.m_Loc && l.m_Map == r.m_Map;
|
||||||
|
|
||||||
public static bool operator <(WorldLocation l, IEntity r) =>
|
public static bool operator >=(WorldLocation l, IEntity r) =>
|
||||||
!ReferenceEquals(r, null) && l.m_Loc < r.Location && l.m_Map == r.Map;
|
!ReferenceEquals(r, null) && l.m_Loc >= r.Location && l.m_Map == r.Map;
|
||||||
|
|
||||||
public static bool operator >=(WorldLocation l, WorldLocation r) => l.m_Loc >= r.m_Loc && l.m_Map == r.m_Map;
|
public static bool operator <=(WorldLocation l, WorldLocation r) => l.m_Loc <= r.m_Loc && l.m_Map == r.m_Map;
|
||||||
|
|
||||||
public static bool operator >=(WorldLocation l, IEntity r) =>
|
public static bool operator <=(WorldLocation l, IEntity r) =>
|
||||||
!ReferenceEquals(r, null) && l.m_Loc >= r.Location && l.m_Map == r.Map;
|
!ReferenceEquals(r, null) && l.m_Loc <= r.Location && l.m_Map == r.Map;
|
||||||
|
|
||||||
public static bool operator <=(WorldLocation l, WorldLocation r) => l.m_Loc <= r.m_Loc && l.m_Map == r.m_Map;
|
public static WorldLocation Parse(string value)
|
||||||
|
{
|
||||||
|
var start = value.IndexOfOrdinal('(');
|
||||||
|
var end = value.IndexOf(',', start + 1);
|
||||||
|
|
||||||
public static bool operator <=(WorldLocation l, IEntity r) =>
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||||
!ReferenceEquals(r, null) && l.m_Loc <= r.Location && l.m_Map == r.Map;
|
|
||||||
|
|
||||||
public static WorldLocation Parse(string value)
|
start = end;
|
||||||
{
|
end = value.IndexOf(',', start + 1);
|
||||||
var start = value.IndexOfOrdinal('(');
|
|
||||||
var end = value.IndexOf(',', start + 1);
|
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||||
|
|
||||||
start = end;
|
start = end;
|
||||||
end = value.IndexOf(',', start + 1);
|
end = value.IndexOf(',', start + 1);
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
||||||
|
|
||||||
start = end;
|
start = end;
|
||||||
end = value.IndexOf(',', start + 1);
|
end = value.IndexOf(')', start + 1);
|
||||||
|
|
||||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
var map = Map.Parse(value.AsSpan(start + 1, end - (start + 1)).Trim());
|
||||||
|
|
||||||
start = end;
|
return new WorldLocation(x, y, z, map);
|
||||||
end = value.IndexOf(')', start + 1);
|
|
||||||
|
|
||||||
var map = Map.Parse(value.AsSpan(start + 1, end - (start + 1)).Trim());
|
|
||||||
|
|
||||||
return new WorldLocation(x, y, z, map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Guild.cs *
|
* File: Guild.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,125 +16,124 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Server.Guilds
|
namespace Server.Guilds;
|
||||||
|
|
||||||
|
public enum GuildType
|
||||||
{
|
{
|
||||||
public enum GuildType
|
Regular,
|
||||||
{
|
Chaos,
|
||||||
Regular,
|
Order
|
||||||
Chaos,
|
}
|
||||||
Order
|
|
||||||
}
|
public abstract class BaseGuild : ISerializable
|
||||||
|
{
|
||||||
public abstract class BaseGuild : ISerializable
|
protected BaseGuild()
|
||||||
{
|
{
|
||||||
protected BaseGuild()
|
Serial = World.NewGuild;
|
||||||
{
|
World.AddGuild(this);
|
||||||
Serial = World.NewGuild;
|
|
||||||
World.AddGuild(this);
|
SetTypeRef(GetType());
|
||||||
|
}
|
||||||
SetTypeRef(GetType());
|
|
||||||
}
|
protected BaseGuild(Serial serial)
|
||||||
|
{
|
||||||
protected BaseGuild(Serial serial)
|
Serial = serial;
|
||||||
{
|
SetTypeRef(GetType());
|
||||||
Serial = serial;
|
}
|
||||||
SetTypeRef(GetType());
|
|
||||||
}
|
public void SetTypeRef(Type type)
|
||||||
|
{
|
||||||
public void SetTypeRef(Type type)
|
TypeRef = World.GuildTypes.IndexOf(type);
|
||||||
{
|
|
||||||
TypeRef = World.GuildTypes.IndexOf(type);
|
if (TypeRef == -1)
|
||||||
|
{
|
||||||
if (TypeRef == -1)
|
World.GuildTypes.Add(type);
|
||||||
{
|
TypeRef = World.GuildTypes.Count - 1;
|
||||||
World.GuildTypes.Add(type);
|
}
|
||||||
TypeRef = World.GuildTypes.Count - 1;
|
}
|
||||||
}
|
|
||||||
}
|
public abstract string Abbreviation { get; set; }
|
||||||
|
public abstract string Name { get; set; }
|
||||||
public abstract string Abbreviation { get; set; }
|
public abstract GuildType Type { get; set; }
|
||||||
public abstract string Name { get; set; }
|
public abstract bool Disbanded { get; }
|
||||||
public abstract GuildType Type { get; set; }
|
public abstract void Delete();
|
||||||
public abstract bool Disbanded { get; }
|
|
||||||
public abstract void Delete();
|
public bool Deleted => Disbanded;
|
||||||
|
|
||||||
public bool Deleted => Disbanded;
|
[CommandProperty(AccessLevel.Counselor)]
|
||||||
|
public Serial Serial { get; }
|
||||||
[CommandProperty(AccessLevel.Counselor)]
|
|
||||||
public Serial Serial { get; }
|
[CommandProperty(AccessLevel.GameMaster, readOnly: true)]
|
||||||
|
public DateTime Created { get; set; } = Core.Now;
|
||||||
[CommandProperty(AccessLevel.GameMaster, readOnly: true)]
|
|
||||||
public DateTime Created { get; set; } = Core.Now;
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
|
DateTime ISerializable.LastSerialized { get; set; } = Core.Now;
|
||||||
[CommandProperty(AccessLevel.GameMaster)]
|
|
||||||
DateTime ISerializable.LastSerialized { get; set; } = Core.Now;
|
long ISerializable.SavePosition { get; set; } = -1;
|
||||||
|
|
||||||
long ISerializable.SavePosition { get; set; } = -1;
|
BufferWriter ISerializable.SaveBuffer { get; set; }
|
||||||
|
|
||||||
BufferWriter ISerializable.SaveBuffer { get; set; }
|
public int TypeRef { get; private set; }
|
||||||
|
|
||||||
public int TypeRef { get; private set; }
|
public abstract void BeforeSerialize();
|
||||||
|
public abstract void Serialize(IGenericWriter writer);
|
||||||
public abstract void BeforeSerialize();
|
|
||||||
public abstract void Serialize(IGenericWriter writer);
|
public abstract void Deserialize(IGenericReader reader);
|
||||||
|
public abstract void OnDelete(Mobile mob);
|
||||||
public abstract void Deserialize(IGenericReader reader);
|
|
||||||
public abstract void OnDelete(Mobile mob);
|
public static BaseGuild FindByName(string name)
|
||||||
|
{
|
||||||
public static BaseGuild FindByName(string name)
|
foreach (var g in World.Guilds.Values)
|
||||||
{
|
{
|
||||||
foreach (var g in World.Guilds.Values)
|
if (g.Name == name)
|
||||||
{
|
{
|
||||||
if (g.Name == name)
|
return g;
|
||||||
{
|
}
|
||||||
return g;
|
}
|
||||||
}
|
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return null;
|
|
||||||
}
|
public static BaseGuild FindByAbbrev(string abbr)
|
||||||
|
{
|
||||||
public static BaseGuild FindByAbbrev(string abbr)
|
foreach (var g in World.Guilds.Values)
|
||||||
{
|
{
|
||||||
foreach (var g in World.Guilds.Values)
|
if (g.Abbreviation == abbr)
|
||||||
{
|
{
|
||||||
if (g.Abbreviation == abbr)
|
return g;
|
||||||
{
|
}
|
||||||
return g;
|
}
|
||||||
}
|
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return null;
|
|
||||||
}
|
public static HashSet<BaseGuild> Search(string find)
|
||||||
|
{
|
||||||
public static HashSet<BaseGuild> Search(string find)
|
var words = find.ToLower().Split(' ');
|
||||||
{
|
var results = new HashSet<BaseGuild>();
|
||||||
var words = find.ToLower().Split(' ');
|
|
||||||
var results = new HashSet<BaseGuild>();
|
foreach (var g in World.Guilds.Values)
|
||||||
|
{
|
||||||
foreach (var g in World.Guilds.Values)
|
var name = g.Name;
|
||||||
{
|
|
||||||
var name = g.Name;
|
bool all = true;
|
||||||
|
foreach (var t in words)
|
||||||
bool all = true;
|
{
|
||||||
foreach (var t in words)
|
if (name.InsensitiveIndexOf(t) == -1)
|
||||||
{
|
{
|
||||||
if (name.InsensitiveIndexOf(t) == -1)
|
all = false;
|
||||||
{
|
break;
|
||||||
all = false;
|
}
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
if (all)
|
||||||
|
{
|
||||||
if (all)
|
results.Add(g);
|
||||||
{
|
}
|
||||||
results.Add(g);
|
}
|
||||||
}
|
|
||||||
}
|
return results;
|
||||||
|
}
|
||||||
return results;
|
|
||||||
}
|
public override string ToString() => $"{Serial} \"{Name} [{Abbreviation}]\"";
|
||||||
|
|
||||||
public override string ToString() => $"{Serial} \"{Name} [{Abbreviation}]\"";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GumpECHandleInput.cs *
|
* File: GumpECHandleInput.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GumpMasterGump.cs *
|
* File: GumpMasterGump.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GumpSpriteImage.cs *
|
* File: GumpSpriteImage.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GumpTooltip.cs *
|
* File: GumpTooltip.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,32 @@
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.HuePickers
|
namespace Server.HuePickers;
|
||||||
|
|
||||||
|
public class HuePicker
|
||||||
{
|
{
|
||||||
public class HuePicker
|
private static Serial _nextSerial = (Serial)1;
|
||||||
|
|
||||||
|
public HuePicker(int itemID)
|
||||||
{
|
{
|
||||||
private static Serial _nextSerial = (Serial)1;
|
do
|
||||||
|
|
||||||
public HuePicker(int itemID)
|
|
||||||
{
|
{
|
||||||
do
|
Serial = _nextSerial++;
|
||||||
{
|
} while (Serial == 0);
|
||||||
Serial = _nextSerial++;
|
|
||||||
} while (Serial == 0);
|
|
||||||
|
|
||||||
ItemID = itemID;
|
ItemID = itemID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serial Serial { get; }
|
public Serial Serial { get; }
|
||||||
|
|
||||||
public int ItemID { get; }
|
public int ItemID { get; }
|
||||||
|
|
||||||
public virtual void OnResponse(int hue)
|
public virtual void OnResponse(int hue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendTo(NetState state)
|
public void SendTo(NetState state)
|
||||||
{
|
{
|
||||||
state.SendDisplayHuePicker(Serial, ItemID);
|
state.SendDisplayHuePicker(Serial, ItemID);
|
||||||
state.AddHuePicker(this);
|
state.AddHuePicker(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,112 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server.Accounting
|
namespace Server.Accounting;
|
||||||
|
|
||||||
|
public static class AccountGold
|
||||||
{
|
{
|
||||||
public static class AccountGold
|
public static bool Enabled { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This amount specifies the value at which point Gold turns to Platinum.
|
||||||
|
/// By default, when 1,000,000,000 Gold is accumulated, it will transform
|
||||||
|
/// into 1 Platinum.
|
||||||
|
/// !!! WARNING !!!
|
||||||
|
/// The client is designed to perceive the currency threshold at 1,000,000,000
|
||||||
|
/// if you change this, it may cause unexpected results when using secure trading.
|
||||||
|
/// </summary>
|
||||||
|
public static int CurrencyThreshold = 1000000000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||||
|
/// when they are added to a bank box container.
|
||||||
|
/// </summary>
|
||||||
|
public static bool ConvertOnBank { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||||
|
/// when they are added to a secure trade container.
|
||||||
|
/// </summary>
|
||||||
|
public static bool ConvertOnTrade { get; private set; }
|
||||||
|
|
||||||
|
public static void Configure()
|
||||||
{
|
{
|
||||||
public static bool Enabled { get; private set; }
|
Enabled = ServerConfiguration.GetSetting("accountGold.enable", Core.TOL);
|
||||||
|
ConvertOnBank = ServerConfiguration.GetSetting("accountGold.convertOnBank", true);
|
||||||
/// <summary>
|
ConvertOnTrade = ServerConfiguration.GetSetting("accountGold.convertOnTrade", false);
|
||||||
/// This amount specifies the value at which point Gold turns to Platinum.
|
|
||||||
/// By default, when 1,000,000,000 Gold is accumulated, it will transform
|
|
||||||
/// into 1 Platinum.
|
|
||||||
/// !!! WARNING !!!
|
|
||||||
/// The client is designed to perceive the currency threshold at 1,000,000,000
|
|
||||||
/// if you change this, it may cause unexpected results when using secure trading.
|
|
||||||
/// </summary>
|
|
||||||
public static int CurrencyThreshold = 1000000000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
|
||||||
/// when they are added to a bank box container.
|
|
||||||
/// </summary>
|
|
||||||
public static bool ConvertOnBank { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
|
||||||
/// when they are added to a secure trade container.
|
|
||||||
/// </summary>
|
|
||||||
public static bool ConvertOnTrade { get; private set; }
|
|
||||||
|
|
||||||
public static void Configure()
|
|
||||||
{
|
|
||||||
Enabled = ServerConfiguration.GetSetting("accountGold.enable", Core.TOL);
|
|
||||||
ConvertOnBank = ServerConfiguration.GetSetting("accountGold.convertOnBank", true);
|
|
||||||
ConvertOnTrade = ServerConfiguration.GetSetting("accountGold.convertOnTrade", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IGoldAccount
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This amount represents the current amount of Gold owned by the player.
|
|
||||||
/// The value does not include the value of Platinum and ranges from
|
|
||||||
/// 0 to 999,999,999 by default.
|
|
||||||
/// </summary>
|
|
||||||
[CommandProperty(AccessLevel.Administrator)]
|
|
||||||
int TotalGold { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This amount represents the current amount of Platinum owned by the player.
|
|
||||||
/// The value does not include the value of Gold and ranges from
|
|
||||||
/// 0 to 2,147,483,647 by default.
|
|
||||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
|
||||||
/// </summary>
|
|
||||||
[CommandProperty(AccessLevel.Administrator)]
|
|
||||||
int TotalPlat { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to deposit the given amount of Gold into this account.
|
|
||||||
/// If the given amount is greater than the CurrencyThreshold,
|
|
||||||
/// Platinum will be deposited to offset the difference.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="amount">Amount to deposit.</param>
|
|
||||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
|
||||||
bool DepositGold(int amount);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to deposit the given amount of Platinum into this account.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="amount">Amount to deposit.</param>
|
|
||||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
|
||||||
bool DepositPlat(int amount);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to withdraw the given amount of Gold from this account.
|
|
||||||
/// If the given amount is greater than the CurrencyThreshold,
|
|
||||||
/// Platinum will be withdrawn to offset the difference.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="amount">Amount to withdraw.</param>
|
|
||||||
/// <returns>True if successful, false if balance was too low.</returns>
|
|
||||||
bool WithdrawGold(int amount);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to withdraw the given amount of Platinum from this account.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="amount">Amount to withdraw.</param>
|
|
||||||
/// <returns>True if successful, false if balance was too low.</returns>
|
|
||||||
bool WithdrawPlat(int amount);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns total gold inclusive of platinum, capped to Int32.
|
|
||||||
/// This is strictly for backwards compatibility
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
|
||||||
long GetTotalGold();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
|
||||||
{
|
|
||||||
string Username { get; set; }
|
|
||||||
string Email { get; set; }
|
|
||||||
AccessLevel AccessLevel { get; set; }
|
|
||||||
|
|
||||||
int Length { get; }
|
|
||||||
int Limit { get; }
|
|
||||||
int Count { get; }
|
|
||||||
Mobile this[int index] { get; set; }
|
|
||||||
|
|
||||||
void Delete();
|
|
||||||
void SetPassword(string password);
|
|
||||||
bool CheckPassword(string password);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IGoldAccount
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This amount represents the current amount of Gold owned by the player.
|
||||||
|
/// The value does not include the value of Platinum and ranges from
|
||||||
|
/// 0 to 999,999,999 by default.
|
||||||
|
/// </summary>
|
||||||
|
[CommandProperty(AccessLevel.Administrator)]
|
||||||
|
int TotalGold { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This amount represents the current amount of Platinum owned by the player.
|
||||||
|
/// The value does not include the value of Gold and ranges from
|
||||||
|
/// 0 to 2,147,483,647 by default.
|
||||||
|
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||||
|
/// </summary>
|
||||||
|
[CommandProperty(AccessLevel.Administrator)]
|
||||||
|
int TotalPlat { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to deposit the given amount of Gold into this account.
|
||||||
|
/// If the given amount is greater than the CurrencyThreshold,
|
||||||
|
/// Platinum will be deposited to offset the difference.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amount">Amount to deposit.</param>
|
||||||
|
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||||
|
bool DepositGold(int amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to deposit the given amount of Platinum into this account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amount">Amount to deposit.</param>
|
||||||
|
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||||
|
bool DepositPlat(int amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to withdraw the given amount of Gold from this account.
|
||||||
|
/// If the given amount is greater than the CurrencyThreshold,
|
||||||
|
/// Platinum will be withdrawn to offset the difference.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amount">Amount to withdraw.</param>
|
||||||
|
/// <returns>True if successful, false if balance was too low.</returns>
|
||||||
|
bool WithdrawGold(int amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to withdraw the given amount of Platinum from this account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amount">Amount to withdraw.</param>
|
||||||
|
/// <returns>True if successful, false if balance was too low.</returns>
|
||||||
|
bool WithdrawPlat(int amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns total gold inclusive of platinum, capped to Int32.
|
||||||
|
/// This is strictly for backwards compatibility
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
||||||
|
long GetTotalGold();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
||||||
|
{
|
||||||
|
string Username { get; set; }
|
||||||
|
string Email { get; set; }
|
||||||
|
AccessLevel AccessLevel { get; set; }
|
||||||
|
|
||||||
|
int Length { get; }
|
||||||
|
int Limit { get; }
|
||||||
|
int Count { get; }
|
||||||
|
Mobile this[int index] { get; set; }
|
||||||
|
|
||||||
|
void Delete();
|
||||||
|
void SetPassword(string password);
|
||||||
|
bool CheckPassword(string password);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: IEntity.cs *
|
* File: IEntity.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,110 +15,109 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public interface IEntity : IPoint3D, ISerializable
|
||||||
{
|
{
|
||||||
public interface IEntity : IPoint3D, ISerializable
|
Point3D Location { get; }
|
||||||
|
Map Map { get; }
|
||||||
|
void MoveToWorld(Point3D location, Map map);
|
||||||
|
|
||||||
|
void ProcessDelta();
|
||||||
|
|
||||||
|
bool InRange(Point2D p, int range);
|
||||||
|
|
||||||
|
bool InRange(Point3D p, int range);
|
||||||
|
|
||||||
|
void RemoveItem(Item item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Entity : IEntity
|
||||||
|
{
|
||||||
|
public Entity(Serial serial, Point3D loc, Map map) : this(serial)
|
||||||
{
|
{
|
||||||
Point3D Location { get; }
|
Location = loc;
|
||||||
Map Map { get; }
|
Map = map;
|
||||||
void MoveToWorld(Point3D location, Map map);
|
Deleted = false;
|
||||||
|
|
||||||
void ProcessDelta();
|
|
||||||
|
|
||||||
bool InRange(Point2D p, int range);
|
|
||||||
|
|
||||||
bool InRange(Point3D p, int range);
|
|
||||||
|
|
||||||
void RemoveItem(Item item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Entity : IEntity
|
public Entity(Serial serial) => Serial = serial;
|
||||||
|
|
||||||
|
public void SetTypeRef(Type type)
|
||||||
{
|
{
|
||||||
public Entity(Serial serial, Point3D loc, Map map) : this(serial)
|
}
|
||||||
{
|
|
||||||
Location = loc;
|
|
||||||
Map = map;
|
|
||||||
Deleted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entity(Serial serial) => Serial = serial;
|
DateTime ISerializable.Created { get; set; } = Core.Now;
|
||||||
|
|
||||||
public void SetTypeRef(Type type)
|
DateTime ISerializable.LastSerialized { get; set; } = DateTime.MaxValue;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime ISerializable.Created { get; set; } = Core.Now;
|
long ISerializable.SavePosition { get; set; } = -1;
|
||||||
|
|
||||||
DateTime ISerializable.LastSerialized { get; set; } = DateTime.MaxValue;
|
BufferWriter ISerializable.SaveBuffer { get; set; }
|
||||||
|
|
||||||
long ISerializable.SavePosition { get; set; } = -1;
|
public int TypeRef => -1;
|
||||||
|
|
||||||
BufferWriter ISerializable.SaveBuffer { get; set; }
|
public Serial Serial { get; }
|
||||||
|
|
||||||
public int TypeRef => -1;
|
public Point3D Location { get; private set; }
|
||||||
|
|
||||||
public Serial Serial { get; }
|
public int X => Location.X;
|
||||||
|
|
||||||
public Point3D Location { get; private set; }
|
public int Y => Location.Y;
|
||||||
|
|
||||||
public int X => Location.X;
|
public int Z => Location.Z;
|
||||||
|
|
||||||
public int Y => Location.Y;
|
public Map Map { get; private set; }
|
||||||
|
|
||||||
public int Z => Location.Z;
|
public void MoveToWorld(Point3D newLocation, Map map)
|
||||||
|
{
|
||||||
|
Location = newLocation;
|
||||||
|
Map = map;
|
||||||
|
}
|
||||||
|
|
||||||
public Map Map { get; private set; }
|
public bool Deleted { get; }
|
||||||
|
|
||||||
public void MoveToWorld(Point3D newLocation, Map map)
|
public void Delete()
|
||||||
{
|
{
|
||||||
Location = newLocation;
|
}
|
||||||
Map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Deleted { get; }
|
public void ProcessDelta()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void Delete()
|
public void RemoveItem(Item item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessDelta()
|
public bool InRange(Point2D p, int range) =>
|
||||||
{
|
p.m_X >= Location.m_X - range
|
||||||
}
|
&& p.m_X <= Location.m_X + range
|
||||||
|
&& p.m_Y >= Location.m_Y - range
|
||||||
|
&& p.m_Y <= Location.m_Y + range;
|
||||||
|
|
||||||
public void RemoveItem(Item item)
|
public bool InRange(Point3D p, int range) =>
|
||||||
{
|
p.m_X >= Location.m_X - range
|
||||||
}
|
&& p.m_X <= Location.m_X + range
|
||||||
|
&& p.m_Y >= Location.m_Y - range
|
||||||
|
&& p.m_Y <= Location.m_Y + range;
|
||||||
|
|
||||||
public bool InRange(Point2D p, int range) =>
|
public bool InRange(IPoint2D p, int range) =>
|
||||||
p.m_X >= Location.m_X - range
|
p.X >= Location.m_X - range
|
||||||
&& p.m_X <= Location.m_X + range
|
&& p.X <= Location.m_X + range
|
||||||
&& p.m_Y >= Location.m_Y - range
|
&& p.Y >= Location.m_Y - range
|
||||||
&& p.m_Y <= Location.m_Y + range;
|
&& p.Y <= Location.m_Y + range;
|
||||||
|
|
||||||
public bool InRange(Point3D p, int range) =>
|
public void BeforeSerialize()
|
||||||
p.m_X >= Location.m_X - range
|
{
|
||||||
&& p.m_X <= Location.m_X + range
|
}
|
||||||
&& p.m_Y >= Location.m_Y - range
|
|
||||||
&& p.m_Y <= Location.m_Y + range;
|
|
||||||
|
|
||||||
public bool InRange(IPoint2D p, int range) =>
|
public void Deserialize(IGenericReader reader)
|
||||||
p.X >= Location.m_X - range
|
{
|
||||||
&& p.X <= Location.m_X + range
|
// Should not actually be saved
|
||||||
&& p.Y >= Location.m_Y - range
|
Timer.StartTimer(Delete);
|
||||||
&& p.Y <= Location.m_Y + range;
|
}
|
||||||
|
|
||||||
public void BeforeSerialize()
|
public void Serialize(IGenericWriter writer)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public void Deserialize(IGenericReader reader)
|
|
||||||
{
|
|
||||||
// Should not actually be saved
|
|
||||||
Timer.StartTimer(Delete);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Serialize(IGenericWriter writer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1,74 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public interface IPoint2D
|
||||||
{
|
{
|
||||||
public interface IPoint2D
|
int X { get; }
|
||||||
{
|
int Y { get; }
|
||||||
int X { get; }
|
}
|
||||||
int Y { get; }
|
|
||||||
}
|
public interface IPoint3D : IPoint2D
|
||||||
|
{
|
||||||
public interface IPoint3D : IPoint2D
|
int Z { get; }
|
||||||
{
|
}
|
||||||
int Z { get; }
|
|
||||||
}
|
public interface ICarvable
|
||||||
|
{
|
||||||
public interface ICarvable
|
void Carve(Mobile from, Item item);
|
||||||
{
|
}
|
||||||
void Carve(Mobile from, Item item);
|
|
||||||
}
|
public interface IWeapon
|
||||||
|
{
|
||||||
public interface IWeapon
|
int MaxRange { get; }
|
||||||
{
|
void OnBeforeSwing(Mobile attacker, Mobile defender);
|
||||||
int MaxRange { get; }
|
TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0);
|
||||||
void OnBeforeSwing(Mobile attacker, Mobile defender);
|
void GetStatusDamage(Mobile from, out int min, out int max);
|
||||||
TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0);
|
}
|
||||||
void GetStatusDamage(Mobile from, out int min, out int max);
|
|
||||||
}
|
public interface IHued
|
||||||
|
{
|
||||||
public interface IHued
|
int HuedItemID { get; }
|
||||||
{
|
}
|
||||||
int HuedItemID { get; }
|
|
||||||
}
|
public interface ISpell
|
||||||
|
{
|
||||||
public interface ISpell
|
bool IsCasting { get; }
|
||||||
{
|
void OnCasterHurt();
|
||||||
bool IsCasting { get; }
|
void OnCasterKilled();
|
||||||
void OnCasterHurt();
|
void OnConnectionChanged();
|
||||||
void OnCasterKilled();
|
bool OnCasterMoving(Direction d);
|
||||||
void OnConnectionChanged();
|
bool OnCasterEquipping(Item item);
|
||||||
bool OnCasterMoving(Direction d);
|
bool OnCasterUsingObject(IEntity entity);
|
||||||
bool OnCasterEquipping(Item item);
|
bool OnCastInTown(Region r);
|
||||||
bool OnCasterUsingObject(IEntity entity);
|
void FinishSequence();
|
||||||
bool OnCastInTown(Region r);
|
}
|
||||||
void FinishSequence();
|
|
||||||
}
|
public interface IParty
|
||||||
|
{
|
||||||
public interface IParty
|
void OnStamChanged(Mobile m);
|
||||||
{
|
void OnManaChanged(Mobile m);
|
||||||
void OnStamChanged(Mobile m);
|
void OnStatsQuery(Mobile beholder, Mobile beheld);
|
||||||
void OnManaChanged(Mobile m);
|
}
|
||||||
void OnStatsQuery(Mobile beholder, Mobile beheld);
|
|
||||||
}
|
// TODO: Add SpawnMap and change Spawner.Map to use it
|
||||||
|
public interface ISpawner : IEntity
|
||||||
// TODO: Add SpawnMap and change Spawner.Map to use it
|
{
|
||||||
public interface ISpawner : IEntity
|
Guid Guid { get; }
|
||||||
{
|
bool UnlinkOnTaming { get; }
|
||||||
Guid Guid { get; }
|
Point3D HomeLocation { get; }
|
||||||
bool UnlinkOnTaming { get; }
|
int HomeRange { get; }
|
||||||
Point3D HomeLocation { get; }
|
Region Region { get; }
|
||||||
int HomeRange { get; }
|
bool ReturnOnDeactivate { get; }
|
||||||
Region Region { get; }
|
|
||||||
bool ReturnOnDeactivate { get; }
|
void Remove(ISpawnable spawn);
|
||||||
|
Point3D GetSpawnPosition(ISpawnable spawned, Map map);
|
||||||
void Remove(ISpawnable spawn);
|
void Respawn();
|
||||||
Point3D GetSpawnPosition(ISpawnable spawned, Map map);
|
}
|
||||||
void Respawn();
|
|
||||||
}
|
public interface ISpawnable : IEntity
|
||||||
|
{
|
||||||
public interface ISpawnable : IEntity
|
ISpawner Spawner { get; set; }
|
||||||
{
|
void OnBeforeSpawn(Point3D location, Map map);
|
||||||
ISpawner Spawner { get; set; }
|
void OnAfterSpawn();
|
||||||
void OnBeforeSpawn(Point3D location, Map map);
|
|
||||||
void OnAfterSpawn();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,125 +1,124 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server.Items
|
namespace Server.Items;
|
||||||
|
|
||||||
|
public abstract class BaseMulti : Item
|
||||||
{
|
{
|
||||||
public abstract class BaseMulti : Item
|
public BaseMulti(int itemID) : base(itemID) => Movable = false;
|
||||||
|
|
||||||
|
public BaseMulti(Serial serial) : base(serial)
|
||||||
{
|
{
|
||||||
public BaseMulti(int itemID) : base(itemID) => Movable = false;
|
}
|
||||||
|
|
||||||
public BaseMulti(Serial serial) : base(serial)
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
|
public override int ItemID
|
||||||
|
{
|
||||||
|
get => base.ItemID;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
}
|
if (base.ItemID != value)
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.GameMaster)]
|
|
||||||
public override int ItemID
|
|
||||||
{
|
|
||||||
get => base.ItemID;
|
|
||||||
set
|
|
||||||
{
|
{
|
||||||
if (base.ItemID != value)
|
var facet = Parent == null ? Map : null;
|
||||||
{
|
|
||||||
var facet = Parent == null ? Map : null;
|
|
||||||
|
|
||||||
facet?.OnLeave(this);
|
facet?.OnLeave(this);
|
||||||
|
|
||||||
base.ItemID = value;
|
base.ItemID = value;
|
||||||
|
|
||||||
facet?.OnEnter(this);
|
facet?.OnEnter(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int LabelNumber
|
public override int LabelNumber
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
|
||||||
var mcl = Components;
|
|
||||||
|
|
||||||
if (mcl.List.Length > 0)
|
|
||||||
{
|
|
||||||
int id = mcl.List[0].ItemId;
|
|
||||||
|
|
||||||
if (id < 0x4000)
|
|
||||||
{
|
|
||||||
return 1020000 + id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1078872 + id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.LabelNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool AllowsRelativeDrop => false;
|
|
||||||
|
|
||||||
public virtual MultiComponentList Components => MultiData.GetComponents(ItemID);
|
|
||||||
|
|
||||||
[Obsolete("Replace with calls to OnLeave and OnEnter surrounding component invalidation.", true)]
|
|
||||||
public virtual void RefreshComponents()
|
|
||||||
{
|
|
||||||
if (Parent == null)
|
|
||||||
{
|
|
||||||
var facet = Map;
|
|
||||||
|
|
||||||
if (facet != null)
|
|
||||||
{
|
|
||||||
facet.OnLeave(this);
|
|
||||||
facet.OnEnter(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetMaxUpdateRange() => 22;
|
|
||||||
|
|
||||||
public override int GetUpdateRange(Mobile m) => 22;
|
|
||||||
|
|
||||||
public virtual bool Contains(Point2D p) => Contains(p.m_X, p.m_Y);
|
|
||||||
|
|
||||||
public virtual bool Contains(Point3D p) => Contains(p.m_X, p.m_Y);
|
|
||||||
|
|
||||||
public virtual bool Contains(IPoint3D p) => Contains(p.X, p.Y);
|
|
||||||
|
|
||||||
public virtual bool Contains(int x, int y)
|
|
||||||
{
|
{
|
||||||
var mcl = Components;
|
var mcl = Components;
|
||||||
|
|
||||||
x -= X + mcl.Min.m_X;
|
if (mcl.List.Length > 0)
|
||||||
y -= Y + mcl.Min.m_Y;
|
|
||||||
|
|
||||||
return x >= 0
|
|
||||||
&& x < mcl.Width
|
|
||||||
&& y >= 0
|
|
||||||
&& y < mcl.Height
|
|
||||||
&& mcl.Tiles[x][y].Length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Contains(Mobile m) => m.Map == Map && Contains(m.X, m.Y);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Contains(Item item) => item.Map == Map && Contains(item.X, item.Y);
|
|
||||||
|
|
||||||
public override void Serialize(IGenericWriter writer)
|
|
||||||
{
|
|
||||||
base.Serialize(writer);
|
|
||||||
|
|
||||||
writer.Write(1); // version
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Deserialize(IGenericReader reader)
|
|
||||||
{
|
|
||||||
base.Deserialize(reader);
|
|
||||||
|
|
||||||
var version = reader.ReadInt();
|
|
||||||
|
|
||||||
if (version == 0)
|
|
||||||
{
|
{
|
||||||
if (ItemID >= 0x4000)
|
int id = mcl.List[0].ItemId;
|
||||||
|
|
||||||
|
if (id < 0x4000)
|
||||||
{
|
{
|
||||||
ItemID -= 0x4000;
|
return 1020000 + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1078872 + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.LabelNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool AllowsRelativeDrop => false;
|
||||||
|
|
||||||
|
public virtual MultiComponentList Components => MultiData.GetComponents(ItemID);
|
||||||
|
|
||||||
|
[Obsolete("Replace with calls to OnLeave and OnEnter surrounding component invalidation.", true)]
|
||||||
|
public virtual void RefreshComponents()
|
||||||
|
{
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
var facet = Map;
|
||||||
|
|
||||||
|
if (facet != null)
|
||||||
|
{
|
||||||
|
facet.OnLeave(this);
|
||||||
|
facet.OnEnter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMaxUpdateRange() => 22;
|
||||||
|
|
||||||
|
public override int GetUpdateRange(Mobile m) => 22;
|
||||||
|
|
||||||
|
public virtual bool Contains(Point2D p) => Contains(p.m_X, p.m_Y);
|
||||||
|
|
||||||
|
public virtual bool Contains(Point3D p) => Contains(p.m_X, p.m_Y);
|
||||||
|
|
||||||
|
public virtual bool Contains(IPoint3D p) => Contains(p.X, p.Y);
|
||||||
|
|
||||||
|
public virtual bool Contains(int x, int y)
|
||||||
|
{
|
||||||
|
var mcl = Components;
|
||||||
|
|
||||||
|
x -= X + mcl.Min.m_X;
|
||||||
|
y -= Y + mcl.Min.m_Y;
|
||||||
|
|
||||||
|
return x >= 0
|
||||||
|
&& x < mcl.Width
|
||||||
|
&& y >= 0
|
||||||
|
&& y < mcl.Height
|
||||||
|
&& mcl.Tiles[x][y].Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Contains(Mobile m) => m.Map == Map && Contains(m.X, m.Y);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Contains(Item item) => item.Map == Map && Contains(item.X, item.Y);
|
||||||
|
|
||||||
|
public override void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
base.Serialize(writer);
|
||||||
|
|
||||||
|
writer.Write(1); // version
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(IGenericReader reader)
|
||||||
|
{
|
||||||
|
base.Deserialize(reader);
|
||||||
|
|
||||||
|
var version = reader.ReadInt();
|
||||||
|
|
||||||
|
if (version == 0)
|
||||||
|
{
|
||||||
|
if (ItemID >= 0x4000)
|
||||||
|
{
|
||||||
|
ItemID -= 0x4000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,126 +1,125 @@
|
||||||
using Server.Accounting;
|
using Server.Accounting;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.Items
|
namespace Server.Items;
|
||||||
|
|
||||||
|
public class BankBox : Container
|
||||||
{
|
{
|
||||||
public class BankBox : Container
|
public BankBox(Serial serial) : base(serial)
|
||||||
{
|
{
|
||||||
public BankBox(Serial serial) : base(serial)
|
}
|
||||||
|
|
||||||
|
public BankBox(Mobile owner) : base(0xE7C)
|
||||||
|
{
|
||||||
|
Layer = Layer.Bank;
|
||||||
|
Movable = false;
|
||||||
|
Owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int DefaultMaxWeight => 0;
|
||||||
|
|
||||||
|
public override bool IsVirtualItem => true;
|
||||||
|
|
||||||
|
public Mobile Owner { get; private set; }
|
||||||
|
|
||||||
|
public bool Opened { get; private set; }
|
||||||
|
|
||||||
|
public static bool SendDeleteOnClose { get; set; }
|
||||||
|
|
||||||
|
public void Open()
|
||||||
|
{
|
||||||
|
Opened = true;
|
||||||
|
|
||||||
|
if (Owner != null)
|
||||||
{
|
{
|
||||||
}
|
Owner.PrivateOverheadMessage(
|
||||||
|
MessageType.Regular,
|
||||||
|
0x3B2,
|
||||||
|
true,
|
||||||
|
$"Bank container has {TotalItems} items, {TotalWeight} stones",
|
||||||
|
Owner.NetState
|
||||||
|
);
|
||||||
|
|
||||||
public BankBox(Mobile owner) : base(0xE7C)
|
Owner.NetState?.SendEquipUpdate(this);
|
||||||
{
|
DisplayTo(Owner);
|
||||||
Layer = Layer.Bank;
|
|
||||||
Movable = false;
|
|
||||||
Owner = owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int DefaultMaxWeight => 0;
|
|
||||||
|
|
||||||
public override bool IsVirtualItem => true;
|
|
||||||
|
|
||||||
public Mobile Owner { get; private set; }
|
|
||||||
|
|
||||||
public bool Opened { get; private set; }
|
|
||||||
|
|
||||||
public static bool SendDeleteOnClose { get; set; }
|
|
||||||
|
|
||||||
public void Open()
|
|
||||||
{
|
|
||||||
Opened = true;
|
|
||||||
|
|
||||||
if (Owner != null)
|
|
||||||
{
|
|
||||||
Owner.PrivateOverheadMessage(
|
|
||||||
MessageType.Regular,
|
|
||||||
0x3B2,
|
|
||||||
true,
|
|
||||||
$"Bank container has {TotalItems} items, {TotalWeight} stones",
|
|
||||||
Owner.NetState
|
|
||||||
);
|
|
||||||
|
|
||||||
Owner.NetState?.SendEquipUpdate(this);
|
|
||||||
DisplayTo(Owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Serialize(IGenericWriter writer)
|
|
||||||
{
|
|
||||||
base.Serialize(writer);
|
|
||||||
|
|
||||||
writer.Write(0); // version
|
|
||||||
|
|
||||||
writer.Write(Owner);
|
|
||||||
writer.Write(Opened);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Deserialize(IGenericReader reader)
|
|
||||||
{
|
|
||||||
base.Deserialize(reader);
|
|
||||||
|
|
||||||
var version = reader.ReadInt();
|
|
||||||
|
|
||||||
switch (version)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
Owner = reader.ReadEntity<Mobile>();
|
|
||||||
Opened = reader.ReadBool();
|
|
||||||
|
|
||||||
if (Owner == null)
|
|
||||||
{
|
|
||||||
Delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ItemID == 0xE41)
|
|
||||||
{
|
|
||||||
ItemID = 0xE7C;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
Opened = false;
|
|
||||||
|
|
||||||
if (SendDeleteOnClose)
|
|
||||||
{
|
|
||||||
Owner?.NetState.SendRemoveEntity(Serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnSingleClick(Mobile from)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnDoubleClick(Mobile from)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DeathMoveResult OnParentDeath(Mobile parent) => DeathMoveResult.RemainEquipped;
|
|
||||||
|
|
||||||
public override bool IsAccessibleTo(Mobile check) =>
|
|
||||||
(check == Owner && Opened || check.AccessLevel >= AccessLevel.GameMaster) && base.IsAccessibleTo(check);
|
|
||||||
|
|
||||||
public override bool OnDragDrop(Mobile from, Item dropped) =>
|
|
||||||
(from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) && base.OnDragDrop(from, dropped);
|
|
||||||
|
|
||||||
public override bool OnDragDropInto(Mobile from, Item item, Point3D p) =>
|
|
||||||
(from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) &&
|
|
||||||
base.OnDragDropInto(from, item, p);
|
|
||||||
|
|
||||||
public override int GetTotal(TotalType type)
|
|
||||||
{
|
|
||||||
if (AccountGold.Enabled && Owner?.Account != null && type == TotalType.Gold)
|
|
||||||
{
|
|
||||||
return Owner.Account.TotalGold;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.GetTotal(type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
base.Serialize(writer);
|
||||||
|
|
||||||
|
writer.Write(0); // version
|
||||||
|
|
||||||
|
writer.Write(Owner);
|
||||||
|
writer.Write(Opened);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(IGenericReader reader)
|
||||||
|
{
|
||||||
|
base.Deserialize(reader);
|
||||||
|
|
||||||
|
var version = reader.ReadInt();
|
||||||
|
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
Owner = reader.ReadEntity<Mobile>();
|
||||||
|
Opened = reader.ReadBool();
|
||||||
|
|
||||||
|
if (Owner == null)
|
||||||
|
{
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ItemID == 0xE41)
|
||||||
|
{
|
||||||
|
ItemID = 0xE7C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
Opened = false;
|
||||||
|
|
||||||
|
if (SendDeleteOnClose)
|
||||||
|
{
|
||||||
|
Owner?.NetState.SendRemoveEntity(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSingleClick(Mobile from)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDoubleClick(Mobile from)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DeathMoveResult OnParentDeath(Mobile parent) => DeathMoveResult.RemainEquipped;
|
||||||
|
|
||||||
|
public override bool IsAccessibleTo(Mobile check) =>
|
||||||
|
(check == Owner && Opened || check.AccessLevel >= AccessLevel.GameMaster) && base.IsAccessibleTo(check);
|
||||||
|
|
||||||
|
public override bool OnDragDrop(Mobile from, Item dropped) =>
|
||||||
|
(from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) && base.OnDragDrop(from, dropped);
|
||||||
|
|
||||||
|
public override bool OnDragDropInto(Mobile from, Item item, Point3D p) =>
|
||||||
|
(from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) &&
|
||||||
|
base.OnDragDropInto(from, item, p);
|
||||||
|
|
||||||
|
public override int GetTotal(TotalType type)
|
||||||
|
{
|
||||||
|
if (AccountGold.Enabled && Owner?.Account != null && type == TotalType.Gold)
|
||||||
|
{
|
||||||
|
return Owner.Account.TotalGold;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetTotal(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Layer.cs *
|
* File: Layer.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -13,176 +13,175 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of item layer values.
|
||||||
|
/// </summary>
|
||||||
|
public enum Layer : byte
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enumeration of item layer values.
|
/// Invalid layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum Layer : byte
|
Invalid = 0x00,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid layer.
|
|
||||||
/// </summary>
|
|
||||||
Invalid = 0x00,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// First valid layer. Equivalent to <c>Layer.OneHanded</c>.
|
/// First valid layer. Equivalent to <c>Layer.OneHanded</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FirstValid = 0x01,
|
FirstValid = 0x01,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// One handed weapon.
|
/// One handed weapon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OneHanded = 0x01,
|
OneHanded = 0x01,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Two handed weapon or shield.
|
/// Two handed weapon or shield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TwoHanded = 0x02,
|
TwoHanded = 0x02,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shoes.
|
/// Shoes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Shoes = 0x03,
|
Shoes = 0x03,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pants.
|
/// Pants.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Pants = 0x04,
|
Pants = 0x04,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shirts.
|
/// Shirts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Shirt = 0x05,
|
Shirt = 0x05,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helmets, hats, and masks.
|
/// Helmets, hats, and masks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Helm = 0x06,
|
Helm = 0x06,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gloves.
|
/// Gloves.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Gloves = 0x07,
|
Gloves = 0x07,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rings.
|
/// Rings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Ring = 0x08,
|
Ring = 0x08,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Talismans.
|
/// Talismans.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Talisman = 0x09,
|
Talisman = 0x09,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gorgets and necklaces.
|
/// Gorgets and necklaces.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Neck = 0x0A,
|
Neck = 0x0A,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hair.
|
/// Hair.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Hair = 0x0B,
|
Hair = 0x0B,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Half aprons.
|
/// Half aprons.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Waist = 0x0C,
|
Waist = 0x0C,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Torso, inner layer.
|
/// Torso, inner layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InnerTorso = 0x0D,
|
InnerTorso = 0x0D,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bracelets.
|
/// Bracelets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bracelet = 0x0E,
|
Bracelet = 0x0E,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unused.
|
/// Unused.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Unused_xF = 0x0F,
|
Unused_xF = 0x0F,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Beards and mustaches.
|
/// Beards and mustaches.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FacialHair = 0x10,
|
FacialHair = 0x10,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Torso, outer layer.
|
/// Torso, outer layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MiddleTorso = 0x11,
|
MiddleTorso = 0x11,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Earings.
|
/// Earings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Earrings = 0x12,
|
Earrings = 0x12,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Arms and sleeves.
|
/// Arms and sleeves.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Arms = 0x13,
|
Arms = 0x13,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cloaks.
|
/// Cloaks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Cloak = 0x14,
|
Cloak = 0x14,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Backpacks.
|
/// Backpacks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Backpack = 0x15,
|
Backpack = 0x15,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Torso, outer layer.
|
/// Torso, outer layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OuterTorso = 0x16,
|
OuterTorso = 0x16,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Leggings, outer layer.
|
/// Leggings, outer layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OuterLegs = 0x17,
|
OuterLegs = 0x17,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Leggings, inner layer.
|
/// Leggings, inner layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InnerLegs = 0x18,
|
InnerLegs = 0x18,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Last valid non-internal layer. Equivalent to <c>Layer.InnerLegs</c>.
|
/// Last valid non-internal layer. Equivalent to <c>Layer.InnerLegs</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LastUserValid = 0x18,
|
LastUserValid = 0x18,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mount item layer.
|
/// Mount item layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Mount = 0x19,
|
Mount = 0x19,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Vendor 'buy pack' layer.
|
/// Vendor 'buy pack' layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ShopBuy = 0x1A,
|
ShopBuy = 0x1A,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Vendor 'resale pack' layer.
|
/// Vendor 'resale pack' layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ShopResale = 0x1B,
|
ShopResale = 0x1B,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Vendor 'sell pack' layer.
|
/// Vendor 'sell pack' layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ShopSell = 0x1C,
|
ShopSell = 0x1C,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bank box layer.
|
/// Bank box layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bank = 0x1D,
|
Bank = 0x1D,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Last valid layer. Equivalent to <c>Layer.Bank</c>.
|
/// Last valid layer. Equivalent to <c>Layer.Bank</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LastValid = 0x1D
|
LastValid = 0x1D
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: LightType.cs *
|
* File: LightType.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -13,291 +13,290 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public enum LightType
|
||||||
{
|
{
|
||||||
public enum LightType
|
/// <summary>
|
||||||
{
|
/// Window shape, arched, ray shining east.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Window shape, arched, ray shining east.
|
ArchedWindowEast,
|
||||||
/// </summary>
|
|
||||||
ArchedWindowEast,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium circular shape.
|
/// Medium circular shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Circle225,
|
Circle225,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Small circular shape.
|
/// Small circular shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Circle150,
|
Circle150,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Door shape, shining south.
|
/// Door shape, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DoorSouth,
|
DoorSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Door shape, shining east.
|
/// Door shape, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DoorEast,
|
DoorEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), north wall.
|
/// Large semicircular shape (180 degrees), north wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthBig,
|
NorthBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large pie shape (90 degrees), north-east corner.
|
/// Large pie shape (90 degrees), north-east corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthEastBig,
|
NorthEastBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), east wall.
|
/// Large semicircular shape (180 degrees), east wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
EastBig,
|
EastBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), west wall.
|
/// Large semicircular shape (180 degrees), west wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
WestBig,
|
WestBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large pie shape (90 degrees), south-west corner.
|
/// Large pie shape (90 degrees), south-west corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SouthWestBig,
|
SouthWestBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), south wall.
|
/// Large semicircular shape (180 degrees), south wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SouthBig,
|
SouthBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium semicircular shape (180 degrees), north wall.
|
/// Medium semicircular shape (180 degrees), north wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthSmall,
|
NorthSmall,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium pie shape (90 degrees), north-east corner.
|
/// Medium pie shape (90 degrees), north-east corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthEastSmall,
|
NorthEastSmall,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium semicircular shape (180 degrees), east wall.
|
/// Medium semicircular shape (180 degrees), east wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
EastSmall,
|
EastSmall,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium semicircular shape (180 degrees), west wall.
|
/// Medium semicircular shape (180 degrees), west wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
WestSmall,
|
WestSmall,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Medium semicircular shape (180 degrees), south wall.
|
/// Medium semicircular shape (180 degrees), south wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SouthSmall,
|
SouthSmall,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a wall decoration, north wall.
|
/// Shaped like a wall decoration, north wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecorationNorth,
|
DecorationNorth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a wall decoration, north-east corner.
|
/// Shaped like a wall decoration, north-east corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecorationNorthEast,
|
DecorationNorthEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Small semicircular shape (180 degrees), east wall.
|
/// Small semicircular shape (180 degrees), east wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
EastTiny,
|
EastTiny,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a wall decoration, west wall.
|
/// Shaped like a wall decoration, west wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecorationWest,
|
DecorationWest,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a wall decoration, south-west corner.
|
/// Shaped like a wall decoration, south-west corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecorationSouthWest,
|
DecorationSouthWest,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Small semicircular shape (180 degrees), south wall.
|
/// Small semicircular shape (180 degrees), south wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SouthTiny,
|
SouthTiny,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, rectangular, no ray, shining south.
|
/// Window shape, rectangular, no ray, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RectWindowSouthNoRay,
|
RectWindowSouthNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, rectangular, no ray, shining east.
|
/// Window shape, rectangular, no ray, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RectWindowEastNoRay,
|
RectWindowEastNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, rectangular, ray shining south.
|
/// Window shape, rectangular, ray shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RectWindowSouth,
|
RectWindowSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, rectangular, ray shining east.
|
/// Window shape, rectangular, ray shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RectWindowEast,
|
RectWindowEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, arched, no ray, shining south.
|
/// Window shape, arched, no ray, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ArchedWindowSouthNoRay,
|
ArchedWindowSouthNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, arched, no ray, shining east.
|
/// Window shape, arched, no ray, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ArchedWindowEastNoRay,
|
ArchedWindowEastNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, arched, ray shining south.
|
/// Window shape, arched, ray shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ArchedWindowSouth,
|
ArchedWindowSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large circular shape.
|
/// Large circular shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Circle300,
|
Circle300,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large pie shape (90 degrees), north-west corner.
|
/// Large pie shape (90 degrees), north-west corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthWestBig,
|
NorthWestBig,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Medium pie shape (90 degrees), south-east corner.
|
/// Negative light. Medium pie shape (90 degrees), south-east corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkSouthEast,
|
DarkSouthEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Medium semicircular shape (180 degrees), south wall.
|
/// Negative light. Medium semicircular shape (180 degrees), south wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkSouth,
|
DarkSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Medium pie shape (90 degrees), north-west corner.
|
/// Negative light. Medium pie shape (90 degrees), north-west corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkNorthWest,
|
DarkNorthWest,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to <c>LightType.SouthEast</c>.
|
/// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to <c>LightType.SouthEast</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkSouthEast2,
|
DarkSouthEast2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Medium circular shape (180 degrees), east wall.
|
/// Negative light. Medium circular shape (180 degrees), east wall.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkEast,
|
DarkEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negative light. Large circular shape.
|
/// Negative light. Large circular shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DarkCircle300,
|
DarkCircle300,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opened door shape, shining south.
|
/// Opened door shape, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DoorOpenSouth,
|
DoorOpenSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opened door shape, shining east.
|
/// Opened door shape, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DoorOpenEast,
|
DoorOpenEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, square, ray shining east.
|
/// Window shape, square, ray shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SquareWindowEast,
|
SquareWindowEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, square, no ray, shining east.
|
/// Window shape, square, no ray, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SquareWindowEastNoRay,
|
SquareWindowEastNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, square, ray shining south.
|
/// Window shape, square, ray shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SquareWindowSouth,
|
SquareWindowSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, square, no ray, shining south.
|
/// Window shape, square, no ray, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SquareWindowSouthNoRay,
|
SquareWindowSouthNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Empty.
|
/// Empty.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Empty,
|
Empty,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, skinny, no ray, shining south.
|
/// Window shape, skinny, no ray, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SkinnyWindowSouthNoRay,
|
SkinnyWindowSouthNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, skinny, ray shining east.
|
/// Window shape, skinny, ray shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SkinnyWindowEast,
|
SkinnyWindowEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window shape, skinny, no ray, shining east.
|
/// Window shape, skinny, no ray, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SkinnyWindowEastNoRay,
|
SkinnyWindowEastNoRay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a hole, shining south.
|
/// Shaped like a hole, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HoleSouth,
|
HoleSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a hole, shining south.
|
/// Shaped like a hole, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HoleEast,
|
HoleEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large circular shape with a moongate graphic embedded.
|
/// Large circular shape with a moongate graphic embedded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Moongate,
|
Moongate,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unknown usage. Many rows of slightly angled lines.
|
/// Unknown usage. Many rows of slightly angled lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Strips,
|
Strips,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a small hole, shining south.
|
/// Shaped like a small hole, shining south.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SmallHoleSouth,
|
SmallHoleSouth,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shaped like a small hole, shining east.
|
/// Shaped like a small hole, shining east.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SmallHoleEast,
|
SmallHoleEast,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), north wall. Identical graphic as <c>LightType.NorthBig</c>, but slightly
|
/// Large semicircular shape (180 degrees), north wall. Identical graphic as <c>LightType.NorthBig</c>, but slightly
|
||||||
/// different
|
/// different
|
||||||
/// positioning.
|
/// positioning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthBig2,
|
NorthBig2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large semicircular shape (180 degrees), west wall. Identical graphic as <c>LightType.WestBig</c>, but slightly different
|
/// Large semicircular shape (180 degrees), west wall. Identical graphic as <c>LightType.WestBig</c>, but slightly different
|
||||||
/// positioning.
|
/// positioning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
WestBig2,
|
WestBig2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Large pie shape (90 degrees), north-west corner. Equivalent to <c>LightType.NorthWestBig</c>.
|
/// Large pie shape (90 degrees), north-west corner. Equivalent to <c>LightType.NorthWestBig</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NorthWestBig2
|
NorthWestBig2
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,112 @@
|
||||||
using Server.Accounting;
|
using Server.Accounting;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.Items
|
namespace Server.Items;
|
||||||
|
|
||||||
|
public class SecureTradeContainer : Container
|
||||||
{
|
{
|
||||||
public class SecureTradeContainer : Container
|
public SecureTradeContainer(SecureTrade trade) : base(0x1E5E)
|
||||||
{
|
{
|
||||||
public SecureTradeContainer(SecureTrade trade) : base(0x1E5E)
|
Trade = trade;
|
||||||
{
|
|
||||||
Trade = trade;
|
|
||||||
|
|
||||||
Movable = false;
|
Movable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureTradeContainer(Serial serial) : base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureTrade Trade { get; }
|
||||||
|
|
||||||
|
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
|
||||||
|
{
|
||||||
|
if (item == Trade.From.VirtualCheck || item == Trade.To.VirtualCheck)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecureTradeContainer(Serial serial) : base(serial)
|
var to = Trade.From.Container != this ? Trade.From.Mobile : Trade.To.Mobile;
|
||||||
|
|
||||||
|
return m.CheckTrade(to, item, this, message, checkItems, plusItems, plusWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
|
||||||
|
{
|
||||||
|
reject = LRReason.CannotLift;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsAccessibleTo(Mobile check) =>
|
||||||
|
IsChildOf(check) && Trade?.Valid == true && base.IsAccessibleTo(check);
|
||||||
|
|
||||||
|
public override void OnItemAdded(Item item)
|
||||||
|
{
|
||||||
|
if (item is not VirtualCheck)
|
||||||
{
|
{
|
||||||
}
|
ClearChecks();
|
||||||
|
|
||||||
public SecureTrade Trade { get; }
|
|
||||||
|
|
||||||
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
|
|
||||||
{
|
|
||||||
if (item == Trade.From.VirtualCheck || item == Trade.To.VirtualCheck)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var to = Trade.From.Container != this ? Trade.From.Mobile : Trade.To.Mobile;
|
|
||||||
|
|
||||||
return m.CheckTrade(to, item, this, message, checkItems, plusItems, plusWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
|
|
||||||
{
|
|
||||||
reject = LRReason.CannotLift;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsAccessibleTo(Mobile check) =>
|
|
||||||
IsChildOf(check) && Trade?.Valid == true && base.IsAccessibleTo(check);
|
|
||||||
|
|
||||||
public override void OnItemAdded(Item item)
|
|
||||||
{
|
|
||||||
if (item is not VirtualCheck)
|
|
||||||
{
|
|
||||||
ClearChecks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnItemRemoved(Item item)
|
|
||||||
{
|
|
||||||
if (item is not VirtualCheck)
|
|
||||||
{
|
|
||||||
ClearChecks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnSubItemAdded(Item item)
|
|
||||||
{
|
|
||||||
if (item is not VirtualCheck)
|
|
||||||
{
|
|
||||||
ClearChecks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnSubItemRemoved(Item item)
|
|
||||||
{
|
|
||||||
if (item is not VirtualCheck)
|
|
||||||
{
|
|
||||||
ClearChecks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearChecks()
|
|
||||||
{
|
|
||||||
if (Trade == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Trade.From?.IsDisposed == false)
|
|
||||||
{
|
|
||||||
Trade.From.Accepted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Trade.To?.IsDisposed == false)
|
|
||||||
{
|
|
||||||
Trade.To.Accepted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Trade.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsChildVisibleTo(Mobile m, Item child) =>
|
|
||||||
child is VirtualCheck
|
|
||||||
? AccountGold.Enabled && m.NetState is not { NewSecureTrading: true }
|
|
||||||
: base.IsChildVisibleTo(m, child);
|
|
||||||
|
|
||||||
public override void Serialize(IGenericWriter writer)
|
|
||||||
{
|
|
||||||
base.Serialize(writer);
|
|
||||||
|
|
||||||
writer.Write(0); // version
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Deserialize(IGenericReader reader)
|
|
||||||
{
|
|
||||||
base.Deserialize(reader);
|
|
||||||
|
|
||||||
var version = reader.ReadInt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnItemRemoved(Item item)
|
||||||
|
{
|
||||||
|
if (item is not VirtualCheck)
|
||||||
|
{
|
||||||
|
ClearChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSubItemAdded(Item item)
|
||||||
|
{
|
||||||
|
if (item is not VirtualCheck)
|
||||||
|
{
|
||||||
|
ClearChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSubItemRemoved(Item item)
|
||||||
|
{
|
||||||
|
if (item is not VirtualCheck)
|
||||||
|
{
|
||||||
|
ClearChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearChecks()
|
||||||
|
{
|
||||||
|
if (Trade == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Trade.From?.IsDisposed == false)
|
||||||
|
{
|
||||||
|
Trade.From.Accepted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Trade.To?.IsDisposed == false)
|
||||||
|
{
|
||||||
|
Trade.To.Accepted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trade.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsChildVisibleTo(Mobile m, Item child) =>
|
||||||
|
child is VirtualCheck
|
||||||
|
? AccountGold.Enabled && m.NetState is not { NewSecureTrading: true }
|
||||||
|
: base.IsChildVisibleTo(m, child);
|
||||||
|
|
||||||
|
public override void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
base.Serialize(writer);
|
||||||
|
|
||||||
|
writer.Write(0); // version
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(IGenericReader reader)
|
||||||
|
{
|
||||||
|
base.Deserialize(reader);
|
||||||
|
|
||||||
|
var version = reader.ReadInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: VirtualCheck.cs *
|
* File: VirtualCheck.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,382 +16,381 @@
|
||||||
using Server.Gumps;
|
using Server.Gumps;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.Items
|
namespace Server.Items;
|
||||||
|
|
||||||
|
public sealed class VirtualCheck : Item
|
||||||
{
|
{
|
||||||
public sealed class VirtualCheck : Item
|
public static bool UseEditGump { get; private set; }
|
||||||
|
|
||||||
|
public static void Configure()
|
||||||
{
|
{
|
||||||
public static bool UseEditGump { get; private set; }
|
UseEditGump = ServerConfiguration.GetSetting("virtualChecks.useEditGump", Core.TOL);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Configure()
|
private int m_Gold;
|
||||||
|
|
||||||
|
private int m_Plat;
|
||||||
|
|
||||||
|
public VirtualCheck(int plat = 0, int gold = 0) : base(0x14F0)
|
||||||
|
{
|
||||||
|
Plat = plat;
|
||||||
|
Gold = gold;
|
||||||
|
|
||||||
|
Movable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualCheck(Serial serial)
|
||||||
|
: base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsVirtualItem => true;
|
||||||
|
|
||||||
|
public override bool DisplayWeight => false;
|
||||||
|
public override bool DisplayLootType => false;
|
||||||
|
|
||||||
|
public override double DefaultWeight => 0;
|
||||||
|
|
||||||
|
public override string DefaultName => "Offer Of Currency";
|
||||||
|
|
||||||
|
public EditGump Editor { get; private set; }
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Administrator)]
|
||||||
|
public int Plat
|
||||||
|
{
|
||||||
|
get => m_Plat;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
UseEditGump = ServerConfiguration.GetSetting("virtualChecks.useEditGump", Core.TOL);
|
m_Plat = value;
|
||||||
|
InvalidateProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.Administrator)]
|
||||||
|
public int Gold
|
||||||
|
{
|
||||||
|
get => m_Gold;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_Gold = value;
|
||||||
|
InvalidateProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsAccessibleTo(Mobile check)
|
||||||
|
{
|
||||||
|
var c = GetSecureTradeCont();
|
||||||
|
|
||||||
|
if (check == null || c == null)
|
||||||
|
{
|
||||||
|
return base.IsAccessibleTo(check);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int m_Gold;
|
return c.RootParent == check && IsChildOf(c);
|
||||||
|
}
|
||||||
|
|
||||||
private int m_Plat;
|
public override void OnDoubleClickSecureTrade(Mobile from)
|
||||||
|
{
|
||||||
public VirtualCheck(int plat = 0, int gold = 0) : base(0x14F0)
|
if (UseEditGump && IsAccessibleTo(from))
|
||||||
{
|
{
|
||||||
Plat = plat;
|
if (Editor?.Check?.Deleted != false)
|
||||||
Gold = gold;
|
|
||||||
|
|
||||||
Movable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VirtualCheck(Serial serial)
|
|
||||||
: base(serial)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsVirtualItem => true;
|
|
||||||
|
|
||||||
public override bool DisplayWeight => false;
|
|
||||||
public override bool DisplayLootType => false;
|
|
||||||
|
|
||||||
public override double DefaultWeight => 0;
|
|
||||||
|
|
||||||
public override string DefaultName => "Offer Of Currency";
|
|
||||||
|
|
||||||
public EditGump Editor { get; private set; }
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Administrator)]
|
|
||||||
public int Plat
|
|
||||||
{
|
|
||||||
get => m_Plat;
|
|
||||||
set
|
|
||||||
{
|
{
|
||||||
m_Plat = value;
|
Editor = new EditGump(from, this);
|
||||||
InvalidateProperties();
|
Editor.Send();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.Administrator)]
|
|
||||||
public int Gold
|
|
||||||
{
|
|
||||||
get => m_Gold;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_Gold = value;
|
|
||||||
InvalidateProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsAccessibleTo(Mobile check)
|
|
||||||
{
|
|
||||||
var c = GetSecureTradeCont();
|
|
||||||
|
|
||||||
if (check == null || c == null)
|
|
||||||
{
|
|
||||||
return base.IsAccessibleTo(check);
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.RootParent == check && IsChildOf(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnDoubleClickSecureTrade(Mobile from)
|
|
||||||
{
|
|
||||||
if (UseEditGump && IsAccessibleTo(from))
|
|
||||||
{
|
|
||||||
if (Editor?.Check?.Deleted != false)
|
|
||||||
{
|
|
||||||
Editor = new EditGump(from, this);
|
|
||||||
Editor.Send();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Editor.Refresh(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Editor != null)
|
Editor.Refresh(true);
|
||||||
{
|
|
||||||
Editor.Close();
|
|
||||||
Editor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnDoubleClickSecureTrade(from);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public override void OnSingleClick(Mobile from)
|
|
||||||
{
|
{
|
||||||
LabelTo(from, "Offer: {0:#,0} platinum, {1:#,0} gold", Plat, Gold);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GetProperties(IPropertyList list)
|
|
||||||
{
|
|
||||||
base.GetProperties(list);
|
|
||||||
|
|
||||||
list.Add(1060738, $"{Plat:#,0} platinum, {Gold:#,0} gold"); // value: ~1_val~
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateTrade(Mobile user)
|
|
||||||
{
|
|
||||||
var c = GetSecureTradeCont();
|
|
||||||
|
|
||||||
if (c?.Trade == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user == c.Trade.From.Mobile)
|
|
||||||
{
|
|
||||||
c.Trade.UpdateFromCurrency();
|
|
||||||
}
|
|
||||||
else if (user == c.Trade.To.Mobile)
|
|
||||||
{
|
|
||||||
c.Trade.UpdateToCurrency();
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ClearChecks();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAfterDelete()
|
|
||||||
{
|
|
||||||
base.OnAfterDelete();
|
|
||||||
|
|
||||||
if (Editor != null)
|
if (Editor != null)
|
||||||
{
|
{
|
||||||
Editor.Close();
|
Editor.Close();
|
||||||
Editor = null;
|
Editor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.OnDoubleClickSecureTrade(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSingleClick(Mobile from)
|
||||||
|
{
|
||||||
|
LabelTo(from, "Offer: {0:#,0} platinum, {1:#,0} gold", Plat, Gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GetProperties(IPropertyList list)
|
||||||
|
{
|
||||||
|
base.GetProperties(list);
|
||||||
|
|
||||||
|
list.Add(1060738, $"{Plat:#,0} platinum, {Gold:#,0} gold"); // value: ~1_val~
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTrade(Mobile user)
|
||||||
|
{
|
||||||
|
var c = GetSecureTradeCont();
|
||||||
|
|
||||||
|
if (c?.Trade == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Serialize(IGenericWriter writer)
|
if (user == c.Trade.From.Mobile)
|
||||||
{
|
{
|
||||||
|
c.Trade.UpdateFromCurrency();
|
||||||
|
}
|
||||||
|
else if (user == c.Trade.To.Mobile)
|
||||||
|
{
|
||||||
|
c.Trade.UpdateToCurrency();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deserialize(IGenericReader reader)
|
c.ClearChecks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAfterDelete()
|
||||||
|
{
|
||||||
|
base.OnAfterDelete();
|
||||||
|
|
||||||
|
if (Editor != null)
|
||||||
{
|
{
|
||||||
Delete();
|
Editor.Close();
|
||||||
|
Editor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(IGenericReader reader)
|
||||||
|
{
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditGump : Gump
|
||||||
|
{
|
||||||
|
public enum Buttons
|
||||||
|
{
|
||||||
|
Close,
|
||||||
|
Clear,
|
||||||
|
Accept,
|
||||||
|
AllPlat,
|
||||||
|
AllGold
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EditGump : Gump
|
private int m_Plat, m_Gold;
|
||||||
|
|
||||||
|
public EditGump(Mobile user, VirtualCheck check) : base(50, 50)
|
||||||
{
|
{
|
||||||
public enum Buttons
|
User = user;
|
||||||
|
Check = check;
|
||||||
|
|
||||||
|
m_Plat = Check.Plat;
|
||||||
|
m_Gold = Check.Gold;
|
||||||
|
|
||||||
|
Closable = true;
|
||||||
|
Disposable = true;
|
||||||
|
Draggable = true;
|
||||||
|
Resizable = false;
|
||||||
|
|
||||||
|
User.CloseGump<EditGump>();
|
||||||
|
|
||||||
|
CompileLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mobile User { get; }
|
||||||
|
public VirtualCheck Check { get; private set; }
|
||||||
|
|
||||||
|
public override void OnServerClose(NetState owner)
|
||||||
|
{
|
||||||
|
base.OnServerClose(owner);
|
||||||
|
|
||||||
|
if (Check?.Deleted == false)
|
||||||
{
|
{
|
||||||
Close,
|
Check.UpdateTrade(User);
|
||||||
Clear,
|
}
|
||||||
Accept,
|
}
|
||||||
AllPlat,
|
|
||||||
AllGold
|
public void Close()
|
||||||
|
{
|
||||||
|
User.CloseGump<EditGump>();
|
||||||
|
|
||||||
|
if (Check?.Deleted == false)
|
||||||
|
{
|
||||||
|
Check.UpdateTrade(User);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Check = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send()
|
||||||
|
{
|
||||||
|
if (Check?.Deleted == false)
|
||||||
|
{
|
||||||
|
User.SendGump(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Refresh(bool recompile)
|
||||||
|
{
|
||||||
|
if (Check?.Deleted != false)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int m_Plat, m_Gold;
|
if (recompile)
|
||||||
|
|
||||||
public EditGump(Mobile user, VirtualCheck check) : base(50, 50)
|
|
||||||
{
|
{
|
||||||
User = user;
|
|
||||||
Check = check;
|
|
||||||
|
|
||||||
m_Plat = Check.Plat;
|
|
||||||
m_Gold = Check.Gold;
|
|
||||||
|
|
||||||
Closable = true;
|
|
||||||
Disposable = true;
|
|
||||||
Draggable = true;
|
|
||||||
Resizable = false;
|
|
||||||
|
|
||||||
User.CloseGump<EditGump>();
|
|
||||||
|
|
||||||
CompileLayout();
|
CompileLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mobile User { get; }
|
Close();
|
||||||
public VirtualCheck Check { get; private set; }
|
Send();
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnServerClose(NetState owner)
|
private void CompileLayout()
|
||||||
|
{
|
||||||
|
if (Check?.Deleted != false)
|
||||||
{
|
{
|
||||||
base.OnServerClose(owner);
|
return;
|
||||||
|
|
||||||
if (Check?.Deleted == false)
|
|
||||||
{
|
|
||||||
Check.UpdateTrade(User);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close()
|
Entries.ForEach(e => e.Parent = null);
|
||||||
|
Entries.Clear();
|
||||||
|
|
||||||
|
AddPage(0);
|
||||||
|
|
||||||
|
AddBackground(0, 0, 400, 160, 3500);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
AddImageTiled(25, 35, 350, 3, 96);
|
||||||
|
AddImage(10, 8, 113);
|
||||||
|
AddImage(360, 8, 113);
|
||||||
|
|
||||||
|
var title =
|
||||||
|
$"<BASEFONT COLOR=#FF2F4F4F><CENTER>BANK OF {User.RawName.ToUpper()}</CENTER>";
|
||||||
|
|
||||||
|
AddHtml(40, 15, 320, 20, title);
|
||||||
|
|
||||||
|
// Platinum Row
|
||||||
|
AddBackground(15, 60, 175, 20, 9300);
|
||||||
|
AddBackground(20, 45, 165, 30, 9350);
|
||||||
|
AddItem(20, 45, 3826); // Plat
|
||||||
|
AddLabel(60, 50, 0, User.Account.TotalPlat.ToString("#,0"));
|
||||||
|
|
||||||
|
AddButton(195, 50, 95, 95, (int)Buttons.AllPlat); // ->
|
||||||
|
|
||||||
|
AddBackground(210, 60, 175, 20, 9300);
|
||||||
|
AddBackground(215, 45, 165, 30, 9350);
|
||||||
|
AddTextEntry(225, 50, 145, 20, 0, 0, m_Plat.ToString(), User.Account.TotalPlat.ToString().Length);
|
||||||
|
|
||||||
|
// Gold Row
|
||||||
|
AddBackground(15, 100, 175, 20, 9300);
|
||||||
|
AddBackground(20, 85, 165, 30, 9350);
|
||||||
|
AddItem(20, 85, 3823); // Gold
|
||||||
|
AddLabel(60, 90, 0, User.Account.TotalGold.ToString("#,0"));
|
||||||
|
|
||||||
|
AddButton(195, 90, 95, 95, (int)Buttons.AllGold); // ->
|
||||||
|
|
||||||
|
AddBackground(210, 100, 175, 20, 9300);
|
||||||
|
AddBackground(215, 85, 165, 30, 9350);
|
||||||
|
AddTextEntry(225, 90, 145, 20, 0, 1, m_Gold.ToString(), User.Account.TotalGold.ToString().Length);
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
AddButton(20, 128, 12006, 12007, (int)Buttons.Close);
|
||||||
|
AddButton(215, 128, 12003, 12004, (int)Buttons.Clear);
|
||||||
|
AddButton(305, 128, 12000, 12002, (int)Buttons.Accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnResponse(NetState sender, RelayInfo info)
|
||||||
|
{
|
||||||
|
if (Check?.Deleted != false || sender.Mobile != User)
|
||||||
{
|
{
|
||||||
User.CloseGump<EditGump>();
|
|
||||||
|
|
||||||
if (Check?.Deleted == false)
|
|
||||||
{
|
|
||||||
Check.UpdateTrade(User);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Check = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send()
|
|
||||||
{
|
|
||||||
if (Check?.Deleted == false)
|
|
||||||
{
|
|
||||||
User.SendGump(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Refresh(bool recompile)
|
|
||||||
{
|
|
||||||
if (Check?.Deleted != false)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recompile)
|
|
||||||
{
|
|
||||||
CompileLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
Send();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompileLayout()
|
bool refresh = false, updated = false;
|
||||||
|
|
||||||
|
switch ((Buttons)info.ButtonID)
|
||||||
{
|
{
|
||||||
if (Check?.Deleted != false)
|
case Buttons.Close:
|
||||||
{
|
break;
|
||||||
return;
|
case Buttons.Clear:
|
||||||
}
|
{
|
||||||
|
m_Plat = m_Gold = 0;
|
||||||
|
refresh = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Buttons.Accept:
|
||||||
|
{
|
||||||
|
var platText = info.GetTextEntry(0).Text;
|
||||||
|
var goldText = info.GetTextEntry(1).Text;
|
||||||
|
|
||||||
Entries.ForEach(e => e.Parent = null);
|
if (!int.TryParse(platText, out m_Plat))
|
||||||
Entries.Clear();
|
|
||||||
|
|
||||||
AddPage(0);
|
|
||||||
|
|
||||||
AddBackground(0, 0, 400, 160, 3500);
|
|
||||||
|
|
||||||
// Title
|
|
||||||
AddImageTiled(25, 35, 350, 3, 96);
|
|
||||||
AddImage(10, 8, 113);
|
|
||||||
AddImage(360, 8, 113);
|
|
||||||
|
|
||||||
var title =
|
|
||||||
$"<BASEFONT COLOR=#FF2F4F4F><CENTER>BANK OF {User.RawName.ToUpper()}</CENTER>";
|
|
||||||
|
|
||||||
AddHtml(40, 15, 320, 20, title);
|
|
||||||
|
|
||||||
// Platinum Row
|
|
||||||
AddBackground(15, 60, 175, 20, 9300);
|
|
||||||
AddBackground(20, 45, 165, 30, 9350);
|
|
||||||
AddItem(20, 45, 3826); // Plat
|
|
||||||
AddLabel(60, 50, 0, User.Account.TotalPlat.ToString("#,0"));
|
|
||||||
|
|
||||||
AddButton(195, 50, 95, 95, (int)Buttons.AllPlat); // ->
|
|
||||||
|
|
||||||
AddBackground(210, 60, 175, 20, 9300);
|
|
||||||
AddBackground(215, 45, 165, 30, 9350);
|
|
||||||
AddTextEntry(225, 50, 145, 20, 0, 0, m_Plat.ToString(), User.Account.TotalPlat.ToString().Length);
|
|
||||||
|
|
||||||
// Gold Row
|
|
||||||
AddBackground(15, 100, 175, 20, 9300);
|
|
||||||
AddBackground(20, 85, 165, 30, 9350);
|
|
||||||
AddItem(20, 85, 3823); // Gold
|
|
||||||
AddLabel(60, 90, 0, User.Account.TotalGold.ToString("#,0"));
|
|
||||||
|
|
||||||
AddButton(195, 90, 95, 95, (int)Buttons.AllGold); // ->
|
|
||||||
|
|
||||||
AddBackground(210, 100, 175, 20, 9300);
|
|
||||||
AddBackground(215, 85, 165, 30, 9350);
|
|
||||||
AddTextEntry(225, 90, 145, 20, 0, 1, m_Gold.ToString(), User.Account.TotalGold.ToString().Length);
|
|
||||||
|
|
||||||
// Buttons
|
|
||||||
AddButton(20, 128, 12006, 12007, (int)Buttons.Close);
|
|
||||||
AddButton(215, 128, 12003, 12004, (int)Buttons.Clear);
|
|
||||||
AddButton(305, 128, 12000, 12002, (int)Buttons.Accept);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnResponse(NetState sender, RelayInfo info)
|
|
||||||
{
|
|
||||||
if (Check?.Deleted != false || sender.Mobile != User)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool refresh = false, updated = false;
|
|
||||||
|
|
||||||
switch ((Buttons)info.ButtonID)
|
|
||||||
{
|
|
||||||
case Buttons.Close:
|
|
||||||
break;
|
|
||||||
case Buttons.Clear:
|
|
||||||
{
|
{
|
||||||
m_Plat = m_Gold = 0;
|
User.SendMessage("That is not a valid amount of platinum.");
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
break;
|
else if (!int.TryParse(goldText, out m_Gold))
|
||||||
case Buttons.Accept:
|
|
||||||
{
|
{
|
||||||
var platText = info.GetTextEntry(0).Text;
|
User.SendMessage("That is not a valid amount of gold.");
|
||||||
var goldText = info.GetTextEntry(1).Text;
|
refresh = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var totalPlat = User.Account.TotalPlat;
|
||||||
|
var totalGold = User.Account.TotalGold;
|
||||||
|
|
||||||
if (!int.TryParse(platText, out m_Plat))
|
if (totalPlat < m_Plat || totalGold < m_Gold)
|
||||||
{
|
{
|
||||||
User.SendMessage("That is not a valid amount of platinum.");
|
m_Plat = User.Account.TotalPlat;
|
||||||
refresh = true;
|
m_Gold = User.Account.TotalGold;
|
||||||
}
|
User.SendMessage("You do not have that much currency.");
|
||||||
else if (!int.TryParse(goldText, out m_Gold))
|
|
||||||
{
|
|
||||||
User.SendMessage("That is not a valid amount of gold.");
|
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var totalPlat = User.Account.TotalPlat;
|
Check.Plat = m_Plat;
|
||||||
var totalGold = User.Account.TotalGold;
|
Check.Gold = m_Gold;
|
||||||
|
updated = true;
|
||||||
if (totalPlat < m_Plat || totalGold < m_Gold)
|
|
||||||
{
|
|
||||||
m_Plat = User.Account.TotalPlat;
|
|
||||||
m_Gold = User.Account.TotalGold;
|
|
||||||
User.SendMessage("You do not have that much currency.");
|
|
||||||
refresh = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Check.Plat = m_Plat;
|
|
||||||
Check.Gold = m_Gold;
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case Buttons.AllPlat:
|
break;
|
||||||
{
|
case Buttons.AllPlat:
|
||||||
m_Plat = User.Account.TotalPlat;
|
{
|
||||||
refresh = true;
|
m_Plat = User.Account.TotalPlat;
|
||||||
}
|
refresh = true;
|
||||||
break;
|
}
|
||||||
case Buttons.AllGold:
|
break;
|
||||||
{
|
case Buttons.AllGold:
|
||||||
m_Gold = User.Account.TotalGold;
|
{
|
||||||
refresh = true;
|
m_Gold = User.Account.TotalGold;
|
||||||
}
|
refresh = true;
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (updated)
|
|
||||||
{
|
|
||||||
User.SendMessage("Your offer has been updated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refresh && Check?.Deleted == false)
|
|
||||||
{
|
|
||||||
Refresh(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
User.SendMessage("Your offer has been updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refresh && Check?.Deleted == false)
|
||||||
|
{
|
||||||
|
Refresh(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,146 +3,145 @@ using System.Buffers;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public static class OutgoingVirtualHairPackets
|
||||||
{
|
{
|
||||||
public static class OutgoingVirtualHairPackets
|
public const int EquipUpdatePacketLength = 15;
|
||||||
|
public const int RemovePacketLength = 5;
|
||||||
|
|
||||||
|
public static void SendHairEquipUpdatePacket(this NetState ns, Mobile m, uint hairSerial, int itemId, int hue, Layer layer)
|
||||||
{
|
{
|
||||||
public const int EquipUpdatePacketLength = 15;
|
if (ns.CannotSendPackets())
|
||||||
public const int RemovePacketLength = 5;
|
|
||||||
|
|
||||||
public static void SendHairEquipUpdatePacket(this NetState ns, Mobile m, uint hairSerial, int itemId, int hue, Layer layer)
|
|
||||||
{
|
{
|
||||||
if (ns.CannotSendPackets())
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<byte> buffer = stackalloc byte[EquipUpdatePacketLength];
|
|
||||||
CreateHairEquipUpdatePacket(buffer, m, hairSerial, itemId, hue, layer);
|
|
||||||
ns.Send(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateHairEquipUpdatePacket(Span<byte> buffer, Mobile m, uint hairSerial, int itemId, int hue, Layer layer)
|
Span<byte> buffer = stackalloc byte[EquipUpdatePacketLength];
|
||||||
{
|
CreateHairEquipUpdatePacket(buffer, m, hairSerial, itemId, hue, layer);
|
||||||
if (buffer[0] != 0)
|
ns.Send(buffer);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var writer = new SpanWriter(buffer);
|
|
||||||
writer.Write((byte)0x2E); // Packet ID
|
|
||||||
|
|
||||||
writer.Write(hairSerial);
|
|
||||||
writer.Write((short)itemId);
|
|
||||||
writer.Write((byte)0);
|
|
||||||
writer.Write((byte)layer);
|
|
||||||
writer.Write(m.Serial);
|
|
||||||
writer.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : hue));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendRemoveHairPacket(this NetState ns, uint hairSerial)
|
|
||||||
{
|
|
||||||
if (ns.CannotSendPackets())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<byte> buffer = stackalloc byte[RemovePacketLength];
|
|
||||||
CreateRemoveHairPacket(buffer, hairSerial);
|
|
||||||
ns.Send(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CreateRemoveHairPacket(Span<byte> buffer, uint hairSerial)
|
|
||||||
{
|
|
||||||
if (buffer[0] != 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var writer = new SpanWriter(buffer);
|
|
||||||
writer.Write((byte)0x1D); // Packet ID
|
|
||||||
writer.Write(hairSerial);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class BaseHairInfo
|
public static void CreateHairEquipUpdatePacket(Span<byte> buffer, Mobile m, uint hairSerial, int itemId, int hue, Layer layer)
|
||||||
{
|
{
|
||||||
protected BaseHairInfo(int itemid, int hue = 0)
|
if (buffer[0] != 0)
|
||||||
{
|
{
|
||||||
ItemID = itemid;
|
return;
|
||||||
Hue = hue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BaseHairInfo(IGenericReader reader)
|
var writer = new SpanWriter(buffer);
|
||||||
{
|
writer.Write((byte)0x2E); // Packet ID
|
||||||
var version = reader.ReadInt();
|
|
||||||
|
|
||||||
switch (version)
|
writer.Write(hairSerial);
|
||||||
{
|
writer.Write((short)itemId);
|
||||||
case 0:
|
writer.Write((byte)0);
|
||||||
{
|
writer.Write((byte)layer);
|
||||||
ItemID = reader.ReadInt();
|
writer.Write(m.Serial);
|
||||||
Hue = reader.ReadInt();
|
writer.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : hue));
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.GameMaster)]
|
|
||||||
public int ItemID { get; set; }
|
|
||||||
|
|
||||||
[CommandProperty(AccessLevel.GameMaster)]
|
|
||||||
public int Hue { get; set; }
|
|
||||||
|
|
||||||
public virtual void Serialize(IGenericWriter writer)
|
|
||||||
{
|
|
||||||
writer.Write(0); // version
|
|
||||||
writer.Write(ItemID);
|
|
||||||
writer.Write(Hue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HairInfo : BaseHairInfo
|
public static void SendRemoveHairPacket(this NetState ns, uint hairSerial)
|
||||||
{
|
{
|
||||||
public HairInfo(int itemid)
|
if (ns.CannotSendPackets())
|
||||||
: base(itemid)
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HairInfo(int itemid, int hue)
|
Span<byte> buffer = stackalloc byte[RemovePacketLength];
|
||||||
: base(itemid, hue)
|
CreateRemoveHairPacket(buffer, hairSerial);
|
||||||
{
|
ns.Send(buffer);
|
||||||
}
|
|
||||||
|
|
||||||
public HairInfo(IGenericReader reader)
|
|
||||||
: base(reader)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Can we make this higher for newer clients?
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - m.Value * 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FacialHairInfo : BaseHairInfo
|
public static void CreateRemoveHairPacket(Span<byte> buffer, uint hairSerial)
|
||||||
{
|
{
|
||||||
public FacialHairInfo(int itemid)
|
if (buffer[0] != 0)
|
||||||
: base(itemid)
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FacialHairInfo(int itemid, int hue)
|
var writer = new SpanWriter(buffer);
|
||||||
: base(itemid, hue)
|
writer.Write((byte)0x1D); // Packet ID
|
||||||
{
|
writer.Write(hairSerial);
|
||||||
}
|
|
||||||
|
|
||||||
public FacialHairInfo(IGenericReader reader)
|
|
||||||
: base(reader)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Can we make this higher for newer clients?
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - 1 - m.Value* 4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class BaseHairInfo
|
||||||
|
{
|
||||||
|
protected BaseHairInfo(int itemid, int hue = 0)
|
||||||
|
{
|
||||||
|
ItemID = itemid;
|
||||||
|
Hue = hue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BaseHairInfo(IGenericReader reader)
|
||||||
|
{
|
||||||
|
var version = reader.ReadInt();
|
||||||
|
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
ItemID = reader.ReadInt();
|
||||||
|
Hue = reader.ReadInt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
|
public int ItemID { get; set; }
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
|
public int Hue { get; set; }
|
||||||
|
|
||||||
|
public virtual void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write(0); // version
|
||||||
|
writer.Write(ItemID);
|
||||||
|
writer.Write(Hue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HairInfo : BaseHairInfo
|
||||||
|
{
|
||||||
|
public HairInfo(int itemid)
|
||||||
|
: base(itemid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HairInfo(int itemid, int hue)
|
||||||
|
: base(itemid, hue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HairInfo(IGenericReader reader)
|
||||||
|
: base(reader)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Can we make this higher for newer clients?
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - m.Value * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FacialHairInfo : BaseHairInfo
|
||||||
|
{
|
||||||
|
public FacialHairInfo(int itemid)
|
||||||
|
: base(itemid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public FacialHairInfo(int itemid, int hue)
|
||||||
|
: base(itemid, hue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public FacialHairInfo(IGenericReader reader)
|
||||||
|
: base(reader)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Can we make this higher for newer clients?
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - 1 - m.Value* 4;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ClientVersionConverterFactory.cs *
|
* File: ClientVersionConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GuidConverter.cs *
|
* File: GuidConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: GuidConverterFactory.cs *
|
* File: GuidConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: IPEndPointConverter.cs *
|
* File: IPEndPointConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: IPEndPointConverterFactory.cs *
|
* File: IPEndPointConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: MapConverter.cs *
|
* File: MapConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: MapConverterFactory.cs *
|
* File: MapConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point2DConverter.cs *
|
* File: Point2DConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point2DConverterFactory.cs *
|
* File: Point2DConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point3DConverter.cs *
|
* File: Point3DConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Point3DConverterFactory.cs *
|
* File: Point3DConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Rectangle3DConverter.cs *
|
* File: Rectangle3DConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: Rectangle3DConverterFactory.cs *
|
* File: Rectangle3DConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: TimeSpanConverter.cs *
|
* File: TimeSpanConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: TimeSpanConverterFactory.cs *
|
* File: TimeSpanConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: TypeConverter.cs *
|
* File: TypeConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: TypeConverterFactory.cs *
|
* File: TypeConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: WorldLocationConverter.cs *
|
* File: WorldLocationConverter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: WorldLocationConverterFactory.cs *
|
* File: WorldLocationConverterFactory.cs *
|
||||||
* *
|
* *
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: DynamicJson.cs *
|
* File: DynamicJson.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -18,50 +18,49 @@ using System.Collections.Generic;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Server.Json
|
namespace Server.Json;
|
||||||
|
|
||||||
|
public class DynamicJson
|
||||||
{
|
{
|
||||||
public class DynamicJson
|
public static DynamicJson Create(Type type) => new()
|
||||||
{
|
{
|
||||||
public static DynamicJson Create(Type type) => new()
|
Type = type.Name,
|
||||||
|
Data = new Dictionary<string, JsonElement>()
|
||||||
|
};
|
||||||
|
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonExtensionData]
|
||||||
|
public Dictionary<string, JsonElement> Data { get; set; }
|
||||||
|
|
||||||
|
// TODO: Use JSON Node in .NET 6
|
||||||
|
public void SetProperty<T>(string key, JsonSerializerOptions options, T value)
|
||||||
|
{
|
||||||
|
using var doc = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, options));
|
||||||
|
Data[key] = doc.RootElement.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetProperty<T>(string key, JsonSerializerOptions options, out T t)
|
||||||
|
{
|
||||||
|
if (Data.TryGetValue(key, out var el))
|
||||||
{
|
{
|
||||||
Type = type.Name,
|
t = el.ToObject<T>(options);
|
||||||
Data = new Dictionary<string, JsonElement>()
|
return true;
|
||||||
};
|
|
||||||
|
|
||||||
[JsonPropertyName("type")]
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
[JsonExtensionData]
|
|
||||||
public Dictionary<string, JsonElement> Data { get; set; }
|
|
||||||
|
|
||||||
// TODO: Use JSON Node in .NET 6
|
|
||||||
public void SetProperty<T>(string key, JsonSerializerOptions options, T value)
|
|
||||||
{
|
|
||||||
using var doc = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, options));
|
|
||||||
Data[key] = doc.RootElement.Clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetProperty<T>(string key, JsonSerializerOptions options, out T t)
|
t = default;
|
||||||
{
|
return false;
|
||||||
if (Data.TryGetValue(key, out var el))
|
}
|
||||||
{
|
|
||||||
t = el.ToObject<T>(options);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = default;
|
public bool GetEnumProperty<T>(string key, JsonSerializerOptions options, out T t) where T : struct, Enum
|
||||||
return false;
|
{
|
||||||
|
if (Data.TryGetValue(key, out var el))
|
||||||
|
{
|
||||||
|
return Enum.TryParse(el.ToObject<string>(options), out t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetEnumProperty<T>(string key, JsonSerializerOptions options, out T t) where T : struct, Enum
|
t = default;
|
||||||
{
|
return false;
|
||||||
if (Data.TryGetValue(key, out var el))
|
|
||||||
{
|
|
||||||
return Enum.TryParse(el.ToObject<string>(options), out t);
|
|
||||||
}
|
|
||||||
|
|
||||||
t = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: JsonConfig.cs *
|
* File: JsonConfig.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -21,93 +21,92 @@ using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Server.Text;
|
using Server.Text;
|
||||||
|
|
||||||
namespace Server.Json
|
namespace Server.Json;
|
||||||
|
|
||||||
|
public static class JsonConfig
|
||||||
{
|
{
|
||||||
public static class JsonConfig
|
public static readonly JsonSerializerOptions DefaultOptions = GetOptions();
|
||||||
|
|
||||||
|
public static JsonSerializerOptions GetOptions(params JsonConverterFactory[] converters)
|
||||||
{
|
{
|
||||||
public static readonly JsonSerializerOptions DefaultOptions = GetOptions();
|
// In the future this should be optimized by cloning DefaultOptions
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
public static JsonSerializerOptions GetOptions(params JsonConverterFactory[] converters)
|
|
||||||
{
|
{
|
||||||
// In the future this should be optimized by cloning DefaultOptions
|
WriteIndented = true,
|
||||||
var options = new JsonSerializerOptions
|
AllowTrailingCommas = true,
|
||||||
{
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
WriteIndented = true,
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
AllowTrailingCommas = true,
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
};
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
};
|
|
||||||
|
|
||||||
options.Converters.Add(new ClientVersionConverterFactory());
|
options.Converters.Add(new ClientVersionConverterFactory());
|
||||||
options.Converters.Add(new GuidConverterFactory());
|
options.Converters.Add(new GuidConverterFactory());
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
options.Converters.Add(new JsonStringEnumConverter());
|
||||||
options.Converters.Add(new MapConverterFactory());
|
options.Converters.Add(new MapConverterFactory());
|
||||||
options.Converters.Add(new Point3DConverterFactory());
|
options.Converters.Add(new Point3DConverterFactory());
|
||||||
options.Converters.Add(new Rectangle3DConverterFactory());
|
options.Converters.Add(new Rectangle3DConverterFactory());
|
||||||
options.Converters.Add(new TimeSpanConverterFactory());
|
options.Converters.Add(new TimeSpanConverterFactory());
|
||||||
options.Converters.Add(new IPEndPointConverterFactory());
|
options.Converters.Add(new IPEndPointConverterFactory());
|
||||||
options.Converters.Add(new TypeConverterFactory());
|
options.Converters.Add(new TypeConverterFactory());
|
||||||
options.Converters.Add(new WorldLocationConverterFactory());
|
options.Converters.Add(new WorldLocationConverterFactory());
|
||||||
|
|
||||||
for (var i = 0; i < converters.Length; i++)
|
for (var i = 0; i < converters.Length; i++)
|
||||||
{
|
{
|
||||||
options.Converters.Add(converters[i]);
|
options.Converters.Add(converters[i]);
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Deserialize<T>(string filePath, JsonSerializerOptions options = null)
|
return options;
|
||||||
{
|
}
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = File.ReadAllText(filePath, TextEncoding.UTF8);
|
public static T Deserialize<T>(string filePath, JsonSerializerOptions options = null)
|
||||||
return JsonSerializer.Deserialize<T>(text, options ?? DefaultOptions);
|
{
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Serialize(object value, JsonSerializerOptions options = null) =>
|
var text = File.ReadAllText(filePath, TextEncoding.UTF8);
|
||||||
JsonSerializer.Serialize(value, options ?? DefaultOptions);
|
return JsonSerializer.Deserialize<T>(text, options ?? DefaultOptions);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Serialize(string filePath, object value, JsonSerializerOptions options = null)
|
public static string Serialize(object value, JsonSerializerOptions options = null) =>
|
||||||
|
JsonSerializer.Serialize(value, options ?? DefaultOptions);
|
||||||
|
|
||||||
|
public static void Serialize(string filePath, object value, JsonSerializerOptions options = null)
|
||||||
|
{
|
||||||
|
var contents = Serialize(value, options);
|
||||||
|
|
||||||
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
var contents = Serialize(value, options);
|
File.Delete(filePath);
|
||||||
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
File.Delete(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
|
|
||||||
|
|
||||||
File.WriteAllText(filePath, contents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T ToObject<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options = null) =>
|
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
|
||||||
JsonSerializer.Deserialize<T>(ref reader, options);
|
|
||||||
|
|
||||||
public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
|
File.WriteAllText(filePath, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T ToObject<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options = null) =>
|
||||||
|
JsonSerializer.Deserialize<T>(ref reader, options);
|
||||||
|
|
||||||
|
public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
|
||||||
|
{
|
||||||
|
var bufferWriter = new ArrayBufferWriter<byte>();
|
||||||
|
using (var writer = new Utf8JsonWriter(bufferWriter))
|
||||||
{
|
{
|
||||||
var bufferWriter = new ArrayBufferWriter<byte>();
|
element.WriteTo(writer);
|
||||||
using (var writer = new Utf8JsonWriter(bufferWriter))
|
|
||||||
{
|
|
||||||
element.WriteTo(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
|
return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
|
||||||
{
|
}
|
||||||
if (document == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(document));
|
|
||||||
}
|
|
||||||
|
|
||||||
return document.RootElement.ToObject<T>(options);
|
public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
|
||||||
|
{
|
||||||
|
if (document == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(document));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return document.RootElement.ToObject<T>(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2020 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: JsonPropertySorter.cs *
|
* File: JsonPropertySorter.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -20,81 +20,80 @@ using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Server.Json
|
namespace Server.Json;
|
||||||
|
|
||||||
|
public static class JsonUtilities
|
||||||
{
|
{
|
||||||
public static class JsonUtilities
|
public static string SortByPropertyName(string jsonStr)
|
||||||
{
|
{
|
||||||
public static string SortByPropertyName(string jsonStr)
|
using JsonDocument doc = JsonDocument.Parse(jsonStr);
|
||||||
|
return SortByPropertyName(doc.RootElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SortByPropertyName(JsonElement je)
|
||||||
|
{
|
||||||
|
// TODO: Better way to do this than a stream?
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
JsonWriterOptions opts = new JsonWriterOptions
|
||||||
{
|
{
|
||||||
using JsonDocument doc = JsonDocument.Parse(jsonStr);
|
Indented = true,
|
||||||
return SortByPropertyName(doc.RootElement);
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var writer = new Utf8JsonWriter(ms, opts))
|
||||||
|
{
|
||||||
|
WriteJsonElementSorted(je, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string SortByPropertyName(JsonElement je)
|
ms.TryGetBuffer(out var buffer);
|
||||||
|
return Encoding.UTF8.GetString(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteJsonElementSorted(JsonElement je, Utf8JsonWriter writer)
|
||||||
|
{
|
||||||
|
switch(je.ValueKind)
|
||||||
{
|
{
|
||||||
// TODO: Better way to do this than a stream?
|
case JsonValueKind.Object:
|
||||||
using var ms = new MemoryStream();
|
writer.WriteStartObject();
|
||||||
JsonWriterOptions opts = new JsonWriterOptions
|
|
||||||
{
|
|
||||||
Indented = true,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
};
|
|
||||||
|
|
||||||
using (var writer = new Utf8JsonWriter(ms, opts))
|
// TODO: This is slow, can make it faster?
|
||||||
{
|
foreach (JsonProperty x in je.EnumerateObject().OrderBy(prop => prop.Name))
|
||||||
WriteJsonElementSorted(je, writer);
|
{
|
||||||
}
|
writer.WritePropertyName(x.Name);
|
||||||
|
WriteJsonElementSorted(x.Value, writer);
|
||||||
|
}
|
||||||
|
|
||||||
ms.TryGetBuffer(out var buffer);
|
writer.WriteEndObject();
|
||||||
return Encoding.UTF8.GetString(buffer);
|
break;
|
||||||
}
|
case JsonValueKind.Array:
|
||||||
|
writer.WriteStartArray();
|
||||||
|
foreach(JsonElement x in je.EnumerateArray())
|
||||||
|
{
|
||||||
|
WriteJsonElementSorted(x, writer);
|
||||||
|
}
|
||||||
|
writer.WriteEndArray();
|
||||||
|
break;
|
||||||
|
case JsonValueKind.Number:
|
||||||
|
writer.WriteNumberValue(je.GetDouble());
|
||||||
|
break;
|
||||||
|
case JsonValueKind.String:
|
||||||
|
// Escape the string
|
||||||
|
writer.WriteStringValue(je.GetString());
|
||||||
|
break;
|
||||||
|
case JsonValueKind.Null:
|
||||||
|
writer.WriteNullValue();
|
||||||
|
break;
|
||||||
|
case JsonValueKind.True:
|
||||||
|
writer.WriteBooleanValue(true);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.False:
|
||||||
|
writer.WriteBooleanValue(false);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.Undefined: // Don't write anything
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Kind: {je.ValueKind}");
|
||||||
|
|
||||||
private static void WriteJsonElementSorted(JsonElement je, Utf8JsonWriter writer)
|
|
||||||
{
|
|
||||||
switch(je.ValueKind)
|
|
||||||
{
|
|
||||||
case JsonValueKind.Object:
|
|
||||||
writer.WriteStartObject();
|
|
||||||
|
|
||||||
// TODO: This is slow, can make it faster?
|
|
||||||
foreach (JsonProperty x in je.EnumerateObject().OrderBy(prop => prop.Name))
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(x.Name);
|
|
||||||
WriteJsonElementSorted(x.Value, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteEndObject();
|
|
||||||
break;
|
|
||||||
case JsonValueKind.Array:
|
|
||||||
writer.WriteStartArray();
|
|
||||||
foreach(JsonElement x in je.EnumerateArray())
|
|
||||||
{
|
|
||||||
WriteJsonElementSorted(x, writer);
|
|
||||||
}
|
|
||||||
writer.WriteEndArray();
|
|
||||||
break;
|
|
||||||
case JsonValueKind.Number:
|
|
||||||
writer.WriteNumberValue(je.GetDouble());
|
|
||||||
break;
|
|
||||||
case JsonValueKind.String:
|
|
||||||
// Escape the string
|
|
||||||
writer.WriteStringValue(je.GetString());
|
|
||||||
break;
|
|
||||||
case JsonValueKind.Null:
|
|
||||||
writer.WriteNullValue();
|
|
||||||
break;
|
|
||||||
case JsonValueKind.True:
|
|
||||||
writer.WriteBooleanValue(true);
|
|
||||||
break;
|
|
||||||
case JsonValueKind.False:
|
|
||||||
writer.WriteBooleanValue(false);
|
|
||||||
break;
|
|
||||||
case JsonValueKind.Undefined: // Don't write anything
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"Kind: {je.ValueKind}");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,64 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public class KeywordList
|
||||||
{
|
{
|
||||||
public class KeywordList
|
private static readonly int[] m_EmptyInts = Array.Empty<int>();
|
||||||
|
private int[] m_Keywords;
|
||||||
|
|
||||||
|
public KeywordList()
|
||||||
{
|
{
|
||||||
private static readonly int[] m_EmptyInts = Array.Empty<int>();
|
m_Keywords = new int[8];
|
||||||
private int[] m_Keywords;
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public KeywordList()
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
public bool Contains(int keyword)
|
||||||
|
{
|
||||||
|
var contains = false;
|
||||||
|
|
||||||
|
for (var i = 0; !contains && i < Count; ++i)
|
||||||
{
|
{
|
||||||
m_Keywords = new int[8];
|
contains = keyword == m_Keywords[i];
|
||||||
Count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count { get; private set; }
|
return contains;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Contains(int keyword)
|
public void Add(int keyword)
|
||||||
|
{
|
||||||
|
if (Count + 1 > m_Keywords.Length)
|
||||||
{
|
{
|
||||||
var contains = false;
|
var old = m_Keywords;
|
||||||
|
m_Keywords = new int[old.Length * 2];
|
||||||
|
|
||||||
for (var i = 0; !contains && i < Count; ++i)
|
for (var i = 0; i < old.Length; ++i)
|
||||||
{
|
{
|
||||||
contains = keyword == m_Keywords[i];
|
m_Keywords[i] = old[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return contains;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(int keyword)
|
m_Keywords[Count++] = keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] ToArray()
|
||||||
|
{
|
||||||
|
if (Count == 0)
|
||||||
{
|
{
|
||||||
if (Count + 1 > m_Keywords.Length)
|
return m_EmptyInts;
|
||||||
{
|
|
||||||
var old = m_Keywords;
|
|
||||||
m_Keywords = new int[old.Length * 2];
|
|
||||||
|
|
||||||
for (var i = 0; i < old.Length; ++i)
|
|
||||||
{
|
|
||||||
m_Keywords[i] = old[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Keywords[Count++] = keyword;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] ToArray()
|
var keywords = new int[Count];
|
||||||
|
|
||||||
|
for (var i = 0; i < Count; ++i)
|
||||||
{
|
{
|
||||||
if (Count == 0)
|
keywords[i] = m_Keywords[i];
|
||||||
{
|
|
||||||
return m_EmptyInts;
|
|
||||||
}
|
|
||||||
|
|
||||||
var keywords = new int[Count];
|
|
||||||
|
|
||||||
for (var i = 0; i < Count; ++i)
|
|
||||||
{
|
|
||||||
keywords[i] = m_Keywords[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Count = 0;
|
|
||||||
|
|
||||||
return keywords;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Count = 0;
|
||||||
|
|
||||||
|
return keywords;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ILogger.cs *
|
* File: ILogger.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -15,23 +15,22 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Server.Logging
|
namespace Server.Logging;
|
||||||
|
|
||||||
|
public interface ILogger
|
||||||
{
|
{
|
||||||
public interface ILogger
|
void Debug(string message, params object[] args);
|
||||||
{
|
void Debug(Exception exception, string message, params object[] args);
|
||||||
void Debug(string message, params object[] args);
|
|
||||||
void Debug(Exception exception, string message, params object[] args);
|
|
||||||
|
|
||||||
void Information(string message, params object[] args);
|
void Information(string message, params object[] args);
|
||||||
void Information(Exception exception, string message, params object[] args);
|
void Information(Exception exception, string message, params object[] args);
|
||||||
|
|
||||||
void Warning(string message, params object[] args);
|
void Warning(string message, params object[] args);
|
||||||
void Warning(Exception exception, string message, params object[] args);
|
void Warning(Exception exception, string message, params object[] args);
|
||||||
|
|
||||||
void Error(string message, params object[] args);
|
void Error(string message, params object[] args);
|
||||||
void Error(Exception exception, string message, params object[] args);
|
void Error(Exception exception, string message, params object[] args);
|
||||||
|
|
||||||
void Fatal(string message, params object[] args);
|
void Fatal(string message, params object[] args);
|
||||||
void Fatal(Exception exception, string message, params object[] args);
|
void Fatal(Exception exception, string message, params object[] args);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: SerilogLogger.cs *
|
* File: SerilogLogger.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -16,53 +16,52 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server.Logging
|
namespace Server.Logging;
|
||||||
|
|
||||||
|
public class SerilogLogger : ILogger
|
||||||
{
|
{
|
||||||
public class SerilogLogger : ILogger
|
private readonly Serilog.ILogger serilogLogger;
|
||||||
{
|
|
||||||
private readonly Serilog.ILogger serilogLogger;
|
|
||||||
|
|
||||||
public SerilogLogger(Serilog.ILogger serilogLogger) =>
|
public SerilogLogger(Serilog.ILogger serilogLogger) =>
|
||||||
this.serilogLogger = serilogLogger;
|
this.serilogLogger = serilogLogger;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Debug(string message, params object[] args) =>
|
public void Debug(string message, params object[] args) =>
|
||||||
serilogLogger.Debug(message, args);
|
serilogLogger.Debug(message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Debug(Exception exception, string message, params object[] args) =>
|
public void Debug(Exception exception, string message, params object[] args) =>
|
||||||
serilogLogger.Debug(exception, message, args);
|
serilogLogger.Debug(exception, message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Information(string message, params object[] args) =>
|
public void Information(string message, params object[] args) =>
|
||||||
serilogLogger.Information(message, args);
|
serilogLogger.Information(message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Information(Exception exception, string message, params object[] args) =>
|
public void Information(Exception exception, string message, params object[] args) =>
|
||||||
serilogLogger.Information(exception, message, args);
|
serilogLogger.Information(exception, message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Warning(string message, params object[] args) =>
|
public void Warning(string message, params object[] args) =>
|
||||||
serilogLogger.Warning(message, args);
|
serilogLogger.Warning(message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Warning(Exception exception, string message, params object[] args) =>
|
public void Warning(Exception exception, string message, params object[] args) =>
|
||||||
serilogLogger.Information(exception, message, args);
|
serilogLogger.Warning(exception, message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Error(string message, params object[] args) =>
|
public void Error(string message, params object[] args) =>
|
||||||
serilogLogger.Error(message, args);
|
serilogLogger.Error(message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Error(Exception exception, string message, params object[] args) =>
|
public void Error(Exception exception, string message, params object[] args) =>
|
||||||
serilogLogger.Error(exception, message, args);
|
serilogLogger.Error(exception, message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Fatal(string message, params object[] args) =>
|
public void Fatal(string message, params object[] args) =>
|
||||||
serilogLogger.Fatal(message, args);
|
serilogLogger.Fatal(message, args);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Fatal(Exception exception, string message, params object[] args) =>
|
public void Fatal(Exception exception, string message, params object[] args) =>
|
||||||
serilogLogger.Fatal(exception, message, args);
|
serilogLogger.Fatal(exception, message, args);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
* Copyright 2019-2022 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: MapLoader.cs *
|
* File: MapLoader.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -22,125 +22,124 @@ using System.Text.Json.Serialization;
|
||||||
using Server.Json;
|
using Server.Json;
|
||||||
using Server.Logging;
|
using Server.Logging;
|
||||||
|
|
||||||
namespace Server
|
namespace Server;
|
||||||
|
|
||||||
|
public static class MapLoader
|
||||||
{
|
{
|
||||||
public static class MapLoader
|
private static readonly ILogger logger = LogFactory.GetLogger(typeof(MapLoader));
|
||||||
|
|
||||||
|
/* Here we configure all maps. Some notes:
|
||||||
|
*
|
||||||
|
* 1) The first 32 maps are reserved for core use.
|
||||||
|
* 2) Map 127 is reserved for core use.
|
||||||
|
* 3) Map 255 is reserved for core use.
|
||||||
|
* 4) Changing or removing any predefined maps may cause server instability.
|
||||||
|
*
|
||||||
|
* Map definitions are modified in Data/Map Definitions/<expansion>.json:
|
||||||
|
* - <index> : An unreserved unique index for this map
|
||||||
|
* - <id> : An identification number used in client communications. For any visible maps, this value must be from 0-5
|
||||||
|
* - <fileIndex> : A file identification number. For any visible maps, this value must be from 0-5
|
||||||
|
* - <width>, <height> : Size of the map (in tiles)
|
||||||
|
* - <season> : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation
|
||||||
|
* - <name> : Reference name for the map, used in props gump, get/set commands, region loading, etc
|
||||||
|
* - <rules> : Rules and restrictions associated with the map. See documentation for details
|
||||||
|
*/
|
||||||
|
[CallPriority(2)]
|
||||||
|
public static void Configure()
|
||||||
{
|
{
|
||||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(MapLoader));
|
var failures = new List<string>();
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
/* Here we configure all maps. Some notes:
|
var path = Path.Combine(Core.BaseDirectory, "Data/map-definitions.json");
|
||||||
*
|
|
||||||
* 1) The first 32 maps are reserved for core use.
|
logger.Information("Loading Map Definitions");
|
||||||
* 2) Map 127 is reserved for core use.
|
|
||||||
* 3) Map 255 is reserved for core use.
|
var stopwatch = Stopwatch.StartNew();
|
||||||
* 4) Changing or removing any predefined maps may cause server instability.
|
var maps = JsonConfig.Deserialize<List<MapDefinition>>(path);
|
||||||
*
|
if (maps == null)
|
||||||
* Map definitions are modified in Data/Map Definitions/<expansion>.json:
|
|
||||||
* - <index> : An unreserved unique index for this map
|
|
||||||
* - <id> : An identification number used in client communications. For any visible maps, this value must be from 0-5
|
|
||||||
* - <fileIndex> : A file identification number. For any visible maps, this value must be from 0-5
|
|
||||||
* - <width>, <height> : Size of the map (in tiles)
|
|
||||||
* - <season> : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation
|
|
||||||
* - <name> : Reference name for the map, used in props gump, get/set commands, region loading, etc
|
|
||||||
* - <rules> : Rules and restrictions associated with the map. See documentation for details
|
|
||||||
*/
|
|
||||||
[CallPriority(2)]
|
|
||||||
public static void Configure()
|
|
||||||
{
|
{
|
||||||
var failures = new List<string>();
|
throw new JsonException($"Failed to deserialize {path}.");
|
||||||
var count = 0;
|
}
|
||||||
|
|
||||||
var path = Path.Combine(Core.BaseDirectory, "Data/map-definitions.json");
|
foreach (var def in maps)
|
||||||
|
{
|
||||||
logger.Information("Loading Map Definitions");
|
try
|
||||||
|
|
||||||
var stopwatch = Stopwatch.StartNew();
|
|
||||||
var maps = JsonConfig.Deserialize<List<MapDefinition>>(path);
|
|
||||||
if (maps == null)
|
|
||||||
{
|
{
|
||||||
throw new JsonException($"Failed to deserialize {path}.");
|
RegisterMap(def);
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
foreach (var def in maps)
|
|
||||||
{
|
{
|
||||||
try
|
logger.Debug(ex, "Failed to load map definition {MapDefName} ({MapDefId})", def.Name, def.Id);
|
||||||
{
|
failures.Add($"\tInvalid map definition {def.Name} ({def.Id})");
|
||||||
RegisterMap(def);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.Debug(ex, "Failed to load map definition {MapDefName} ({MapDefId})", def.Name, def.Id);
|
|
||||||
failures.Add($"\tInvalid map definition {def.Name} ({def.Id})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
|
|
||||||
if (failures.Count > 0)
|
|
||||||
{
|
|
||||||
logger.Warning(
|
|
||||||
"Map Definitions loaded with failures ({Count} maps, {FailureCount} failures) ({Duration:F2} seconds)",
|
|
||||||
count,
|
|
||||||
failures.Count,
|
|
||||||
stopwatch.Elapsed.TotalSeconds
|
|
||||||
);
|
|
||||||
|
|
||||||
logger.Warning("Map load failures: {Failure}", failures);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.Information(
|
|
||||||
"Map Definitions loaded successfully ({Count} maps, {FailureCount} failures) ({Duration:F2} seconds)",
|
|
||||||
count,
|
|
||||||
failures.Count,
|
|
||||||
stopwatch.Elapsed.TotalSeconds
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterMap(MapDefinition mapDefinition)
|
stopwatch.Stop();
|
||||||
|
|
||||||
|
if (failures.Count > 0)
|
||||||
{
|
{
|
||||||
var newMap = new Map(
|
logger.Warning(
|
||||||
mapDefinition.Id,
|
"Map Definitions loaded with failures ({Count} maps, {FailureCount} failures) ({Duration:F2} seconds)",
|
||||||
mapDefinition.Index,
|
count,
|
||||||
mapDefinition.FileIndex,
|
failures.Count,
|
||||||
Math.Max(mapDefinition.Width, Map.SectorSize),
|
stopwatch.Elapsed.TotalSeconds
|
||||||
Math.Max(mapDefinition.Height, Map.SectorSize),
|
|
||||||
mapDefinition.Season,
|
|
||||||
mapDefinition.Name,
|
|
||||||
mapDefinition.Rules
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map.Maps[mapDefinition.Index] = newMap;
|
logger.Warning("Map load failures: {Failure}", failures);
|
||||||
Map.AllMaps.Add(newMap);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
internal class MapDefinition
|
|
||||||
{
|
{
|
||||||
[JsonPropertyName("index")]
|
logger.Information(
|
||||||
public int Index { get; set; }
|
"Map Definitions loaded successfully ({Count} maps, {FailureCount} failures) ({Duration:F2} seconds)",
|
||||||
|
count,
|
||||||
[JsonPropertyName("id")]
|
failures.Count,
|
||||||
public int Id { get; set; }
|
stopwatch.Elapsed.TotalSeconds
|
||||||
|
);
|
||||||
[JsonPropertyName("fileIndex")]
|
|
||||||
public int FileIndex { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("width")]
|
|
||||||
public int Width { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("height")]
|
|
||||||
public int Height { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("season")]
|
|
||||||
public int Season { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("rules")]
|
|
||||||
public MapRules Rules { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void RegisterMap(MapDefinition mapDefinition)
|
||||||
|
{
|
||||||
|
var newMap = new Map(
|
||||||
|
mapDefinition.Id,
|
||||||
|
mapDefinition.Index,
|
||||||
|
mapDefinition.FileIndex,
|
||||||
|
Math.Max(mapDefinition.Width, Map.SectorSize),
|
||||||
|
Math.Max(mapDefinition.Height, Map.SectorSize),
|
||||||
|
mapDefinition.Season,
|
||||||
|
mapDefinition.Name,
|
||||||
|
mapDefinition.Rules
|
||||||
|
);
|
||||||
|
|
||||||
|
Map.Maps[mapDefinition.Index] = newMap;
|
||||||
|
Map.AllMaps.Add(newMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MapDefinition
|
||||||
|
{
|
||||||
|
[JsonPropertyName("index")]
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("fileIndex")]
|
||||||
|
public int FileIndex { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("width")]
|
||||||
|
public int Width { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("height")]
|
||||||
|
public int Height { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("season")]
|
||||||
|
public int Season { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("rules")]
|
||||||
|
public MapRules Rules { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.Menus
|
namespace Server.Menus;
|
||||||
|
|
||||||
|
public interface IMenu
|
||||||
{
|
{
|
||||||
public interface IMenu
|
int Serial { get; }
|
||||||
{
|
int EntryLength { get; }
|
||||||
int Serial { get; }
|
void SendTo(NetState state);
|
||||||
int EntryLength { get; }
|
void OnCancel(NetState state);
|
||||||
void SendTo(NetState state);
|
void OnResponse(NetState state, int index);
|
||||||
void OnCancel(NetState state);
|
|
||||||
void OnResponse(NetState state, int index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,60 @@
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
||||||
namespace Server.Menus.ItemLists
|
namespace Server.Menus.ItemLists;
|
||||||
|
|
||||||
|
public class ItemListEntry
|
||||||
{
|
{
|
||||||
public class ItemListEntry
|
public ItemListEntry(string name, int itemID, int hue = 0)
|
||||||
{
|
{
|
||||||
public ItemListEntry(string name, int itemID, int hue = 0)
|
Name = name?.Trim() ?? "";
|
||||||
{
|
ItemID = itemID;
|
||||||
Name = name?.Trim() ?? "";
|
Hue = hue;
|
||||||
ItemID = itemID;
|
|
||||||
Hue = hue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public int ItemID { get; }
|
|
||||||
|
|
||||||
public int Hue { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ItemListMenu : IMenu
|
public string Name { get; }
|
||||||
|
|
||||||
|
public int ItemID { get; }
|
||||||
|
|
||||||
|
public int Hue { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemListMenu : IMenu
|
||||||
|
{
|
||||||
|
private static int m_NextSerial;
|
||||||
|
|
||||||
|
public ItemListMenu(string question, ItemListEntry[] entries)
|
||||||
{
|
{
|
||||||
private static int m_NextSerial;
|
Question = question.Trim();
|
||||||
|
Entries = entries;
|
||||||
|
|
||||||
public ItemListMenu(string question, ItemListEntry[] entries)
|
do
|
||||||
{
|
{
|
||||||
Question = question.Trim();
|
Serial = m_NextSerial++;
|
||||||
Entries = entries;
|
Serial &= 0x7FFFFFFF;
|
||||||
|
} while (Serial == 0);
|
||||||
|
|
||||||
do
|
Serial = (int)((uint)Serial | 0x80000000);
|
||||||
{
|
}
|
||||||
Serial = m_NextSerial++;
|
|
||||||
Serial &= 0x7FFFFFFF;
|
|
||||||
} while (Serial == 0);
|
|
||||||
|
|
||||||
Serial = (int)((uint)Serial | 0x80000000);
|
public string Question { get; }
|
||||||
}
|
|
||||||
|
|
||||||
public string Question { get; }
|
public ItemListEntry[] Entries { get; set; }
|
||||||
|
|
||||||
public ItemListEntry[] Entries { get; set; }
|
public int Serial { get; }
|
||||||
|
|
||||||
public int Serial { get; }
|
public int EntryLength => Entries.Length;
|
||||||
|
|
||||||
public int EntryLength => Entries.Length;
|
public virtual void OnCancel(NetState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void OnCancel(NetState state)
|
public virtual void OnResponse(NetState state, int index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnResponse(NetState state, int index)
|
public void SendTo(NetState state)
|
||||||
{
|
{
|
||||||
}
|
state.AddMenu(this);
|
||||||
|
state.SendDisplayItemListMenu(this);
|
||||||
public void SendTo(NetState state)
|
|
||||||
{
|
|
||||||
state.AddMenu(this);
|
|
||||||
state.SendDisplayItemListMenu(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue