Merge pull request #5484 from RoosterDragon/startup-efficiency
Improved efficiency of startup methods.
This commit is contained in:
@@ -12,58 +12,58 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public static class Format40
|
||||
{
|
||||
public static int DecodeInto( byte[] src, byte[] dest )
|
||||
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset)
|
||||
{
|
||||
var ctx = new FastByteReader(src);
|
||||
var ctx = new FastByteReader(src, srcOffset);
|
||||
int destIndex = 0;
|
||||
|
||||
while( true )
|
||||
while (true)
|
||||
{
|
||||
byte i = ctx.ReadByte();
|
||||
if( ( i & 0x80 ) == 0 )
|
||||
if ((i & 0x80) == 0)
|
||||
{
|
||||
int count = i & 0x7F;
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
{
|
||||
// case 6
|
||||
count = ctx.ReadByte();
|
||||
byte value = ctx.ReadByte();
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] ^= value;
|
||||
for (int end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 5
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
for (int end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= ctx.ReadByte();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = i & 0x7F;
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
{
|
||||
count = ctx.ReadWord();
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
return destIndex;
|
||||
|
||||
if( ( count & 0x8000 ) == 0 )
|
||||
if ((count & 0x8000) == 0)
|
||||
{
|
||||
// case 2
|
||||
destIndex += ( count & 0x7FFF );
|
||||
destIndex += (count & 0x7FFF);
|
||||
}
|
||||
else if( ( count & 0x4000 ) == 0 )
|
||||
else if ((count & 0x4000) == 0)
|
||||
{
|
||||
// case 3
|
||||
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
|
||||
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= ctx.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 4
|
||||
byte value = ctx.ReadByte();
|
||||
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] ^= value;
|
||||
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= value;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -16,11 +16,12 @@ namespace OpenRA.FileFormats
|
||||
class FastByteReader
|
||||
{
|
||||
readonly byte[] src;
|
||||
int offset = 0;
|
||||
int offset;
|
||||
|
||||
public FastByteReader(byte[] src)
|
||||
public FastByteReader(byte[] src, int offset = 0)
|
||||
{
|
||||
this.src = src;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public bool Done() { return offset >= src.Length; }
|
||||
@@ -59,9 +60,9 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
public static int DecodeInto(byte[] src, byte[] dest)
|
||||
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset = 0)
|
||||
{
|
||||
var ctx = new FastByteReader(src);
|
||||
var ctx = new FastByteReader(src, srcOffset);
|
||||
var destIndex = 0;
|
||||
|
||||
while (true)
|
||||
|
||||
@@ -67,6 +67,9 @@ namespace OpenRA.FileFormats
|
||||
int recurseDepth = 0;
|
||||
readonly int imageCount;
|
||||
|
||||
readonly long shpBytesFileOffset;
|
||||
readonly byte[] shpBytes;
|
||||
|
||||
public ShpReader(Stream stream)
|
||||
{
|
||||
imageCount = stream.ReadUInt16();
|
||||
@@ -93,22 +96,16 @@ namespace OpenRA.FileFormats
|
||||
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
|
||||
}
|
||||
|
||||
shpBytesFileOffset = stream.Position;
|
||||
shpBytes = stream.ReadBytes((int)(stream.Length - stream.Position));
|
||||
|
||||
foreach (var h in headers)
|
||||
Decompress(stream, h);
|
||||
Decompress(h);
|
||||
|
||||
spriteFrames = Exts.Lazy(() => headers.Cast<ISpriteFrame>());
|
||||
}
|
||||
|
||||
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
||||
{
|
||||
stream.Position = h.FileOffset;
|
||||
|
||||
// Actually, far too big. There's no length field with the correct length though :(
|
||||
var compressedLength = (int)(stream.Length - stream.Position);
|
||||
return stream.ReadBytes(compressedLength);
|
||||
}
|
||||
|
||||
void Decompress(Stream stream, ImageHeader h)
|
||||
void Decompress(ImageHeader h)
|
||||
{
|
||||
// No extra work is required for empty frames
|
||||
if (h.Size.Width == 0 || h.Size.Height == 0)
|
||||
@@ -125,19 +122,19 @@ namespace OpenRA.FileFormats
|
||||
if (h.RefImage.Data == null)
|
||||
{
|
||||
++recurseDepth;
|
||||
Decompress(stream, h.RefImage);
|
||||
Decompress(h.RefImage);
|
||||
--recurseDepth;
|
||||
}
|
||||
|
||||
h.Data = CopyImageData(h.RefImage.Data);
|
||||
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
|
||||
Format40.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset));
|
||||
break;
|
||||
}
|
||||
|
||||
case Format.Format80:
|
||||
{
|
||||
var imageBytes = new byte[Size.Width * Size.Height];
|
||||
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
||||
Format80.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset));
|
||||
h.Data = imageBytes;
|
||||
break;
|
||||
}
|
||||
@@ -150,9 +147,7 @@ namespace OpenRA.FileFormats
|
||||
byte[] CopyImageData(byte[] baseImage)
|
||||
{
|
||||
var imageData = new byte[Size.Width * Size.Height];
|
||||
for (var i = 0; i < Size.Width * Size.Height; i++)
|
||||
imageData[i] = baseImage[i];
|
||||
|
||||
Array.Copy(baseImage, imageData, imageData.Length);
|
||||
return imageData;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,11 @@ namespace OpenRA
|
||||
while (t.Count != 0)
|
||||
{
|
||||
var prereqs = PrerequisitesOf(t[index]);
|
||||
var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || n.IsAssignableFrom(x.GetType())));
|
||||
var unsatisfied = prereqs.Where(n => !ret.Any(x =>
|
||||
{
|
||||
var type = x.GetType();
|
||||
return type == n || n.IsAssignableFrom(type);
|
||||
}));
|
||||
if (!unsatisfied.Any())
|
||||
{
|
||||
ret.Add(t[index]);
|
||||
@@ -111,14 +115,13 @@ namespace OpenRA
|
||||
return ret;
|
||||
}
|
||||
|
||||
static List<Type> PrerequisitesOf(ITraitInfo info)
|
||||
static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
|
||||
{
|
||||
return info
|
||||
.GetType()
|
||||
.GetInterfaces()
|
||||
.Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( Requires<> ) )
|
||||
.Select( t => t.GetGenericArguments()[ 0 ] )
|
||||
.ToList();
|
||||
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Requires<>))
|
||||
.Select(t => t.GetGenericArguments()[0]);
|
||||
}
|
||||
|
||||
public IEnumerable<Pair<string, Type>> GetInitKeys()
|
||||
|
||||
@@ -19,10 +19,15 @@ namespace OpenRA
|
||||
{
|
||||
public class ObjectCreator
|
||||
{
|
||||
Pair<Assembly, string>[] assemblies;
|
||||
readonly Cache<string, Type> typeCache;
|
||||
readonly Cache<Type, ConstructorInfo> ctorCache;
|
||||
readonly Pair<Assembly, string>[] assemblies;
|
||||
|
||||
public ObjectCreator(Manifest manifest)
|
||||
{
|
||||
typeCache = new Cache<string, Type>(FindType);
|
||||
ctorCache = new Cache<Type, ConstructorInfo>(GetCtor);
|
||||
|
||||
// All the core namespaces
|
||||
var asms = typeof(Game).Assembly.GetNamespaces() // Game
|
||||
.Select(c => Pair.New(typeof(Game).Assembly, c))
|
||||
@@ -48,23 +53,18 @@ namespace OpenRA
|
||||
|
||||
public T CreateObject<T>(string className, Dictionary<string, object> args)
|
||||
{
|
||||
var type = FindType(className);
|
||||
var type = typeCache[className];
|
||||
if (type == null)
|
||||
{
|
||||
MissingTypeAction(className);
|
||||
return default(T);
|
||||
}
|
||||
|
||||
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
|
||||
var ctors = type.GetConstructors(flags)
|
||||
.Where(x => x.HasAttribute<UseCtorAttribute>()).ToList();
|
||||
|
||||
if (ctors.Count == 0)
|
||||
var ctor = ctorCache[type];
|
||||
if (ctor == null)
|
||||
return (T)CreateBasic(type);
|
||||
else if (ctors.Count == 1)
|
||||
return (T)CreateUsingArgs(ctors[0], args);
|
||||
else
|
||||
throw new InvalidOperationException("ObjectCreator: UseCtor on multiple constructors; invalid.");
|
||||
return (T)CreateUsingArgs(ctor, args);
|
||||
}
|
||||
|
||||
public Type FindType(string className)
|
||||
@@ -74,6 +74,21 @@ namespace OpenRA
|
||||
.FirstOrDefault(t => t != null);
|
||||
}
|
||||
|
||||
public ConstructorInfo GetCtor(Type type)
|
||||
{
|
||||
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
|
||||
var ctors = type.GetConstructors(flags).Where(x => x.HasAttribute<UseCtorAttribute>());
|
||||
using (var e = ctors.GetEnumerator())
|
||||
{
|
||||
if (!e.MoveNext())
|
||||
return null;
|
||||
var ctor = e.Current;
|
||||
if (!e.MoveNext())
|
||||
return ctor;
|
||||
}
|
||||
throw new InvalidOperationException("ObjectCreator: UseCtor on multiple constructors; invalid.");
|
||||
}
|
||||
|
||||
public object CreateBasic(Type type)
|
||||
{
|
||||
return type.GetConstructor(new Type[0]).Invoke(new object[0]);
|
||||
|
||||
@@ -14,18 +14,17 @@ using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Primitives
|
||||
{
|
||||
public class Cache<T, U> : IEnumerable<KeyValuePair<T, U>>
|
||||
public class Cache<T, U> : IReadOnlyDictionary<T, U>
|
||||
{
|
||||
Dictionary<T, U> hax;
|
||||
Func<T,U> loader;
|
||||
readonly Dictionary<T, U> cache;
|
||||
readonly Func<T, U> loader;
|
||||
|
||||
public Cache(Func<T,U> loader, IEqualityComparer<T> c)
|
||||
public Cache(Func<T, U> loader, IEqualityComparer<T> c)
|
||||
{
|
||||
hax = new Dictionary<T, U>(c);
|
||||
if (loader == null)
|
||||
throw new ArgumentNullException("loader");
|
||||
|
||||
this.loader = loader;
|
||||
cache = new Dictionary<T, U>(c);
|
||||
}
|
||||
|
||||
public Cache(Func<T, U> loader)
|
||||
@@ -36,18 +35,17 @@ namespace OpenRA.Primitives
|
||||
get
|
||||
{
|
||||
U result;
|
||||
if (!hax.TryGetValue(key, out result))
|
||||
hax.Add(key, result = loader(key));
|
||||
|
||||
if (!cache.TryGetValue(key, out result))
|
||||
cache.Add(key, result = loader(key));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() { return hax.GetEnumerator(); }
|
||||
|
||||
public bool ContainsKey(T key) { return cache.ContainsKey(key); }
|
||||
public bool TryGetValue(T key, out U value) { return cache.TryGetValue(key, out value); }
|
||||
public int Count { get { return cache.Count; } }
|
||||
public ICollection<T> Keys { get { return cache.Keys; } }
|
||||
public ICollection<U> Values { get { return cache.Values; } }
|
||||
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() { return cache.GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
|
||||
public IEnumerable<T> Keys { get { return hax.Keys; } }
|
||||
public IEnumerable<U> Values { get { return hax.Values; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace OpenRA
|
||||
{
|
||||
int Count { get; }
|
||||
TValue this[TKey key] { get; }
|
||||
IEnumerable<TKey> Keys { get; }
|
||||
IEnumerable<TValue> Values { get; }
|
||||
ICollection<TKey> Keys { get; }
|
||||
ICollection<TValue> Values { get; }
|
||||
|
||||
bool ContainsKey(TKey key);
|
||||
bool TryGetValue(TKey key, out TValue value);
|
||||
@@ -68,9 +68,9 @@ namespace OpenRA
|
||||
|
||||
public TValue this[TKey key] { get { return dict[key]; } }
|
||||
|
||||
public IEnumerable<TKey> Keys { get { return dict.Keys; } }
|
||||
public ICollection<TKey> Keys { get { return dict.Keys; } }
|
||||
|
||||
public IEnumerable<TValue> Values { get { return dict.Values; } }
|
||||
public ICollection<TValue> Values { get { return dict.Values; } }
|
||||
#endregion
|
||||
|
||||
#region IEnumerable implementation
|
||||
|
||||
@@ -80,9 +80,13 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
// Add buildables that have a build limit set and are not already in the list
|
||||
player.World.ActorsWithTrait<Buildable>()
|
||||
.Where(a => a.Actor.Info.Traits.Get<BuildableInfo>().BuildLimit > 0 && !a.Actor.IsDead() && a.Actor.IsInWorld && a.Actor.Owner == player && ret.Keys.All(k => k != a.Actor.Info.Name))
|
||||
.ToList()
|
||||
.ForEach(b => ret[b.Actor.Info.Name].Add(b.Actor));
|
||||
.Where(a =>
|
||||
a.Actor.Owner == player &&
|
||||
a.Actor.IsInWorld &&
|
||||
!a.Actor.IsDead() &&
|
||||
!ret.ContainsKey(a.Actor.Info.Name) &&
|
||||
a.Actor.Info.Traits.Get<BuildableInfo>().BuildLimit > 0)
|
||||
.Do(b => ret[b.Actor.Info.Name].Add(b.Actor));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -111,17 +115,17 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
bool HasPrerequisites(Cache<string, List<Actor>> ownedPrerequisites)
|
||||
{
|
||||
return prerequisites.All(p => !(p.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.Keys.Contains(p.Replace("!", "").Replace("~", ""))));
|
||||
return prerequisites.All(p => !(p.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.ContainsKey(p.Replace("!", "").Replace("~", ""))));
|
||||
}
|
||||
|
||||
bool IsHidden(Cache<string, List<Actor>> ownedPrerequisites)
|
||||
{
|
||||
return prerequisites.Any(prereq => prereq.StartsWith("~") && (prereq.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.Keys.Contains(prereq.Replace("~", "").Replace("!", ""))));
|
||||
return prerequisites.Any(prereq => prereq.StartsWith("~") && (prereq.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.ContainsKey(prereq.Replace("~", "").Replace("!", ""))));
|
||||
}
|
||||
|
||||
public void Update(Cache<string, List<Actor>> ownedPrerequisites)
|
||||
{
|
||||
var hasReachedLimit = limit > 0 && ownedPrerequisites.Keys.Contains(Key) && ownedPrerequisites[Key].Count >= limit;
|
||||
var hasReachedLimit = limit > 0 && ownedPrerequisites.ContainsKey(Key) && ownedPrerequisites[Key].Count >= limit;
|
||||
// The '!' annotation inverts prerequisites: "I'm buildable if this prerequisite *isn't* met"
|
||||
var nowHasPrerequisites = HasPrerequisites(ownedPrerequisites) && !hasReachedLimit;
|
||||
var nowHidden = IsHidden(ownedPrerequisites);
|
||||
|
||||
Reference in New Issue
Block a user