Avoid some allocations during loading.

- In FieldLoader, cache boxed bools and some boxed ints.
- In FieldLoader, presize collections when parsing a List, HashSet or Dictionary.
- In FieldLoader, don't allocate a list of missing items until required.
- In FieldLoader, when a string value is passed, avoid wrapping this in a MiniYaml object by allowing both strings and yaml to be passed in the GetValue overload that does the real work.
- In Animation, avoid allocating no-op actions.
- In VxlReader, use EnsureCapcity to better size the Dictionary.
- In VxlReader change VxlElement to a struct.
- In Locomotor, presize TerrainSpeeds dictionary.
This commit is contained in:
RoosterDragon
2023-07-02 16:35:51 +01:00
committed by abcdefg30
parent be04d232c0
commit 58e8b123db
5 changed files with 55 additions and 29 deletions

View File

@@ -112,10 +112,19 @@ namespace OpenRA
{ typeof(Nullable<>), ParseNullable }, { typeof(Nullable<>), ParseNullable },
}; };
static readonly object BoxedTrue = true;
static readonly object BoxedFalse = false;
static readonly object[] BoxedInts = Exts.MakeArray(33, i => (object)i);
static object ParseInt(string fieldName, Type fieldType, string value, MemberInfo field) static object ParseInt(string fieldName, Type fieldType, string value, MemberInfo field)
{ {
if (Exts.TryParseIntegerInvariant(value, out var res)) if (Exts.TryParseIntegerInvariant(value, out var res))
{
if (res >= 0 && res < BoxedInts.Length)
return BoxedInts[res];
return res; return res;
}
return InvalidValueAction(value, fieldType, fieldName); return InvalidValueAction(value, fieldType, fieldName);
} }
@@ -361,7 +370,7 @@ namespace OpenRA
static object ParseBool(string fieldName, Type fieldType, string value, MemberInfo field) static object ParseBool(string fieldName, Type fieldType, string value, MemberInfo field)
{ {
if (bool.TryParse(value.ToLowerInvariant(), out var result)) if (bool.TryParse(value.ToLowerInvariant(), out var result))
return result; return result ? BoxedTrue : BoxedFalse;
return InvalidValueAction(value, fieldType, fieldName); return InvalidValueAction(value, fieldType, fieldName);
} }
@@ -469,11 +478,11 @@ namespace OpenRA
static object ParseHashSetOrList(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field) static object ParseHashSetOrList(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
{ {
var set = Activator.CreateInstance(fieldType);
if (value == null) if (value == null)
return set; return Activator.CreateInstance(fieldType);
var parts = value.Split(SplitComma, StringSplitOptions.RemoveEmptyEntries); var parts = value.Split(SplitComma, StringSplitOptions.RemoveEmptyEntries);
var set = Activator.CreateInstance(fieldType, parts.Length);
var arguments = fieldType.GetGenericArguments(); var arguments = fieldType.GetGenericArguments();
var addMethod = fieldType.GetMethod(nameof(List<object>.Add), arguments); var addMethod = fieldType.GetMethod(nameof(List<object>.Add), arguments);
var addArgs = new object[1]; var addArgs = new object[1];
@@ -488,7 +497,10 @@ namespace OpenRA
static object ParseDictionary(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field) static object ParseDictionary(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
{ {
var dict = Activator.CreateInstance(fieldType); if (yaml == null)
return Activator.CreateInstance(fieldType);
var dict = Activator.CreateInstance(fieldType, yaml.Nodes.Count);
var arguments = fieldType.GetGenericArguments(); var arguments = fieldType.GetGenericArguments();
var addMethod = fieldType.GetMethod(nameof(Dictionary<object, object>.Add), arguments); var addMethod = fieldType.GetMethod(nameof(Dictionary<object, object>.Add), arguments);
var addArgs = new object[2]; var addArgs = new object[2];
@@ -527,7 +539,7 @@ namespace OpenRA
public static void Load(object self, MiniYaml my) public static void Load(object self, MiniYaml my)
{ {
var loadInfo = TypeLoadInfo[self.GetType()]; var loadInfo = TypeLoadInfo[self.GetType()];
var missing = new List<string>(); List<string> missing = null;
Dictionary<string, MiniYaml> md = null; Dictionary<string, MiniYaml> md = null;
@@ -542,6 +554,7 @@ namespace OpenRA
val = fli.Loader(my); val = fli.Loader(my);
else else
{ {
missing ??= new List<string>();
missing.Add(fli.YamlName); missing.Add(fli.YamlName);
continue; continue;
} }
@@ -551,7 +564,11 @@ namespace OpenRA
if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val)) if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val))
{ {
if (fli.Attribute.Required) if (fli.Attribute.Required)
{
missing ??= new List<string>();
missing.Add(fli.YamlName); missing.Add(fli.YamlName);
}
continue; continue;
} }
} }
@@ -559,7 +576,7 @@ namespace OpenRA
fli.Field.SetValue(self, val); fli.Field.SetValue(self, val);
} }
if (missing.Count > 0) if (missing != null)
throw new MissingFieldsException(missing.ToArray()); throw new MissingFieldsException(missing.ToArray());
} }
@@ -620,12 +637,17 @@ namespace OpenRA
public static object GetValue(string fieldName, Type fieldType, string value, MemberInfo field) public static object GetValue(string fieldName, Type fieldType, string value, MemberInfo field)
{ {
return GetValue(fieldName, fieldType, new MiniYaml(value), field); return GetValue(fieldName, fieldType, value, null, field);
} }
public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field) public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field)
{ {
var value = yaml.Value?.Trim(); return GetValue(fieldName, fieldType, yaml.Value, yaml, field);
}
static object GetValue(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
{
value = value?.Trim();
if (fieldType.IsGenericType) if (fieldType.IsGenericType)
{ {
if (GenericTypeParsers.TryGetValue(fieldType.GetGenericTypeDefinition(), out var parseFuncGeneric)) if (GenericTypeParsers.TryGetValue(fieldType.GetGenericTypeDefinition(), out var parseFuncGeneric))

View File

@@ -30,7 +30,7 @@ namespace OpenRA.Graphics
bool backwards; bool backwards;
bool tickAlways; bool tickAlways;
int timeUntilNextFrame; int timeUntilNextFrame;
Action tickFunc = () => { }; Action tickFunc;
public Animation(World world, string name) public Animation(World world, string name)
: this(world, name, () => WAngle.Zero) { } : this(world, name, () => WAngle.Zero) { }
@@ -164,7 +164,7 @@ namespace OpenRA.Graphics
if (frame >= CurrentSequence.Length) if (frame >= CurrentSequence.Length)
{ {
frame = CurrentSequence.Length - 1; frame = CurrentSequence.Length - 1;
tickFunc = () => { }; tickFunc = null;
after?.Invoke(); after?.Invoke();
} }
}; };
@@ -212,13 +212,13 @@ namespace OpenRA.Graphics
public void Tick(int t) public void Tick(int t)
{ {
if (tickAlways) if (tickAlways)
tickFunc(); tickFunc?.Invoke();
else else
{ {
timeUntilNextFrame -= t; timeUntilNextFrame -= t;
while (timeUntilNextFrame <= 0) while (timeUntilNextFrame <= 0)
{ {
tickFunc(); tickFunc?.Invoke();
timeUntilNextFrame += CurrentSequenceTickOrDefault(); timeUntilNextFrame += CurrentSequenceTickOrDefault();
} }
} }

View File

@@ -15,10 +15,15 @@ using System.IO;
namespace OpenRA.Mods.Cnc.FileFormats namespace OpenRA.Mods.Cnc.FileFormats
{ {
public enum NormalType { TiberianSun = 2, RedAlert2 = 4 } public enum NormalType { TiberianSun = 2, RedAlert2 = 4 }
public class VxlElement public readonly struct VxlElement
{ {
public byte Color; public readonly byte Color;
public byte Normal; public readonly byte Normal;
public VxlElement(byte color, byte normal)
{
Color = color;
Normal = normal;
}
} }
public class VxlLimb public class VxlLimb
@@ -83,20 +88,17 @@ namespace OpenRA.Mods.Cnc.FileFormats
var x = (byte)(i % l.Size[0]); var x = (byte)(i % l.Size[0]);
var y = (byte)(i / l.Size[0]); var y = (byte)(i / l.Size[0]);
byte z = 0; byte z = 0;
l.VoxelMap[x, y] = new Dictionary<byte, VxlElement>(); var voxelMap = new Dictionary<byte, VxlElement>();
l.VoxelMap[x, y] = voxelMap;
do do
{ {
z += s.ReadUInt8(); z += s.ReadUInt8();
var count = s.ReadUInt8(); var count = s.ReadUInt8();
voxelMap.EnsureCapacity(voxelMap.Count + count);
for (var j = 0; j < count; j++) for (var j = 0; j < count; j++)
{ {
var v = new VxlElement var v = new VxlElement(s.ReadUInt8(), s.ReadUInt8());
{ voxelMap.Add(z, v);
Color = s.ReadUInt8(),
Normal = s.ReadUInt8()
};
l.VoxelMap[x, y].Add(z, v);
z++; z++;
} }

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Cnc.Graphics
sheetBuilder = CreateSheetBuilder(); sheetBuilder = CreateSheetBuilder();
} }
Vertex[] GenerateSlicePlane(int su, int sv, Func<int, int, VxlElement> first, Func<int, int, VxlElement> second, Func<int, int, float3> coord) Vertex[] GenerateSlicePlane(int su, int sv, Func<int, int, VxlElement?> first, Func<int, int, VxlElement?> second, Func<int, int, float3> coord)
{ {
var colors = new byte[su * sv]; var colors = new byte[su * sv];
var normals = new byte[su * sv]; var normals = new byte[su * sv];
@@ -68,8 +68,8 @@ namespace OpenRA.Mods.Cnc.Graphics
for (var u = 0; u < su; u++) for (var u = 0; u < su; u++)
{ {
var voxel = first(u, v) ?? second(u, v); var voxel = first(u, v) ?? second(u, v);
colors[c] = voxel == null ? (byte)0 : voxel.Color; colors[c] = voxel == null ? (byte)0 : voxel.Value.Color;
normals[c] = voxel == null ? (byte)0 : voxel.Normal; normals[c] = voxel == null ? (byte)0 : voxel.Value.Normal;
c++; c++;
} }
} }
@@ -99,7 +99,7 @@ namespace OpenRA.Mods.Cnc.Graphics
IEnumerable<Vertex[]> GenerateSlicePlanes(VxlLimb l) IEnumerable<Vertex[]> GenerateSlicePlanes(VxlLimb l)
{ {
VxlElement Get(int x, int y, int z) VxlElement? Get(int x, int y, int z)
{ {
if (x < 0 || y < 0 || z < 0) if (x < 0 || y < 0 || z < 0)
return null; return null;

View File

@@ -84,8 +84,9 @@ namespace OpenRA.Mods.Common.Traits
protected static object LoadSpeeds(MiniYaml y) protected static object LoadSpeeds(MiniYaml y)
{ {
var ret = new Dictionary<string, TerrainInfo>(); var speeds = y.ToDictionary()["TerrainSpeeds"].Nodes;
foreach (var t in y.ToDictionary()["TerrainSpeeds"].Nodes) var ret = new Dictionary<string, TerrainInfo>(speeds.Count);
foreach (var t in speeds)
{ {
var speed = FieldLoader.GetValue<int>("speed", t.Value.Value); var speed = FieldLoader.GetValue<int>("speed", t.Value.Value);
if (speed > 0) if (speed > 0)
@@ -98,6 +99,7 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
ret.TrimExcess();
return ret; return ret;
} }