diff --git a/GamecraftModdingAPI/Blocks/Tweakable.cs b/GamecraftModdingAPI/Blocks/Tweakable.cs new file mode 100644 index 0000000..920bbb6 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/Tweakable.cs @@ -0,0 +1,102 @@ +using System; + +using Svelto.ECS; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// Common tweakable stats operations. + /// The functionality of this class works best in build mode. + /// + public static class Tweakable + { + private static TweakableEngine tweakableEngine = new TweakableEngine(); + + /// + /// Get the tweakable stat's value using a dynamic variable type. + /// This is similar to GetStat but without strong type enforcement. + /// This should be used in dynamically-typed languages like Python. + /// + /// The stat's value. + /// The block's id. + /// The stat's enumerated id. + public static dynamic GetStatD(uint blockID, TweakableStat stat) + { + return tweakableEngine.GetStatDynamic(blockID, stat); + } + + /// + /// Get the tweakable stat's value. + /// If T is not the same type as the stat, an InvalidCastException will be thrown. + /// + /// The stat's value. + /// The block's id. + /// The stat's enumerated id. + /// The stat's type. + public static T GetStat(uint blockID, TweakableStat stat) + { + return tweakableEngine.GetStatAny(blockID, stat); + } + + /// + /// Set the tweakable stat's value using dynamically-typed variables. + /// This is similar to SetStat but without strong type enforcement. + /// This should be used in dynamically-typed languages like Python. + /// + /// The stat's new value. + /// The block's id. + /// The stat's enumerated id. + /// The stat's new value. + public static dynamic SetStatD(uint blockID, TweakableStat stat, dynamic value) + { + return tweakableEngine.SetStatDynamic(blockID, stat, value); + } + + /// + /// Set the tweakable stat's value. + /// If T is not the stat's actual type, an InvalidCastException will be thrown. + /// + /// The stat's new value. + /// The block's id. + /// The stat's enumerated id. + /// The stat's new value. + /// The stat's type. + public static T SetStat(uint blockID, TweakableStat stat, T value) + { + return tweakableEngine.SetStatAny(blockID, stat, value); + } + + /// + /// Add another value to the tweakable stat's value using dynamically-typed variables. + /// This is similar to AddStat but without strong type enforcement. + /// This should be used in dynamically-typed languages like Python. + /// + /// The stat's new value. + /// The block's id. + /// The stat's enumerated id. + /// The value to be added to the stat. + public static dynamic AddStatD(uint blockID, TweakableStat stat, dynamic value) + { + return tweakableEngine.AddStatDynamic(blockID, stat, value); + } + + /// + /// Add another value to the tweakable stat's value. + /// If T is not the stat's actual type, an InvalidCastException will be thrown. + /// + /// The stat's new value. + /// The block's id. + /// The stat's enumerated id. + /// The value to be added to the stat. + /// The stat's type. + public static T AddStat(uint blockID, TweakableStat stat, T value) + { + return tweakableEngine.AddStatAny(blockID, stat, value); + } + + public static void Init() + { + GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(tweakableEngine); + } + } +} diff --git a/GamecraftModdingAPI/Blocks/TweakableEngine.cs b/GamecraftModdingAPI/Blocks/TweakableEngine.cs new file mode 100644 index 0000000..6d23f85 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/TweakableEngine.cs @@ -0,0 +1,452 @@ +using System; +using System.Reflection; + +using RobocraftX.Blocks; +using Gamecraft.Wires; + +using GamecraftModdingAPI.Utility; +using Svelto.ECS; + +namespace GamecraftModdingAPI.Blocks +{ + public class TweakableEngine : IApiEngine + { + public string Name { get; } = "GamecraftModdingAPITweakableGameEngine"; + + public IEntitiesDB entitiesDB { set; private get; } + + public bool IsInGame = false; + + public void Dispose() + { + IsInGame = false; + } + + public void Ready() + { + IsInGame = true; + } + + // Implementations for Tweakable static class + + public T GetStatAny(EGID blockID, TweakableStat stat) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).maxDeviation; + } + break; + case TweakableStat.Reverse: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).reverse; + } + else if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + return (T)(object)entitiesDB.QueryEntity(blockID).startValue; + } + break; + } + return default(T); + } + + public T GetStatAny(uint blockID, TweakableStat stat) + { + return GetStatAny(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat); + } + + public dynamic GetStatDynamic(EGID blockID, TweakableStat stat) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).maxDeviation; + } + break; + case TweakableStat.Reverse: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).reverse; + } + else if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + return entitiesDB.QueryEntity(blockID).startValue; + } + break; + } + return null; + } + + public dynamic GetStatDynamic(uint blockID, TweakableStat stat) + { + return GetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat); + } + + public T SetStatAny(EGID blockID, TweakableStat stat, T value) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxVelocity = (float)(object)value; + return (T)(object)refStruct.maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxForce = (float)(object)value; + return (T)(object)refStruct.maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation = (float)(object)value; + return (T)(object)refStruct.maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.minDeviation = (float)(object)value; + return (T)(object)refStruct.minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation = (float)(object)value; + return (T)(object)refStruct.maxDeviation; + } + break; + case TweakableStat.Reverse: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = (bool)(object)value; + return (T)(object)refStruct.reverse; + } + else if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = (bool)(object)value; + return (T)(object)refStruct.reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.startValue = (float)(object)value; + return (T)(object)refStruct.startValue; + } + break; + } + return default(T); + } + + public T SetStatAny(uint blockID, TweakableStat stat, T value) + { + return SetStatAny(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); + } + + public dynamic SetStatDynamic(EGID blockID, TweakableStat stat, dynamic value) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxVelocity = value; + return refStruct.maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxForce = value; + return refStruct.maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation = value; + return refStruct.maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.minDeviation = value; + return refStruct.minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation = value; + return refStruct.maxDeviation; + } + break; + case TweakableStat.Reverse: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = value; + return refStruct.reverse; + } + else if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = value; + return refStruct.reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.startValue = value; + return refStruct.startValue; + } + break; + } + return null; + } + + public dynamic SetStatDynamic(uint blockID, TweakableStat stat, dynamic value) + { + return SetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); + } + + public T AddStatAny(EGID blockID, TweakableStat stat, T value) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxVelocity += (float)(object)value; + return (T)(object)refStruct.maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxForce += (float)(object)value; + return (T)(object)refStruct.maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation += (float)(object)value; + return (T)(object)refStruct.maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.minDeviation += (float)(object)value; + return (T)(object)refStruct.minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation += (float)(object)value; + return (T)(object)refStruct.maxDeviation; + } + break; + case TweakableStat.Reverse: + // '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = refStruct.reverse || (bool)(object)value; + return (T)(object)refStruct.reverse; + } + else if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = refStruct.reverse || (bool)(object)value; + return (T)(object)refStruct.reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.startValue += (float)(object)value; + return (T)(object)refStruct.startValue; + } + break; + } + return default(T); + } + + public T AddStatAny(uint blockID, TweakableStat stat, T value) + { + return AddStatAny(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); + } + + public dynamic AddStatDynamic(EGID blockID, TweakableStat stat, dynamic value) + { + switch (stat) + { + case TweakableStat.TopSpeed: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxVelocity += value; + return refStruct.maxVelocity; + } + break; + case TweakableStat.Torque: + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxForce += value; + return refStruct.maxForce; + } + break; + case TweakableStat.MaxExtension: + if (entitiesDB.Exists(blockID)) + { + ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation += value; + return refStruct.maxDeviation; + } + break; + case TweakableStat.MinAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.minDeviation += value; + return refStruct.minDeviation; + } + break; + case TweakableStat.MaxAngle: + if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.maxDeviation += value; + return refStruct.maxDeviation; + } + break; + case TweakableStat.Reverse: + // '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans + if (entitiesDB.Exists(blockID)) + { + ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = refStruct.reverse || value; + return refStruct.reverse; + } + else if (entitiesDB.Exists(blockID)) + { + ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.reverse = refStruct.reverse || value; + return refStruct.reverse; + } + break; + case TweakableStat.StartValue: + if (entitiesDB.Exists(blockID)) + { + ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity(blockID); + refStruct.startValue += value; + return refStruct.startValue; + } + break; + } + return null; + } + + public dynamic AddStatDynamic(uint blockID, TweakableStat stat, dynamic value) + { + return AddStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); + } + } +} diff --git a/GamecraftModdingAPI/Blocks/TweakableStat.cs b/GamecraftModdingAPI/Blocks/TweakableStat.cs new file mode 100644 index 0000000..18f5bad --- /dev/null +++ b/GamecraftModdingAPI/Blocks/TweakableStat.cs @@ -0,0 +1,14 @@ +using System; +namespace GamecraftModdingAPI.Blocks +{ + public enum TweakableStat + { + TopSpeed, // MotorReadOnlyStruct + Torque, // MotorReadOnlyStruct + MaxExtension, // PistonReadOnlyStruct + MinAngle, // ServoReadOnlyStruct + MaxAngle, // ServoReadOnlyStruct + Reverse, // MotorReadOnlyStruct or ServoReadOnlyStruct + StartValue, // SignalGeneratorEntityStruct + } +} diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index a96974d..f7a0abf 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -3,12 +3,16 @@ net472 true - 0.1.3.0 + 0.1.4.0 Exmods GNU General Public Licence 3+ https://git.exmods.org/modtainers/GamecraftModdingAPI en-CA + + + + @@ -543,6 +547,7 @@ ..\ref\Gamecraft_Data\Managed\VisualProfiler.dll + diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index 2c51872..5294c75 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -64,6 +64,7 @@ namespace GamecraftModdingAPI Blocks.Rotation.Init(); Blocks.Signals.Init(); Blocks.Placement.Init(); + Blocks.Tweakable.Init(); Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } diff --git a/doxygen.conf b/doxygen.conf index d163852..1d0f155 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.1.3.0" +PROJECT_NUMBER = "v0.1.4.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