From 7aa77940083020301c976df457490359133df877 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 12:44:40 +0000
Subject: [PATCH 01/16] Continues the completion of the region system
---
GJ2022/Game/GameWorld/Regions/Region.cs | 23 +++++++++++
.../Game/GameWorld/Regions/RegionContainer.cs | 15 +++++++
.../Game/GameWorld/Regions/WorldRegionList.cs | 40 +++++++++++++++++--
3 files changed, 75 insertions(+), 3 deletions(-)
create mode 100644 GJ2022/Game/GameWorld/Regions/RegionContainer.cs
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index dd7ef36..5a01911 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -6,6 +6,29 @@
namespace GJ2022.Game.GameWorld.Regions
{
+ ///
+ /// Region system:
+ /// ========
+ ///
+ /// A region determines a section of the world in which all points are accessible to each other.
+ ///
+ /// The world will be broken down into 8x8 chunks and each one designated regions.
+ /// If there is non passable turfs within any of the 8x8 chunks that split the region into pieces, then many regions can be generated for 1 of these.
+ ///
+ /// Region Rules:
+ /// =========
+ /// - For each point within a region, there must exist a valid path between those 2 points without leaving that region
+ /// - A region shares at least 1 superparent with any region that can be accessed by it.
+ /// - At least 2 regions exist for each parent region. A region will never be an own child.
+ ///
+ /// Region Properties:
+ /// =========
+ /// - Checking if a valid path exists between 2 points can be done by getting the regions of the 2 points and seeing if they have a shared super-parent.
+ ///
+ /// Region Functionality:
+ /// =========
+ /// -
+ ///
public class Region
{
diff --git a/GJ2022/Game/GameWorld/Regions/RegionContainer.cs b/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
new file mode 100644
index 0000000..cf80a80
--- /dev/null
+++ b/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GJ2022.Game.GameWorld.Regions
+{
+ public class RegionContainer
+ {
+
+
+
+ }
+}
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 8d701b2..16bc3a9 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -1,4 +1,5 @@
-using System;
+using GJ2022.Utility.MathConstructs;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -10,9 +11,42 @@ public class WorldRegionList
{
///
- /// List of regions with index corresponding to their level
+ /// The nxn area in which the first level regions are
///
- public List> regions = new List>();
+ public const int REGION_PRIMARY_LEVEL_SIZE = 8;
+
+ ///
+ /// nxn regions will exist within a parent region.
+ /// For a 2x2 region then with a 4ax4a world (where a is the primary level size) there will be 3 region sets:
+ /// - 16 primary regions
+ /// - 4 parent regions, each holding 4 primary regions
+ /// - 1 super region which holds the 4 parent regions
+ /// (Since there is only 1 super region, there is no need for a super super region in this example.)
+ ///
+ public const int REGION_CHILDREN_SIZE = 2;
+
+ ///
+ /// Position based binary list for regions, allows for relatively quick finding of locations at positions as well as infinite non-continuous insertion
+ /// requiring O(n) memory with O(log(n)) access time.
+ ///
+ public PositionBasedBinaryList regions = new PositionBasedBinaryList();
+
+ ///
+ /// Generates the region that contains the provided X,Y world coordinates.
+ ///
+ public void GenerateWorldSection(int x, int y)
+ {
+ //WARNING: Integer divison rounds towards 0.
+ //Positive values (8, 16, 24, 32 etc..) should work fine, however it needs to be ensured that (-1 and 1) don't get assigned to the same region,
+ //since we don't want region (x, y), (-x, y), (x, -y), (-x, -y) to all be assigned to region (0, 0)
+ int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
+ int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+ //Check if the region exists already
+ if (regions.Get(regionX, regionY) != null)
+ return;
+ //The region doesn't exist, so we need to generate one
+
+ }
}
}
From 8efeedef169dab1de3f7931cb786e7b3bada090d Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 12:46:13 +0000
Subject: [PATCH 02/16] Adds in a todo comment :)
---
GJ2022/Game/GameWorld/Regions/WorldRegionList.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 16bc3a9..f440c0b 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -45,7 +45,7 @@ public void GenerateWorldSection(int x, int y)
if (regions.Get(regionX, regionY) != null)
return;
//The region doesn't exist, so we need to generate one
-
+ //TODO
}
}
From fade70deff3247b7b0d4271a0de676c5d7a247e1 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 17:44:09 +0000
Subject: [PATCH 03/16] Adds in a unit test that shows that I can successfully
calculate the parent level of regions
---
GJ2022.Tests/GJ2022.Tests.csproj | 1 +
GJ2022.Tests/SuperTest.cs | 143 ++++++++++++++++++
GJ2022/Game/GameWorld/Regions/Region.cs | 17 ++-
.../Game/GameWorld/Regions/RegionContainer.cs | 2 -
.../Game/GameWorld/Regions/WorldRegionList.cs | 24 ++-
5 files changed, 182 insertions(+), 5 deletions(-)
create mode 100644 GJ2022.Tests/SuperTest.cs
diff --git a/GJ2022.Tests/GJ2022.Tests.csproj b/GJ2022.Tests/GJ2022.Tests.csproj
index 0e45ef8..7fd710e 100644
--- a/GJ2022.Tests/GJ2022.Tests.csproj
+++ b/GJ2022.Tests/GJ2022.Tests.csproj
@@ -173,6 +173,7 @@
+
diff --git a/GJ2022.Tests/SuperTest.cs b/GJ2022.Tests/SuperTest.cs
new file mode 100644
index 0000000..108969c
--- /dev/null
+++ b/GJ2022.Tests/SuperTest.cs
@@ -0,0 +1,143 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GJ2022.Tests
+{
+ [TestClass]
+ public class SuperTest
+ {
+
+ [TestMethod]
+ public void DoTest()
+ {
+ List<(int, int, int)> testValues = new List<(int, int, int)>() {
+ //First row
+ (0, 0, 0),
+ (1, 0, 1),
+ (2, 0, 2),
+ (3, 0, 2),
+ (4, 0, 3),
+ (5, 0, 3),
+ (6, 0, 3),
+ (7, 0, 3),
+
+ (0, 1, 1),
+ (1, 1, 0),
+ (2, 1, 2),
+ (3, 1, 2),
+ (4, 1, 3),
+ (5, 1, 3),
+ (6, 1, 3),
+ (7, 1, 3),
+
+ (0, 2, 2),
+ (1, 2, 2),
+ (2, 2, 0),
+ (3, 2, 1),
+ (4, 2, 3),
+ (5, 2, 3),
+ (6, 2, 3),
+ (7, 2, 3),
+
+ (0, 3, 2),
+ (1, 3, 2),
+ (2, 3, 1),
+ (3, 3, 0),
+ (4, 3, 3),
+ (5, 3, 3),
+ (6, 3, 3),
+ (7, 3, 3),
+
+ (0, 4, 3),
+ (1, 4, 3),
+ (2, 4, 3),
+ (3, 4, 3),
+ (4, 4, 0),
+ (5, 4, 1),
+ (6, 4, 2),
+ (7, 4, 2),
+
+ (0, 5, 3),
+ (1, 5, 3),
+ (2, 5, 3),
+ (3, 5, 3),
+ (4, 5, 1),
+ (5, 5, 0),
+ (6, 5, 2),
+ (7, 5, 2),
+
+ (0, 6, 3),
+ (1, 6, 3),
+ (2, 6, 3),
+ (3, 6, 3),
+ (4, 6, 2),
+ (5, 6, 2),
+ (6, 6, 0),
+ (7, 6, 1),
+
+ (0, 7, 3),
+ (1, 7, 3),
+ (2, 7, 3),
+ (3, 7, 3),
+ (4, 7, 2),
+ (5, 7, 2),
+ (6, 7, 1),
+ (7, 7, 0),
+
+ (7, 8, 4),
+ (11, 8, 2),
+ (9, 13, 3),
+ };
+
+ bool failed = false;
+
+ foreach ((int, int, int) testValue in testValues)
+ {
+ if (GetResult(testValue.Item1, testValue.Item2) != testValue.Item3)
+ {
+ Log.WriteLine($"Fail: ({testValue.Item1}, {testValue.Item2}): Expected: {testValue.Item3} Actual: {GetResult(testValue.Item1, testValue.Item2)}");
+ failed = true;
+ }
+ }
+
+ if (failed)
+ Assert.Fail("Failed for at least 1 point");
+
+ }
+
+ ///
+ /// Recursive algorithm to calculate the parent level of regions.
+ /// Recursion depth should never pass 1 in theory, however hits 2 for (1,0) and (0,1)
+ ///
+ private int GetResult(int x, int y)
+ {
+ if (x == y)
+ return 0;
+ int logx = (int)Math.Ceiling(Math.Log(x + 1, 2));
+ int logy = (int)Math.Ceiling(Math.Log(y + 1, 2));
+ int powx = (int)Math.Pow(2, logx - 1);
+ int powy = (int)Math.Pow(2, logy - 1);
+ int maxpow = Math.Max(powx, powy);
+ //Bottom Left
+ if (y >= maxpow && x < maxpow)
+ {
+ return logy;
+ }
+ //Top Right
+ else if (x >= maxpow && y < maxpow)
+ {
+ return logx;
+ }
+ //Bottom Right
+ else
+ {
+ return GetResult(x - powx, y - powy);
+ }
+ }
+
+ }
+}
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index 5a01911..8dae1bc 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -19,7 +19,7 @@ namespace GJ2022.Game.GameWorld.Regions
/// =========
/// - For each point within a region, there must exist a valid path between those 2 points without leaving that region
/// - A region shares at least 1 superparent with any region that can be accessed by it.
- /// - At least 2 regions exist for each parent region. A region will never be an own child.
+ /// - Regions can be only children as long as they have a parent up high enough that has 2 children.
///
/// Region Properties:
/// =========
@@ -27,7 +27,12 @@ namespace GJ2022.Game.GameWorld.Regions
///
/// Region Functionality:
/// =========
- /// -
+ /// When a new region is created we need to create parent regions if neccessary.
+ /// To do this, we need to locate any regions that we are attached to directly.
+ /// We then need to calculate the level of our shared parent.
+ /// We then traverse up both trees until we hit the top level, or the level of the shared parent.
+ /// We then create parents where necessary until we hit the shared parent.
+ /// Both nodes should now have the same superparent
///
public class Region
{
@@ -39,6 +44,14 @@ public class Region
//A height of 0 indicates that this region is the parent of actual world positions.
public int Height { get; }
+ //The X position of the region
+ //The world coordinated of the left divided by the primary level size
+ public int X { get; }
+
+ //The Y position of the region
+ //The world coordinated of the bottom divided by the primary level size
+ public int Y { get; }
+
///
/// Instantiate an instance of region based on a parent instance.
///
diff --git a/GJ2022/Game/GameWorld/Regions/RegionContainer.cs b/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
index cf80a80..978e54c 100644
--- a/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
+++ b/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
@@ -9,7 +9,5 @@ namespace GJ2022.Game.GameWorld.Regions
public class RegionContainer
{
-
-
}
}
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index f440c0b..7c0a1b7 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -31,6 +31,17 @@ public class WorldRegionList
///
public PositionBasedBinaryList regions = new PositionBasedBinaryList();
+ ///
+ /// Contains a list that uses the index as the depth of the region and holds a position based binary list that holds the regions containers
+ /// stored at that location.
+ /// Example:
+ /// [0] = {(0, 0), (1, 0), (0, 1), (1, 1)}
+ /// [1] = {(0, 0)}
+ /// Where the coordinates represent keys of the position based binary list.
+ /// The associated value would be a list of regions within that section of the world.
+ ///
+ public List> regionContainersByPosition = new List>();
+
///
/// Generates the region that contains the provided X,Y world coordinates.
///
@@ -45,7 +56,18 @@ public void GenerateWorldSection(int x, int y)
if (regions.Get(regionX, regionY) != null)
return;
//The region doesn't exist, so we need to generate one
- //TODO
+
+ }
+
+ ///
+ /// Returns the level at which 2 nodes would in theory have a shared parent.
+ ///
+ /// The first region
+ /// The second region
+ /// An integer value representing the theoretical level that 2 regions would have a shared parent on. If 2 nodes are siblings, 1 is returned. If the nodes are the same 0 is returned.
+ private int GetSharedParentLevel(Region region, Region sibling)
+ {
+ throw new NotImplementedException();
}
}
From 1663c71a820c3f9cddc1cafbc0b2485b4993e6e8 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 17:52:31 +0000
Subject: [PATCH 04/16] Update SuperTest.cs
---
GJ2022.Tests/SuperTest.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/GJ2022.Tests/SuperTest.cs b/GJ2022.Tests/SuperTest.cs
index 108969c..0aec4b2 100644
--- a/GJ2022.Tests/SuperTest.cs
+++ b/GJ2022.Tests/SuperTest.cs
@@ -91,6 +91,9 @@ public void DoTest()
(7, 8, 4),
(11, 8, 2),
(9, 13, 3),
+
+ (8+16, 9+16, 1),
+ (8+16, 10+16, 2),
};
bool failed = false;
From 0df3a20065fd46862ae0dafb9dd230fe4e84bd29 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 17:53:59 +0000
Subject: [PATCH 05/16] Update SuperTest.cs
---
GJ2022.Tests/SuperTest.cs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/GJ2022.Tests/SuperTest.cs b/GJ2022.Tests/SuperTest.cs
index 0aec4b2..a41c7f5 100644
--- a/GJ2022.Tests/SuperTest.cs
+++ b/GJ2022.Tests/SuperTest.cs
@@ -115,6 +115,8 @@ public void DoTest()
///
/// Recursive algorithm to calculate the parent level of regions.
/// Recursion depth should never pass 1 in theory, however hits 2 for (1,0) and (0,1)
+ ///
+ /// I am sure there is a way to mathematically optimise this but I am not sure how
///
private int GetResult(int x, int y)
{
From 57f1d3d0682434b50be79ac5a9d9aff0a5d6e98c Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Tue, 15 Mar 2022 17:59:07 +0000
Subject: [PATCH 06/16] Update SuperTest.cs
---
GJ2022.Tests/SuperTest.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/GJ2022.Tests/SuperTest.cs b/GJ2022.Tests/SuperTest.cs
index a41c7f5..1a9e56b 100644
--- a/GJ2022.Tests/SuperTest.cs
+++ b/GJ2022.Tests/SuperTest.cs
@@ -137,7 +137,7 @@ private int GetResult(int x, int y)
{
return logx;
}
- //Bottom Right
+ //Bottom Right, translate so that we aren't the top right anymore
else
{
return GetResult(x - powx, y - powy);
From 8b0ff383c2844970deb56394f47dbc7df0ebc877 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Wed, 16 Mar 2022 14:34:59 +0000
Subject: [PATCH 07/16] Updates the unit tests
---
GJ2022.Tests/RegionTests.cs | 103 +++++++++++++++++++++++++
GJ2022.Tests/SuperTest.cs | 148 ------------------------------------
2 files changed, 103 insertions(+), 148 deletions(-)
delete mode 100644 GJ2022.Tests/SuperTest.cs
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index e888510..5a70efb 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -18,5 +18,108 @@ public void TestRegionConnectivity()
}
+ [TestMethod]
+ public void TestSharedParentImplementation()
+ {
+ List<(int, int, int)> testValues = new List<(int, int, int)>() {
+ //First row
+ (0, 0, 0),
+ (1, 0, 1),
+ (2, 0, 2),
+ (3, 0, 2),
+ (4, 0, 3),
+ (5, 0, 3),
+ (6, 0, 3),
+ (7, 0, 3),
+
+ (0, 1, 1),
+ (1, 1, 0),
+ (2, 1, 2),
+ (3, 1, 2),
+ (4, 1, 3),
+ (5, 1, 3),
+ (6, 1, 3),
+ (7, 1, 3),
+
+ (0, 2, 2),
+ (1, 2, 2),
+ (2, 2, 0),
+ (3, 2, 1),
+ (4, 2, 3),
+ (5, 2, 3),
+ (6, 2, 3),
+ (7, 2, 3),
+
+ (0, 3, 2),
+ (1, 3, 2),
+ (2, 3, 1),
+ (3, 3, 0),
+ (4, 3, 3),
+ (5, 3, 3),
+ (6, 3, 3),
+ (7, 3, 3),
+
+ (0, 4, 3),
+ (1, 4, 3),
+ (2, 4, 3),
+ (3, 4, 3),
+ (4, 4, 0),
+ (5, 4, 1),
+ (6, 4, 2),
+ (7, 4, 2),
+
+ (0, 5, 3),
+ (1, 5, 3),
+ (2, 5, 3),
+ (3, 5, 3),
+ (4, 5, 1),
+ (5, 5, 0),
+ (6, 5, 2),
+ (7, 5, 2),
+
+ (0, 6, 3),
+ (1, 6, 3),
+ (2, 6, 3),
+ (3, 6, 3),
+ (4, 6, 2),
+ (5, 6, 2),
+ (6, 6, 0),
+ (7, 6, 1),
+
+ (0, 7, 3),
+ (1, 7, 3),
+ (2, 7, 3),
+ (3, 7, 3),
+ (4, 7, 2),
+ (5, 7, 2),
+ (6, 7, 1),
+ (7, 7, 0),
+
+ (7, 8, 4),
+ (11, 8, 2),
+ (9, 13, 3),
+
+ (8+16, 9+16, 1),
+ (8+16, 10+16, 2),
+ };
+
+ bool failed = false;
+
+ WorldRegionList wrl = new WorldRegionList();
+
+ foreach ((int, int, int) testValue in testValues)
+ {
+ if (wrl.GetSharedParentLevel(testValue.Item1, testValue.Item2) != testValue.Item3)
+ {
+ Log.WriteLine($"Fail: ({testValue.Item1}, {testValue.Item2}): Expected: {testValue.Item3} Actual: {GetResult(testValue.Item1, testValue.Item2)}");
+ failed = true;
+ }
+ }
+
+ if (failed)
+ Assert.Fail("Failed for at least 1 point");
+
+ }
+
}
}
diff --git a/GJ2022.Tests/SuperTest.cs b/GJ2022.Tests/SuperTest.cs
deleted file mode 100644
index 1a9e56b..0000000
--- a/GJ2022.Tests/SuperTest.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace GJ2022.Tests
-{
- [TestClass]
- public class SuperTest
- {
-
- [TestMethod]
- public void DoTest()
- {
- List<(int, int, int)> testValues = new List<(int, int, int)>() {
- //First row
- (0, 0, 0),
- (1, 0, 1),
- (2, 0, 2),
- (3, 0, 2),
- (4, 0, 3),
- (5, 0, 3),
- (6, 0, 3),
- (7, 0, 3),
-
- (0, 1, 1),
- (1, 1, 0),
- (2, 1, 2),
- (3, 1, 2),
- (4, 1, 3),
- (5, 1, 3),
- (6, 1, 3),
- (7, 1, 3),
-
- (0, 2, 2),
- (1, 2, 2),
- (2, 2, 0),
- (3, 2, 1),
- (4, 2, 3),
- (5, 2, 3),
- (6, 2, 3),
- (7, 2, 3),
-
- (0, 3, 2),
- (1, 3, 2),
- (2, 3, 1),
- (3, 3, 0),
- (4, 3, 3),
- (5, 3, 3),
- (6, 3, 3),
- (7, 3, 3),
-
- (0, 4, 3),
- (1, 4, 3),
- (2, 4, 3),
- (3, 4, 3),
- (4, 4, 0),
- (5, 4, 1),
- (6, 4, 2),
- (7, 4, 2),
-
- (0, 5, 3),
- (1, 5, 3),
- (2, 5, 3),
- (3, 5, 3),
- (4, 5, 1),
- (5, 5, 0),
- (6, 5, 2),
- (7, 5, 2),
-
- (0, 6, 3),
- (1, 6, 3),
- (2, 6, 3),
- (3, 6, 3),
- (4, 6, 2),
- (5, 6, 2),
- (6, 6, 0),
- (7, 6, 1),
-
- (0, 7, 3),
- (1, 7, 3),
- (2, 7, 3),
- (3, 7, 3),
- (4, 7, 2),
- (5, 7, 2),
- (6, 7, 1),
- (7, 7, 0),
-
- (7, 8, 4),
- (11, 8, 2),
- (9, 13, 3),
-
- (8+16, 9+16, 1),
- (8+16, 10+16, 2),
- };
-
- bool failed = false;
-
- foreach ((int, int, int) testValue in testValues)
- {
- if (GetResult(testValue.Item1, testValue.Item2) != testValue.Item3)
- {
- Log.WriteLine($"Fail: ({testValue.Item1}, {testValue.Item2}): Expected: {testValue.Item3} Actual: {GetResult(testValue.Item1, testValue.Item2)}");
- failed = true;
- }
- }
-
- if (failed)
- Assert.Fail("Failed for at least 1 point");
-
- }
-
- ///
- /// Recursive algorithm to calculate the parent level of regions.
- /// Recursion depth should never pass 1 in theory, however hits 2 for (1,0) and (0,1)
- ///
- /// I am sure there is a way to mathematically optimise this but I am not sure how
- ///
- private int GetResult(int x, int y)
- {
- if (x == y)
- return 0;
- int logx = (int)Math.Ceiling(Math.Log(x + 1, 2));
- int logy = (int)Math.Ceiling(Math.Log(y + 1, 2));
- int powx = (int)Math.Pow(2, logx - 1);
- int powy = (int)Math.Pow(2, logy - 1);
- int maxpow = Math.Max(powx, powy);
- //Bottom Left
- if (y >= maxpow && x < maxpow)
- {
- return logy;
- }
- //Top Right
- else if (x >= maxpow && y < maxpow)
- {
- return logx;
- }
- //Bottom Right, translate so that we aren't the top right anymore
- else
- {
- return GetResult(x - powx, y - powy);
- }
- }
-
- }
-}
From 9b7eed0e12ed32e296e67d5254b95e52f78a8071 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Wed, 16 Mar 2022 17:06:54 +0000
Subject: [PATCH 08/16] Successful region implementation
---
GJ2022.Tests/GJ2022.Tests.csproj | 1 -
GJ2022.Tests/RegionTests.cs | 25 ++-
GJ2022/Game/GameWorld/Regions/Region.cs | 13 +-
.../Game/GameWorld/Regions/WorldRegionList.cs | 179 +++++++++++++++++-
4 files changed, 208 insertions(+), 10 deletions(-)
diff --git a/GJ2022.Tests/GJ2022.Tests.csproj b/GJ2022.Tests/GJ2022.Tests.csproj
index 7fd710e..0e45ef8 100644
--- a/GJ2022.Tests/GJ2022.Tests.csproj
+++ b/GJ2022.Tests/GJ2022.Tests.csproj
@@ -173,7 +173,6 @@
-
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index 5a70efb..3c550d4 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -13,9 +13,25 @@ public class RegionTests
{
[TestMethod]
- public void TestRegionConnectivity()
+ public void TestRegionWorldSection()
{
-
+ WorldRegionList wrl = new WorldRegionList();
+ //Test pathing within a region
+ wrl.GenerateWorldSection(0, 0);
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(7, 7)), "Failed to locate valid path within own region");
+ //Test pathing to an adjacent region
+ wrl.GenerateWorldSection(8, 0);
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(8, 0)), "Failed to locate valid path within adjacent region");
+ //Test invalid pathing
+ wrl.GenerateWorldSection(24, 0);
+ Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(24, 0)), "Failed to identify that a path shouldn't exist between 2 non-connected regions");
+ //Test connection
+ wrl.GenerateWorldSection(16, 0);
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(24, 0)), "Failed to identify completed path between a line of 4 regions");
+ //Test 2 dimension functionality
+ wrl.GenerateWorldSection(24, 16);
+ wrl.GenerateWorldSection(24, 8);
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(24, 16)), "Failed to identify completed path in a 2D grid");
}
[TestMethod]
@@ -109,9 +125,10 @@ public void TestSharedParentImplementation()
foreach ((int, int, int) testValue in testValues)
{
- if (wrl.GetSharedParentLevel(testValue.Item1, testValue.Item2) != testValue.Item3)
+ int result = wrl.GetSharedParentLevel(testValue.Item1, testValue.Item2);
+ if (result != testValue.Item3)
{
- Log.WriteLine($"Fail: ({testValue.Item1}, {testValue.Item2}): Expected: {testValue.Item3} Actual: {GetResult(testValue.Item1, testValue.Item2)}");
+ Log.WriteLine($"Fail: ({testValue.Item1}, {testValue.Item2}): Expected: {testValue.Item3} Actual: {result}");
failed = true;
}
}
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index 8dae1bc..8174e2e 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -37,8 +37,12 @@ namespace GJ2022.Game.GameWorld.Regions
public class Region
{
+ private static int count = 0;
+
+ public int Id { get; } = count++;
+
//The parent region
- public Region Parent { get; private set; }
+ public Region Parent { get; set; }
//The region height (How many parent's up are we)
//A height of 0 indicates that this region is the parent of actual world positions.
@@ -52,6 +56,13 @@ public class Region
//The world coordinated of the bottom divided by the primary level size
public int Y { get; }
+ public Region(int x, int y, int height = 0)
+ {
+ X = x;
+ Y = y;
+ Height = height;
+ }
+
///
/// Instantiate an instance of region based on a parent instance.
///
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 7c0a1b7..7da5a3e 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -42,6 +42,14 @@ public class WorldRegionList
///
public List> regionContainersByPosition = new List>();
+ ///
+ /// Print the world region list
+ ///
+ public void Print()
+ {
+ Log.WriteLine(regions, LogType.DEBUG);
+ }
+
///
/// Generates the region that contains the provided X,Y world coordinates.
///
@@ -52,11 +60,142 @@ public void GenerateWorldSection(int x, int y)
//since we don't want region (x, y), (-x, y), (x, -y), (-x, -y) to all be assigned to region (0, 0)
int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+ Log.WriteLine($"Generating region ({regionX}, {regionY})");
//Check if the region exists already
- if (regions.Get(regionX, regionY) != null)
+ if (regions.Get(x, y) != null)
return;
//The region doesn't exist, so we need to generate one
-
+ bool[,] processedNodes = new bool[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ //Check each node and flood fill a region if necessary
+ for (int nodeX = 0; nodeX < REGION_PRIMARY_LEVEL_SIZE; nodeX++)
+ {
+ for (int nodeY = 0; nodeY < REGION_PRIMARY_LEVEL_SIZE; nodeY++)
+ {
+ //This node has already been assigned a region
+ if (processedNodes[nodeX, nodeY])
+ continue;
+ //Get the real world coordinates
+ int realX = regionX * REGION_PRIMARY_LEVEL_SIZE + nodeX;
+ int realY = regionY * REGION_PRIMARY_LEVEL_SIZE + nodeY;
+ //This position is solid, ignore (We don't need to update processedNodes, since we will never again access it)
+ if (World.IsSolid(realX, realY))
+ continue;
+ //Create a new region and flood fill outwards
+ Region createdRegion = new Region(regionX, regionY);
+ Log.WriteLine($"Created new region {createdRegion.Id} at ({regionX}, {regionY})");
+ //Have the position join this region
+ regions.Add(realX, realY, createdRegion);
+ Log.WriteLine($"({realX}, {realY}) joined region {createdRegion.Id}");
+ //During this process, get the adjacent regions so we can match up parents
+ List adjacentRegions = new List();
+ //Processing queue
+ Queue> toProcess = new Queue>();
+ toProcess.Enqueue(new Vector(nodeX, nodeY));
+ //While we still have places to floor fill
+ while (toProcess.Count > 0)
+ {
+ //Dequeue
+ Vector relativePosition = toProcess.Dequeue();
+ //If current node is already processed, skip
+ if (processedNodes[relativePosition.X, relativePosition.Y])
+ continue;
+ //Calculate the world position of the current node
+ Vector worldPosition = new Vector(regionX * REGION_PRIMARY_LEVEL_SIZE, regionY * REGION_PRIMARY_LEVEL_SIZE) + relativePosition;
+ //Set node processed
+ processedNodes[relativePosition.X, relativePosition.Y] = true;
+ //If current node is a wall, skip
+ if (World.IsSolid(worldPosition.X, worldPosition.Y))
+ continue;
+ //Join the region
+ regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
+ Log.WriteLine($"({worldPosition.X}, {worldPosition.Y}) joined region {createdRegion.Id}");
+ //Check if we have any adjacent regions
+ Region adjacent;
+ //Add adjacent nodes (Assuming they are within bounds)
+ if (relativePosition.X < REGION_PRIMARY_LEVEL_SIZE - 1)
+ toProcess.Enqueue(new Vector(relativePosition.X + 1, relativePosition.Y));
+ else if ((adjacent = regions.Get(worldPosition.X + 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.X > 0)
+ toProcess.Enqueue(new Vector(relativePosition.X - 1, relativePosition.Y));
+ else if ((adjacent = regions.Get(worldPosition.X - 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.Y < REGION_PRIMARY_LEVEL_SIZE - 1)
+ toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y + 1));
+ else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y + 1)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.Y > 0)
+ toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y - 1));
+ else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y - 1)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ }
+ //Now we have assigned all tiles within our region to be associated to this region
+ //We now need to calculate parent regions with all adjacent regions
+ foreach (Region adjacentRegion in adjacentRegions)
+ {
+ Log.WriteLine($"Joining region {createdRegion.Id} to {adjacentRegion.Id}");
+ //The level of the shared parent
+ int sharedParentLevel = GetSharedParentLevel(createdRegion, adjacentRegion);
+ Log.WriteLine($"Shared parent level: {sharedParentLevel}");
+ //Since these regions are adjacent, they should share a parent at the shared parent level.
+ //Get pointers for the current region
+ Region leftParent = createdRegion;
+ Region rightParent = adjacentRegion;
+ //Iterate upwards, creating parent regions where none exist
+ for (int level = 1; level <= sharedParentLevel - 1; level++)
+ {
+ //Create the parent if either are null
+ if (leftParent.Parent == null)
+ {
+ //Parent position is the integer division result of any
+ //child position divided by the region child size
+ //We can work this out by doing integer division with the position of
+ //The top level child and region children size ^ depth
+ leftParent.Parent = new Region(
+ createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ level);
+ Log.WriteLine($"Created new parent node for {leftParent.Id}, parent node {leftParent.Parent.Id} at depth {level}");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+ }
+ if (rightParent.Parent == null)
+ {
+ rightParent.Parent = new Region(
+ adjacentRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ adjacentRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ level);
+ Log.WriteLine($"Created new parent node for {rightParent.Id}, parent node {rightParent.Parent.Id} at depth {level}");
+ Log.WriteLine($"Joined {rightParent.Id} --> {rightParent.Parent.Id}");
+ }
+ //Get the left and right parent
+ leftParent = leftParent.Parent;
+ rightParent = rightParent.Parent;
+ }
+ //Now we are at a shared parent level, check if anything exists
+ //If so, then attach both to the shared parent
+ //If not, then create a new shared parent and attach both to it
+ if (rightParent.Parent != null)
+ {
+ leftParent.Parent = rightParent.Parent;
+ Log.WriteLine($"Joined {leftParent.Id} --> {rightParent.Parent.Id}");
+ }
+ else
+ {
+ if (leftParent.Parent == null)
+ {
+ leftParent.Parent = new Region(
+ createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
+ createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
+ sharedParentLevel);
+ Log.WriteLine($"Created new parent node {leftParent.Parent.Id} at depth {sharedParentLevel}");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+ }
+ rightParent.Parent = leftParent.Parent;
+ Log.WriteLine($"Joined {rightParent.Id} --> {leftParent.Parent.Id}");
+ }
+ }
+ }
+ }
}
///
@@ -65,9 +204,41 @@ public void GenerateWorldSection(int x, int y)
/// The first region
/// The second region
/// An integer value representing the theoretical level that 2 regions would have a shared parent on. If 2 nodes are siblings, 1 is returned. If the nodes are the same 0 is returned.
- private int GetSharedParentLevel(Region region, Region sibling)
+ public int GetSharedParentLevel(Region region, Region sibling)
+ {
+ return Math.Max(GetSharedParentLevel(region.X, sibling.X), GetSharedParentLevel(region.Y, sibling.Y));
+ }
+
+ ///
+ /// Recursive algorithm to calculate the parent level of regions.
+ /// Recursion depth should never pass 1 in theory, however hits 2 for (1,0) and (0,1)
+ ///
+ /// I am sure there is a way to mathematically optimise this but I am not sure how
+ ///
+ public int GetSharedParentLevel(int x, int y)
{
- throw new NotImplementedException();
+ if (x == y)
+ return 0;
+ int logx = (int)Math.Ceiling(Math.Log(x + 1, 2));
+ int logy = (int)Math.Ceiling(Math.Log(y + 1, 2));
+ int powx = (int)Math.Pow(2, logx - 1);
+ int powy = (int)Math.Pow(2, logy - 1);
+ int maxpow = Math.Max(powx, powy);
+ //Bottom Left
+ if (y >= maxpow && x < maxpow)
+ {
+ return logy;
+ }
+ //Top Right
+ else if (x >= maxpow && y < maxpow)
+ {
+ return logx;
+ }
+ //Bottom Right, translate so that we aren't the top right anymore
+ else
+ {
+ return GetSharedParentLevel(x - powx, y - powy);
+ }
}
}
From 447d6fd85e9db00a32d5715c7d0bade8c43b594d Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Wed, 16 Mar 2022 17:47:38 +0000
Subject: [PATCH 09/16] Adds in optional logging
---
.../Game/GameWorld/Regions/WorldRegionList.cs | 28 ++++++++++++++++---
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 7da5a3e..76985c8 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -1,4 +1,6 @@
-using GJ2022.Utility.MathConstructs;
+//#define REGION_LOGGING
+
+using GJ2022.Utility.MathConstructs;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -60,7 +62,9 @@ public void GenerateWorldSection(int x, int y)
//since we don't want region (x, y), (-x, y), (x, -y), (-x, -y) to all be assigned to region (0, 0)
int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+#if REGION_LOGGING
Log.WriteLine($"Generating region ({regionX}, {regionY})");
+#endif
//Check if the region exists already
if (regions.Get(x, y) != null)
return;
@@ -82,10 +86,11 @@ public void GenerateWorldSection(int x, int y)
continue;
//Create a new region and flood fill outwards
Region createdRegion = new Region(regionX, regionY);
+#if REGION_LOGGING
Log.WriteLine($"Created new region {createdRegion.Id} at ({regionX}, {regionY})");
+#endif
//Have the position join this region
regions.Add(realX, realY, createdRegion);
- Log.WriteLine($"({realX}, {realY}) joined region {createdRegion.Id}");
//During this process, get the adjacent regions so we can match up parents
List adjacentRegions = new List();
//Processing queue
@@ -108,7 +113,6 @@ public void GenerateWorldSection(int x, int y)
continue;
//Join the region
regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
- Log.WriteLine($"({worldPosition.X}, {worldPosition.Y}) joined region {createdRegion.Id}");
//Check if we have any adjacent regions
Region adjacent;
//Add adjacent nodes (Assuming they are within bounds)
@@ -133,10 +137,14 @@ public void GenerateWorldSection(int x, int y)
//We now need to calculate parent regions with all adjacent regions
foreach (Region adjacentRegion in adjacentRegions)
{
+#if REGION_LOGGING
Log.WriteLine($"Joining region {createdRegion.Id} to {adjacentRegion.Id}");
+#endif
//The level of the shared parent
int sharedParentLevel = GetSharedParentLevel(createdRegion, adjacentRegion);
+#if REGION_LOGGING
Log.WriteLine($"Shared parent level: {sharedParentLevel}");
+#endif
//Since these regions are adjacent, they should share a parent at the shared parent level.
//Get pointers for the current region
Region leftParent = createdRegion;
@@ -155,8 +163,10 @@ public void GenerateWorldSection(int x, int y)
createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
level);
+#if REGION_LOGGING
Log.WriteLine($"Created new parent node for {leftParent.Id}, parent node {leftParent.Parent.Id} at depth {level}");
Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
}
if (rightParent.Parent == null)
{
@@ -164,8 +174,12 @@ public void GenerateWorldSection(int x, int y)
adjacentRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
adjacentRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
level);
+#if REGION_LOGGING
Log.WriteLine($"Created new parent node for {rightParent.Id}, parent node {rightParent.Parent.Id} at depth {level}");
- Log.WriteLine($"Joined {rightParent.Id} --> {rightParent.Parent.Id}");
+ Log.WriteLine($"Joined {rightParent.Id} --> {rightParent.Parent.Id}"); t depth { level}
+ ");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
}
//Get the left and right parent
leftParent = leftParent.Parent;
@@ -177,7 +191,9 @@ public void GenerateWorldSection(int x, int y)
if (rightParent.Parent != null)
{
leftParent.Parent = rightParent.Parent;
+#if REGION_LOGGING
Log.WriteLine($"Joined {leftParent.Id} --> {rightParent.Parent.Id}");
+#endif
}
else
{
@@ -187,11 +203,15 @@ public void GenerateWorldSection(int x, int y)
createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
sharedParentLevel);
+#if REGION_LOGGING
Log.WriteLine($"Created new parent node {leftParent.Parent.Id} at depth {sharedParentLevel}");
Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
}
rightParent.Parent = leftParent.Parent;
+#if REGION_LOGGING
Log.WriteLine($"Joined {rightParent.Id} --> {leftParent.Parent.Id}");
+#endif
}
}
}
From 2eb8d4f305e95924cea3c9b0e7bac0831ec0a602 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Wed, 16 Mar 2022 22:56:11 +0000
Subject: [PATCH 10/16] Removes unused content
---
.../Game/GameWorld/Regions/RegionContainer.cs | 13 -------------
.../Game/GameWorld/Regions/WorldRegionList.cs | 19 +------------------
2 files changed, 1 insertion(+), 31 deletions(-)
delete mode 100644 GJ2022/Game/GameWorld/Regions/RegionContainer.cs
diff --git a/GJ2022/Game/GameWorld/Regions/RegionContainer.cs b/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
deleted file mode 100644
index 978e54c..0000000
--- a/GJ2022/Game/GameWorld/Regions/RegionContainer.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace GJ2022.Game.GameWorld.Regions
-{
- public class RegionContainer
- {
-
- }
-}
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 76985c8..6184515 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -33,24 +33,7 @@ public class WorldRegionList
///
public PositionBasedBinaryList regions = new PositionBasedBinaryList();
- ///
- /// Contains a list that uses the index as the depth of the region and holds a position based binary list that holds the regions containers
- /// stored at that location.
- /// Example:
- /// [0] = {(0, 0), (1, 0), (0, 1), (1, 1)}
- /// [1] = {(0, 0)}
- /// Where the coordinates represent keys of the position based binary list.
- /// The associated value would be a list of regions within that section of the world.
- ///
- public List> regionContainersByPosition = new List>();
-
- ///
- /// Print the world region list
- ///
- public void Print()
- {
- Log.WriteLine(regions, LogType.DEBUG);
- }
+
///
/// Generates the region that contains the provided X,Y world coordinates.
From 72e75f03efcfb76b2a6e90ce0e2e7e0990653b9d Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Fri, 18 Mar 2022 00:30:17 +0000
Subject: [PATCH 11/16] Comments
---
GJ2022/Game/GameWorld/Regions/Region.cs | 24 +++++++++++++++++++
.../Game/GameWorld/Regions/WorldRegionList.cs | 10 +++++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index 8174e2e..f5ff781 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -33,12 +33,21 @@ namespace GJ2022.Game.GameWorld.Regions
/// We then traverse up both trees until we hit the top level, or the level of the shared parent.
/// We then create parents where necessary until we hit the shared parent.
/// Both nodes should now have the same superparent
+ ///
+ /// When removing a region:
+ /// =========
+ /// Check if we have created a new region by blocking 2 nodes from each other within a region.
+ /// Create a new region if we need, setting the tiles that are in this region to be adjacent to this region
+ /// Locate the adjacent regions to the updated region
+ /// Calculate which adjacencies no longer exist but are represented in the data structure
+ /// Seperate the tree structure
///
public class Region
{
private static int count = 0;
+ //The unique ID of this region, for debugging purposes
public int Id { get; } = count++;
//The parent region
@@ -56,6 +65,21 @@ public class Region
//The world coordinated of the bottom divided by the primary level size
public int Y { get; }
+ //A list of adjacent regions to this region
+ //This is likely to be null for any region that isn't a primary
+ //level region.
+ //If this region isn't a primary region, then the adjacent regions is calculated
+ //by performing the union operation on the children's linked regions parents.
+ //TODO
+ public List AdjacentRegions { get; set; }
+
+ ///
+ /// Instantiates a region based on an X and Y position, setting the region's height
+ /// to the height parameter
+ ///
+ /// The X value of the bottom left part of region
+ /// The Y value of the bottom left part of the region
+ /// The height of the node in the tree data structure
public Region(int x, int y, int height = 0)
{
X = x;
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 6184515..a1b7328 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -33,7 +33,15 @@ public class WorldRegionList
///
public PositionBasedBinaryList regions = new PositionBasedBinaryList();
-
+ ///
+ /// Update a node to no longer be solid
+ ///
+ public void SetNodeNonSolid(int x, int y)
+ {
+ //Calculate if we need to do anything at all within this region
+ //If we are now seperated from the rest of our region create
+ //a new region to represent this area and calculate adjacencies
+ }
///
/// Generates the region that contains the provided X,Y world coordinates.
From 59802e1adf7351b23ebe89f4dba04442cee2670d Mon Sep 17 00:00:00 2001
From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com>
Date: Fri, 18 Mar 2022 13:43:37 +0000
Subject: [PATCH 12/16] Prepares writting the comments for this stuff
---
.../Game/GameWorld/Regions/WorldRegionList.cs | 40 ++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index 6184515..cdff669 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -33,7 +33,45 @@ public class WorldRegionList
///
public PositionBasedBinaryList regions = new PositionBasedBinaryList();
-
+ ///
+ /// Sets a node in the world to be solid
+ ///
+ /// The X position of the node to set to be solid
+ /// The Y position of the node to set to be solid
+ public void SetNodeSolid(int x, int y)
+ {
+ //Get and remove the node's region
+ Region affectedRegion = regions.Get(x, y);
+ regions.Remove(x, y);
+ //Calculate if we need to take any action at all
+ if (!NodeSolidRequiresUpdate(affectedRegion, x, y))
+ return;
+ }
+
+ ///
+ /// Returns true if the position at X, Y will cause a region to
+ /// be subdivided.
+ /// General Theory:
+ /// If we have only 1 open side return false.
+ /// If we have more than 1 open side, choose any side.
+ /// Flood fill that side outwards applying a unique ID to all nodes that are flood filled.
+ /// Once completed, go to the original node and ensure that all adjacent nodes have the same ID from what we
+ /// flood filled.
+ /// If any open adjacent nodes didn't get tagged by the flood fill, it means our region has
+ /// been subdivided.
+ ///
+ private bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
+ {
+ //Flood fill all nodes in the region and see if we can reconnect with ourselfs
+ //Flood fill with IDs, giving unique values to north, south, east and west
+ int[,] floodFilledIds = new int[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ Queue> updateQueue = new Queue>();
+ //Locate an adjacent, open node.
+ //Insert the first node
+
+ //We did not re-encounter ourselves, so we need to update
+ return true;
+ }
///
/// Generates the region that contains the provided X,Y world coordinates.
From a1a613f0612841a63c7db2fc70a09a3bfd95dac0 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Fri, 18 Mar 2022 21:10:34 +0000
Subject: [PATCH 13/16] Updates world to be non-static
---
GJ2022.Tests/RegionTests.cs | 67 +++++++++-
.../Component_AtmosphericBlocker.cs | 8 +-
.../Components/Generic/Component_Tracked.cs | 12 +-
.../Component_InternalEntity_Hardsuit.cs | 2 +-
GJ2022/Entities/Areas/Area.cs | 6 +-
GJ2022/Entities/Debug/DebugCanister.cs | 2 +-
GJ2022/Entities/Items/Item.cs | 16 +--
GJ2022/Entities/Markers/Marker.cs | 6 +-
GJ2022/Entities/Markers/MiningMarker.cs | 8 +-
GJ2022/Entities/Pawns/Health/Bodies/Body.cs | 2 +-
GJ2022/Entities/Pawns/Pawn.cs | 8 +-
GJ2022/Entities/Pawns/PawnBreathing.cs | 2 +-
GJ2022/Entities/Structures/Fire.cs | 6 +-
.../Structures/Power/AreaPowerController.cs | 8 +-
.../Structures/Power/PacmanGenerator.cs | 4 +-
.../Entities/Structures/Power/PowerConduit.cs | 6 +-
GJ2022/Entities/Structures/Structure.cs | 6 +-
GJ2022/Entities/Turfs/Turf.cs | 10 +-
GJ2022/Game/GameWorld/Regions/Region.cs | 2 +-
GJ2022/Game/GameWorld/World.cs | 122 +++++++++---------
GJ2022/Game/Power/Powernet.cs | 2 +-
GJ2022/Managers/Stockpile/StockpileManager.cs | 4 +-
.../PawnBehaviours/PawnActions/HaulItems.cs | 20 +--
.../PawnBehaviours/PawnActions/MineAction.cs | 8 +-
GJ2022/PawnBehaviours/PawnActions/SmeltOre.cs | 8 +-
GJ2022/Subsystems/AtmosphericsSystem.cs | 74 +++++------
GJ2022/Subsystems/MouseCollisionSubsystem.cs | 2 +-
GJ2022/Subsystems/PathfindingSystem.cs | 28 ++--
GJ2022/Subsystems/PawnControllerSystem.cs | 2 +-
GJ2022/Subsystems/Subsystem.cs | 2 +-
GJ2022/UserInterface/UserInterfaceCreator.cs | 4 +-
31 files changed, 262 insertions(+), 195 deletions(-)
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index 3c550d4..ace0183 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -1,4 +1,6 @@
-using GJ2022.Game.GameWorld.Regions;
+using GJ2022.Entities.Turfs;
+using GJ2022.Game.GameWorld;
+using GJ2022.Game.GameWorld.Current.Regions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
@@ -12,6 +14,69 @@ namespace GJ2022.Tests
public class RegionTests
{
+ [TestMethod]
+ public void TestRegionCreation()
+ {
+ //Generate a wall
+ Turf solidTurf = new Turf();
+ solidTurf.SetProperty("Solid", true);
+ //Reset the world
+ World.Current = new World();
+ World.Current.SetTurf(4, 0, solidTurf);
+ World.Current.SetTurf(4, 1, solidTurf);
+ World.Current.SetTurf(4, 2, solidTurf);
+ World.Current.SetTurf(4, 3, solidTurf);
+ World.Current.SetTurf(4, 4, solidTurf);
+ World.Current.SetTurf(4, 5, solidTurf);
+ World.Current.SetTurf(4, 6, solidTurf);
+ World.Current.SetTurf(4, 7, solidTurf);
+ WorldRegionList wrl = new WorldRegionList();
+ wrl.GenerateWorldSection(0, 0);
+ Region left = null;
+ for (int x = 0; x < 4; x++)
+ {
+ for (int y = 0; y < 8; y++)
+ {
+ if (left == null)
+ left = wrl.regions.Get(x, y);
+ Assert.AreEqual(left, wrl.regions.Get(x, y), "Expected left region to be the same");
+ }
+ }
+ for (int x = 5; x < 8; x++)
+ {
+ for (int y = 0; y < 8; y++)
+ {
+ Assert.AreNotEqual(left, wrl.regions.Get(x, y), "Expected right region to be different");
+ }
+ }
+ }
+
+ [TestMethod]
+ public void TestRegionUpdateRequirements()
+ {
+ //Generate a wall
+ Turf solidTurf = new Turf();
+ solidTurf.SetProperty("Solid", true);
+ //Reset the world
+ World.Current = new World();
+ World.Current.SetTurf(4, 0, solidTurf);
+ World.Current.SetTurf(4, 1, solidTurf);
+ World.Current.SetTurf(4, 2, solidTurf);
+ World.Current.SetTurf(4, 3, solidTurf);
+ World.Current.SetTurf(4, 5, solidTurf);
+ World.Current.SetTurf(4, 6, solidTurf);
+ World.Current.SetTurf(4, 7, solidTurf);
+ WorldRegionList wrl = new WorldRegionList();
+ wrl.GenerateWorldSection(0, 0);
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 4, 4));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 3, 1));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 5, 5));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 4, 6));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 3, 3));
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 5, 4));
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 3, 4));
+ }
+
[TestMethod]
public void TestRegionWorldSection()
{
diff --git a/GJ2022/Components/Atmospherics/Component_AtmosphericBlocker.cs b/GJ2022/Components/Atmospherics/Component_AtmosphericBlocker.cs
index 701818a..9edf563 100644
--- a/GJ2022/Components/Atmospherics/Component_AtmosphericBlocker.cs
+++ b/GJ2022/Components/Atmospherics/Component_AtmosphericBlocker.cs
@@ -18,22 +18,22 @@ public override void OnComponentAdd()
{
Entity parent = Parent as Entity;
blockingPosition = parent.Position;
- World.AddAtmosphericBlocker(blockingPosition.X, blockingPosition.Y);
+ World.Current.AddAtmosphericBlocker(blockingPosition.X, blockingPosition.Y);
Parent.RegisterSignal(Signal.SIGNAL_ENTITY_MOVED, -1, ParentMoveReact);
}
public override void OnComponentRemove()
{
- World.RemoveAtmosphericBlock(blockingPosition.X, blockingPosition.Y);
+ World.Current.RemoveAtmosphericBlock(blockingPosition.X, blockingPosition.Y);
Parent.UnregisterSignal(Signal.SIGNAL_ENTITY_MOVED, ParentMoveReact);
}
private object ParentMoveReact(object source, params object[] parameters)
{
- World.RemoveAtmosphericBlock(blockingPosition.X, blockingPosition.Y);
+ World.Current.RemoveAtmosphericBlock(blockingPosition.X, blockingPosition.Y);
Entity parent = Parent as Entity;
blockingPosition = parent.Position;
- World.AddAtmosphericBlocker(blockingPosition.X, blockingPosition.Y);
+ World.Current.AddAtmosphericBlocker(blockingPosition.X, blockingPosition.Y);
return null;
}
diff --git a/GJ2022/Components/Generic/Component_Tracked.cs b/GJ2022/Components/Generic/Component_Tracked.cs
index 555d5e0..73a7002 100644
--- a/GJ2022/Components/Generic/Component_Tracked.cs
+++ b/GJ2022/Components/Generic/Component_Tracked.cs
@@ -25,7 +25,7 @@ public override void OnComponentAdd()
//Start tracking
trackedX = (int)parent.Position.X;
trackedY = (int)parent.Position.Y;
- World.AddThing(Key, trackedX, trackedY, Parent);
+ World.Current.AddThing(Key, trackedX, trackedY, Parent);
Parent.RegisterSignal(Signal.SIGNAL_ENTITY_MOVED, -1, OnParentMoved);
Parent.RegisterSignal(Signal.SIGNAL_ENTITY_LOCATION, -1, OnLocationChanged);
}
@@ -36,7 +36,7 @@ public override void OnComponentRemove()
Entity parent = Parent as Entity;
//No track will exist
if (parent.Location == null)
- World.RemoveThing(Key, trackedX, trackedY, Parent);
+ World.Current.RemoveThing(Key, trackedX, trackedY, Parent);
Parent.UnregisterSignal(Signal.SIGNAL_ENTITY_MOVED, OnParentMoved);
Parent.UnregisterSignal(Signal.SIGNAL_ENTITY_LOCATION, OnLocationChanged);
}
@@ -48,14 +48,14 @@ private object OnLocationChanged(object source, params object[] parameters)
//Remove the old track
if(newLocation != null && oldLocation == null)
- World.RemoveThing(Key, trackedX, trackedY, Parent);
+ World.Current.RemoveThing(Key, trackedX, trackedY, Parent);
//Start tracking
if (newLocation == null && oldLocation != null)
{
Entity parent = Parent as Entity;
trackedX = (int)parent.Position.X;
trackedY = (int)parent.Position.Y;
- World.AddThing(Key, trackedX, trackedY, Parent);
+ World.Current.AddThing(Key, trackedX, trackedY, Parent);
}
return null;
}
@@ -68,11 +68,11 @@ private object OnParentMoved(object source, params object[] parameters)
if (parent.Location != null)
return null;
//Remove the old track
- World.RemoveThing(Key, trackedX, trackedY, Parent);
+ World.Current.RemoveThing(Key, trackedX, trackedY, Parent);
//Start tracking
trackedX = (int)parent.Position.X;
trackedY = (int)parent.Position.Y;
- World.AddThing(Key, trackedX, trackedY, Parent);
+ World.Current.AddThing(Key, trackedX, trackedY, Parent);
return null;
}
diff --git a/GJ2022/Components/Items/Component_InternalEntity_Hardsuit.cs b/GJ2022/Components/Items/Component_InternalEntity_Hardsuit.cs
index c9bae23..63b232e 100644
--- a/GJ2022/Components/Items/Component_InternalEntity_Hardsuit.cs
+++ b/GJ2022/Components/Items/Component_InternalEntity_Hardsuit.cs
@@ -59,7 +59,7 @@ private object OnPawnMoved(object source, params object[] parmeters)
private bool ShouldDeployHelmet(Pawn pawn)
{
- Turf turf = World.GetTurf((int)pawn.Position.X, (int)pawn.Position.Y);
+ Turf turf = World.Current.GetTurf((int)pawn.Position.X, (int)pawn.Position.Y);
Atmosphere locatedAtmosphere = turf?.Atmosphere?.ContainedAtmosphere;
if (locatedAtmosphere == null)
return true;
diff --git a/GJ2022/Entities/Areas/Area.cs b/GJ2022/Entities/Areas/Area.cs
index b523749..1531e5f 100644
--- a/GJ2022/Entities/Areas/Area.cs
+++ b/GJ2022/Entities/Areas/Area.cs
@@ -16,15 +16,15 @@ public Area() : base()
public override bool Destroy()
{
Destroyed = true;
- World.SetArea((int)Position.X, (int)Position.Y, null);
+ World.Current.SetArea((int)Position.X, (int)Position.Y, null);
return base.Destroy();
}
public override void Initialize(Vector initializePosition)
{
base.Initialize(initializePosition);
- World.GetArea((int)initializePosition.X, (int)initializePosition.Y)?.Destroy();
- World.SetArea((int)initializePosition.X, (int)initializePosition.Y, this);
+ World.Current.GetArea((int)initializePosition.X, (int)initializePosition.Y)?.Destroy();
+ World.Current.SetArea((int)initializePosition.X, (int)initializePosition.Y, this);
}
}
}
diff --git a/GJ2022/Entities/Debug/DebugCanister.cs b/GJ2022/Entities/Debug/DebugCanister.cs
index c2b2493..fd8ed75 100644
--- a/GJ2022/Entities/Debug/DebugCanister.cs
+++ b/GJ2022/Entities/Debug/DebugCanister.cs
@@ -14,7 +14,7 @@ public class DebugCanister : Structure
public DebugCanister(Vector position) : base(position, Layers.LAYER_STRUCTURE)
{
- Turf turf = World.GetTurf((int)position.X, (int)position.Y);
+ Turf turf = World.Current.GetTurf((int)position.X, (int)position.Y);
if (turf == null)
return;
if (turf.Atmosphere == null)
diff --git a/GJ2022/Entities/Items/Item.cs b/GJ2022/Entities/Items/Item.cs
index a4dc324..f7854dc 100644
--- a/GJ2022/Entities/Items/Item.cs
+++ b/GJ2022/Entities/Items/Item.cs
@@ -44,8 +44,8 @@ public override bool Destroy()
{
base.Destroy();
Destroyed = true;
- World.RemoveItem((int)Position.X, (int)Position.Y, this);
- World.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
+ World.Current.RemoveItem((int)Position.X, (int)Position.Y, this);
+ World.Current.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
//Handle inventory removal
if (Location is Pawn holder)
{
@@ -63,11 +63,11 @@ public void OnMoved(Vector oldPosition)
{
if ((int)oldPosition.X == (int)Position.X && (int)oldPosition.Y == (int)Position.Y)
return;
- World.RemoveItem((int)oldPosition.X, (int)oldPosition.Y, this);
- World.AddItem((int)Position.X, (int)Position.Y, this);
+ World.Current.RemoveItem((int)oldPosition.X, (int)oldPosition.Y, this);
+ World.Current.AddItem((int)Position.X, (int)Position.Y, this);
//Calculate stockpile
- World.GetArea((int)oldPosition.X, (int)oldPosition.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
- World.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_ADDED, this);
+ World.Current.GetArea((int)oldPosition.X, (int)oldPosition.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
+ World.Current.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_ADDED, this);
}
public void OnMoved(Entity oldLocation)
@@ -80,8 +80,8 @@ public void OnMoved(Entity oldLocation)
return;
}
MouseCollisionSubsystem.Singleton.StopTracking(this);
- World.RemoveItem((int)Position.X, (int)Position.Y, this);
- World.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
+ World.Current.RemoveItem((int)Position.X, (int)Position.Y, this);
+ World.Current.GetArea((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_AREA_CONTENTS_REMOVED, this);
}
public void UpdateCount()
diff --git a/GJ2022/Entities/Markers/Marker.cs b/GJ2022/Entities/Markers/Marker.cs
index cc7ad1d..431d1e9 100644
--- a/GJ2022/Entities/Markers/Marker.cs
+++ b/GJ2022/Entities/Markers/Marker.cs
@@ -17,19 +17,19 @@ public Marker(Vector position, float layer) : base(position, layer)
Destroy();
return;
}
- Marker marker = World.GetMarker((int)position.X, (int)position.Y);
+ Marker marker = World.Current.GetMarker((int)position.X, (int)position.Y);
if (marker != null)
{
marker.Destroy();
return;
}
- World.SetMarker((int)position.X, (int)position.Y, this);
+ World.Current.SetMarker((int)position.X, (int)position.Y, this);
}
public override bool Destroy()
{
Destroyed = true;
- World.SetMarker((int)Position.X, (int)Position.Y, null);
+ World.Current.SetMarker((int)Position.X, (int)Position.Y, null);
return base.Destroy();
}
diff --git a/GJ2022/Entities/Markers/MiningMarker.cs b/GJ2022/Entities/Markers/MiningMarker.cs
index 6c26c48..8e4467b 100644
--- a/GJ2022/Entities/Markers/MiningMarker.cs
+++ b/GJ2022/Entities/Markers/MiningMarker.cs
@@ -19,17 +19,17 @@ public MiningMarker(Vector position) : base(position, Layers.LAYER_MARKER
if (Destroyed)
return;
//Register signal
- World.GetTurf((int)Position.X, (int)Position.Y).RegisterSignal(Signal.SIGNAL_ENTITY_DESTROYED, 0, DestroyMarker);
+ World.Current.GetTurf((int)Position.X, (int)Position.Y).RegisterSignal(Signal.SIGNAL_ENTITY_DESTROYED, 0, DestroyMarker);
}
public override bool IsValidPosition()
{
- return World.GetThings("Mine", (int)Position.X, (int)Position.Y).Count > 0;
+ return World.Current.GetThings("Mine", (int)Position.X, (int)Position.Y).Count > 0;
}
public override bool Destroy()
{
- World.GetTurf((int)Position.X, (int)Position.Y)?.UnregisterSignal(Signal.SIGNAL_ENTITY_DESTROYED, DestroyMarker);
+ World.Current.GetTurf((int)Position.X, (int)Position.Y)?.UnregisterSignal(Signal.SIGNAL_ENTITY_DESTROYED, DestroyMarker);
return base.Destroy();
}
@@ -45,7 +45,7 @@ public void HandleAction(Pawn pawn)
{
new AudioSource().PlaySound($"effects/picaxe{World.Random.Next(1, 4)}.wav", Position.X, Position.Y);
//Perform mining
- World.GetTurf((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_ENTITY_MINE, pawn);
+ World.Current.GetTurf((int)Position.X, (int)Position.Y)?.SendSignal(Signal.SIGNAL_ENTITY_MINE, pawn);
if(!Destroyed)
Destroy();
}
diff --git a/GJ2022/Entities/Pawns/Health/Bodies/Body.cs b/GJ2022/Entities/Pawns/Health/Bodies/Body.cs
index f031f3d..89df290 100644
--- a/GJ2022/Entities/Pawns/Health/Bodies/Body.cs
+++ b/GJ2022/Entities/Pawns/Health/Bodies/Body.cs
@@ -164,7 +164,7 @@ public void Process(float deltaTime)
//Process bleeding
ProcessBleeding(deltaTime);
//Process pressure damage (TODO: If not protected via pressure resistant clothing)
- Turf location = World.GetTurf((int)Parent.Position.X, (int)Parent.Position.Y);
+ Turf location = World.Current.GetTurf((int)Parent.Position.X, (int)Parent.Position.Y);
float pressure = location?.Atmosphere?.ContainedAtmosphere.KiloPascalPressure ?? 0;
for (int i = InsertedLimbs.Count - 1; i >= 0; i--)
{
diff --git a/GJ2022/Entities/Pawns/Pawn.cs b/GJ2022/Entities/Pawns/Pawn.cs
index 892e396..d3ca002 100644
--- a/GJ2022/Entities/Pawns/Pawn.cs
+++ b/GJ2022/Entities/Pawns/Pawn.cs
@@ -195,7 +195,7 @@ private void TraversePath(float deltaTime, float _speed = -1)
private float CalculateSpeed()
{
//If we have gravity return movement factor
- if (World.HasGravity(Position))
+ if (World.Current.HasGravity(Position))
return 0.04f * PawnBody.Movement;
//Return regular speed
return 4f;
@@ -278,15 +278,15 @@ public void OnMoved(Vector oldPosition)
{
if ((int)oldPosition.X == (int)Position.X && (int)oldPosition.Y == (int)Position.Y)
return;
- World.RemovePawn((int)oldPosition.X, (int)oldPosition.Y, this);
- World.AddPawn((int)Position.X, (int)Position.Y, this);
+ World.Current.RemovePawn((int)oldPosition.X, (int)oldPosition.Y, this);
+ World.Current.AddPawn((int)Position.X, (int)Position.Y, this);
}
public void OnMoved(Entity oldLocation)
{
if (oldLocation == Location)
return;
- World.RemovePawn((int)Position.X, (int)Position.Y, this);
+ World.Current.RemovePawn((int)Position.X, (int)Position.Y, this);
}
}
diff --git a/GJ2022/Entities/Pawns/PawnBreathing.cs b/GJ2022/Entities/Pawns/PawnBreathing.cs
index b5af8c6..c9b1148 100644
--- a/GJ2022/Entities/Pawns/PawnBreathing.cs
+++ b/GJ2022/Entities/Pawns/PawnBreathing.cs
@@ -32,7 +32,7 @@ public Atmosphere GetBreathSource()
}
}
//Return atmosphere at the current location
- return World.GetTurf((int)Position.X, (int)Position.Y)?.Atmosphere?.ContainedAtmosphere;
+ return World.Current.GetTurf((int)Position.X, (int)Position.Y)?.Atmosphere?.ContainedAtmosphere;
}
///
diff --git a/GJ2022/Entities/Structures/Fire.cs b/GJ2022/Entities/Structures/Fire.cs
index 1c0e25e..e62f552 100644
--- a/GJ2022/Entities/Structures/Fire.cs
+++ b/GJ2022/Entities/Structures/Fire.cs
@@ -49,7 +49,7 @@ public override bool Destroy()
public void Process(float deltaTime)
{
//Get the current turf
- Turf turf = World.GetTurf((int)Position.X, (int)Position.Y);
+ Turf turf = World.Current.GetTurf((int)Position.X, (int)Position.Y);
//Check turf atmos
if (turf == null || turf.Atmosphere == null)
{
@@ -67,7 +67,7 @@ public void Process(float deltaTime)
return;
}
//Hurt pawns
- foreach (Pawn pawn in World.GetPawns(turf.X, turf.Y))
+ foreach (Pawn pawn in World.Current.GetPawns(turf.X, turf.Y))
{
pawn.PawnBody.ApplyDamageRandomly(new Burn(0.5f * deltaTime));
}
@@ -94,7 +94,7 @@ public void Process(float deltaTime)
//Go through directions
Vector spreadDirction = directions[i];
//Check for atmospheric flow allowance
- if (!World.AllowsAtmosphericFlow(x + spreadDirction[0], y + spreadDirction[1]))
+ if (!World.Current.AllowsAtmosphericFlow(x + spreadDirction[0], y + spreadDirction[1]))
return;
//Check for fires
if (GlobalFires.Get(x + spreadDirction[0], y + spreadDirction[1]) != null)
diff --git a/GJ2022/Entities/Structures/Power/AreaPowerController.cs b/GJ2022/Entities/Structures/Power/AreaPowerController.cs
index 5438510..31fd2c1 100644
--- a/GJ2022/Entities/Structures/Power/AreaPowerController.cs
+++ b/GJ2022/Entities/Structures/Power/AreaPowerController.cs
@@ -40,8 +40,8 @@ public AreaPowerController(Vector position, Directions direction) : base(
offset = new Vector(0, -offsetAmount);
break;
}
- World.AddAreaPowerController((int)position.X, (int)position.Y, this);
- World.AddPowernetInteractor((int)position.X, (int)position.Y, PowernetInteractor);
+ World.Current.AddAreaPowerController((int)position.X, (int)position.Y, this);
+ World.Current.AddPowernetInteractor((int)position.X, (int)position.Y, PowernetInteractor);
Position += offset;
//TODO: Move this to a definition file
insertedCell = EntityCreator.CreateEntity("Cell_Standard", position);
@@ -64,8 +64,8 @@ public AreaPowerController(Vector position, Directions direction) : base(
public override bool Destroy()
{
Position -= offset;
- World.RemoveAreaPowerController((int)Position.X, (int)Position.Y, this);
- World.RemovePowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
+ World.Current.RemoveAreaPowerController((int)Position.X, (int)Position.Y, this);
+ World.Current.RemovePowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
PowerProcessingSystem.Singleton.StopProcessing(this);
return base.Destroy();
}
diff --git a/GJ2022/Entities/Structures/Power/PacmanGenerator.cs b/GJ2022/Entities/Structures/Power/PacmanGenerator.cs
index 5cf4144..96c14d4 100644
--- a/GJ2022/Entities/Structures/Power/PacmanGenerator.cs
+++ b/GJ2022/Entities/Structures/Power/PacmanGenerator.cs
@@ -17,7 +17,7 @@ class PacmanGenerator : Structure, IProcessable
public PacmanGenerator(Vector position) : base(position, Layers.LAYER_STRUCTURE)
{
- World.AddPowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
+ World.Current.AddPowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
PowerProcessingSystem.Singleton.StartProcessing(this);
}
@@ -31,7 +31,7 @@ public PacmanGenerator(Vector position) : base(position, Layers.LAYER_STR
public override bool Destroy()
{
- World.RemovePowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
+ World.Current.RemovePowernetInteractor((int)Position.X, (int)Position.Y, PowernetInteractor);
PowerProcessingSystem.Singleton.StopProcessing(this);
return base.Destroy();
}
diff --git a/GJ2022/Entities/Structures/Power/PowerConduit.cs b/GJ2022/Entities/Structures/Power/PowerConduit.cs
index 3de2c30..9d32edf 100644
--- a/GJ2022/Entities/Structures/Power/PowerConduit.cs
+++ b/GJ2022/Entities/Structures/Power/PowerConduit.cs
@@ -26,7 +26,7 @@ public PowerConduit(Vector position) : base(position, Layers.LAYER_CONDUI
textObjectOffset = new Vector(0, -0.6f);
attachedTextObject = new TextObject($"{Powernet?.PowernetId}", Colour.White, Position + textObjectOffset, TextObject.PositionModes.WORLD_POSITION, 0.4f);
AddNode();
- World.SetPowerCable((int)position.X, (int)position.Y, this);
+ World.Current.SetPowerCable((int)position.X, (int)position.Y, this);
}
}
@@ -61,7 +61,7 @@ public bool Destroy(bool initialized = true)
if (!base.Destroy())
return false;
RemoveNode();
- World.SetPowerCable((int)Position.X, (int)Position.Y, null);
+ World.Current.SetPowerCable((int)Position.X, (int)Position.Y, null);
return true;
}
@@ -212,7 +212,7 @@ public void UpdateIconState()
private PowerConduit LocateConduit(int x, int y)
{
- List locatedStructures = World.GetStructures(x, y);
+ List locatedStructures = World.Current.GetStructures(x, y);
for (int i = locatedStructures.Count - 1; i >= 0; i = Math.Min(i - 1, locatedStructures.Count - 1))
{
Structure structure = locatedStructures[i];
diff --git a/GJ2022/Entities/Structures/Structure.cs b/GJ2022/Entities/Structures/Structure.cs
index 9b6afae..fb186de 100644
--- a/GJ2022/Entities/Structures/Structure.cs
+++ b/GJ2022/Entities/Structures/Structure.cs
@@ -15,7 +15,7 @@ public Structure() : base()
public override void Initialize(Vector initializePosition)
{
- World.AddStructure((int)initializePosition.X, (int)initializePosition.Y, this);
+ World.Current.AddStructure((int)initializePosition.X, (int)initializePosition.Y, this);
base.Initialize(initializePosition);
}
@@ -23,7 +23,7 @@ public override void Initialize(Vector initializePosition)
public Structure(Vector position, float layer) : base(position, layer)
{
//Add the structure to the world list
- World.AddStructure((int)position.X, (int)position.Y, this);
+ World.Current.AddStructure((int)position.X, (int)position.Y, this);
}
public bool Destroyed { get; private set; } = false;
@@ -31,7 +31,7 @@ public Structure(Vector position, float layer) : base(position, layer)
public override bool Destroy()
{
Destroyed = true;
- World.RemoveStructure((int)Position.X, (int)Position.Y, this);
+ World.Current.RemoveStructure((int)Position.X, (int)Position.Y, this);
return base.Destroy();
}
}
diff --git a/GJ2022/Entities/Turfs/Turf.cs b/GJ2022/Entities/Turfs/Turf.cs
index 87edc08..130d379 100644
--- a/GJ2022/Entities/Turfs/Turf.cs
+++ b/GJ2022/Entities/Turfs/Turf.cs
@@ -46,15 +46,15 @@ public override void Initialize(Vector initializePosition)
//Set the position to update the renderable
Position = new Vector(X, Y);
//Destroy the old turf
- Turf oldTurf = World.GetTurf(X, Y);
+ Turf oldTurf = World.Current.GetTurf(X, Y);
//Set the new turf
oldTurf?.Destroy(true);
- World.SetTurf(X, Y, this);
+ World.Current.SetTurf(X, Y, this);
//Set the direction
Direction = Directions.NONE;
//Atmos flow blocking
if (!AllowAtmosphericFlow)
- World.AddAtmosphericBlocker(X, Y, false);
+ World.Current.AddAtmosphericBlocker(X, Y, false);
//Tell the atmos system a turf was created / changed at this location
if (oldTurf == null)
AtmosphericsSystem.Singleton.OnTurfCreated(this);
@@ -79,7 +79,7 @@ public bool Destroy(bool changed)
#endif
//Atmos flow blocking
if (!AllowAtmosphericFlow)
- World.RemoveAtmosphericBlock(X, Y, false);
+ World.Current.RemoveAtmosphericBlock(X, Y, false);
//If we weren't changed, destroy the turf
if (!changed)
AtmosphericsSystem.Singleton.OnTurfDestroyed(this);
@@ -89,7 +89,7 @@ public bool Destroy(bool changed)
public override bool Destroy()
{
//Dereference
- World.SetTurf(X, Y, null);
+ World.Current.SetTurf(X, Y, null);
//Set destroyed
Destroyed = true;
return base.Destroy();
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index f5ff781..d2079e7 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;
-namespace GJ2022.Game.GameWorld.Regions
+namespace GJ2022.Game.GameWorld.Current.Regions
{
///
/// Region system:
diff --git a/GJ2022/Game/GameWorld/World.cs b/GJ2022/Game/GameWorld/World.cs
index c686b2e..c32ed91 100644
--- a/GJ2022/Game/GameWorld/World.cs
+++ b/GJ2022/Game/GameWorld/World.cs
@@ -17,9 +17,11 @@
namespace GJ2022.Game.GameWorld
{
- public static class World
+ public class World
{
+ public static World Current { get; set; } = new World();
+
public static Random Random { get; } = new Random();
public static int EntitiesCreated { get; set; } = 0;
@@ -43,76 +45,76 @@ public IntegerReference(int value)
/// is the position based binary list containing the details of the
/// things being tracked.
///
- public static Dictionary>> TrackedComponentHandlers = new Dictionary>>();
+ public Dictionary>> TrackedComponentHandlers = new Dictionary>>();
//Dictionary of turfs in the world
- public static PositionBasedBinaryList WorldTurfs = new PositionBasedBinaryList();
+ public PositionBasedBinaryList WorldTurfs = new PositionBasedBinaryList();
//Dictionary of areas in the world
- public static PositionBasedBinaryList WorldAreas = new PositionBasedBinaryList();
+ public PositionBasedBinaryList WorldAreas = new PositionBasedBinaryList();
//Dictionary of markers in the world
- public static PositionBasedBinaryList WorldMarkers = new PositionBasedBinaryList();
+ public PositionBasedBinaryList WorldMarkers = new PositionBasedBinaryList();
//Dictionary of power cables in the world
- public static PositionBasedBinaryList PowerCables = new PositionBasedBinaryList();
+ public PositionBasedBinaryList PowerCables = new PositionBasedBinaryList();
//Collection of interactors with the powernet.
- public static PositionBasedBinaryList> PowernetInteractors = new PositionBasedBinaryList>();
+ public PositionBasedBinaryList> PowernetInteractors = new PositionBasedBinaryList>();
//Dictionary containing all items in the world at a specified position.
//When an item moves, it needs to be updated in this list.
- public static PositionBasedBinaryList> WorldItems = new PositionBasedBinaryList>();
+ public PositionBasedBinaryList> WorldItems = new PositionBasedBinaryList>();
//Dictionary containing all structures in the world
- public static PositionBasedBinaryList> WorldStructures = new PositionBasedBinaryList>();
+ public PositionBasedBinaryList> WorldStructures = new PositionBasedBinaryList>();
//Dictionary containing all mobs in the world
- public static PositionBasedBinaryList> WorldPawns = new PositionBasedBinaryList>();
+ public PositionBasedBinaryList> WorldPawns = new PositionBasedBinaryList>();
//Dictionary containing all mobs in the world
- public static PositionBasedBinaryList> AreaPowerControllers = new PositionBasedBinaryList>();
+ public PositionBasedBinaryList> AreaPowerControllers = new PositionBasedBinaryList>();
//An integer storing the amount of atmospheric blocking things at this location
- private static PositionBasedBinaryList AtmosphericBlockers = new PositionBasedBinaryList();
+ private PositionBasedBinaryList AtmosphericBlockers = new PositionBasedBinaryList();
//======================
// In range detectors
//======================
- public static bool HasThingInRange(string thingGroup, int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasThingInRange(string thingGroup, int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
{
if (!TrackedComponentHandlers.ContainsKey(thingGroup))
return false;
return TrackedComponentHandlers[thingGroup].ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasMarkerInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasMarkerInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldMarkers.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasTurfInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasTurfInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldTurfs.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasAreaInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasAreaInRange(int x, int y, int range, BinaryList.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldAreas.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasItemsInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasItemsInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldItems.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasStructuresInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasStructuresInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldStructures.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
- public static bool HasPawnsInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
+ public bool HasPawnsInRange(int x, int y, int range, BinaryList>.BinaryListValidityCheckDelegate conditionalCheck = null)
{
return WorldPawns.ElementsInRange(x - range, y - range, x + range, y + range, 0, -1, conditionalCheck);
}
@@ -122,7 +124,7 @@ public static bool HasPawnsInRange(int x, int y, int range, BinaryList GetSpiralThings(string thingGroup, int original_x, int original_y, int range)
+ public List GetSpiralThings(string thingGroup, int original_x, int original_y, int range)
where T : IComponentHandler
{
List output = new List();
@@ -150,7 +152,7 @@ public static List GetSpiralThings(string thingGroup, int original_x, int
/// NOTE: It would be better to just iterate all the items (although that would
/// require a distance check)
///
- public static List GetSprialMarkers(int original_x, int original_y, int range)
+ public List GetSprialMarkers(int original_x, int original_y, int range)
{
List output = new List();
for (int r = 0; r <= range; r++)
@@ -172,7 +174,7 @@ public static List GetSprialMarkers(int original_x, int original_y, int
///
/// Get spiral items, ordered by distance from the origin
///
- public static List GetSprialAreas(int original_x, int original_y, int range)
+ public List GetSprialAreas(int original_x, int original_y, int range)
{
List output = new List();
for (int r = 0; r <= range; r++)
@@ -194,7 +196,7 @@ public static List GetSprialAreas(int original_x, int original_y, int rang
///
/// Get spiral items, ordered by distance from the origin
///
- public static List- GetSprialItems(int original_x, int original_y, int range)
+ public List
- GetSprialItems(int original_x, int original_y, int range)
{
List
- output = new List
- ();
for (int r = 0; r <= range; r++)
@@ -216,7 +218,7 @@ public static List
- GetSprialItems(int original_x, int original_y, int rang
///
/// Get spiral structures, ordered by distance from the origin
///
- public static List GetSprialStructure(int original_x, int original_y, int range)
+ public List GetSprialStructure(int original_x, int original_y, int range)
{
List output = new List();
for (int r = 0; r <= range; r++)
@@ -239,7 +241,7 @@ public static List GetSprialStructure(int original_x, int original_y,
// Atmospheric Blockers
//======================
- public static void AddAtmosphericBlocker(int x, int y, bool updateAtmos = true)
+ public void AddAtmosphericBlocker(int x, int y, bool updateAtmos = true)
{
IntegerReference reference = AtmosphericBlockers.Get(x, y);
if (reference == null)
@@ -252,7 +254,7 @@ public static void AddAtmosphericBlocker(int x, int y, bool updateAtmos = true)
reference.Value++;
}
- public static void RemoveAtmosphericBlock(int x, int y, bool updateAtmos = true)
+ public void RemoveAtmosphericBlock(int x, int y, bool updateAtmos = true)
{
IntegerReference reference = AtmosphericBlockers.Get(x, y);
if (reference == null)
@@ -270,7 +272,7 @@ public static void RemoveAtmosphericBlock(int x, int y, bool updateAtmos = true)
// Atmospheric Flow
//======================
- public static bool AllowsAtmosphericFlow(int x, int y)
+ public bool AllowsAtmosphericFlow(int x, int y)
{
return AtmosphericBlockers.Get(x, y) == null;
}
@@ -279,7 +281,7 @@ public static bool AllowsAtmosphericFlow(int x, int y)
// Things
//======================
- public static List GetThings(string thingGroup, int x, int y)
+ public List GetThings(string thingGroup, int x, int y)
{
if (!TrackedComponentHandlers.ContainsKey(thingGroup))
return new List() { };
@@ -289,7 +291,7 @@ public static List GetThings(string thingGroup, int x, int y)
///
/// Add an pawn to the world list
///
- public static void AddThing(string thingGroup, int x, int y, IComponentHandler thing)
+ public void AddThing(string thingGroup, int x, int y, IComponentHandler thing)
{
if (!TrackedComponentHandlers.ContainsKey(thingGroup))
TrackedComponentHandlers.Add(thingGroup, new PositionBasedBinaryList
>());
@@ -303,7 +305,7 @@ public static void AddThing(string thingGroup, int x, int y, IComponentHandler t
///
/// Remove the pawn from the world list
///
- public static bool RemoveThing(string thingGroup, int x, int y, IComponentHandler thing)
+ public bool RemoveThing(string thingGroup, int x, int y, IComponentHandler thing)
{
if (!TrackedComponentHandlers.ContainsKey(thingGroup))
return false;
@@ -320,7 +322,7 @@ public static bool RemoveThing(string thingGroup, int x, int y, IComponentHandle
// APCs
//======================
- public static List GetAreaPowerControllers(int x, int y)
+ public List GetAreaPowerControllers(int x, int y)
{
return AreaPowerControllers.Get(x, y) ?? new List() { };
}
@@ -328,7 +330,7 @@ public static List GetAreaPowerControllers(int x, int y)
///
/// Add an pawn to the world list
///
- public static void AddAreaPowerController(int x, int y, AreaPowerController apc)
+ public void AddAreaPowerController(int x, int y, AreaPowerController apc)
{
List located = AreaPowerControllers.Get(x, y);
if (located != null)
@@ -340,7 +342,7 @@ public static void AddAreaPowerController(int x, int y, AreaPowerController apc)
///
/// Remove the pawn from the world list
///
- public static bool RemoveAreaPowerController(int x, int y, AreaPowerController apc)
+ public bool RemoveAreaPowerController(int x, int y, AreaPowerController apc)
{
List located = AreaPowerControllers.Get(x, y);
if (located == null)
@@ -355,7 +357,7 @@ public static bool RemoveAreaPowerController(int x, int y, AreaPowerController a
// Pawns
//======================
- public static List GetPawns(int x, int y)
+ public List GetPawns(int x, int y)
{
return WorldPawns.Get(x, y) ?? new List() { };
}
@@ -363,7 +365,7 @@ public static List GetPawns(int x, int y)
///
/// Add an pawn to the world list
///
- public static void AddPawn(int x, int y, Pawn pawn)
+ public void AddPawn(int x, int y, Pawn pawn)
{
List located = WorldPawns.Get(x, y);
if (located != null)
@@ -375,7 +377,7 @@ public static void AddPawn(int x, int y, Pawn pawn)
///
/// Remove the pawn from the world list
///
- public static bool RemovePawn(int x, int y, Pawn pawn)
+ public bool RemovePawn(int x, int y, Pawn pawn)
{
List located = WorldPawns.Get(x, y);
if (located == null)
@@ -390,7 +392,7 @@ public static bool RemovePawn(int x, int y, Pawn pawn)
// Structures
//======================
- public static List GetStructures(int x, int y)
+ public List GetStructures(int x, int y)
{
return WorldStructures.Get(x, y) ?? new List() { };
}
@@ -398,7 +400,7 @@ public static List GetStructures(int x, int y)
///
/// Add an structure to the world list
///
- public static void AddStructure(int x, int y, Structure structure)
+ public void AddStructure(int x, int y, Structure structure)
{
List located = WorldStructures.Get(x, y);
if (located != null)
@@ -410,7 +412,7 @@ public static void AddStructure(int x, int y, Structure structure)
///
/// Remove the istructuretem from the world list
///
- public static bool RemoveStructure(int x, int y, Structure structure)
+ public bool RemoveStructure(int x, int y, Structure structure)
{
List located = WorldStructures.Get(x, y);
if (located == null)
@@ -425,7 +427,7 @@ public static bool RemoveStructure(int x, int y, Structure structure)
// All Entities
//======================
- public static List GetEntities(int x, int y)
+ public List GetEntities(int x, int y)
{
List output = new List();
output.AddRange(GetItems(x, y));
@@ -444,7 +446,7 @@ public static List GetEntities(int x, int y)
// Items
//======================
- public static List- GetItems(int x, int y)
+ public List
- GetItems(int x, int y)
{
return WorldItems.Get(x, y) ?? new List
- () { };
}
@@ -452,7 +454,7 @@ public static List
- GetItems(int x, int y)
///
/// Add an item to the world list
///
- public static void AddItem(int x, int y, Item item)
+ public void AddItem(int x, int y, Item item)
{
List
- located = WorldItems.Get(x, y);
if (located != null)
@@ -464,7 +466,7 @@ public static void AddItem(int x, int y, Item item)
///
/// Remove the item from the world list
///
- public static bool RemoveItem(int x, int y, Item item)
+ public bool RemoveItem(int x, int y, Item item)
{
List
- located = WorldItems.Get(x, y);
if (located == null)
@@ -482,7 +484,7 @@ public static bool RemoveItem(int x, int y, Item item)
///
/// Get the area at the specified location.
///
- public static PowerConduit GetPowerCable(int x, int y)
+ public PowerConduit GetPowerCable(int x, int y)
{
return PowerCables.Get(x, y);
}
@@ -490,7 +492,7 @@ public static PowerConduit GetPowerCable(int x, int y)
///
/// Set the area at the specified location
///
- public static void SetPowerCable(int x, int y, PowerConduit cable)
+ public void SetPowerCable(int x, int y, PowerConduit cable)
{
if (cable == null)
PowerCables.Remove(x, y);
@@ -510,7 +512,7 @@ public static void SetPowerCable(int x, int y, PowerConduit cable)
// Powernet Interactors
//======================
- public static List GetPowernetInteractors(int x, int y)
+ public List GetPowernetInteractors(int x, int y)
{
return PowernetInteractors.Get(x, y) ?? new List() { };
}
@@ -518,7 +520,7 @@ public static List GetPowernetInteractors(int x, int y)
///
/// Add an structure to the world list
///
- public static void AddPowernetInteractor(int x, int y, PowernetInteractor interactor)
+ public void AddPowernetInteractor(int x, int y, PowernetInteractor interactor)
{
List located = PowernetInteractors.Get(x, y);
if (located != null)
@@ -537,7 +539,7 @@ public static void AddPowernetInteractor(int x, int y, PowernetInteractor intera
///
/// Remove the istructuretem from the world list
///
- public static bool RemovePowernetInteractor(int x, int y, PowernetInteractor interactor)
+ public bool RemovePowernetInteractor(int x, int y, PowernetInteractor interactor)
{
List located = PowernetInteractors.Get(x, y);
if (located == null)
@@ -555,7 +557,7 @@ public static bool RemovePowernetInteractor(int x, int y, PowernetInteractor int
///
/// Get the area at the specified location.
///
- public static Area GetArea(int x, int y)
+ public Area GetArea(int x, int y)
{
return WorldAreas.Get(x, y);
}
@@ -563,7 +565,7 @@ public static Area GetArea(int x, int y)
///
/// Set the area at the specified location
///
- public static void SetArea(int x, int y, Area area)
+ public void SetArea(int x, int y, Area area)
{
if (area == null)
WorldAreas.Remove(x, y);
@@ -578,7 +580,7 @@ public static void SetArea(int x, int y, Area area)
///
/// Get the turf at the specified location.
///
- public static Marker GetMarker(int x, int y)
+ public Marker GetMarker(int x, int y)
{
return WorldMarkers.Get(x, y);
}
@@ -586,7 +588,7 @@ public static Marker GetMarker(int x, int y)
///
/// Set the turfs
///
- public static void SetMarker(int x, int y, Marker marker)
+ public void SetMarker(int x, int y, Marker marker)
{
if (marker == null)
WorldMarkers.Remove(x, y);
@@ -601,7 +603,7 @@ public static void SetMarker(int x, int y, Marker marker)
///
/// Get the turf at the specified location.
///
- public static Turf GetTurf(int x, int y)
+ public Turf GetTurf(int x, int y)
{
return WorldTurfs.Get(x, y);
}
@@ -609,7 +611,7 @@ public static Turf GetTurf(int x, int y)
///
/// Set the turfs
///
- public static void SetTurf(int x, int y, Turf turf)
+ public void SetTurf(int x, int y, Turf turf)
{
if (turf == null)
WorldTurfs.Remove(x, y);
@@ -621,12 +623,12 @@ public static void SetTurf(int x, int y, Turf turf)
// Surrounded detected
//======================
- public static bool IsLocationFullyEnclosed(int x, int y)
+ public bool IsLocationFullyEnclosed(int x, int y)
{
return IsSolid(x, y + 1) && IsSolid(x + 1, y) && IsSolid(x, y - 1) && IsSolid(x - 1, y);
}
- public static Vector? GetFreeAdjacentLocation(int x, int y)
+ public Vector? GetFreeAdjacentLocation(int x, int y)
{
if (!IsSolid(x, y + 1))
return new Vector(x, y + 1);
@@ -643,7 +645,7 @@ public static bool IsLocationFullyEnclosed(int x, int y)
// Solidity
//======================
- public static bool IsSolid(Vector position)
+ public bool IsSolid(Vector position)
{
return IsSolid(position.X, position.Y);
}
@@ -651,7 +653,7 @@ public static bool IsSolid(Vector position)
///
/// Check if a position is solid or not
///
- public static bool IsSolid(int x, int y)
+ public bool IsSolid(int x, int y)
{
Turf locatedTurf = GetTurf(x, y);
//TODO: Proper ISolid + directional solidity
@@ -662,12 +664,12 @@ public static bool IsSolid(int x, int y)
// Gravity
//======================
- public static bool HasGravity(Vector position)
+ public bool HasGravity(Vector position)
{
return HasGravity(position.X, position.Y);
}
- public static bool HasGravity(int x, int y)
+ public bool HasGravity(int x, int y)
{
//Structure = gravity
if (GetStructures(x, y).Count > 0)
diff --git a/GJ2022/Game/Power/Powernet.cs b/GJ2022/Game/Power/Powernet.cs
index bee1f20..3240ec4 100644
--- a/GJ2022/Game/Power/Powernet.cs
+++ b/GJ2022/Game/Power/Powernet.cs
@@ -77,7 +77,7 @@ public void Adopt(Powernet powernet)
conduit.attachedTextObject.Text = $"{PowernetId}";
conduits.Add(conduit);
//Update attached powernets
- foreach (PowernetInteractor interactor in World.GetPowernetInteractors((int)conduit.Position.X, (int)conduit.Position.Y))
+ foreach (PowernetInteractor interactor in World.Current.GetPowernetInteractors((int)conduit.Position.X, (int)conduit.Position.Y))
{
interactor.AttachedPowernet = this;
}
diff --git a/GJ2022/Managers/Stockpile/StockpileManager.cs b/GJ2022/Managers/Stockpile/StockpileManager.cs
index 7974686..153d0b6 100644
--- a/GJ2022/Managers/Stockpile/StockpileManager.cs
+++ b/GJ2022/Managers/Stockpile/StockpileManager.cs
@@ -58,7 +58,7 @@ public static Item LocateItemInStockpile(Type wantedType)
public static void AddStockpileArea(Vector position)
{
//Add all items at this position to the stockpile
- foreach (Item item in World.GetItems((int)position.X, (int)position.Y))
+ foreach (Item item in World.Current.GetItems((int)position.X, (int)position.Y))
{
AddItem(item);
}
@@ -66,7 +66,7 @@ public static void AddStockpileArea(Vector position)
public static void RemoveStockpileArea(Vector position)
{
- foreach (Item item in World.GetItems((int)position.X, (int)position.Y))
+ foreach (Item item in World.Current.GetItems((int)position.X, (int)position.Y))
{
RemoveItem(item);
}
diff --git a/GJ2022/PawnBehaviours/PawnActions/HaulItems.cs b/GJ2022/PawnBehaviours/PawnActions/HaulItems.cs
index e18e9cc..947ecee 100644
--- a/GJ2022/PawnBehaviours/PawnActions/HaulItems.cs
+++ b/GJ2022/PawnBehaviours/PawnActions/HaulItems.cs
@@ -46,21 +46,21 @@ public override bool CanPerform(PawnBehaviour parent)
{
if (parent.Owner.InCrit)
return false;
- if (World.HasAreaInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (Area area) =>
+ if (World.Current.HasAreaInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (Area area) =>
{
if (unreachablePositions.Contains(area.Position))
return false;
- if (World.GetThings("Stockpile", (int)area.Position.X, (int)area.Position.Y).Count > 0)
+ if (World.Current.GetThings("Stockpile", (int)area.Position.X, (int)area.Position.Y).Count > 0)
return false;
return true;
})
- && World.HasItemsInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (List
- toCheck) =>
+ && World.Current.HasItemsInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (List
- toCheck) =>
{
foreach (Item item in toCheck)
{
if (unreachablePositions.Contains(item.Position))
continue;
- if (World.GetThings("Stockpile", (int)item.Position.X, (int)item.Position.Y).Count > 0)
+ if (World.Current.GetThings("Stockpile", (int)item.Position.X, (int)item.Position.Y).Count > 0)
continue;
return true;
}
@@ -166,7 +166,7 @@ private void GracefullyDeliver(PawnBehaviour parent)
StoreHeldItems(parent);
}
//Check if the claimed area location is still empty
- else if (World.GetItems((int)claimedArea.Position.X, (int)claimedArea.Position.Y).Count > 0)
+ else if (World.Current.GetItems((int)claimedArea.Position.X, (int)claimedArea.Position.Y).Count > 0)
{
//Redeliver items
StoreHeldItems(parent);
@@ -193,7 +193,7 @@ private void LocateOrStoreItems(PawnBehaviour parent)
return;
}
//Attempt to locate items
- List
- itemsToSearch = World.GetSprialItems((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40);
+ List
- itemsToSearch = World.Current.GetSprialItems((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40);
Item targetItem = null;
if (forcedTarget == null)
{
@@ -211,7 +211,7 @@ private void LocateOrStoreItems(PawnBehaviour parent)
continue;
//Check if the item
//is in a stockpile, if it is, skip it
- if (World.GetThings("Stockpile", (int)item.Position.X, (int)item.Position.Y).Count > 0)
+ if (World.Current.GetThings("Stockpile", (int)item.Position.X, (int)item.Position.Y).Count > 0)
continue;
//Looks like the item is valid!
targetItem = item;
@@ -220,7 +220,7 @@ private void LocateOrStoreItems(PawnBehaviour parent)
}
else
{
- if (!forcedTarget.IsClaimed && forcedTarget.Location == null && !unreachablePositions.Contains(forcedTarget.Position) && World.GetThings("Stockpile", (int)forcedTarget.Position.X, (int)forcedTarget.Position.Y).Count == 0)
+ if (!forcedTarget.IsClaimed && forcedTarget.Location == null && !unreachablePositions.Contains(forcedTarget.Position) && World.Current.GetThings("Stockpile", (int)forcedTarget.Position.X, (int)forcedTarget.Position.Y).Count == 0)
targetItem = forcedTarget;
}
//No item was located
@@ -257,7 +257,7 @@ private void StoreHeldItems(PawnBehaviour parent)
}
Area freeStockpileArea = null;
//Extend range for forced haul
- foreach (Area area in World.GetSpiralThings("Stockpile", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, forcedTarget == null ? 60 : 120))
+ foreach (Area area in World.Current.GetSpiralThings("Stockpile", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, forcedTarget == null ? 60 : 120))
{
//If the area is claimed, skip it
if (area.IsClaimed)
@@ -266,7 +266,7 @@ private void StoreHeldItems(PawnBehaviour parent)
if (unreachablePositions.Contains(area.Position))
continue;
//If the area has items in it, skip it
- if (World.GetItems((int)area.Position.X, (int)area.Position.Y).Count > 0)
+ if (World.Current.GetItems((int)area.Position.X, (int)area.Position.Y).Count > 0)
continue;
//A good stockpile area
freeStockpileArea = area;
diff --git a/GJ2022/PawnBehaviours/PawnActions/MineAction.cs b/GJ2022/PawnBehaviours/PawnActions/MineAction.cs
index 6302d56..372c391 100644
--- a/GJ2022/PawnBehaviours/PawnActions/MineAction.cs
+++ b/GJ2022/PawnBehaviours/PawnActions/MineAction.cs
@@ -31,7 +31,7 @@ public override bool CanPerform(PawnBehaviour parent)
if (parent.Owner.InCrit)
return false;
//Quick check
- return World.HasMarkerInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 60, (Marker toCheck) =>
+ return World.Current.HasMarkerInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 60, (Marker toCheck) =>
{
return !unreachableLocations.Contains(toCheck.Position);
});
@@ -64,7 +64,7 @@ public override void OnActionStart(PawnBehaviour parent)
return;
}
//Go towards the blueprint
- Vector? targetPosition = World.GetFreeAdjacentLocation((int)target.Position.X, (int)target.Position.Y);
+ Vector? targetPosition = World.Current.GetFreeAdjacentLocation((int)target.Position.X, (int)target.Position.Y);
if (targetPosition != null)
parent.Owner.MoveTowardsPosition(targetPosition.Value);
else
@@ -111,7 +111,7 @@ public override void PerformProcess(PawnBehaviour parent)
///
private MiningMarker LocateValidMarker(PawnBehaviour parent)
{
- foreach (Marker marker in World.GetSprialMarkers((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 60))
+ foreach (Marker marker in World.Current.GetSprialMarkers((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 60))
{
if (!(marker is MiningMarker))
continue;
@@ -122,7 +122,7 @@ private MiningMarker LocateValidMarker(PawnBehaviour parent)
if (marker.IsClaimed || marker.Destroyed)
continue;
//Is the marker completed surrounded?
- if (World.IsLocationFullyEnclosed((int)marker.Position.X, (int)marker.Position.Y))
+ if (World.Current.IsLocationFullyEnclosed((int)marker.Position.X, (int)marker.Position.Y))
continue;
//Return the marker
return marker as MiningMarker;
diff --git a/GJ2022/PawnBehaviours/PawnActions/SmeltOre.cs b/GJ2022/PawnBehaviours/PawnActions/SmeltOre.cs
index 7b6d1dc..d90b7fc 100644
--- a/GJ2022/PawnBehaviours/PawnActions/SmeltOre.cs
+++ b/GJ2022/PawnBehaviours/PawnActions/SmeltOre.cs
@@ -34,7 +34,7 @@ public override bool CanPerform(PawnBehaviour parent)
{
if (parent.Owner.InCrit)
return false;
- if (World.HasThingInRange("Furnace", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 20, (List area) =>
+ if (World.Current.HasThingInRange("Furnace", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 20, (List area) =>
{
foreach (IComponentHandler structure in area)
{
@@ -46,7 +46,7 @@ public override bool CanPerform(PawnBehaviour parent)
}
return false;
})
- && World.HasItemsInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (List
- toCheck) =>
+ && World.Current.HasItemsInRange((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40, (List
- toCheck) =>
{
foreach (Item item in toCheck)
{
@@ -183,7 +183,7 @@ public override void PerformProcess(PawnBehaviour parent)
private Entity LocateValidFurnace(PawnBehaviour parent)
{
- foreach (Entity structure in World.GetSpiralThings("Furnace", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 20))
+ foreach (Entity structure in World.Current.GetSpiralThings("Furnace", (int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 20))
{
//If we marked this location as unreachable, ignore it.
if (unreachableLocations.Contains(structure.Position))
@@ -205,7 +205,7 @@ private Entity LocateValidFurnace(PawnBehaviour parent)
///
private IronOre LocateMaterials(PawnBehaviour parent)
{
- foreach (Item item in World.GetSprialItems((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40))
+ foreach (Item item in World.Current.GetSprialItems((int)parent.Owner.Position.X, (int)parent.Owner.Position.Y, 40))
{
//If we marked this location as unreachable, ignore it.
if (unreachableLocations.Contains(item.Position))
diff --git a/GJ2022/Subsystems/AtmosphericsSystem.cs b/GJ2022/Subsystems/AtmosphericsSystem.cs
index 03b8d14..dbad14d 100644
--- a/GJ2022/Subsystems/AtmosphericsSystem.cs
+++ b/GJ2022/Subsystems/AtmosphericsSystem.cs
@@ -52,20 +52,20 @@ public override void Fire(Window window)
public void OnTurfDestroyed(Turf destroyedTurf)
{
//Do nothing if nothing changed.
- if (!destroyedTurf.AllowAtmosphericFlow && !World.AllowsAtmosphericFlow(destroyedTurf.X, destroyedTurf.Y))
+ if (!destroyedTurf.AllowAtmosphericFlow && !World.Current.AllowsAtmosphericFlow(destroyedTurf.X, destroyedTurf.Y))
return;
List blocksToClear = new List();
//If we didn't allow atmospheric flow, collect all surrounding atmospheres and merge them with null
if (!destroyedTurf.AllowAtmosphericFlow)
{
AtmosphericBlock atmos;
- if ((atmos = World.GetTurf(destroyedTurf.X, destroyedTurf.Y + 1).Atmosphere) != null && !blocksToClear.Contains(atmos))
+ if ((atmos = World.Current.GetTurf(destroyedTurf.X, destroyedTurf.Y + 1).Atmosphere) != null && !blocksToClear.Contains(atmos))
blocksToClear.Add(atmos);
- if ((atmos = World.GetTurf(destroyedTurf.X + 1, destroyedTurf.Y).Atmosphere) != null && !blocksToClear.Contains(atmos))
+ if ((atmos = World.Current.GetTurf(destroyedTurf.X + 1, destroyedTurf.Y).Atmosphere) != null && !blocksToClear.Contains(atmos))
blocksToClear.Add(atmos);
- if ((atmos = World.GetTurf(destroyedTurf.X, destroyedTurf.Y - 1).Atmosphere) != null && !blocksToClear.Contains(atmos))
+ if ((atmos = World.Current.GetTurf(destroyedTurf.X, destroyedTurf.Y - 1).Atmosphere) != null && !blocksToClear.Contains(atmos))
blocksToClear.Add(atmos);
- if ((atmos = World.GetTurf(destroyedTurf.X - 1, destroyedTurf.Y).Atmosphere) != null && !blocksToClear.Contains(atmos))
+ if ((atmos = World.Current.GetTurf(destroyedTurf.X - 1, destroyedTurf.Y).Atmosphere) != null && !blocksToClear.Contains(atmos))
blocksToClear.Add(atmos);
}
else
@@ -88,19 +88,19 @@ public void OnAtmosBlockingChange(int x, int y, bool flowBlocked)
AtmosphericBlock atmos;
Turf turf;
bool spaceAdjacent = false;
- if ((atmos = (turf = World.GetTurf(x, y + 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(x, y + 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(x + 1, y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(x + 1, y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(x, y - 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(x, y - 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(x - 1, y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(x - 1, y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- Turf locatedTurf = World.GetTurf(x, y);
+ Turf locatedTurf = World.Current.GetTurf(x, y);
//At this point if located turf is null, we don't need to do anything else
if (locatedTurf == null)
return;
@@ -137,7 +137,7 @@ public void OnAtmosBlockingChange(int x, int y, bool flowBlocked)
else
{
//Atmos flow allowed -> disallowed
- Turf locatedTurf = World.GetTurf(x, y);
+ Turf locatedTurf = World.Current.GetTurf(x, y);
if (locatedTurf != null)
{
if (locatedTurf.Atmosphere != null)
@@ -146,13 +146,13 @@ public void OnAtmosBlockingChange(int x, int y, bool flowBlocked)
}
//Generate new atmospheric blocks
Turf turf;
- if ((turf = World.GetTurf(x + 1, y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(x + 1, y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(x + 1, y, turf);
- if ((turf = World.GetTurf(x, y + 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(x, y + 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(x, y + 1, turf);
- if ((turf = World.GetTurf(x - 1, y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(x - 1, y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(x - 1, y, turf);
- if ((turf = World.GetTurf(x, y - 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(x, y - 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(x, y - 1, turf);
}
}
@@ -161,7 +161,7 @@ public void OnAtmosBlockingChange(int x, int y, bool flowBlocked)
public void OnTurfChanged(Turf oldTurf, Turf newTurf)
{
//atmos flow is allowed in the new location if the new turf allows flow and the world allows flow
- bool newAtmosphericFlowAllowed = newTurf.AllowAtmosphericFlow && World.AllowsAtmosphericFlow(newTurf.X, newTurf.Y);
+ bool newAtmosphericFlowAllowed = newTurf.AllowAtmosphericFlow && World.Current.AllowsAtmosphericFlow(newTurf.X, newTurf.Y);
//Atmosflow allowed => allowed - inherit the old turfs atmosphere
if (oldTurf.AllowAtmosphericFlow && newAtmosphericFlowAllowed)
{
@@ -178,13 +178,13 @@ public void OnTurfChanged(Turf oldTurf, Turf newTurf)
//The new atmosphere created by processing delta needs to get the air from the old atmosphere
oldTurf.Atmosphere?.RemoveTurf(oldTurf);
Turf turf;
- if ((turf = World.GetTurf(newTurf.X + 1, newTurf.Y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(newTurf.X + 1, newTurf.Y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(newTurf.X + 1, newTurf.Y, turf);
- if ((turf = World.GetTurf(newTurf.X, newTurf.Y + 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(newTurf.X, newTurf.Y + 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(newTurf.X, newTurf.Y + 1, turf);
- if ((turf = World.GetTurf(newTurf.X - 1, newTurf.Y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(newTurf.X - 1, newTurf.Y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(newTurf.X - 1, newTurf.Y, turf);
- if ((turf = World.GetTurf(newTurf.X, newTurf.Y - 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(newTurf.X, newTurf.Y - 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(newTurf.X, newTurf.Y - 1, turf);
}
//Atmosflow disallowed => allowed - Merge surrounding atmospheres
@@ -196,16 +196,16 @@ public void OnTurfChanged(Turf oldTurf, Turf newTurf)
AtmosphericBlock atmos;
Turf turf;
bool spaceAdjacent = false;
- if ((atmos = (turf = World.GetTurf(newTurf.X, newTurf.Y + 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(newTurf.X, newTurf.Y + 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(newTurf.X + 1, newTurf.Y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(newTurf.X + 1, newTurf.Y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(newTurf.X, newTurf.Y - 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(newTurf.X, newTurf.Y - 1))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
- if ((atmos = (turf = World.GetTurf(newTurf.X - 1, newTurf.Y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
+ if ((atmos = (turf = World.Current.GetTurf(newTurf.X - 1, newTurf.Y))?.Atmosphere) != null && !blocksToMerge.Contains(atmos))
blocksToMerge.Add(atmos);
spaceAdjacent = spaceAdjacent || turf == null || (turf.AllowAtmosphericFlow && atmos == null);
//Merge all surrounding atmospheres into 1
@@ -248,13 +248,13 @@ public void OnTurfCreated(Turf createdTurf)
if (!createdTurf.AllowAtmosphericFlow)
{
Turf turf;
- if ((turf = World.GetTurf(createdTurf.X + 1, createdTurf.Y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(createdTurf.X + 1, createdTurf.Y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(createdTurf.X + 1, createdTurf.Y, turf);
- if ((turf = World.GetTurf(createdTurf.X, createdTurf.Y + 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(createdTurf.X, createdTurf.Y + 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(createdTurf.X, createdTurf.Y + 1, turf);
- if ((turf = World.GetTurf(createdTurf.X - 1, createdTurf.Y)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(createdTurf.X - 1, createdTurf.Y)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(createdTurf.X - 1, createdTurf.Y, turf);
- if ((turf = World.GetTurf(createdTurf.X, createdTurf.Y - 1)) != null && turf.AllowAtmosphericFlow)
+ if ((turf = World.Current.GetTurf(createdTurf.X, createdTurf.Y - 1)) != null && turf.AllowAtmosphericFlow)
processingDeltas.Add(createdTurf.X, createdTurf.Y - 1, turf);
}
//If the new turf allows atmospheric flow then add it to the processing queue
@@ -278,10 +278,10 @@ public void OnTurfCreated(Turf createdTurf)
private AtmosphericBlock FindMergeBlock(Turf createdTurf)
{
//Get surrounding turfs
- Turf above = World.GetTurf(createdTurf.X, createdTurf.Y + 1);
- Turf right = World.GetTurf(createdTurf.X + 1, createdTurf.Y);
- Turf below = World.GetTurf(createdTurf.X, createdTurf.Y - 1);
- Turf left = World.GetTurf(createdTurf.X - 1, createdTurf.Y);
+ Turf above = World.Current.GetTurf(createdTurf.X, createdTurf.Y + 1);
+ Turf right = World.Current.GetTurf(createdTurf.X + 1, createdTurf.Y);
+ Turf below = World.Current.GetTurf(createdTurf.X, createdTurf.Y - 1);
+ Turf left = World.Current.GetTurf(createdTurf.X - 1, createdTurf.Y);
//Check invalid
//If any turf is null, then atmos will be null
if (above == null || right == null || below == null || left == null)
@@ -334,7 +334,7 @@ private void ProcessDelta(int x, int y, Turf processing)
//Get the tile we should search
Vector searchTile = searchRadiusEdgeTiles.Dequeue();
//Check this tile
- Turf locatedTurf = World.GetTurf(searchTile[0], searchTile[1]);
+ Turf locatedTurf = World.Current.GetTurf(searchTile[0], searchTile[1]);
//If space, then we lose all of our gas and atmosphere :(
if (locatedTurf == null)
{
@@ -355,25 +355,25 @@ private void ProcessDelta(int x, int y, Turf processing)
}
//Add surrounding tiles that allow gas flow
//Check north
- if (World.AllowsAtmosphericFlow(searchTile[0], searchTile[1] + 1) && !searchedTiles.Get(searchTile[0], searchTile[1] + 1))
+ if (World.Current.AllowsAtmosphericFlow(searchTile[0], searchTile[1] + 1) && !searchedTiles.Get(searchTile[0], searchTile[1] + 1))
{
searchedTiles.Add(searchTile[0], searchTile[1] + 1, true);
searchRadiusEdgeTiles.Enqueue(new Vector(searchTile[0], searchTile[1] + 1));
}
//Check east
- if (World.AllowsAtmosphericFlow(searchTile[0] + 1, searchTile[1]) && !searchedTiles.Get(searchTile[0] + 1, searchTile[1]))
+ if (World.Current.AllowsAtmosphericFlow(searchTile[0] + 1, searchTile[1]) && !searchedTiles.Get(searchTile[0] + 1, searchTile[1]))
{
searchedTiles.Add(searchTile[0] + 1, searchTile[1], true);
searchRadiusEdgeTiles.Enqueue(new Vector(searchTile[0] + 1, searchTile[1]));
}
//Check south
- if (World.AllowsAtmosphericFlow(searchTile[0], searchTile[1] - 1) && !searchedTiles.Get(searchTile[0], searchTile[1] - 1))
+ if (World.Current.AllowsAtmosphericFlow(searchTile[0], searchTile[1] - 1) && !searchedTiles.Get(searchTile[0], searchTile[1] - 1))
{
searchedTiles.Add(searchTile[0], searchTile[1] - 1, true);
searchRadiusEdgeTiles.Enqueue(new Vector(searchTile[0], searchTile[1] - 1));
}
//Check west
- if (World.AllowsAtmosphericFlow(searchTile[0] - 1, searchTile[1]) && !searchedTiles.Get(searchTile[0] - 1, searchTile[1]))
+ if (World.Current.AllowsAtmosphericFlow(searchTile[0] - 1, searchTile[1]) && !searchedTiles.Get(searchTile[0] - 1, searchTile[1]))
{
searchedTiles.Add(searchTile[0] - 1, searchTile[1], true);
searchRadiusEdgeTiles.Enqueue(new Vector(searchTile[0] - 1, searchTile[1]));
diff --git a/GJ2022/Subsystems/MouseCollisionSubsystem.cs b/GJ2022/Subsystems/MouseCollisionSubsystem.cs
index 85f197c..4606196 100644
--- a/GJ2022/Subsystems/MouseCollisionSubsystem.cs
+++ b/GJ2022/Subsystems/MouseCollisionSubsystem.cs
@@ -85,7 +85,7 @@ public override void Fire(Window window)
int x = worldTile[0];
int y = worldTile[1];
//Get clickable things at these world coordinates
- foreach (Entity entity in World.GetEntities(x, y))
+ foreach (Entity entity in World.Current.GetEntities(x, y))
{
if (mousePressed)
(entity as IMousePress)?.OnPressed();
diff --git a/GJ2022/Subsystems/PathfindingSystem.cs b/GJ2022/Subsystems/PathfindingSystem.cs
index d7f6332..0be7e4b 100644
--- a/GJ2022/Subsystems/PathfindingSystem.cs
+++ b/GJ2022/Subsystems/PathfindingSystem.cs
@@ -85,13 +85,13 @@ public static void ProcessPathImmediate(Vector start, Vector end)
private void ProcessPath(PathfindingRequest request)
{
//If the end of the request is blocked, don't both
- if (World.IsSolid(request.End))
+ if (World.Current.IsSolid(request.End))
{
request.failedDelegate?.Invoke();
return;
}
//If the start has no pressure and the end does, allow low-pressure pathfinding
- Atmosphere startAtmos = World.GetTurf(request.Start[0], request.Start[1])?.Atmosphere?.ContainedAtmosphere;
+ Atmosphere startAtmos = World.Current.GetTurf(request.Start[0], request.Start[1])?.Atmosphere?.ContainedAtmosphere;
if (startAtmos == null || startAtmos.KiloPascalPressure < 50)
{
request.ignoringHazards |= PawnHazards.HAZARD_LOW_PRESSURE;
@@ -145,13 +145,13 @@ private void AddSurroundingNodes(PathNode current, PawnHazards ignoringHazards,
CheckAddNode(current, ref processData, new Vector(0, -1), ConnectingDirections.SOUTH);
if ((validDirections & ConnectingDirections.WEST) != 0)
CheckAddNode(current, ref processData, new Vector(-1, 0), ConnectingDirections.WEST);
- if ((validDirections & ConnectingDirections.NORTH_EAST) == ConnectingDirections.NORTH_EAST && !World.IsSolid(current.Position + new Vector(1, 1)))
+ if ((validDirections & ConnectingDirections.NORTH_EAST) == ConnectingDirections.NORTH_EAST && !World.Current.IsSolid(current.Position + new Vector(1, 1)))
CheckAddNode(current, ref processData, new Vector(1, 1), ConnectingDirections.NORTH_EAST);
- if ((validDirections & ConnectingDirections.SOUTH_EAST) == ConnectingDirections.SOUTH_EAST && !World.IsSolid(current.Position + new Vector(1, -1)))
+ if ((validDirections & ConnectingDirections.SOUTH_EAST) == ConnectingDirections.SOUTH_EAST && !World.Current.IsSolid(current.Position + new Vector(1, -1)))
CheckAddNode(current, ref processData, new Vector(1, -1), ConnectingDirections.SOUTH_EAST);
- if ((validDirections & ConnectingDirections.SOUTH_WEST) == ConnectingDirections.SOUTH_WEST && !World.IsSolid(current.Position + new Vector(-1, -1)))
+ if ((validDirections & ConnectingDirections.SOUTH_WEST) == ConnectingDirections.SOUTH_WEST && !World.Current.IsSolid(current.Position + new Vector(-1, -1)))
CheckAddNode(current, ref processData, new Vector(-1, -1), ConnectingDirections.SOUTH_WEST);
- if ((validDirections & ConnectingDirections.NORTH_WEST) == ConnectingDirections.NORTH_WEST && !World.IsSolid(current.Position + new Vector(-1, 1)))
+ if ((validDirections & ConnectingDirections.NORTH_WEST) == ConnectingDirections.NORTH_WEST && !World.Current.IsSolid(current.Position + new Vector(-1, 1)))
CheckAddNode(current, ref processData, new Vector(-1, 1), ConnectingDirections.NORTH_WEST);
}
@@ -202,25 +202,25 @@ private ConnectingDirections GetValidDirections(PathfindingProcessData processDa
//Check north
if (!IsPointChecked(processData, position + new Vector(0, 1), ConnectingDirections.NORTH_SOUTH, ignoringHazards)
&& position.Y < processData.MaximumY
- && !World.IsSolid(position + new Vector(0, 1))
+ && !World.Current.IsSolid(position + new Vector(0, 1))
&& HazardCheck(ignoringHazards, position, source, ConnectingDirections.NORTH))
connectingDirections |= ConnectingDirections.NORTH;
//Check east
if (!IsPointChecked(processData, position + new Vector(1, 0), ConnectingDirections.EAST_WEST, ignoringHazards)
&& position.X < processData.MaximumX
- && !World.IsSolid(position + new Vector(1, 0))
+ && !World.Current.IsSolid(position + new Vector(1, 0))
&& HazardCheck(ignoringHazards, position, source, ConnectingDirections.EAST))
connectingDirections |= ConnectingDirections.EAST;
//Check south
if (!IsPointChecked(processData, position + new Vector(0, -1), ConnectingDirections.NORTH_SOUTH, ignoringHazards)
&& position.Y > processData.MinimumY
- && !World.IsSolid(position + new Vector(0, -1))
+ && !World.Current.IsSolid(position + new Vector(0, -1))
&& HazardCheck(ignoringHazards, position, source, ConnectingDirections.SOUTH))
connectingDirections |= ConnectingDirections.SOUTH;
//Check west
if (!IsPointChecked(processData, position + new Vector(-1, 0), ConnectingDirections.EAST_WEST, ignoringHazards)
&& position.X > processData.MinimumX
- && !World.IsSolid(position + new Vector(-1, 0))
+ && !World.Current.IsSolid(position + new Vector(-1, 0))
&& HazardCheck(ignoringHazards, position, source, ConnectingDirections.WEST))
connectingDirections |= ConnectingDirections.WEST;
//Return valid directions
@@ -236,7 +236,7 @@ private bool IsPointChecked(PathfindingProcessData processData, Vector posi
if (!processData.ProcessedPoints.ContainsKey(position))
return false;
//If this location has gravity, then we checked it
- if (World.HasGravity(position))
+ if (World.Current.HasGravity(position))
return true;
//Check if we have scanned the incomming direction
ConnectingDirections scannedDirections = processData.ProcessedPoints[position];
@@ -254,7 +254,7 @@ private bool LowPressureCheck(PawnHazards ignoringHazards, Vector position,
if ((ignoringHazards & PawnHazards.HAZARD_LOW_PRESSURE) != 0)
return true;
//Check for pressure (50 should be safe)
- return World.GetTurf(position.X, position.Y)?.Atmosphere?.ContainedAtmosphere?.KiloPascalPressure > 50;
+ return World.Current.GetTurf(position.X, position.Y)?.Atmosphere?.ContainedAtmosphere?.KiloPascalPressure > 50;
}
private bool BreathCheck(PawnHazards ignoringHazards, Vector position, Vector source, ConnectingDirections direction)
@@ -263,7 +263,7 @@ private bool BreathCheck(PawnHazards ignoringHazards, Vector position, Vect
if ((ignoringHazards & PawnHazards.HAZARD_BREATH) != 0)
return true;
//Check air
- if (World.GetTurf(position.X, position.Y)?.Atmosphere?.ContainedAtmosphere?.GetMoles(Oxygen.Singleton) > 0.02f)
+ if (World.Current.GetTurf(position.X, position.Y)?.Atmosphere?.ContainedAtmosphere?.GetMoles(Oxygen.Singleton) > 0.02f)
return true;
//Area has no air
return false;
@@ -275,7 +275,7 @@ private bool GravityCheck(PawnHazards ignoringHazards, Vector position, Vec
if ((ignoringHazards & PawnHazards.HAZARD_GRAVITY) != 0)
return true;
//Place has gravity
- if (World.HasGravity(position))
+ if (World.Current.HasGravity(position))
return true;
//We can move in a straight line without gravity
int delta_x = position.X - source[0];
diff --git a/GJ2022/Subsystems/PawnControllerSystem.cs b/GJ2022/Subsystems/PawnControllerSystem.cs
index 6c7aa7f..8f2a835 100644
--- a/GJ2022/Subsystems/PawnControllerSystem.cs
+++ b/GJ2022/Subsystems/PawnControllerSystem.cs
@@ -30,7 +30,7 @@ public void SelectPawn(Pawn target)
public static void QueueBlueprint(Vector position, Blueprint blueprint, int layer)
{
//Check if the blueprint is redundant
- if (World.GetTurf((int)position.X, (int)position.Y)?.GetType() == blueprint.BlueprintDetail.CreatedType)
+ if (World.Current.GetTurf((int)position.X, (int)position.Y)?.GetType() == blueprint.BlueprintDetail.CreatedType)
{
blueprint.Destroy();
return;
diff --git a/GJ2022/Subsystems/Subsystem.cs b/GJ2022/Subsystems/Subsystem.cs
index f460fb2..19c9d7c 100644
--- a/GJ2022/Subsystems/Subsystem.cs
+++ b/GJ2022/Subsystems/Subsystem.cs
@@ -182,7 +182,7 @@ private void Update(Window window)
stopwatch = new Stopwatch();
stopwatch.Start();
//Check if the world has been initialized yet.
- if (/*World.Initialized*/ true)
+ if (/*World.Current.Initialized*/ true)
{
//Check the subsystem fires.
if ((SubsystemFlags & SubsystemFlags.NO_FIRE) == 0)
diff --git a/GJ2022/UserInterface/UserInterfaceCreator.cs b/GJ2022/UserInterface/UserInterfaceCreator.cs
index 1c84ed7..29498ad 100644
--- a/GJ2022/UserInterface/UserInterfaceCreator.cs
+++ b/GJ2022/UserInterface/UserInterfaceCreator.cs
@@ -99,9 +99,9 @@ public static void CreateUserInterface()
CreateEntitySpawnDD();
},
() => {
- foreach(string key in World.TrackedComponentHandlers.Keys)
+ foreach(string key in World.Current.TrackedComponentHandlers.Keys)
{
- Log.WriteLine($"{key} => {World.TrackedComponentHandlers[key]}", LogType.DEBUG);
+ Log.WriteLine($"{key} => {World.Current.TrackedComponentHandlers[key]}", LogType.DEBUG);
}
},
});
From ce34c4ac0fbac51542c343de10b65b8d0b917a2f Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Fri, 18 Mar 2022 21:22:19 +0000
Subject: [PATCH 14/16] Updates the unit tests, fixes some namespace auto
replace issues.
---
GJ2022.Tests/RegionTests.cs | 72 +++++++++++++++-
GJ2022/Game/GameWorld/Regions/Region.cs | 6 +-
.../Game/GameWorld/Regions/WorldRegionList.cs | 85 +++++++++++++++++--
3 files changed, 153 insertions(+), 10 deletions(-)
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index ace0183..14e5da5 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -1,6 +1,6 @@
using GJ2022.Entities.Turfs;
using GJ2022.Game.GameWorld;
-using GJ2022.Game.GameWorld.Current.Regions;
+using GJ2022.Game.GameWorld.Regions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
@@ -14,6 +14,72 @@ namespace GJ2022.Tests
public class RegionTests
{
+ [TestMethod]
+ public void TestValidPathThatGetsBlocked()
+ {
+ //Reset the world
+ World.Current = new World();
+ //Generate a wall with a hole in it
+ Turf solidTurf = new Turf();
+ solidTurf.SetProperty("Solid", true);
+ World.Current.SetTurf(13, 0, solidTurf);
+ World.Current.SetTurf(13, 1, solidTurf);
+ World.Current.SetTurf(13, 2, solidTurf);
+ World.Current.SetTurf(13, 3, solidTurf);
+ World.Current.SetTurf(13, 5, solidTurf);
+ World.Current.SetTurf(13, 6, solidTurf);
+ World.Current.SetTurf(13, 7, solidTurf);
+ //Create a world region list
+ WorldRegionList wrl = new WorldRegionList();
+ wrl.GenerateWorldSection(0, 0);
+ wrl.GenerateWorldSection(8, 0);
+ wrl.GenerateWorldSection(16, 0);
+ //Test accessability
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(5, 5)), "There should exist a valid path from region (0, 0) to (5, 5)");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(10, 5)), "There should exist a valid path from region (0, 0) to (10, 5)");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(14, 5)), "There should exist a valid path from region (0, 0) to (14, 5)");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(18, 5)), "There should exist a valid path from region (0, 0) to (18, 5)");
+ Assert.IsTrue(wrl.regions.Get(14, 5).HasPath(wrl.regions.Get(18, 5)), "There should exist a valid path from region (14, 5) to (18, 5)");
+ //Block off the wall
+ World.Current.SetTurf(13, 4, solidTurf);
+ wrl.SetNodeSolid(13, 4);
+ Log.WriteLine("World has been divided");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(5, 5)), "There should still exist a valid path from region (0, 0) to (5, 5)");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(10, 5)), "There should still exist a valid path from region (0, 0) to (10, 5)");
+ Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(14, 5)), "There should no longer exist a valid path from region (0, 0) to (14, 5)");
+ Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(18, 5)), "There should no longer exist a valid path from region (0, 0) to (18, 5)");
+ Assert.IsTrue(wrl.regions.Get(14, 5).HasPath(wrl.regions.Get(18, 5)), "There should still exist a valid path from region (14, 5) to (18, 5)");
+ }
+
+ [TestMethod]
+ public void TestVerticalWall()
+ {
+ //Reset the world
+ World.Current = new World();
+ //Generate a wall
+ Turf solidTurf = new Turf();
+ solidTurf.SetProperty("Solid", true);
+ World.Current.SetTurf(13, 0, solidTurf);
+ World.Current.SetTurf(13, 1, solidTurf);
+ World.Current.SetTurf(13, 2, solidTurf);
+ World.Current.SetTurf(13, 3, solidTurf);
+ World.Current.SetTurf(13, 4, solidTurf);
+ World.Current.SetTurf(13, 5, solidTurf);
+ World.Current.SetTurf(13, 6, solidTurf);
+ World.Current.SetTurf(13, 7, solidTurf);
+ //Create a world region list
+ WorldRegionList wrl = new WorldRegionList();
+ wrl.GenerateWorldSection(0, 0);
+ wrl.GenerateWorldSection(8, 0);
+ wrl.GenerateWorldSection(16, 0);
+ //Test accessability
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(5, 5)), "There should exist a valid path from region (0, 0) to (5, 5)");
+ Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(10, 5)), "There should exist a valid path from region (0, 0) to (10, 5)");
+ Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(14, 5)), "There should not exist a valid path from region (0, 0) to (14, 5)");
+ Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(18, 5)), "There should not exist a valid path from region (0, 0) to (18, 5)");
+ Assert.IsTrue(wrl.regions.Get(14, 5).HasPath(wrl.regions.Get(18, 5)), "There should exist a valid path from region (14, 5) to (18, 5)");
+ }
+
[TestMethod]
public void TestRegionCreation()
{
@@ -42,6 +108,10 @@ public void TestRegionCreation()
Assert.AreEqual(left, wrl.regions.Get(x, y), "Expected left region to be the same");
}
}
+ for (int y = 0; y < 8; y++)
+ {
+ Assert.AreEqual(null, wrl.regions.Get(4, y), "Expected center line to be null");
+ }
for (int x = 5; x < 8; x++)
{
for (int y = 0; y < 8; y++)
diff --git a/GJ2022/Game/GameWorld/Regions/Region.cs b/GJ2022/Game/GameWorld/Regions/Region.cs
index d2079e7..ddd7e79 100644
--- a/GJ2022/Game/GameWorld/Regions/Region.cs
+++ b/GJ2022/Game/GameWorld/Regions/Region.cs
@@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;
-namespace GJ2022.Game.GameWorld.Current.Regions
+namespace GJ2022.Game.GameWorld.Regions
{
///
/// Region system:
@@ -147,5 +147,9 @@ public bool HasPath(Region other)
return false;
}
+ public override string ToString()
+ {
+ return $"Region {Id}";
+ }
}
}
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index cdff669..b01f55e 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -34,7 +34,8 @@ public class WorldRegionList
public PositionBasedBinaryList regions = new PositionBasedBinaryList();
///
- /// Sets a node in the world to be solid
+ /// Sets a node in the world to be solid.
+ /// Time complexity of O(REGION_PRIMARY_LEVEL_SIZE^2)
///
/// The X position of the node to set to be solid
/// The Y position of the node to set to be solid
@@ -46,6 +47,9 @@ public void SetNodeSolid(int x, int y)
//Calculate if we need to take any action at all
if (!NodeSolidRequiresUpdate(affectedRegion, x, y))
return;
+ //Calculate the region's current adjacencies O(REGION_PRIMARY_LEVEL_SIZE)
+ //An update is required, subdivide the region
+
}
///
@@ -59,18 +63,83 @@ public void SetNodeSolid(int x, int y)
/// flood filled.
/// If any open adjacent nodes didn't get tagged by the flood fill, it means our region has
/// been subdivided.
+ /// O(REGION_PRIMARY_LEVEL_SIZE^2)
///
- private bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
+ public bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
{
+ //Get the relative X and Y with a safe mod operation
+ int relX = ((x % REGION_PRIMARY_LEVEL_SIZE) + REGION_PRIMARY_LEVEL_SIZE) % REGION_PRIMARY_LEVEL_SIZE;
+ int relY = ((y % REGION_PRIMARY_LEVEL_SIZE) + REGION_PRIMARY_LEVEL_SIZE) % REGION_PRIMARY_LEVEL_SIZE;
//Flood fill all nodes in the region and see if we can reconnect with ourselfs
//Flood fill with IDs, giving unique values to north, south, east and west
- int[,] floodFilledIds = new int[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ bool[,] floodFilledIds = new bool[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ floodFilledIds[relX, relY] = true;
Queue> updateQueue = new Queue>();
//Locate an adjacent, open node.
//Insert the first node
-
- //We did not re-encounter ourselves, so we need to update
- return true;
+ if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX + 1, relY))
+ {
+ updateQueue.Enqueue(new Vector(relX + 1, relY));
+ }
+ else if (relX > 0 && !World.Current.IsSolid(relX - 1, relY))
+ {
+ updateQueue.Enqueue(new Vector(relX - 1, relY));
+ }
+ else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX, relY + 1))
+ {
+ updateQueue.Enqueue(new Vector(relX, relY + 1));
+ }
+ else if (relY > 0 && !World.Current.IsSolid(relX, relY - 1))
+ {
+ updateQueue.Enqueue(new Vector(relX, relY - 1));
+ }
+ else
+ {
+ //We have no non-solid adjacent nodes, so we do not need to make an update
+ return false;
+ }
+ //Perform the flood fill operation
+ while (updateQueue.Count > 0)
+ {
+ Vector current = updateQueue.Dequeue();
+ //Mark the current node
+ floodFilledIds[current.X, current.Y] = true;
+ //Add adjacent, non-solid, unmarked nodes
+ if (current.X < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(current.X + 1, current.Y) && !floodFilledIds[current.X + 1, current.Y])
+ {
+ updateQueue.Enqueue(new Vector(current.X + 1, current.Y));
+ }
+ if (current.X > 0 && !World.Current.IsSolid(current.X - 1, current.Y) && !floodFilledIds[current.X - 1, current.Y])
+ {
+ updateQueue.Enqueue(new Vector(current.X - 1, current.Y));
+ }
+ if (current.Y < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(current.X, current.Y + 1) && !floodFilledIds[current.X, current.Y + 1])
+ {
+ updateQueue.Enqueue(new Vector(current.X, current.Y + 1));
+ }
+ if (current.Y > 0 && !World.Current.IsSolid(current.X, current.Y - 1) && !floodFilledIds[current.X, current.Y - 1])
+ {
+ updateQueue.Enqueue(new Vector(current.X, current.Y - 1));
+ }
+ }
+ //Require an update if all adjacent, non-solid nodes are not marked
+ if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX + 1, relY) && !floodFilledIds[relX + 1, relY])
+ {
+ return true;
+ }
+ else if (relX > 0 && !World.Current.IsSolid(relX - 1, relY) && !floodFilledIds[relX - 1, relY])
+ {
+ return true;
+ }
+ else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX, relY + 1) && !floodFilledIds[relX, relY + 1])
+ {
+ return true;
+ }
+ else if (relY > 0 && !World.Current.IsSolid(relX, relY - 1) && !floodFilledIds[relX, relY - 1])
+ {
+ return true;
+ }
+ return false;
}
///
@@ -103,7 +172,7 @@ public void GenerateWorldSection(int x, int y)
int realX = regionX * REGION_PRIMARY_LEVEL_SIZE + nodeX;
int realY = regionY * REGION_PRIMARY_LEVEL_SIZE + nodeY;
//This position is solid, ignore (We don't need to update processedNodes, since we will never again access it)
- if (World.IsSolid(realX, realY))
+ if (World.Current.IsSolid(realX, realY))
continue;
//Create a new region and flood fill outwards
Region createdRegion = new Region(regionX, regionY);
@@ -130,7 +199,7 @@ public void GenerateWorldSection(int x, int y)
//Set node processed
processedNodes[relativePosition.X, relativePosition.Y] = true;
//If current node is a wall, skip
- if (World.IsSolid(worldPosition.X, worldPosition.Y))
+ if (World.Current.IsSolid(worldPosition.X, worldPosition.Y))
continue;
//Join the region
regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
From c7727462478477122b86515bdceec2632469a864 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Fri, 18 Mar 2022 23:34:49 +0000
Subject: [PATCH 15/16] Some region progress
---
GJ2022.Tests/RegionTests.cs | 42 +-
.../Game/GameWorld/Regions/WorldRegionList.cs | 448 +++++++++++-------
2 files changed, 297 insertions(+), 193 deletions(-)
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index 14e5da5..e016947 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -17,18 +17,18 @@ public class RegionTests
[TestMethod]
public void TestValidPathThatGetsBlocked()
{
- //Reset the world
- World.Current = new World();
- //Generate a wall with a hole in it
+ //Generate a wall
Turf solidTurf = new Turf();
solidTurf.SetProperty("Solid", true);
- World.Current.SetTurf(13, 0, solidTurf);
- World.Current.SetTurf(13, 1, solidTurf);
- World.Current.SetTurf(13, 2, solidTurf);
- World.Current.SetTurf(13, 3, solidTurf);
- World.Current.SetTurf(13, 5, solidTurf);
- World.Current.SetTurf(13, 6, solidTurf);
- World.Current.SetTurf(13, 7, solidTurf);
+ //Reset the world
+ World.Current = new World();
+ World.Current.SetTurf(12, 0, solidTurf);
+ World.Current.SetTurf(12, 1, solidTurf);
+ World.Current.SetTurf(12, 2, solidTurf);
+ World.Current.SetTurf(12, 3, solidTurf);
+ World.Current.SetTurf(12, 5, solidTurf);
+ World.Current.SetTurf(12, 6, solidTurf);
+ World.Current.SetTurf(12, 7, solidTurf);
//Create a world region list
WorldRegionList wrl = new WorldRegionList();
wrl.GenerateWorldSection(0, 0);
@@ -40,9 +40,11 @@ public void TestValidPathThatGetsBlocked()
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(14, 5)), "There should exist a valid path from region (0, 0) to (14, 5)");
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(18, 5)), "There should exist a valid path from region (0, 0) to (18, 5)");
Assert.IsTrue(wrl.regions.Get(14, 5).HasPath(wrl.regions.Get(18, 5)), "There should exist a valid path from region (14, 5) to (18, 5)");
+ //Check this
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(12, 4), 12, 4));
//Block off the wall
- World.Current.SetTurf(13, 4, solidTurf);
- wrl.SetNodeSolid(13, 4);
+ World.Current.SetTurf(12, 4, solidTurf);
+ wrl.SetNodeSolid(12, 4);
Log.WriteLine("World has been divided");
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(5, 5)), "There should still exist a valid path from region (0, 0) to (5, 5)");
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(10, 5)), "There should still exist a valid path from region (0, 0) to (10, 5)");
@@ -145,6 +147,22 @@ public void TestRegionUpdateRequirements()
Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 3, 3));
Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 5, 4));
Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(0, 0), 3, 4));
+ wrl.GenerateWorldSection(8, 0);
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(12, 4), 12, 4));
+ World.Current.SetTurf(12, 0, solidTurf);
+ World.Current.SetTurf(12, 1, solidTurf);
+ World.Current.SetTurf(12, 2, solidTurf);
+ World.Current.SetTurf(12, 3, solidTurf);
+ World.Current.SetTurf(12, 5, solidTurf);
+ World.Current.SetTurf(12, 6, solidTurf);
+ World.Current.SetTurf(12, 7, solidTurf);
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(12, 4), 12, 4));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(11, 1), 11, 1));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(8, 0), 13, 5));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(8, 0), 12, 6));
+ Assert.IsFalse(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(8, 0), 11, 3));
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(8, 0), 13, 4));
+ Assert.IsTrue(wrl.NodeSolidRequiresUpdate(wrl.regions.Get(8, 0), 11, 4));
}
[TestMethod]
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index b01f55e..e32cc95 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -1,4 +1,4 @@
-//#define REGION_LOGGING
+#define REGION_LOGGING
using GJ2022.Utility.MathConstructs;
using System;
@@ -9,6 +9,12 @@
namespace GJ2022.Game.GameWorld.Regions
{
+ ///
+ /// Pretty complicated way of splitting the world into a region based tree
+ /// structure so that impossible path finding can be avoided, saving us from attempting
+ /// to calculate paths where there is none, resulting in every world tile needing to
+ /// be examined.
+ ///
public class WorldRegionList
{
@@ -45,11 +51,252 @@ public void SetNodeSolid(int x, int y)
Region affectedRegion = regions.Get(x, y);
regions.Remove(x, y);
//Calculate if we need to take any action at all
+ Log.WriteLine("Checking...");
if (!NodeSolidRequiresUpdate(affectedRegion, x, y))
return;
- //Calculate the region's current adjacencies O(REGION_PRIMARY_LEVEL_SIZE)
- //An update is required, subdivide the region
+ Log.WriteLine("Requires update!");
+ //Calculate the span of the subdivided region
+ //(Note that it is possible to subdivide into multiple regions at once (4 regions at max))
+ List createdRegions = new List();
+ List adjacentRegions = new List();
+ //Calculate required values
+ //Calculate region X and Y
+ int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
+ int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+ //Calcualte relative X and Y
+ int relX = x - regionX * REGION_PRIMARY_LEVEL_SIZE;
+ int relY = y - regionY * REGION_PRIMARY_LEVEL_SIZE;
+ //Check each adjacent tile to the changed node
+ //Check if that tile is part of one of the regions we created already
+ //If not, create a new region at that location
+ if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x + 1, y))
+ {
+ createdRegions.Add(FloodFillCreateRegion(x + 1, y, ref adjacentRegions));
+ }
+ if (relX > 0 && !World.Current.IsSolid(x - 1, y) && !createdRegions.Contains(regions.Get(x - 1, y)))
+ {
+ createdRegions.Add(FloodFillCreateRegion(x - 1, y, ref adjacentRegions));
+ }
+ if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x, y + 1) && !createdRegions.Contains(regions.Get(x, y + 1)))
+ {
+ createdRegions.Add(FloodFillCreateRegion(x, y + 1, ref adjacentRegions));
+ }
+ if (relY > 0 && !World.Current.IsSolid(x, y - 1) && !createdRegions.Contains(regions.Get(x, y - 1)))
+ {
+ createdRegions.Add(FloodFillCreateRegion(x, y - 1, ref adjacentRegions));
+ }
+ //Recalculate adjacencies
+ foreach (Region r in createdRegions)
+ {
+ Log.WriteLine($"Created region {r.Id}");
+ }
+ foreach (Region r in adjacentRegions)
+ {
+ Log.WriteLine($"Adjacent to {r.Id}");
+ }
+ }
+
+ ///
+ /// Creates a region at {x, y} and flood fills the region outwards,
+ /// generating parents and adjacent regions where necessary.
+ ///
+ /// The X world coordinate of where to create the new region
+ /// The Y world coordinate of where to create the new region
+ /// The created region
+ private Region FloodFillCreateRegion(int x, int y, ref List adjacentRegions)
+ {
+ bool[,] nullRegion = null;
+ return FloodFillCreateRegion(x, y, ref nullRegion, ref adjacentRegions);
+ }
+ ///
+ /// Creates a region at {x, y} and flood fills the region outwards,
+ /// generating parents and adjacent regions where necessary.
+ ///
+ /// The X world coordinate of where to create the new region
+ /// The Y world coordinate of where to create the new region
+ /// A 2D array that will be set to indicate which nodes have been processed.
+ /// A list of the regions adjacent to the created Region
+ /// The created region
+ private Region FloodFillCreateRegion(int x, int y, ref bool[,] processedNodes, ref List adjacentRegions)
+ {
+ if (processedNodes == null)
+ processedNodes = new bool[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ //Calculate region X and Y
+ int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
+ int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+ //Calcualte relative X and Y
+ int relX = x - regionX * REGION_PRIMARY_LEVEL_SIZE;
+ int relY = y - regionY * REGION_PRIMARY_LEVEL_SIZE;
+ //Create a new region and flood fill outwards
+ Region createdRegion = new Region(regionX, regionY);
+#if REGION_LOGGING
+ Log.WriteLine($"Created new region {createdRegion.Id} at ({regionX}, {regionY})");
+#endif
+ //Have the position join this region
+ regions.Add(x, y, createdRegion);
+ //During this process, get the adjacent regions so we can match up parents
+ if(adjacentRegions == null)
+ adjacentRegions = new List();
+ //Processing queue
+ Queue> toProcess = new Queue>();
+ toProcess.Enqueue(new Vector(relX, relY));
+ //While we still have places to floor fill
+ while (toProcess.Count > 0)
+ {
+ //Dequeue
+ Vector relativePosition = toProcess.Dequeue();
+ //If current node is already processed, skip
+ if (processedNodes[relativePosition.X, relativePosition.Y])
+ continue;
+ //Calculate the world position of the current node
+ Vector worldPosition = new Vector(regionX * REGION_PRIMARY_LEVEL_SIZE, regionY * REGION_PRIMARY_LEVEL_SIZE) + relativePosition;
+ //Set node processed
+ processedNodes[relativePosition.X, relativePosition.Y] = true;
+ //If current node is a wall, skip
+ if (World.Current.IsSolid(worldPosition.X, worldPosition.Y))
+ continue;
+ //Join the region
+ regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
+ //Check if we have any adjacent regions
+ Region adjacent;
+ //Add adjacent nodes (Assuming they are within bounds)
+ if (relativePosition.X < REGION_PRIMARY_LEVEL_SIZE - 1)
+ toProcess.Enqueue(new Vector(relativePosition.X + 1, relativePosition.Y));
+ else if ((adjacent = regions.Get(worldPosition.X + 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.X > 0)
+ toProcess.Enqueue(new Vector(relativePosition.X - 1, relativePosition.Y));
+ else if ((adjacent = regions.Get(worldPosition.X - 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.Y < REGION_PRIMARY_LEVEL_SIZE - 1)
+ toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y + 1));
+ else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y + 1)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ if (relativePosition.Y > 0)
+ toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y - 1));
+ else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y - 1)) != null && !adjacentRegions.Contains(adjacent))
+ adjacentRegions.Add(adjacent);
+ }
+ //Now we have assigned all tiles within our region to be associated to this region
+ //We now need to calculate parent regions with all adjacent regions
+ foreach (Region adjacentRegion in adjacentRegions)
+ {
+#if REGION_LOGGING
+ Log.WriteLine($"Joining region {createdRegion.Id} to {adjacentRegion.Id}");
+#endif
+ //The level of the shared parent
+ int sharedParentLevel = GetSharedParentLevel(createdRegion, adjacentRegion);
+#if REGION_LOGGING
+ Log.WriteLine($"Shared parent level: {sharedParentLevel}");
+#endif
+ //Since these regions are adjacent, they should share a parent at the shared parent level.
+ //Get pointers for the current region
+ Region leftParent = createdRegion;
+ Region rightParent = adjacentRegion;
+ //Iterate upwards, creating parent regions where none exist
+ for (int level = 1; level <= sharedParentLevel - 1; level++)
+ {
+ //Create the parent if either are null
+ if (leftParent.Parent == null)
+ {
+ //Parent position is the integer division result of any
+ //child position divided by the region child size
+ //We can work this out by doing integer division with the position of
+ //The top level child and region children size ^ depth
+ leftParent.Parent = new Region(
+ createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ level);
+#if REGION_LOGGING
+ Log.WriteLine($"Created new parent node for {leftParent.Id}, parent node {leftParent.Parent.Id} at depth {level}");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
+ }
+ if (rightParent.Parent == null)
+ {
+ rightParent.Parent = new Region(
+ adjacentRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ adjacentRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
+ level);
+#if REGION_LOGGING
+ Log.WriteLine($"Created new parent node for {rightParent.Id}, parent node {rightParent.Parent.Id} at depth {level}");
+ Log.WriteLine($"Joined {rightParent.Id} --> {rightParent.Parent.Id}");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
+ }
+ //Get the left and right parent
+ leftParent = leftParent.Parent;
+ rightParent = rightParent.Parent;
+ }
+ //Now we are at a shared parent level, check if anything exists
+ //If so, then attach both to the shared parent
+ //If not, then create a new shared parent and attach both to it
+ if (rightParent.Parent != null)
+ {
+ leftParent.Parent = rightParent.Parent;
+#if REGION_LOGGING
+ Log.WriteLine($"Joined {leftParent.Id} --> {rightParent.Parent.Id}");
+#endif
+ }
+ else
+ {
+ if (leftParent.Parent == null)
+ {
+ leftParent.Parent = new Region(
+ createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
+ createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
+ sharedParentLevel);
+#if REGION_LOGGING
+ Log.WriteLine($"Created new parent node {leftParent.Parent.Id} at depth {sharedParentLevel}");
+ Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
+#endif
+ }
+ rightParent.Parent = leftParent.Parent;
+#if REGION_LOGGING
+ Log.WriteLine($"Joined {rightParent.Id} --> {leftParent.Parent.Id}");
+#endif
+ }
+ }
+ return createdRegion;
+ }
+
+ ///
+ /// Generates the region that contains the provided X,Y world coordinates.
+ ///
+ public void GenerateWorldSection(int x, int y)
+ {
+ //WARNING: Integer divison rounds towards 0.
+ //Positive values (8, 16, 24, 32 etc..) should work fine, however it needs to be ensured that (-1 and 1) don't get assigned to the same region,
+ //since we don't want region (x, y), (-x, y), (x, -y), (-x, -y) to all be assigned to region (0, 0)
+ int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
+ int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+#if REGION_LOGGING
+ Log.WriteLine($"Generating region ({regionX}, {regionY})");
+#endif
+ //Check if the region exists already
+ if (regions.Get(x, y) != null)
+ return;
+ //The region doesn't exist, so we need to generate one
+ bool[,] processedNodes = new bool[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
+ //Check each node and flood fill a region if necessary
+ for (int nodeX = 0; nodeX < REGION_PRIMARY_LEVEL_SIZE; nodeX++)
+ {
+ for (int nodeY = 0; nodeY < REGION_PRIMARY_LEVEL_SIZE; nodeY++)
+ {
+ //This node has already been assigned a region
+ if (processedNodes[nodeX, nodeY])
+ continue;
+ //Get the real world coordinates
+ int realX = regionX * REGION_PRIMARY_LEVEL_SIZE + nodeX;
+ int realY = regionY * REGION_PRIMARY_LEVEL_SIZE + nodeY;
+ //This position is solid, ignore (We don't need to update processedNodes, since we will never again access it)
+ if (World.Current.IsSolid(realX, realY))
+ continue;
+ List adjacentRegions = null;
+ FloodFillCreateRegion(realX, realY, ref processedNodes, ref adjacentRegions);
+ }
+ }
}
///
@@ -67,6 +314,11 @@ public void SetNodeSolid(int x, int y)
///
public bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
{
+ //Calculate region X and Y
+ int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
+ int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
+ int regionOffsetX = regionX * REGION_PRIMARY_LEVEL_SIZE;
+ int regionOffsetY = regionY * REGION_PRIMARY_LEVEL_SIZE;
//Get the relative X and Y with a safe mod operation
int relX = ((x % REGION_PRIMARY_LEVEL_SIZE) + REGION_PRIMARY_LEVEL_SIZE) % REGION_PRIMARY_LEVEL_SIZE;
int relY = ((y % REGION_PRIMARY_LEVEL_SIZE) + REGION_PRIMARY_LEVEL_SIZE) % REGION_PRIMARY_LEVEL_SIZE;
@@ -77,19 +329,19 @@ public bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
Queue> updateQueue = new Queue>();
//Locate an adjacent, open node.
//Insert the first node
- if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX + 1, relY))
+ if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x + 1, y))
{
updateQueue.Enqueue(new Vector(relX + 1, relY));
}
- else if (relX > 0 && !World.Current.IsSolid(relX - 1, relY))
+ else if (relX > 0 && !World.Current.IsSolid(x - 1, y))
{
updateQueue.Enqueue(new Vector(relX - 1, relY));
}
- else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX, relY + 1))
+ else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x, y + 1))
{
updateQueue.Enqueue(new Vector(relX, relY + 1));
}
- else if (relY > 0 && !World.Current.IsSolid(relX, relY - 1))
+ else if (relY > 0 && !World.Current.IsSolid(x, y - 1))
{
updateQueue.Enqueue(new Vector(relX, relY - 1));
}
@@ -105,209 +357,43 @@ public bool NodeSolidRequiresUpdate(Region actingRegion, int x, int y)
//Mark the current node
floodFilledIds[current.X, current.Y] = true;
//Add adjacent, non-solid, unmarked nodes
- if (current.X < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(current.X + 1, current.Y) && !floodFilledIds[current.X + 1, current.Y])
+ if (current.X < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(regionOffsetX + current.X + 1, regionOffsetY + current.Y) && !floodFilledIds[current.X + 1, current.Y])
{
updateQueue.Enqueue(new Vector(current.X + 1, current.Y));
}
- if (current.X > 0 && !World.Current.IsSolid(current.X - 1, current.Y) && !floodFilledIds[current.X - 1, current.Y])
+ if (current.X > 0 && !World.Current.IsSolid(regionOffsetX + current.X - 1, regionOffsetY + current.Y) && !floodFilledIds[current.X - 1, current.Y])
{
updateQueue.Enqueue(new Vector(current.X - 1, current.Y));
}
- if (current.Y < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(current.X, current.Y + 1) && !floodFilledIds[current.X, current.Y + 1])
+ if (current.Y < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(regionOffsetX + current.X, regionOffsetY + current.Y + 1) && !floodFilledIds[current.X, current.Y + 1])
{
updateQueue.Enqueue(new Vector(current.X, current.Y + 1));
}
- if (current.Y > 0 && !World.Current.IsSolid(current.X, current.Y - 1) && !floodFilledIds[current.X, current.Y - 1])
+ if (current.Y > 0 && !World.Current.IsSolid(regionOffsetX + current.X, regionOffsetY + current.Y - 1) && !floodFilledIds[current.X, current.Y - 1])
{
updateQueue.Enqueue(new Vector(current.X, current.Y - 1));
}
}
//Require an update if all adjacent, non-solid nodes are not marked
- if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX + 1, relY) && !floodFilledIds[relX + 1, relY])
+ if (relX < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x + 1, y) && !floodFilledIds[relX + 1, relY])
{
return true;
}
- else if (relX > 0 && !World.Current.IsSolid(relX - 1, relY) && !floodFilledIds[relX - 1, relY])
+ else if (relX > 0 && !World.Current.IsSolid(x - 1, y) && !floodFilledIds[relX - 1, relY])
{
return true;
}
- else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(relX, relY + 1) && !floodFilledIds[relX, relY + 1])
+ else if (relY < REGION_PRIMARY_LEVEL_SIZE - 1 && !World.Current.IsSolid(x, y + 1) && !floodFilledIds[relX, relY + 1])
{
return true;
}
- else if (relY > 0 && !World.Current.IsSolid(relX, relY - 1) && !floodFilledIds[relX, relY - 1])
+ else if (relY > 0 && !World.Current.IsSolid(x, y - 1) && !floodFilledIds[relX, relY - 1])
{
return true;
}
return false;
}
- ///
- /// Generates the region that contains the provided X,Y world coordinates.
- ///
- public void GenerateWorldSection(int x, int y)
- {
- //WARNING: Integer divison rounds towards 0.
- //Positive values (8, 16, 24, 32 etc..) should work fine, however it needs to be ensured that (-1 and 1) don't get assigned to the same region,
- //since we don't want region (x, y), (-x, y), (x, -y), (-x, -y) to all be assigned to region (0, 0)
- int regionX = (int)Math.Floor((float)x / REGION_PRIMARY_LEVEL_SIZE);
- int regionY = (int)Math.Floor((float)y / REGION_PRIMARY_LEVEL_SIZE);
-#if REGION_LOGGING
- Log.WriteLine($"Generating region ({regionX}, {regionY})");
-#endif
- //Check if the region exists already
- if (regions.Get(x, y) != null)
- return;
- //The region doesn't exist, so we need to generate one
- bool[,] processedNodes = new bool[REGION_PRIMARY_LEVEL_SIZE, REGION_PRIMARY_LEVEL_SIZE];
- //Check each node and flood fill a region if necessary
- for (int nodeX = 0; nodeX < REGION_PRIMARY_LEVEL_SIZE; nodeX++)
- {
- for (int nodeY = 0; nodeY < REGION_PRIMARY_LEVEL_SIZE; nodeY++)
- {
- //This node has already been assigned a region
- if (processedNodes[nodeX, nodeY])
- continue;
- //Get the real world coordinates
- int realX = regionX * REGION_PRIMARY_LEVEL_SIZE + nodeX;
- int realY = regionY * REGION_PRIMARY_LEVEL_SIZE + nodeY;
- //This position is solid, ignore (We don't need to update processedNodes, since we will never again access it)
- if (World.Current.IsSolid(realX, realY))
- continue;
- //Create a new region and flood fill outwards
- Region createdRegion = new Region(regionX, regionY);
-#if REGION_LOGGING
- Log.WriteLine($"Created new region {createdRegion.Id} at ({regionX}, {regionY})");
-#endif
- //Have the position join this region
- regions.Add(realX, realY, createdRegion);
- //During this process, get the adjacent regions so we can match up parents
- List adjacentRegions = new List();
- //Processing queue
- Queue> toProcess = new Queue>();
- toProcess.Enqueue(new Vector(nodeX, nodeY));
- //While we still have places to floor fill
- while (toProcess.Count > 0)
- {
- //Dequeue
- Vector relativePosition = toProcess.Dequeue();
- //If current node is already processed, skip
- if (processedNodes[relativePosition.X, relativePosition.Y])
- continue;
- //Calculate the world position of the current node
- Vector worldPosition = new Vector(regionX * REGION_PRIMARY_LEVEL_SIZE, regionY * REGION_PRIMARY_LEVEL_SIZE) + relativePosition;
- //Set node processed
- processedNodes[relativePosition.X, relativePosition.Y] = true;
- //If current node is a wall, skip
- if (World.Current.IsSolid(worldPosition.X, worldPosition.Y))
- continue;
- //Join the region
- regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
- //Check if we have any adjacent regions
- Region adjacent;
- //Add adjacent nodes (Assuming they are within bounds)
- if (relativePosition.X < REGION_PRIMARY_LEVEL_SIZE - 1)
- toProcess.Enqueue(new Vector(relativePosition.X + 1, relativePosition.Y));
- else if ((adjacent = regions.Get(worldPosition.X + 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
- adjacentRegions.Add(adjacent);
- if (relativePosition.X > 0)
- toProcess.Enqueue(new Vector(relativePosition.X - 1, relativePosition.Y));
- else if ((adjacent = regions.Get(worldPosition.X - 1, worldPosition.Y)) != null && !adjacentRegions.Contains(adjacent))
- adjacentRegions.Add(adjacent);
- if (relativePosition.Y < REGION_PRIMARY_LEVEL_SIZE - 1)
- toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y + 1));
- else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y + 1)) != null && !adjacentRegions.Contains(adjacent))
- adjacentRegions.Add(adjacent);
- if (relativePosition.Y > 0)
- toProcess.Enqueue(new Vector(relativePosition.X, relativePosition.Y - 1));
- else if ((adjacent = regions.Get(worldPosition.X, worldPosition.Y - 1)) != null && !adjacentRegions.Contains(adjacent))
- adjacentRegions.Add(adjacent);
- }
- //Now we have assigned all tiles within our region to be associated to this region
- //We now need to calculate parent regions with all adjacent regions
- foreach (Region adjacentRegion in adjacentRegions)
- {
-#if REGION_LOGGING
- Log.WriteLine($"Joining region {createdRegion.Id} to {adjacentRegion.Id}");
-#endif
- //The level of the shared parent
- int sharedParentLevel = GetSharedParentLevel(createdRegion, adjacentRegion);
-#if REGION_LOGGING
- Log.WriteLine($"Shared parent level: {sharedParentLevel}");
-#endif
- //Since these regions are adjacent, they should share a parent at the shared parent level.
- //Get pointers for the current region
- Region leftParent = createdRegion;
- Region rightParent = adjacentRegion;
- //Iterate upwards, creating parent regions where none exist
- for (int level = 1; level <= sharedParentLevel - 1; level++)
- {
- //Create the parent if either are null
- if (leftParent.Parent == null)
- {
- //Parent position is the integer division result of any
- //child position divided by the region child size
- //We can work this out by doing integer division with the position of
- //The top level child and region children size ^ depth
- leftParent.Parent = new Region(
- createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
- createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
- level);
-#if REGION_LOGGING
- Log.WriteLine($"Created new parent node for {leftParent.Id}, parent node {leftParent.Parent.Id} at depth {level}");
- Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
-#endif
- }
- if (rightParent.Parent == null)
- {
- rightParent.Parent = new Region(
- adjacentRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
- adjacentRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, level),
- level);
-#if REGION_LOGGING
- Log.WriteLine($"Created new parent node for {rightParent.Id}, parent node {rightParent.Parent.Id} at depth {level}");
- Log.WriteLine($"Joined {rightParent.Id} --> {rightParent.Parent.Id}"); t depth { level}
- ");
- Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
-#endif
- }
- //Get the left and right parent
- leftParent = leftParent.Parent;
- rightParent = rightParent.Parent;
- }
- //Now we are at a shared parent level, check if anything exists
- //If so, then attach both to the shared parent
- //If not, then create a new shared parent and attach both to it
- if (rightParent.Parent != null)
- {
- leftParent.Parent = rightParent.Parent;
-#if REGION_LOGGING
- Log.WriteLine($"Joined {leftParent.Id} --> {rightParent.Parent.Id}");
-#endif
- }
- else
- {
- if (leftParent.Parent == null)
- {
- leftParent.Parent = new Region(
- createdRegion.X / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
- createdRegion.Y / (int)Math.Pow(REGION_CHILDREN_SIZE, sharedParentLevel),
- sharedParentLevel);
-#if REGION_LOGGING
- Log.WriteLine($"Created new parent node {leftParent.Parent.Id} at depth {sharedParentLevel}");
- Log.WriteLine($"Joined {leftParent.Id} --> {leftParent.Parent.Id}");
-#endif
- }
- rightParent.Parent = leftParent.Parent;
-#if REGION_LOGGING
- Log.WriteLine($"Joined {rightParent.Id} --> {leftParent.Parent.Id}");
-#endif
- }
- }
- }
- }
- }
-
///
/// Returns the level at which 2 nodes would in theory have a shared parent.
///
From 369ed0bcabded0ad72c1e1f7a8c6e19e6c97f744 Mon Sep 17 00:00:00 2001
From: PowerfulBacon <>
Date: Sat, 19 Mar 2022 20:33:55 +0000
Subject: [PATCH 16/16] Almost finishes this
---
GJ2022.Tests/RegionTests.cs | 2 +
.../PositionBasedBinaryListUnitTests.cs | 29 ++++++++++++++
.../Game/GameWorld/Regions/WorldRegionList.cs | 6 +--
.../MathConstructs/PositionBasedBinaryList.cs | 38 +++++++++++++++----
4 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/GJ2022.Tests/RegionTests.cs b/GJ2022.Tests/RegionTests.cs
index e016947..084fad2 100644
--- a/GJ2022.Tests/RegionTests.cs
+++ b/GJ2022.Tests/RegionTests.cs
@@ -46,6 +46,8 @@ public void TestValidPathThatGetsBlocked()
World.Current.SetTurf(12, 4, solidTurf);
wrl.SetNodeSolid(12, 4);
Log.WriteLine("World has been divided");
+ Log.WriteLine("World status:");
+ Log.WriteLine(wrl.regions);
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(5, 5)), "There should still exist a valid path from region (0, 0) to (5, 5)");
Assert.IsTrue(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(10, 5)), "There should still exist a valid path from region (0, 0) to (10, 5)");
Assert.IsFalse(wrl.regions.Get(0, 0).HasPath(wrl.regions.Get(14, 5)), "There should no longer exist a valid path from region (0, 0) to (14, 5)");
diff --git a/GJ2022.Tests/UtilityTests/PositionBasedBinaryListUnitTests.cs b/GJ2022.Tests/UtilityTests/PositionBasedBinaryListUnitTests.cs
index 63b16d4..bf62b07 100644
--- a/GJ2022.Tests/UtilityTests/PositionBasedBinaryListUnitTests.cs
+++ b/GJ2022.Tests/UtilityTests/PositionBasedBinaryListUnitTests.cs
@@ -7,6 +7,35 @@ namespace GJ2022.Tests.UtilityTests
public class PositionBasedBinaryListUnitTests
{
+ [TestMethod]
+ [ExpectedException(typeof(System.IndexOutOfRangeException))]
+ public void TestInsertionFailure()
+ {
+ PositionBasedBinaryList randomList = new PositionBasedBinaryList();
+ randomList.Add(0, 0, 1);
+ randomList.Add(0, 0, 2);
+ }
+
+ [TestMethod]
+ public void TestReplace()
+ {
+ PositionBasedBinaryList randomList = new PositionBasedBinaryList();
+ randomList.Add(0, 0, 1);
+ randomList.Add(0, 1, 2);
+ randomList.Add(0, 2, 4);
+ randomList.Add(0, 3, 5);
+ randomList.Add(0, 1, 3, true);
+ randomList.Add(0, 2, 3, true);
+ //Account for both cases of midpoint rounding
+ Assert.AreEqual(3, randomList.Get(0, 1), "Expected 3 at (0, 1)");
+ Assert.AreEqual(3, randomList.Get(0, 2), "Expected 3 at (0, 2)");
+ for (int i = 0; i < 4; i++)
+ {
+ randomList.TakeFirst();
+ }
+ Assert.IsFalse(randomList.HasElements, $"Expected list to only contain 4 elements, actually contains {randomList}");
+ }
+
[TestMethod]
public void TestTakeFirst()
{
diff --git a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
index e32cc95..bdde0c4 100644
--- a/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
+++ b/GJ2022/Game/GameWorld/Regions/WorldRegionList.cs
@@ -85,7 +85,7 @@ public void SetNodeSolid(int x, int y)
{
createdRegions.Add(FloodFillCreateRegion(x, y - 1, ref adjacentRegions));
}
- //Recalculate adjacencies
+ //Recalculate adjacencies of the created regions
foreach (Region r in createdRegions)
{
Log.WriteLine($"Created region {r.Id}");
@@ -134,7 +134,7 @@ private Region FloodFillCreateRegion(int x, int y, ref bool[,] processedNodes, r
Log.WriteLine($"Created new region {createdRegion.Id} at ({regionX}, {regionY})");
#endif
//Have the position join this region
- regions.Add(x, y, createdRegion);
+ regions.Add(x, y, createdRegion, true);
//During this process, get the adjacent regions so we can match up parents
if(adjacentRegions == null)
adjacentRegions = new List();
@@ -157,7 +157,7 @@ private Region FloodFillCreateRegion(int x, int y, ref bool[,] processedNodes, r
if (World.Current.IsSolid(worldPosition.X, worldPosition.Y))
continue;
//Join the region
- regions.Add(worldPosition.X, worldPosition.Y, createdRegion);
+ regions.Add(worldPosition.X, worldPosition.Y, createdRegion, true);
//Check if we have any adjacent regions
Region adjacent;
//Add adjacent nodes (Assuming they are within bounds)
diff --git a/GJ2022/Utility/MathConstructs/PositionBasedBinaryList.cs b/GJ2022/Utility/MathConstructs/PositionBasedBinaryList.cs
index 9009345..077a986 100644
--- a/GJ2022/Utility/MathConstructs/PositionBasedBinaryList.cs
+++ b/GJ2022/Utility/MathConstructs/PositionBasedBinaryList.cs
@@ -42,7 +42,7 @@ public int Length()
return binaryListElements.Count;
}
- public int Add(int key, T toAdd, int start = 0, int _end = -1)
+ public int Add(int key, T toAdd, bool replace = false, int start = 0, int _end = -1)
{
//No elements, just add
if (binaryListElements.Count == 0)
@@ -62,19 +62,43 @@ public int Add(int key, T toAdd, int start = 0, int _end = -1)
{
//Check if the midpoint is too small or too large
BinaryListElement convergedPoint = binaryListElements.ElementAt(midPoint);
+ //Check regular cases
if (convergedPoint.key > key)
- binaryListElements.Insert(midPoint, new BinaryListElement(key, toAdd));
+ {
+ //Check next element is what we were looking for
+ if (midPoint > 0 && binaryListElements.ElementAt(midPoint - 1).key == key)
+ {
+ if (replace)
+ binaryListElements.ElementAt(midPoint - 1).value = toAdd;
+ else
+ throw new IndexOutOfRangeException($"Duplicate element added to binary list at {key}");
+ }
+ else
+ binaryListElements.Insert(midPoint, new BinaryListElement(key, toAdd));
+ }
+ else if (convergedPoint.key < key)
+ if (midPoint < binaryListElements.Count - 1 && binaryListElements.ElementAt(midPoint + 1).key == key)
+ {
+ if (replace)
+ binaryListElements.ElementAt(midPoint + 1).value = toAdd;
+ else
+ throw new IndexOutOfRangeException($"Duplicate element added to binary list at {key}");
+ }
+ else
+ binaryListElements.Insert(midPoint + 1, new BinaryListElement(key, toAdd));
+ else if (replace)
+ convergedPoint.value = toAdd;
else
- binaryListElements.Insert(midPoint + 1, new BinaryListElement(key, toAdd));
+ throw new IndexOutOfRangeException($"Duplicate element added to binary list at {key}");
return -1;
}
//Locate the element at the midpoint
BinaryListElement current = binaryListElements.ElementAt(midPoint);
//Perform next search
if (current.key > key)
- return Add(key, toAdd, start, Math.Max(midPoint - 1, 0));
+ return Add(key, toAdd, replace, start, Math.Max(midPoint - 1, 0));
else
- return Add(key, toAdd, midPoint + 1, end);
+ return Add(key, toAdd, replace, midPoint + 1, end);
}
public void Remove(int key)
@@ -170,7 +194,7 @@ public T First()
return list.First().First();
}
- public void Add(int x, int y, T element)
+ public void Add(int x, int y, T element, bool replace = false)
{
//Locate the X element
BinaryList located = list.ElementWithKey(x);
@@ -182,7 +206,7 @@ public void Add(int x, int y, T element)
list.Add(x, located);
}
//Add the y element
- located.Add(y, element);
+ located.Add(y, element, replace);
}
public void Remove(int x, int y)