Fixes dupe exception (#258)

- [X] Cleans up ActivatorUtil
- [X] Fixes dupe exception
- [X] Fixes a bug in BasePotion
- [X] Fixes a few possible memory leaks

Bumps release version
This commit is contained in:
Kamron Batman 2020-09-19 15:46:07 -07:00 committed by GitHub
parent 4d6e584b6c
commit e9c1e4cbba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 597 additions and 496 deletions

View file

@ -5738,7 +5738,7 @@ namespace Server
Item item;
try
{
item = (Item)ActivatorUtil.CreateInstance(oldItem.GetType());
item = oldItem.GetType().CreateInstance<Item>();
}
catch
{

View file

@ -46,7 +46,7 @@ namespace Server
continue;
}
var region = ActivatorUtil.CreateInstance(type, json, JsonConfig.DefaultOptions) as Region;
var region = type.CreateInstance<Region>(json, JsonConfig.DefaultOptions);
region?.Register();
count++;
}

View file

@ -0,0 +1,153 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ActivatorExtensions.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Reflection;
namespace Server.Utilities
{
public static class ActivatorExtensions
{
public static ConstructorInfo GetConstructor(
this Type type,
Predicate<ConstructorInfo> predicate = null,
Type[] args = null
) => type.GetConstructor(predicate, args, out _);
public static ConstructorInfo GetConstructor(
this Type type,
Predicate<ConstructorInfo> predicate,
Type[] args,
out int paramCount
)
{
args ??= Array.Empty<Type>();
var ctors = type.GetConstructors();
try
{
for (int i = 0; i < ctors.Length; i++)
{
ConstructorInfo info = ctors[i];
if (predicate?.Invoke(info) == false)
{
continue;
}
var parameters = info.GetParameters();
paramCount = parameters.Length;
if (args.Length > parameters.Length)
{
continue;
}
bool validated = true;
// Check that all args match params
for (var j = 0; j < parameters.Length; j++)
{
ParameterInfo param = parameters[j];
// All extra parameters must be optional
if (j >= args.Length)
{
if (!param.IsOptional)
{
validated = false;
break;
}
continue;
}
var arg = args[j];
if (arg == null && param.ParameterType.IsValueType)
{
validated = false;
break;
}
if (arg != null && !param.ParameterType.IsAssignableFrom(arg))
{
validated = false;
break;
}
}
if (validated)
{
return info;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
paramCount = 0;
return null;
}
public static T CreateInstance<T>(
this Type type,
params object[] args
) where T : class => type.CreateInstance<T>(null, args);
public static T CreateInstance<T>(
this Type type,
Predicate<ConstructorInfo> predicate,
object[] args = null
) where T : class
{
var argLength = args?.Length ?? 0;
var types = argLength > 0 ? new Type[argLength] : Array.Empty<Type>();
for (int i = 0; i < types.Length; i++)
{
types[i] = args![i]?.GetType();
}
var ctor = type.GetConstructor(predicate, types, out var paramCount);
if (ctor == null)
{
Console.WriteLine("There is no constructor for {0} that matches the given predicate.", type);
return default;
}
object[] paramArgs;
if (paramCount == 0)
{
paramArgs = Array.Empty<object>();
}
else if (argLength == paramCount)
{
paramArgs = args;
}
else
{
paramArgs = new object[paramCount];
for (int i = 0; i < paramCount; i++)
{
paramArgs[i] = i < argLength ? args![i] : Type.Missing;
}
}
return ctor.Invoke(paramArgs) as T;
}
}
}

View file

@ -1,155 +0,0 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ActivatorUtil.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Linq;
using System.Reflection;
namespace Server.Utilities
{
public static class ActivatorUtil
{
public static ConstructorInfo GetConstructor(Type type, Predicate<ConstructorInfo> predicate = null)
{
var emptyCtor = type.GetConstructor(Type.EmptyTypes);
if (emptyCtor != null && predicate?.Invoke(emptyCtor) != false)
{
return emptyCtor;
}
var optionalCtor = type.GetConstructors()
.SingleOrDefault(
info =>
predicate?.Invoke(info) != false && info.GetParameters().All(x => x.IsOptional)
);
if (optionalCtor != null)
{
return optionalCtor;
}
throw new TypeInitializationException(
type.ToString(),
new Exception($"There is no empty/default constructor for {type} that matches predicate.")
);
}
public static ConstructorInfo GetConstructor(Type type, Predicate<ConstructorInfo> predicate, params Type[] args)
{
try
{
ConstructorInfo ctor;
if (args.All(x => x != null))
{
ctor = type.GetConstructor(args);
if (ctor != null && predicate?.Invoke(ctor) != false)
{
return ctor;
}
}
else
{
ctor = type.GetConstructors()
.SingleOrDefault(
info =>
{
if (predicate?.Invoke(info) == false)
{
return false;
}
var paramList = info.GetParameters().ToList();
// If more args are given than parameters, skip.
if (args.Length > paramList.Count)
{
return false;
}
// check all given args map to params.
for (var i = 0; i < args.Length; i++)
// if a null reference is passed, but the type is not nullable
{
if (args[i] == null && paramList[i].ParameterType.IsValueType
// or if an arg is not null and is not assignable to the parameter type, skip.
|| !(args[i] == null || paramList[i].ParameterType.IsAssignableFrom(args[i])))
{
return false;
}
}
// If there are more parameters, check if they any are not optional, if any are not, skip.
// Otherwise all checks have passed. We have found a match
return args.Length <= paramList.Count || paramList
.GetRange(args.Length, paramList.Count - args.Length)
.All(x => x.IsOptional);
}
);
if (ctor != null)
{
return ctor;
}
}
throw new Exception($"There is no empty/default constructor for {type} that matches predicate.");
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public static object CreateInstance(Type type, Predicate<ConstructorInfo> constructorPredicate = null)
{
var cctor = GetConstructor(type, constructorPredicate);
var args = cctor.GetParameters();
if (args.Length == 0)
{
return cctor.Invoke(Type.EmptyTypes);
}
var argList = new object[args.Length];
Array.Fill(argList, Type.Missing);
return cctor.Invoke(argList);
}
public static object CreateInstance(
Type type, Predicate<ConstructorInfo> constructorPredicate = null,
params object[] args
)
{
if (args == null || args.Length == 0)
{
return CreateInstance(type, constructorPredicate);
}
var cctor = GetConstructor(type, constructorPredicate, args.Select(x => x?.GetType()).ToArray());
return cctor.Invoke(args);
}
public static object CreateInstance(Type type, params object[] args) => CreateInstance(type, null, args);
public static T CreateInstance<T>(Predicate<ConstructorInfo> constructorPredicate = null) =>
(T)CreateInstance(typeof(T), constructorPredicate);
public static T CreateInstance<T>(params object[] args) => (T)CreateInstance(typeof(T), null, args);
}
}

View file

@ -0,0 +1,46 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: EntityActivatorExtensions.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Reflection;
namespace Server.Utilities
{
public static class EntityActivatorExtensions
{
public static T CreateEntityInstance<T>(
this Type type,
params object[] args
) where T : IEntity => type.CreateEntityInstance<T>(null, args);
public static T CreateEntityInstance<T>(
this Type type,
Predicate<ConstructorInfo> predicate,
object[] args = null
) where T : IEntity
{
var entity = type.CreateInstance<IEntity>(predicate, args);
if (entity is T t)
{
return t;
}
// Handles memory leaks by deleting the offending entity
entity?.Delete();
return default;
}
}
}