diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs
index 46fb00c..271ca1c 100644
--- a/GamecraftModdingAPI/Block.cs
+++ b/GamecraftModdingAPI/Block.cs
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
+using System.Threading.Tasks;
using Svelto.ECS;
using Svelto.ECS.EntityStructs;
@@ -29,6 +30,8 @@ namespace GamecraftModdingAPI
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
/// Place blocks next to each other to connect them.
/// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
+ ///
+ /// This method causes a sync which may have a performance impact. Use the async version if possible.
///
/// The block's type
/// The block's color
@@ -59,6 +62,44 @@ namespace GamecraftModdingAPI
return null;
}
+ ///
+ /// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
+ /// Place blocks next to each other to connect them.
+ /// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
+ ///
+ /// This method waits for the block to be constructed in the game.
+ ///
+ /// The block's type
+ /// The block's color
+ /// The block color's darkness (0-9) - 0 is default color
+ /// The block's position in the grid - default block size is 0.2
+ /// The block's rotation in degrees
+ /// The block's uniform scale - default scale is 1 (with 0.2 width)
+ /// The block's non-uniform scale - 0 means is used
+ /// The player who placed the block
+ /// The placed block or null if failed
+ public static async Task PlaceNewAsync(BlockIDs block, float3 position,
+ float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
+ int uscale = 1, float3 scale = default, Player player = null)
+ {
+ if (PlacementEngine.IsInGame && GameState.IsBuildMode())
+ {
+ try
+ {
+ var ret = new Block(PlacementEngine.PlaceBlock(block, color, darkness,
+ position, uscale, scale, player, rotation));
+ await AsyncUtils.WaitForSubmission();
+ return ret;
+ }
+ catch (Exception e)
+ {
+ Logging.MetaDebugLog(e);
+ }
+ }
+
+ return null;
+ }
+
///
/// Returns the most recently placed block.
///
diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs
index 6275ca1..a47a328 100644
--- a/GamecraftModdingAPI/Blocks/BlockEngine.cs
+++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs
@@ -10,6 +10,9 @@ using GamecraftModdingAPI.Engines;
namespace GamecraftModdingAPI.Blocks
{
+ ///
+ /// Engine for executing general block actions
+ ///
public class BlockEngine : IApiEngine
{
public string Name { get; } = "GamecraftModdingAPIBlockGameEngine";
diff --git a/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs b/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
index 9b2bf39..35f075e 100644
--- a/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
+++ b/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
@@ -28,6 +28,8 @@ namespace GamecraftModdingAPI.Events
{
// register custom game engines
GameEngineManager.RegisterEngines(enginesRoot);
+ // initialize AsyncUtils
+ AsyncUtils.Setup(enginesRoot);
// A new EnginesRoot is always created when ActivateGame is called
// so all event emitters and handlers must be re-registered.
EventManager.RegisterEngines(enginesRoot);
diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs
index 56f481f..bea58e1 100644
--- a/GamecraftModdingAPI/Main.cs
+++ b/GamecraftModdingAPI/Main.cs
@@ -71,6 +71,7 @@ namespace GamecraftModdingAPI
Player.Init();
Block.Init();
GameClient.Init();
+ AsyncUtils.Init();
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
}
diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
index 46a7ef8..4c9105c 100644
--- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
+++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
@@ -143,7 +143,11 @@ namespace GamecraftModdingAPI.Tests
CommandBuilder.Builder()
.Name("PlaceAluminium")
.Description("Place a block of aluminium at the given coordinates")
- .Action((float x, float y, float z) => { Block.PlaceNew(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); })
+ .Action(async (float x, float y, float z) =>
+ {
+ var block = await Block.PlaceNewAsync(BlockIDs.AluminiumCube, new float3(x, y, z));
+ Logging.MetaDebugLog("Block placed with type: " + block.Type);
+ })
.Build();
CommandBuilder.Builder("getBlock")
@@ -170,7 +174,7 @@ namespace GamecraftModdingAPI.Tests
Logging.CommandLog("Colored block to " + color);
}).Build();
-
+
GameClient.SetDebugInfo("lookedAt", LookedAt);
/*
diff --git a/GamecraftModdingAPI/Utility/AsyncUtils.cs b/GamecraftModdingAPI/Utility/AsyncUtils.cs
new file mode 100644
index 0000000..fcb5878
--- /dev/null
+++ b/GamecraftModdingAPI/Utility/AsyncUtils.cs
@@ -0,0 +1,29 @@
+using System.Threading.Tasks;
+
+using Svelto.ECS;
+
+namespace GamecraftModdingAPI.Utility
+{
+ public static class AsyncUtils
+ {
+ private static AsyncUtilsEngine gameEngine = new AsyncUtilsEngine();
+
+ ///
+ /// Waits for entity submission asynchronously.
+ ///
+ public static async Task WaitForSubmission()
+ {
+ await gameEngine.WaitForSubmission();
+ }
+
+ public static void Setup(EnginesRoot enginesRoot)
+ {
+ gameEngine.Setup(enginesRoot.GenerateEntityFunctions(), enginesRoot.GenerateEntityFactory());
+ }
+
+ public static void Init()
+ {
+ GameEngineManager.AddGameEngine(gameEngine);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GamecraftModdingAPI/Utility/AsyncUtilsEngine.cs b/GamecraftModdingAPI/Utility/AsyncUtilsEngine.cs
new file mode 100644
index 0000000..9027de1
--- /dev/null
+++ b/GamecraftModdingAPI/Utility/AsyncUtilsEngine.cs
@@ -0,0 +1,50 @@
+using System.Collections;
+using System.Threading.Tasks;
+
+using RobocraftX.Schedulers;
+using Svelto.ECS;
+using Svelto.Tasks.ExtraLean;
+
+using GamecraftModdingAPI.Engines;
+
+namespace GamecraftModdingAPI.Utility
+{
+ public class AsyncUtilsEngine : IApiEngine
+ {
+ private IEntityFunctions _efu;
+ private IEntityFactory _efa;
+ private IEnumerator WaitForSubmissionInternal(IEntityFunctions efu, IEntityFactory efa,
+ EntitiesDB entitiesDB, TaskCompletionSource