diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index c7b5d0d..b901f81 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -372,7 +372,7 @@ namespace GamecraftModdingAPI public SimBody GetSimBody() { return BlockEngine.GetBlockInfo(this, - (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId)); + (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId, st.clusterId)); } private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e) diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 33c4002..2622d41 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Gamecraft.Wires; using RobocraftX.Blocks; @@ -9,6 +10,7 @@ using RobocraftX.Physics; using RobocraftX.Scene.Simulation; using Svelto.DataStructures; using Svelto.ECS; +using Svelto.ECS.Hybrid; using GamecraftModdingAPI.Engines; @@ -90,28 +92,19 @@ namespace GamecraftModdingAPI.Blocks { if (entitiesDB.Exists(block.Id)) return getter(entitiesDB.QueryEntity(block.Id)); - if (block.InitData.Group == null) return def; - var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); - if (initializer.Has()) - return getter(initializer.Get()); - return def; + return GetBlockInitInfo(block, getter, def); } public U GetBlockInfoViewStruct(Block block, Func getter, - U def = default) where T : struct, INeedEGID, IEntityComponent + U def = default) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) - { - // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything - EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); - for (int i = 0; i < entities.count; i++) - { - if (entities[i].ID == block.Id) - { - return getter(entities[i]); - } - } - } + return getter(entitiesDB.QueryEntity(block.Id)); + return GetBlockInitInfo(block, getter, def); + } + + private U GetBlockInitInfo(Block block, Func getter, U def) where T : struct, IEntityComponent + { if (block.InitData.Group == null) return def; var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); if (initializer.Has()) @@ -121,35 +114,26 @@ namespace GamecraftModdingAPI.Blocks public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; - public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, INeedEGID, IEntityComponent + public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) - { - EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); - for (int i = 0; i < entities.count; i++) - { - if (entities[i].ID == block.Id) - { - setter(ref entities[i], value); - return; - } - } - } - else if (block.InitData.Group != null) - { - var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); - T component = initializer.Has() ? initializer.Get() : default; - ref T structRef = ref component; - setter(ref structRef, value); - initializer.Init(structRef); - } + setter(ref entitiesDB.QueryEntity(block.Id), value); + else + SetBlockInitInfo(block, setter, value); } public void SetBlockInfo(Block block, Setter setter, U value) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); - else if (block.InitData.Group != null) + else + SetBlockInitInfo(block, setter, value); + } + + private void SetBlockInitInfo(Block block, Setter setter, U value) + where T : struct, IEntityComponent + { + if (block.InitData.Group != null) { var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); T component = initializer.Has() ? initializer.Get() : default; @@ -222,6 +206,22 @@ namespace GamecraftModdingAPI.Blocks return list.ToArray(); } + public SimBody[] GetClusterBodies(uint cid) + { + var groups = entitiesDB.QueryEntities(); + var bodies = new HashSet(); + foreach (var (coll, _) in groups) + { + foreach (var conn in coll) + { + if (conn.clusterId == cid) + bodies.Add(conn.machineRigidBodyId); + } + } + + return bodies.Select(id => new SimBody(id)).ToArray(); + } + public EGID? FindBlockEGID(uint id) { var groups = entitiesDB.FindGroups(); @@ -234,6 +234,21 @@ namespace GamecraftModdingAPI.Blocks return null; } + public Cluster GetCluster(uint sbid) + { + var groups = entitiesDB.QueryEntities(); + foreach (var (coll, _) in groups) + { + foreach (var conn in coll) + { + if (conn.machineRigidBodyId == sbid) + return new Cluster(conn.clusterId); + } + } + + return null; + } + #if DEBUG public EntitiesDB GetEntitiesDB() { diff --git a/GamecraftModdingAPI/Blocks/BlockIDs.cs b/GamecraftModdingAPI/Blocks/BlockIDs.cs index 596fb38..33f9522 100644 --- a/GamecraftModdingAPI/Blocks/BlockIDs.cs +++ b/GamecraftModdingAPI/Blocks/BlockIDs.cs @@ -192,6 +192,9 @@ namespace GamecraftModdingAPI.Blocks PlayerFilter, TeamFilter, Number2Text, //193 + DestructionManager = 260, + ChunkHealthModifier, + ClusterHealthModifier, //262 BeachTree1 = 200, BeachTree2, BeachTree3, @@ -243,6 +246,8 @@ namespace GamecraftModdingAPI.Blocks AdvancedRotator, MusicBlock, //256 PlasmaCannonBlock, + QuantumRiflePickup = 300, + QuantumRifleAmmoPickup, MagmaRockCube=777, MagmaRockCubeSliced, MagmaRockSlope, diff --git a/GamecraftModdingAPI/Cluster.cs b/GamecraftModdingAPI/Cluster.cs new file mode 100644 index 0000000..074c26c --- /dev/null +++ b/GamecraftModdingAPI/Cluster.cs @@ -0,0 +1,41 @@ +using Gamecraft.Damage; +using RobocraftX.Common; +using Svelto.ECS; + +namespace GamecraftModdingAPI +{ + /// + /// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints. + /// + public class Cluster + { + public EGID Id { get; } + + public Cluster(EGID id) + { + Id = id; + } + + public Cluster(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_CLUSTERS_GROUP)) + { + } + + public float InitialHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).initialHealth; + set => Block.BlockEngine.GetBlockInfo(Id).initialHealth = value; + } + + public float CurrentHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).currentHealth; + set => Block.BlockEngine.GetBlockInfo(Id).currentHealth = value; + } + + public float HealthMultiplier + { + get => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier; + set => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier = value; + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/SimBody.cs b/GamecraftModdingAPI/SimBody.cs index 19f4285..a3f6d55 100644 --- a/GamecraftModdingAPI/SimBody.cs +++ b/GamecraftModdingAPI/SimBody.cs @@ -3,6 +3,7 @@ using Svelto.ECS; using Unity.Mathematics; using UnityEngine; +using Gamecraft.Damage; using RobocraftX.Common; using RobocraftX.Physics; @@ -15,6 +16,14 @@ namespace GamecraftModdingAPI { public EGID Id { get; } + /// + /// The cluster this chunk belongs to, or null if the chunk doesn't exist. Get the SimBody from a Block if possible for good performance here. + /// + public Cluster Cluster => cluster ?? (cluster = clusterId == uint.MaxValue ? Block.BlockEngine.GetCluster(Id.entityID) : new Cluster(clusterId)); + + private Cluster cluster; + private uint clusterId; + public SimBody(EGID id) { Id = id; @@ -24,6 +33,11 @@ namespace GamecraftModdingAPI { } + internal SimBody(uint id, uint clusterID) : this(id) + { + clusterId = clusterID; + } + /// /// The position of this body. When setting the position, update the position of the connected bodies as well, /// otherwise unexpected forces may arise. @@ -70,6 +84,29 @@ namespace GamecraftModdingAPI //set => GetStruct().physicsMass.CenterOfMass = value; } + public float Volume + { + get => GetStruct().volume; + } + + public float InitialHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).initialHealth; + set => Block.BlockEngine.GetBlockInfo(Id).initialHealth = value; + } + + public float CurrentHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).currentHealth; + set => Block.BlockEngine.GetBlockInfo(Id).currentHealth = value; + } + + public float HealthMultiplier + { + get => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier; + set => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier = value; + } + /// /// Whether the body can be moved or static. /// diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index e7bed82..62e369b 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -268,6 +268,16 @@ namespace GamecraftModdingAPI.Tests }) .Build(); + CommandBuilder.Builder("TestChunkHealth", "Sets the chunk looked at to the given health.") + .Action((float val, float max) => + { + var body = new Player(PlayerType.Local).GetSimBodyLookedAt(); + if (body == null) return; + body.CurrentHealth = val; + body.InitialHealth = max; + Logging.CommandLog("Health set to: " + val); + }).Build(); + GameClient.SetDebugInfo("InstalledMods", InstalledMods); Block.Placed += (sender, args) => Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); diff --git a/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs index c604c34..0e4d023 100644 --- a/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs +++ b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using System.Text; using System.Text.Formatting; using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Engines; @@ -46,9 +47,9 @@ namespace GamecraftModdingAPI.Utility var array = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer - new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) + new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) }; - list.InsertRange(index, array); + list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld } catch (Exception e) { @@ -58,13 +59,15 @@ namespace GamecraftModdingAPI.Utility return list; } - public static void AddInfo(StringBuffer sb) + public static void AddInfo(StringBuilder sb) { foreach (var info in _extraInfo) { try { - sb.Append(info.Value() + "\n"); + string text = info.Value().Trim(); + if (text.Length != 0) + sb.Append(text + "\n"); } catch (Exception e) {