From cfaf5a646715f04fea6c7d28506bdcd8a38681a4 Mon Sep 17 00:00:00 2001 From: teinarss Date: Mon, 1 Oct 2018 17:57:28 +0200 Subject: [PATCH] Updated CPos struct to use a bit field for all properties. --- OpenRA.Game/CPos.cs | 31 +++++++++++++++++++++------- OpenRA.Game/Map/MapPreview.cs | 2 +- OpenRA.Game/Network/Order.cs | 4 ++-- OpenRA.Game/Network/OrderIO.cs | 4 +--- OpenRA.Test/OpenRA.Game/CPosTest.cs | 31 ++++++++++++++++++++++++++++ OpenRA.Test/OpenRA.Game/OrderTest.cs | 2 +- OpenRA.Test/OpenRA.Test.csproj | 1 + 7 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 OpenRA.Test/OpenRA.Game/CPosTest.cs diff --git a/OpenRA.Game/CPos.cs b/OpenRA.Game/CPos.cs index 61c413d1ea..8dc3127453 100644 --- a/OpenRA.Game/CPos.cs +++ b/OpenRA.Game/CPos.cs @@ -18,11 +18,28 @@ namespace OpenRA { public struct CPos : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable { - public readonly int X, Y; - public readonly byte Layer; + // Coordinates are packed in a 32 bit signed int + // X and Y are 12 bits (signed): -2048...2047 + // Layer is an unsigned byte + // Packing is XXXX XXXX XXXX YYYY YYYY YYYY LLLL LLLL + public readonly int Bits; + + // X is padded to MSB, so bit shift does the correct sign extension + public int X { get { return Bits >> 20; } } + + // Align Y with a short, cast, then shift the rest of the way + // The signed short bit shift does the correct sign extension + public int Y { get { return ((short)(Bits >> 4)) >> 4; } } + + public byte Layer { get { return (byte)Bits; } } + + public CPos(int bits) { Bits = bits; } + public CPos(int x, int y) : this(x, y, 0) { } + public CPos(int x, int y, byte layer) + { + Bits = (x & 0xFFF) << 20 | (y & 0xFFF) << 8 | layer; + } - public CPos(int x, int y) { X = x; Y = y; Layer = 0; } - public CPos(int x, int y, byte layer) { X = x; Y = y; Layer = layer; } public static readonly CPos Zero = new CPos(0, 0, 0); public static explicit operator CPos(int2 a) { return new CPos(a.X, a.Y); } @@ -32,12 +49,12 @@ namespace OpenRA public static CPos operator -(CPos a, CVec b) { return new CPos(a.X - b.X, a.Y - b.Y, a.Layer); } public static CVec operator -(CPos a, CPos b) { return new CVec(a.X - b.X, a.Y - b.Y); } - public static bool operator ==(CPos me, CPos other) { return me.X == other.X && me.Y == other.Y && me.Layer == other.Layer; } + public static bool operator ==(CPos me, CPos other) { return me.Bits == other.Bits; } public static bool operator !=(CPos me, CPos other) { return !(me == other); } - public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Layer.GetHashCode(); } + public override int GetHashCode() { return Bits.GetHashCode(); } - public bool Equals(CPos other) { return X == other.X && Y == other.Y && Layer == other.Layer; } + public bool Equals(CPos other) { return Bits == other.Bits; } public override bool Equals(object obj) { return obj is CPos && Equals((CPos)obj); } public override string ToString() { return X + "," + Y; } diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index 98d4d80bb5..262b10a533 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -56,7 +56,7 @@ namespace OpenRA public readonly string[] categories; public readonly int players; public readonly Rectangle bounds; - public readonly int[] spawnpoints = { }; + public readonly short[] spawnpoints = { }; public readonly MapGridType map_grid_type; public readonly string minimap; public readonly bool downloading; diff --git a/OpenRA.Game/Network/Order.cs b/OpenRA.Game/Network/Order.cs index 9e8c179081..dc20d57670 100644 --- a/OpenRA.Game/Network/Order.cs +++ b/OpenRA.Game/Network/Order.cs @@ -128,7 +128,7 @@ namespace OpenRA { if (flags.HasField(OrderFields.TargetIsCell)) { - var cell = new CPos(r.ReadInt32(), r.ReadInt32(), r.ReadByte()); + var cell = new CPos(r.ReadInt32()); var subCell = (SubCell)r.ReadByte(); if (world != null) target = Target.FromCell(world, cell, subCell); @@ -146,7 +146,7 @@ namespace OpenRA var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null; var queued = flags.HasField(OrderFields.Queued); - var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32(), r.ReadInt32(), r.ReadByte()) : CPos.Zero; + var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32()) : CPos.Zero; var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0; if (world == null) diff --git a/OpenRA.Game/Network/OrderIO.cs b/OpenRA.Game/Network/OrderIO.cs index 0257220e52..f71ac04ec1 100644 --- a/OpenRA.Game/Network/OrderIO.cs +++ b/OpenRA.Game/Network/OrderIO.cs @@ -58,9 +58,7 @@ namespace OpenRA.Network public static void Write(this BinaryWriter w, CPos cell) { - w.Write(cell.X); - w.Write(cell.Y); - w.Write(cell.Layer); + w.Write(cell.Bits); } public static void Write(this BinaryWriter w, WPos pos) diff --git a/OpenRA.Test/OpenRA.Game/CPosTest.cs b/OpenRA.Test/OpenRA.Game/CPosTest.cs new file mode 100644 index 0000000000..a0fd9ff985 --- /dev/null +++ b/OpenRA.Test/OpenRA.Game/CPosTest.cs @@ -0,0 +1,31 @@ +using System.Runtime.Remoting.Metadata; +using NUnit.Framework; + +namespace OpenRA.Test +{ + [TestFixture] + public class CPosTest + { + [TestCase(TestName = "Packing x,y and layer into int")] + public void PackUnpackBits() + { + var values = new int[] { -2048, -1024, 0, 1024, 2047 }; + var layerValues = new byte[] { 0, 128, 255 }; + + foreach (var x in values) + { + foreach (var y in values) + { + foreach (var layer in layerValues) + { + var cell = new CPos(x, y, layer); + + Assert.AreEqual(x, cell.X); + Assert.AreEqual(y, cell.Y); + Assert.AreEqual(layer, cell.Layer); + } + } + } + } + } +} \ No newline at end of file diff --git a/OpenRA.Test/OpenRA.Game/OrderTest.cs b/OpenRA.Test/OpenRA.Game/OrderTest.cs index 71514eb452..e9fec354f1 100644 --- a/OpenRA.Test/OpenRA.Game/OrderTest.cs +++ b/OpenRA.Test/OpenRA.Game/OrderTest.cs @@ -64,7 +64,7 @@ namespace OpenRA.Test var o = new Order("Test", null, Target.Invalid, true) { TargetString = "TargetString", - ExtraLocation = new CPos(int.MinValue, int.MaxValue, 128), + ExtraLocation = new CPos(2047, 2047, 128), ExtraData = uint.MaxValue, IsImmediate = true, }.Serialize(); diff --git a/OpenRA.Test/OpenRA.Test.csproj b/OpenRA.Test/OpenRA.Test.csproj index 637e1c7a98..2f9121ba1b 100644 --- a/OpenRA.Test/OpenRA.Test.csproj +++ b/OpenRA.Test/OpenRA.Test.csproj @@ -46,6 +46,7 @@ +