diff --git a/GamecraftModdingAPI/Commands/CommandBuilder.cs b/GamecraftModdingAPI/Commands/CommandBuilder.cs
new file mode 100644
index 0000000..f0f9258
--- /dev/null
+++ b/GamecraftModdingAPI/Commands/CommandBuilder.cs
@@ -0,0 +1,181 @@
+using System;
+
+using Svelto.ECS;
+
+using GamecraftModdingAPI.Utility;
+
+namespace GamecraftModdingAPI.Commands
+{
+ ///
+ /// Custom Command builder.
+ ///
+ public class CommandBuilder
+ {
+ private string name;
+
+ private string description;
+
+ private short parameterCount;
+
+ private ICustomCommandEngine commandEngine;
+
+ ///
+ /// Create a new command builder.
+ ///
+ public CommandBuilder()
+ {
+ name = "";
+ description = null;
+ parameterCount = -1;
+ }
+
+ ///
+ /// Create and return a command builder.
+ ///
+ /// The builder.
+ public static CommandBuilder Builder()
+ {
+ return new CommandBuilder();
+ }
+
+ ///
+ /// Create a new command builder.
+ ///
+ /// The command name.
+ /// The command description (shown in help).
+ public CommandBuilder(string name, string description = null)
+ {
+ this.name = name;
+ this.description = description;
+ parameterCount = -1;
+ }
+
+ ///
+ /// Create and return a command builder.
+ /// If name and description are provided, this is equivalent to Builder().Name(name).Description(description)
+ ///
+ /// The command name.
+ /// The command description (shown in help).
+ /// The builder.
+ public static CommandBuilder Builder(string name, string description = null)
+ {
+ return new CommandBuilder(name, description);
+ }
+
+ ///
+ /// Name the command.
+ ///
+ /// The builder.
+ /// The command name.
+ public CommandBuilder Name(string name)
+ {
+ this.name = name;
+ return this;
+ }
+
+ ///
+ /// Describe the command.
+ ///
+ /// The builder.
+ /// The command description (shown in help).
+ public CommandBuilder Description(string description)
+ {
+ this.description = description;
+ return this;
+ }
+
+ ///
+ /// Set the action the command performs.
+ ///
+ /// The builder.
+ /// The action to perform when the command is called.
+ public CommandBuilder Action(Action action)
+ {
+ parameterCount = 0;
+ commandEngine = new SimpleCustomCommandEngine(action, name, description);
+ return this;
+ }
+
+ ///
+ /// Set the action the command performs.
+ ///
+ /// The builder.
+ /// The action to perform when the command is called.
+ /// The 1st parameter's type.
+ public CommandBuilder Action(Action action)
+ {
+ parameterCount = 1;
+ commandEngine = new SimpleCustomCommandEngine(action, name, description);
+ return this;
+ }
+
+ ///
+ /// Set the action the command performs.
+ ///
+ /// The builder.
+ /// The action to perform when the command is called.
+ /// The 1st parameter's type.
+ /// The 2nd parameter's type.
+ public CommandBuilder Action(Action action)
+ {
+ parameterCount = 2;
+ commandEngine = new SimpleCustomCommandEngine(action, name, description);
+ return this;
+ }
+
+ ///
+ /// Set the action the command performs.
+ ///
+ /// The builder.
+ /// The action to perform when the command is called.
+ /// The 1st parameter's type.
+ /// The 2nd parameter's type.
+ /// The 3rd parameter's type.
+ public CommandBuilder Action(Action action)
+ {
+ parameterCount = 3;
+ commandEngine = new SimpleCustomCommandEngine(action, name, description);
+ return this;
+ }
+
+ ///
+ /// Build the command.
+ ///
+ /// The built command.
+ /// Automatically register the command with CommandManager.AddCommand()?
+ public ICustomCommandEngine Build(bool register = true)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new InvalidOperationException("Command name must be defined before Build() is called");
+ }
+ if (commandEngine == null)
+ {
+ throw new InvalidOperationException("Command action must be defined before Build() is called");
+ }
+ if (string.IsNullOrWhiteSpace(description))
+ {
+ Logging.LogWarning($"Command {name} was built without a description");
+ }
+ if (register)
+ {
+ CommandManager.AddCommand(commandEngine);
+ Logging.MetaDebugLog($"Command {FullName()} was automatically registered");
+ }
+ return commandEngine;
+ }
+
+ ///
+ /// Get the full command name, in the form [name]::[description]::[# of parameters]
+ ///
+ /// The name.
+ public string FullName()
+ {
+ if (string.IsNullOrWhiteSpace(description))
+ {
+ return name + "::" + parameterCount;
+ }
+ return name + "::" + description + "::" + parameterCount;
+ }
+ }
+}
diff --git a/GamecraftModdingAPI/Commands/CommandManager.cs b/GamecraftModdingAPI/Commands/CommandManager.cs
index f2f79b4..986405e 100644
--- a/GamecraftModdingAPI/Commands/CommandManager.cs
+++ b/GamecraftModdingAPI/Commands/CommandManager.cs
@@ -22,6 +22,10 @@ namespace GamecraftModdingAPI.Commands
public static void AddCommand(ICustomCommandEngine engine)
{
+ if (ExistsCommand(engine))
+ {
+ Logging.LogWarning($"Command {engine.Name} already exists!");
+ }
_customCommands[engine.Name] = engine;
if (_lastEngineRoot != null)
{
diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj
index 9b76ea5..263c18a 100644
--- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj
+++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj
@@ -3,7 +3,7 @@
net472
true
- 0.2.2
+ 1.0.0
Exmods
GNU General Public Licence 3+
https://git.exmods.org/modtainers/GamecraftModdingAPI
diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
index 11d63c6..732854e 100644
--- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
+++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
@@ -81,8 +81,67 @@ namespace GamecraftModdingAPI.Tests
// debug/test commands
if (Dependency.Hell("ExtraCommands"))
{
- CommandManager.AddCommand(new SimpleCustomCommandEngine(() => { UnityEngine.Application.Quit(); },
- "Exit", "Close Gamecraft without any prompts"));
+ CommandBuilder.Builder()
+ .Name("Exit")
+ .Description("Close Gamecraft immediately, without any prompts")
+ .Action(() => { UnityEngine.Application.Quit(); })
+ .Build();
+
+ CommandBuilder.Builder()
+ .Name("SetFOV")
+ .Description("Set the player camera's field of view")
+ .Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; })
+ .Build();
+
+ CommandBuilder.Builder()
+ .Name("MoveLastBlock")
+ .Description("Move the most-recently-placed block, and any connected blocks by the given offset")
+ .Action((float x, float y, float z) => {
+ bool success = GamecraftModdingAPI.Blocks.Movement.MoveConnectedBlocks(
+ GamecraftModdingAPI.Blocks.BlockIdentifiers.LatestBlockID,
+ new Unity.Mathematics.float3(x, y, z));
+ if (!success)
+ {
+ GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!");
+ }
+ }).Build();
+
+ CommandBuilder.Builder()
+ .Name("PlaceAluminium")
+ .Description("Place a block of aluminium at the given coordinates")
+ .Action((float x, float y, float z) => { Blocks.Placement.PlaceBlock(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); })
+ .Build();
+
+ System.Random random = new System.Random(); // for command below
+ CommandBuilder.Builder()
+ .Name("RandomizeSignalsInputs")
+ .Description("Do the thing")
+ .Action(() => {
+ if (!GameState.IsSimulationMode())
+ {
+ Logging.CommandLogError("You must be in simulation mode for this to work!");
+ return;
+ }
+ Tasks.Repeatable task = new Tasks.Repeatable(
+ () => {
+ uint count = 0;
+ EGID[] eBlocks = Blocks.Signals.GetElectricBlocks();
+ for (uint i = 0u; i < eBlocks.Length; i++)
+ {
+ uint[] ids = Blocks.Signals.GetSignalIDs(eBlocks[i]);
+ for (uint j = 0u; j < ids.Length; j++)
+ {
+ Blocks.Signals.SetSignalByID(ids[j], (float)random.NextDouble());
+ count++;
+ }
+ }
+ Logging.MetaDebugLog($"Did the thing on {count} inputs");
+ },
+ () => { return GameState.IsSimulationMode(); });
+ Tasks.Scheduler.Schedule(task);
+ }).Build();
+
+ /*
CommandManager.AddCommand(new SimpleCustomCommandEngine((float d) => { UnityEngine.Camera.main.fieldOfView = d; },
"SetFOV", "Set the player camera's field of view"));
CommandManager.AddCommand(new SimpleCustomCommandEngine(
@@ -98,10 +157,6 @@ namespace GamecraftModdingAPI.Tests
CommandManager.AddCommand(new SimpleCustomCommandEngine(
(x, y, z) => { Blocks.Placement.PlaceBlock(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); },
"PlaceAluminium", "Place a block of aluminium at the given coordinates"));
- Analytics.DeltaDNAHelper.PlayerLifetimeParameters plp = new Analytics.DeltaDNAHelper.PlayerLifetimeParameters();
- CommandManager.AddCommand(new SimpleCustomCommandEngine(
- (s) => { Analytics.DeltaDNAHelper.SendActionCompletedEvent(in plp, s.Replace(", ", " ")); },
- "SendAnalyticsAction", "Send an analytics action"));
System.Random random = new System.Random(); // for command below
CommandManager.AddCommand(new SimpleCustomCommandEngine(
() => {
@@ -127,6 +182,7 @@ namespace GamecraftModdingAPI.Tests
() => { return GameState.IsSimulationMode(); });
Tasks.Scheduler.Schedule(task);
}, "RandomizeSignalsInputs", "Do the thing"));
+ */
}
// dependency test
diff --git a/doxygen.conf b/doxygen.conf
index 4596b01..0535320 100644
--- a/doxygen.conf
+++ b/doxygen.conf
@@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "v0.2.2"
+PROJECT_NUMBER = "v1.0.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a