Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
198
Scripts/Commands/Generic/Extensions/BaseExtension.cs
Normal file
198
Scripts/Commands/Generic/Extensions/BaseExtension.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public delegate BaseExtension ExtensionConstructor();
|
||||
|
||||
public sealed class ExtensionInfo
|
||||
{
|
||||
private static readonly Dictionary<string, ExtensionInfo> m_Table = new Dictionary<string, ExtensionInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private readonly int m_Order;
|
||||
private readonly string m_Name;
|
||||
private readonly int m_Size;
|
||||
private readonly ExtensionConstructor m_Constructor;
|
||||
public ExtensionInfo(int order, string name, int size, ExtensionConstructor constructor)
|
||||
{
|
||||
this.m_Name = name;
|
||||
this.m_Size = size;
|
||||
|
||||
this.m_Order = order;
|
||||
|
||||
this.m_Constructor = constructor;
|
||||
}
|
||||
|
||||
public static Dictionary<string, ExtensionInfo> Table
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Table;
|
||||
}
|
||||
}
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Order;
|
||||
}
|
||||
}
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Name;
|
||||
}
|
||||
}
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Size;
|
||||
}
|
||||
}
|
||||
public bool IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Size >= 0);
|
||||
}
|
||||
}
|
||||
public ExtensionConstructor Constructor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Constructor;
|
||||
}
|
||||
}
|
||||
public static void Register(ExtensionInfo ext)
|
||||
{
|
||||
m_Table[ext.m_Name] = ext;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Extensions : List<BaseExtension>
|
||||
{
|
||||
public Extensions()
|
||||
{
|
||||
}
|
||||
|
||||
public static Extensions Parse(Mobile from, ref string[] args)
|
||||
{
|
||||
Extensions parsed = new Extensions();
|
||||
|
||||
int size = args.Length;
|
||||
|
||||
Type baseType = null;
|
||||
|
||||
for (int i = args.Length - 1; i >= 0; --i)
|
||||
{
|
||||
ExtensionInfo extInfo = null;
|
||||
|
||||
if (!ExtensionInfo.Table.TryGetValue(args[i], out extInfo))
|
||||
continue;
|
||||
|
||||
if (extInfo.IsFixedSize && i != (size - extInfo.Size - 1))
|
||||
throw new Exception("Invalid extended argument count.");
|
||||
|
||||
BaseExtension ext = extInfo.Constructor();
|
||||
|
||||
ext.Parse(from, args, i + 1, size - i - 1);
|
||||
|
||||
if (ext is WhereExtension)
|
||||
baseType = (ext as WhereExtension).Conditional.Type;
|
||||
|
||||
parsed.Add(ext);
|
||||
|
||||
size = i;
|
||||
}
|
||||
|
||||
parsed.Sort(delegate(BaseExtension a, BaseExtension b)
|
||||
{
|
||||
return (a.Order - b.Order);
|
||||
});
|
||||
|
||||
AssemblyEmitter emitter = null;
|
||||
|
||||
foreach (BaseExtension update in parsed)
|
||||
update.Optimize(from, baseType, ref emitter);
|
||||
|
||||
if (size != args.Length)
|
||||
{
|
||||
string[] old = args;
|
||||
args = new string[size];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
args[i] = old[i];
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public bool IsValid(object obj)
|
||||
{
|
||||
for (int i = 0; i < this.Count; ++i)
|
||||
{
|
||||
if (!this[i].IsValid(obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Filter(ArrayList list)
|
||||
{
|
||||
for (int i = 0; i < this.Count; ++i)
|
||||
this[i].Filter(list);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BaseExtension
|
||||
{
|
||||
public abstract ExtensionInfo Info { get; }
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Name;
|
||||
}
|
||||
}
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Size;
|
||||
}
|
||||
}
|
||||
public bool IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.IsFixedSize;
|
||||
}
|
||||
}
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Order;
|
||||
}
|
||||
}
|
||||
public virtual void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool IsValid(object obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Filter(ArrayList list)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,549 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public interface IConditional
|
||||
{
|
||||
bool Verify(object obj);
|
||||
}
|
||||
|
||||
public interface ICondition
|
||||
{
|
||||
// Invoked during the constructor
|
||||
void Construct(TypeBuilder typeBuilder, ILGenerator il, int index);
|
||||
|
||||
// Target object will be loaded on the stack
|
||||
void Compile(MethodEmitter emitter);
|
||||
}
|
||||
|
||||
public sealed class TypeCondition : ICondition
|
||||
{
|
||||
public static TypeCondition Default = new TypeCondition();
|
||||
|
||||
void ICondition.Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
}
|
||||
|
||||
void ICondition.Compile(MethodEmitter emitter)
|
||||
{
|
||||
// The object was safely cast to be the conditionals type
|
||||
// If it's null, then the type cast didn't work...
|
||||
emitter.LoadNull();
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PropertyValue
|
||||
{
|
||||
private readonly Type m_Type;
|
||||
private object m_Value;
|
||||
private FieldInfo m_Field;
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Type;
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Value;
|
||||
}
|
||||
}
|
||||
|
||||
public FieldInfo Field
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Field;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasField
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Field != null);
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyValue(Type type, object value)
|
||||
{
|
||||
this.m_Type = type;
|
||||
this.m_Value = value;
|
||||
}
|
||||
|
||||
public void Load(MethodEmitter method)
|
||||
{
|
||||
if (this.m_Field != null)
|
||||
{
|
||||
method.LoadArgument(0);
|
||||
method.LoadField(this.m_Field);
|
||||
}
|
||||
else if (this.m_Value == null)
|
||||
{
|
||||
method.LoadNull(this.m_Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.m_Value is int)
|
||||
method.Load((int)this.m_Value);
|
||||
else if (this.m_Value is long)
|
||||
method.Load((long)this.m_Value);
|
||||
else if (this.m_Value is float)
|
||||
method.Load((float)this.m_Value);
|
||||
else if (this.m_Value is double)
|
||||
method.Load((double)this.m_Value);
|
||||
else if (this.m_Value is char)
|
||||
method.Load((char)this.m_Value);
|
||||
else if (this.m_Value is bool)
|
||||
method.Load((bool)this.m_Value);
|
||||
else if (this.m_Value is string)
|
||||
method.Load((string)this.m_Value);
|
||||
else if (this.m_Value is Enum)
|
||||
method.Load((Enum)this.m_Value);
|
||||
else
|
||||
throw new InvalidOperationException("Unrecognized comparison value.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Acquire(TypeBuilder typeBuilder, ILGenerator il, string fieldName)
|
||||
{
|
||||
if (this.m_Value is string)
|
||||
{
|
||||
string toParse = (string)this.m_Value;
|
||||
|
||||
if (!this.m_Type.IsValueType && toParse == "null")
|
||||
{
|
||||
this.m_Value = null;
|
||||
}
|
||||
else if (this.m_Type == typeof(string))
|
||||
{
|
||||
if (toParse == @"@""null""")
|
||||
toParse = "null";
|
||||
|
||||
this.m_Value = toParse;
|
||||
}
|
||||
else if (this.m_Type.IsEnum)
|
||||
{
|
||||
this.m_Value = Enum.Parse(this.m_Type, toParse, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodInfo parseMethod = null;
|
||||
object[] parseArgs = null;
|
||||
|
||||
MethodInfo parseNumber = this.m_Type.GetMethod(
|
||||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[] { typeof(string), typeof(NumberStyles) },
|
||||
null);
|
||||
|
||||
if (parseNumber != null)
|
||||
{
|
||||
NumberStyles style = NumberStyles.Integer;
|
||||
|
||||
if (Insensitive.StartsWith(toParse, "0x"))
|
||||
{
|
||||
style = NumberStyles.HexNumber;
|
||||
toParse = toParse.Substring(2);
|
||||
}
|
||||
|
||||
parseMethod = parseNumber;
|
||||
parseArgs = new object[] { toParse, style };
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodInfo parseGeneral = this.m_Type.GetMethod(
|
||||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[] { typeof(string) },
|
||||
null);
|
||||
|
||||
parseMethod = parseGeneral;
|
||||
parseArgs = new object[] { toParse };
|
||||
}
|
||||
|
||||
if (parseMethod != null)
|
||||
{
|
||||
this.m_Value = parseMethod.Invoke(null, parseArgs);
|
||||
|
||||
if (!this.m_Type.IsPrimitive)
|
||||
{
|
||||
this.m_Field = typeBuilder.DefineField(
|
||||
fieldName,
|
||||
this.m_Type,
|
||||
FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
il.Emit(OpCodes.Ldstr, toParse);
|
||||
|
||||
if (parseArgs.Length == 2) // dirty evil hack :-(
|
||||
il.Emit(OpCodes.Ldc_I4, (int)parseArgs[1]);
|
||||
|
||||
il.Emit(OpCodes.Call, parseMethod);
|
||||
il.Emit(OpCodes.Stfld, this.m_Field);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format(
|
||||
"Unable to convert string \"{0}\" into type '{1}'.",
|
||||
this.m_Value,
|
||||
this.m_Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class PropertyCondition : ICondition
|
||||
{
|
||||
protected Property m_Property;
|
||||
protected bool m_Not;
|
||||
|
||||
public PropertyCondition(Property property, bool not)
|
||||
{
|
||||
this.m_Property = property;
|
||||
this.m_Not = not;
|
||||
}
|
||||
|
||||
public abstract void Construct(TypeBuilder typeBuilder, ILGenerator il, int index);
|
||||
|
||||
public abstract void Compile(MethodEmitter emitter);
|
||||
}
|
||||
|
||||
public enum StringOperator
|
||||
{
|
||||
Equal,
|
||||
NotEqual,
|
||||
|
||||
Contains,
|
||||
|
||||
StartsWith,
|
||||
EndsWith
|
||||
}
|
||||
|
||||
public sealed class StringCondition : PropertyCondition
|
||||
{
|
||||
private readonly StringOperator m_Operator;
|
||||
private readonly PropertyValue m_Value;
|
||||
|
||||
private readonly bool m_IgnoreCase;
|
||||
|
||||
public StringCondition(Property property, bool not, StringOperator op, object value, bool ignoreCase)
|
||||
: base(property, not)
|
||||
{
|
||||
this.m_Operator = op;
|
||||
this.m_Value = new PropertyValue(property.Type, value);
|
||||
|
||||
this.m_IgnoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
public override void Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
this.m_Value.Acquire(typeBuilder, il, "v" + index);
|
||||
}
|
||||
|
||||
public override void Compile(MethodEmitter emitter)
|
||||
{
|
||||
bool inverse = false;
|
||||
|
||||
string methodName;
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case StringOperator.Equal:
|
||||
methodName = "Equals";
|
||||
break;
|
||||
case StringOperator.NotEqual:
|
||||
methodName = "Equals";
|
||||
inverse = true;
|
||||
break;
|
||||
case StringOperator.Contains:
|
||||
methodName = "Contains";
|
||||
break;
|
||||
case StringOperator.StartsWith:
|
||||
methodName = "StartsWith";
|
||||
break;
|
||||
case StringOperator.EndsWith:
|
||||
methodName = "EndsWith";
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid string comparison operator.");
|
||||
}
|
||||
|
||||
if (this.m_IgnoreCase || methodName == "Equals")
|
||||
{
|
||||
Type type = (this.m_IgnoreCase ? typeof(Insensitive) : typeof(String));
|
||||
|
||||
emitter.BeginCall(
|
||||
type.GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(string)
|
||||
},
|
||||
null));
|
||||
|
||||
emitter.Chain(this.m_Property);
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
emitter.FinishCall();
|
||||
}
|
||||
else
|
||||
{
|
||||
Label notNull = emitter.CreateLabel();
|
||||
Label moveOn = emitter.CreateLabel();
|
||||
|
||||
LocalBuilder temp = emitter.AcquireTemp(this.m_Property.Type);
|
||||
|
||||
emitter.Chain(this.m_Property);
|
||||
|
||||
emitter.StoreLocal(temp);
|
||||
emitter.LoadLocal(temp);
|
||||
|
||||
emitter.BranchIfTrue(notNull);
|
||||
|
||||
emitter.Load(false);
|
||||
emitter.Pop();
|
||||
emitter.Branch(moveOn);
|
||||
|
||||
emitter.MarkLabel(notNull);
|
||||
emitter.LoadLocal(temp);
|
||||
|
||||
emitter.BeginCall(
|
||||
typeof(string).GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Public | BindingFlags.Instance,
|
||||
null,
|
||||
new Type[]
|
||||
{
|
||||
typeof(string)
|
||||
},
|
||||
null));
|
||||
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
emitter.FinishCall();
|
||||
|
||||
emitter.MarkLabel(moveOn);
|
||||
}
|
||||
|
||||
if (this.m_Not != inverse)
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public enum ComparisonOperator
|
||||
{
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Lesser,
|
||||
LesserEqual
|
||||
}
|
||||
|
||||
public sealed class ComparisonCondition : PropertyCondition
|
||||
{
|
||||
private readonly ComparisonOperator m_Operator;
|
||||
private readonly PropertyValue m_Value;
|
||||
|
||||
public ComparisonCondition(Property property, bool not, ComparisonOperator op, object value)
|
||||
: base(property, not)
|
||||
{
|
||||
this.m_Operator = op;
|
||||
this.m_Value = new PropertyValue(property.Type, value);
|
||||
}
|
||||
|
||||
public override void Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
this.m_Value.Acquire(typeBuilder, il, "v" + index);
|
||||
}
|
||||
|
||||
public override void Compile(MethodEmitter emitter)
|
||||
{
|
||||
emitter.Chain(this.m_Property);
|
||||
|
||||
bool inverse = false;
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(1, delegate()
|
||||
{
|
||||
this.m_Value.Load(emitter);
|
||||
});
|
||||
|
||||
if (couldCompare)
|
||||
{
|
||||
emitter.Load(0);
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Greater:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
break;
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Lesser:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
break;
|
||||
case ComparisonOperator.LesserEqual:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
inverse = true;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid comparison operator.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This type is -not- comparable
|
||||
// We can only support == and != operations
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Greater:
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
case ComparisonOperator.Lesser:
|
||||
case ComparisonOperator.LesserEqual:
|
||||
throw new InvalidOperationException("Property does not support relational comparisons.");
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operator.");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_Not != inverse)
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConditionalCompiler
|
||||
{
|
||||
public static IConditional Compile(AssemblyEmitter assembly, Type objectType, ICondition[] conditions, int index)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__conditional" + index,
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
for (int i = 0; i < conditions.Length; ++i)
|
||||
conditions[i].Construct(typeBuilder, il, i);
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IConditional));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Verify",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(bool),
|
||||
/* params */ new Type[] { typeof(object) });
|
||||
|
||||
LocalBuilder obj = emitter.CreateLocal(objectType);
|
||||
LocalBuilder eq = emitter.CreateLocal(typeof(bool));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(obj);
|
||||
|
||||
Label done = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < conditions.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(eq);
|
||||
|
||||
emitter.BranchIfFalse(done);
|
||||
}
|
||||
|
||||
emitter.LoadLocal(obj);
|
||||
|
||||
conditions[i].Compile(emitter);
|
||||
|
||||
emitter.StoreLocal(eq);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(done);
|
||||
|
||||
emitter.LoadLocal(eq);
|
||||
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IConditional).GetMethod(
|
||||
"Verify",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type conditionalType = typeBuilder.CreateType();
|
||||
|
||||
return (IConditional)Activator.CreateInstance(conditionalType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public static class DistinctCompiler
|
||||
{
|
||||
public static IComparer Compile(AssemblyEmitter assembly, Type objectType, Property[] props)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__distinct",
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IComparer));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Compare",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
LocalBuilder a = emitter.CreateLocal(objectType);
|
||||
LocalBuilder b = emitter.CreateLocal(objectType);
|
||||
|
||||
LocalBuilder v = emitter.CreateLocal(typeof(int));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(a);
|
||||
|
||||
emitter.LoadArgument(2);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(b);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.StoreLocal(v);
|
||||
|
||||
Label end = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < props.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(v);
|
||||
emitter.BranchIfTrue(end); // if ( v != 0 ) return v;
|
||||
}
|
||||
|
||||
Property prop = props[i];
|
||||
|
||||
emitter.LoadLocal(a);
|
||||
emitter.Chain(prop);
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(1, delegate()
|
||||
{
|
||||
emitter.LoadLocal(b);
|
||||
emitter.Chain(prop);
|
||||
});
|
||||
|
||||
if (!couldCompare)
|
||||
throw new InvalidOperationException("Property is not comparable.");
|
||||
|
||||
emitter.StoreLocal(v);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(end);
|
||||
|
||||
emitter.LoadLocal(v);
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IComparer).GetMethod(
|
||||
"Compare",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region IEqualityComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IEqualityComparer<object>));
|
||||
|
||||
#region Equals
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Equals",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(bool),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_0);
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_1);
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_2);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Call, compareMethod);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ldc_I4_0);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ceq);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ret);
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IEqualityComparer<object>).GetMethod(
|
||||
"Equals",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetHashCode
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "GetHashCode",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object) });
|
||||
|
||||
LocalBuilder obj = emitter.CreateLocal(objectType);
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(obj);
|
||||
|
||||
for (int i = 0; i < props.Length; ++i)
|
||||
{
|
||||
Property prop = props[i];
|
||||
|
||||
emitter.LoadLocal(obj);
|
||||
emitter.Chain(prop);
|
||||
|
||||
Type active = emitter.Active;
|
||||
|
||||
MethodInfo getHashCode = active.GetMethod("GetHashCode", Type.EmptyTypes);
|
||||
|
||||
if (getHashCode == null)
|
||||
getHashCode = typeof(object).GetMethod("GetHashCode", Type.EmptyTypes);
|
||||
|
||||
if (active != typeof(int))
|
||||
{
|
||||
if (!active.IsValueType)
|
||||
{
|
||||
LocalBuilder value = emitter.AcquireTemp(active);
|
||||
|
||||
Label valueNotNull = emitter.CreateLabel();
|
||||
Label done = emitter.CreateLabel();
|
||||
|
||||
emitter.StoreLocal(value);
|
||||
emitter.LoadLocal(value);
|
||||
|
||||
emitter.BranchIfTrue(valueNotNull);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.Pop(typeof(int));
|
||||
|
||||
emitter.Branch(done);
|
||||
|
||||
emitter.MarkLabel(valueNotNull);
|
||||
|
||||
emitter.LoadLocal(value);
|
||||
emitter.Call(getHashCode);
|
||||
|
||||
emitter.ReleaseTemp(value);
|
||||
|
||||
emitter.MarkLabel(done);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitter.Call(getHashCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
emitter.Xor();
|
||||
}
|
||||
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IEqualityComparer<object>).GetMethod(
|
||||
"GetHashCode",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type comparerType = typeBuilder.CreateType();
|
||||
|
||||
return (IComparer)Activator.CreateInstance(comparerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
186
Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs
Normal file
186
Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class OrderInfo
|
||||
{
|
||||
private Property m_Property;
|
||||
private int m_Order;
|
||||
|
||||
public Property Property
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Property;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Property = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAscending
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Order > 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = (value ? +1 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDescending
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Order < 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = (value ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
public int Sign
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Sign(this.m_Order);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = Math.Sign(value);
|
||||
|
||||
if (this.m_Order == 0)
|
||||
throw new InvalidOperationException("Sign cannot be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
public OrderInfo(Property property, bool isAscending)
|
||||
{
|
||||
this.m_Property = property;
|
||||
|
||||
this.IsAscending = isAscending;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SortCompiler
|
||||
{
|
||||
public static IComparer Compile(AssemblyEmitter assembly, Type objectType, OrderInfo[] orders)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__sort",
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IComparer));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Compare",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
LocalBuilder a = emitter.CreateLocal(objectType);
|
||||
LocalBuilder b = emitter.CreateLocal(objectType);
|
||||
|
||||
LocalBuilder v = emitter.CreateLocal(typeof(int));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(a);
|
||||
|
||||
emitter.LoadArgument(2);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(b);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.StoreLocal(v);
|
||||
|
||||
Label end = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < orders.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(v);
|
||||
emitter.BranchIfTrue(end); // if ( v != 0 ) return v;
|
||||
}
|
||||
|
||||
OrderInfo orderInfo = orders[i];
|
||||
|
||||
Property prop = orderInfo.Property;
|
||||
int sign = orderInfo.Sign;
|
||||
|
||||
emitter.LoadLocal(a);
|
||||
emitter.Chain(prop);
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(sign, delegate()
|
||||
{
|
||||
emitter.LoadLocal(b);
|
||||
emitter.Chain(prop);
|
||||
});
|
||||
|
||||
if (!couldCompare)
|
||||
throw new InvalidOperationException("Property is not comparable.");
|
||||
|
||||
emitter.StoreLocal(v);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(end);
|
||||
|
||||
emitter.LoadLocal(v);
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IComparer).GetMethod(
|
||||
"Compare",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type comparerType = typeBuilder.CreateType();
|
||||
|
||||
return (IComparer)Activator.CreateInstance(comparerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Scripts/Commands/Generic/Extensions/DistinctExtension.cs
Normal file
86
Scripts/Commands/Generic/Extensions/DistinctExtension.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class DistinctExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(30, "Distinct", -1, delegate() { return new DistinctExtension(); });
|
||||
private readonly List<Property> m_Properties;
|
||||
private IComparer m_Comparer;
|
||||
public DistinctExtension()
|
||||
{
|
||||
this.m_Properties = new List<Property>();
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new Exception("Distinct extension may only be used in combination with an object conditional.");
|
||||
|
||||
foreach (Property prop in this.m_Properties)
|
||||
{
|
||||
prop.BindTo(baseType, PropertyAccess.Read);
|
||||
prop.CheckAccess(from);
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
assembly = new AssemblyEmitter("__dynamic", false);
|
||||
|
||||
this.m_Comparer = DistinctCompiler.Compile(assembly, baseType, this.m_Properties.ToArray());
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid distinction syntax.");
|
||||
|
||||
int end = offset + size;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
string binding = arguments[offset++];
|
||||
|
||||
this.m_Properties.Add(new Property(binding));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (this.m_Comparer == null)
|
||||
throw new InvalidOperationException("The extension must first be optimized.");
|
||||
|
||||
ArrayList copy = new ArrayList(list);
|
||||
|
||||
copy.Sort(this.m_Comparer);
|
||||
|
||||
list.Clear();
|
||||
|
||||
object last = null;
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
object obj = copy[i];
|
||||
|
||||
if (last == null || this.m_Comparer.Compare(obj, last) != 0)
|
||||
{
|
||||
list.Add(obj);
|
||||
last = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Scripts/Commands/Generic/Extensions/LimitExtension.cs
Normal file
47
Scripts/Commands/Generic/Extensions/LimitExtension.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class LimitExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(80, "Limit", 1, delegate() { return new LimitExtension(); });
|
||||
private int m_Limit;
|
||||
public LimitExtension()
|
||||
{
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public int Limit
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Limit;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
this.m_Limit = Utility.ToInt32(arguments[offset]);
|
||||
|
||||
if (this.m_Limit < 0)
|
||||
throw new Exception("Limit cannot be less than zero.");
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (list.Count > this.m_Limit)
|
||||
list.RemoveRange(this.m_Limit, list.Count - this.m_Limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Scripts/Commands/Generic/Extensions/SortExtension.cs
Normal file
105
Scripts/Commands/Generic/Extensions/SortExtension.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class SortExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(40, "Order", -1, delegate() { return new SortExtension(); });
|
||||
private readonly List<OrderInfo> m_Orders;
|
||||
private IComparer m_Comparer;
|
||||
public SortExtension()
|
||||
{
|
||||
this.m_Orders = new List<OrderInfo>();
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new Exception("The ordering extension may only be used in combination with an object conditional.");
|
||||
|
||||
foreach (OrderInfo order in this.m_Orders)
|
||||
{
|
||||
order.Property.BindTo(baseType, PropertyAccess.Read);
|
||||
order.Property.CheckAccess(from);
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
assembly = new AssemblyEmitter("__dynamic", false);
|
||||
|
||||
this.m_Comparer = SortCompiler.Compile(assembly, baseType, this.m_Orders.ToArray());
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid ordering syntax.");
|
||||
|
||||
if (Insensitive.Equals(arguments[offset], "by"))
|
||||
{
|
||||
++offset;
|
||||
--size;
|
||||
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid ordering syntax.");
|
||||
}
|
||||
|
||||
int end = offset + size;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
string binding = arguments[offset++];
|
||||
|
||||
bool isAscending = true;
|
||||
|
||||
if (offset < end)
|
||||
{
|
||||
string next = arguments[offset];
|
||||
|
||||
switch ( next.ToLower() )
|
||||
{
|
||||
case "+":
|
||||
case "up":
|
||||
case "asc":
|
||||
case "ascending":
|
||||
isAscending = true;
|
||||
++offset;
|
||||
break;
|
||||
case "-":
|
||||
case "down":
|
||||
case "desc":
|
||||
case "descending":
|
||||
isAscending = false;
|
||||
++offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Property property = new Property(binding);
|
||||
|
||||
this.m_Orders.Add(new OrderInfo(property, isAscending));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (this.m_Comparer == null)
|
||||
throw new InvalidOperationException("The extension must first be optimized.");
|
||||
|
||||
list.Sort(this.m_Comparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Scripts/Commands/Generic/Extensions/WhereExtension.cs
Normal file
53
Scripts/Commands/Generic/Extensions/WhereExtension.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class WhereExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(20, "Where", -1, delegate() { return new WhereExtension(); });
|
||||
private ObjectConditional m_Conditional;
|
||||
public WhereExtension()
|
||||
{
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public ObjectConditional Conditional
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Conditional;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new InvalidOperationException("Insanity.");
|
||||
|
||||
this.m_Conditional.Compile(ref assembly);
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid condition syntax.");
|
||||
|
||||
this.m_Conditional = ObjectConditional.ParseDirect(from, arguments, offset, size);
|
||||
}
|
||||
|
||||
public override bool IsValid(object obj)
|
||||
{
|
||||
return this.m_Conditional.CheckCondition(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user