Fixes, block IDs, cluster & chunk health support

This commit is contained in:
Norbi Peti 2020-08-13 16:59:13 +02:00
parent 50ebf4f0a6
commit 2172364d26
7 changed files with 154 additions and 43 deletions

View file

@ -372,7 +372,7 @@ namespace GamecraftModdingAPI
public SimBody GetSimBody() public SimBody GetSimBody()
{ {
return BlockEngine.GetBlockInfo(this, 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) private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e)

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Gamecraft.Wires; using Gamecraft.Wires;
using RobocraftX.Blocks; using RobocraftX.Blocks;
@ -9,6 +10,7 @@ using RobocraftX.Physics;
using RobocraftX.Scene.Simulation; using RobocraftX.Scene.Simulation;
using Svelto.DataStructures; using Svelto.DataStructures;
using Svelto.ECS; using Svelto.ECS;
using Svelto.ECS.Hybrid;
using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Engines;
@ -90,28 +92,19 @@ namespace GamecraftModdingAPI.Blocks
{ {
if (entitiesDB.Exists<T>(block.Id)) if (entitiesDB.Exists<T>(block.Id))
return getter(entitiesDB.QueryEntity<T>(block.Id)); return getter(entitiesDB.QueryEntity<T>(block.Id));
if (block.InitData.Group == null) return def; return GetBlockInitInfo(block, getter, def);
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
if (initializer.Has<T>())
return getter(initializer.Get<T>());
return def;
} }
public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter, public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter,
U def = default) where T : struct, INeedEGID, IEntityComponent U def = default) where T : struct, IEntityViewComponent
{ {
if (entitiesDB.Exists<T>(block.Id)) if (entitiesDB.Exists<T>(block.Id))
{ return getter(entitiesDB.QueryEntity<T>(block.Id));
// TODO: optimize by using EntitiesDB internal calls instead of iterating over everything return GetBlockInitInfo(block, getter, def);
EntityCollection<T> entities = entitiesDB.QueryEntities<T>(block.Id.groupID); }
for (int i = 0; i < entities.count; i++)
{ private U GetBlockInitInfo<T, U>(Block block, Func<T, U> getter, U def) where T : struct, IEntityComponent
if (entities[i].ID == block.Id) {
{
return getter(entities[i]);
}
}
}
if (block.InitData.Group == null) return def; if (block.InitData.Group == null) return def;
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
if (initializer.Has<T>()) if (initializer.Has<T>())
@ -121,35 +114,26 @@ namespace GamecraftModdingAPI.Blocks
public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent; public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent;
public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, INeedEGID, IEntityComponent public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, IEntityViewComponent
{ {
if (entitiesDB.Exists<T>(block.Id)) if (entitiesDB.Exists<T>(block.Id))
{ setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
EntityCollection<T> entities = entitiesDB.QueryEntities<T>(block.Id.groupID); else
for (int i = 0; i < entities.count; i++) SetBlockInitInfo(block, setter, value);
{
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<T>() ? initializer.Get<T>() : default;
ref T structRef = ref component;
setter(ref structRef, value);
initializer.Init(structRef);
}
} }
public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent
{ {
if (entitiesDB.Exists<T>(block.Id)) if (entitiesDB.Exists<T>(block.Id))
setter(ref entitiesDB.QueryEntity<T>(block.Id), value); setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
else if (block.InitData.Group != null) else
SetBlockInitInfo(block, setter, value);
}
private void SetBlockInitInfo<T, U>(Block block, Setter<T, U> setter, U value)
where T : struct, IEntityComponent
{
if (block.InitData.Group != null)
{ {
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
T component = initializer.Has<T>() ? initializer.Get<T>() : default; T component = initializer.Has<T>() ? initializer.Get<T>() : default;
@ -222,6 +206,22 @@ namespace GamecraftModdingAPI.Blocks
return list.ToArray(); return list.ToArray();
} }
public SimBody[] GetClusterBodies(uint cid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
var bodies = new HashSet<uint>();
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) public EGID? FindBlockEGID(uint id)
{ {
var groups = entitiesDB.FindGroups<DBEntityStruct>(); var groups = entitiesDB.FindGroups<DBEntityStruct>();
@ -234,6 +234,21 @@ namespace GamecraftModdingAPI.Blocks
return null; return null;
} }
public Cluster GetCluster(uint sbid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
foreach (var (coll, _) in groups)
{
foreach (var conn in coll)
{
if (conn.machineRigidBodyId == sbid)
return new Cluster(conn.clusterId);
}
}
return null;
}
#if DEBUG #if DEBUG
public EntitiesDB GetEntitiesDB() public EntitiesDB GetEntitiesDB()
{ {

View file

@ -192,6 +192,9 @@ namespace GamecraftModdingAPI.Blocks
PlayerFilter, PlayerFilter,
TeamFilter, TeamFilter,
Number2Text, //193 Number2Text, //193
DestructionManager = 260,
ChunkHealthModifier,
ClusterHealthModifier, //262
BeachTree1 = 200, BeachTree1 = 200,
BeachTree2, BeachTree2,
BeachTree3, BeachTree3,
@ -243,6 +246,8 @@ namespace GamecraftModdingAPI.Blocks
AdvancedRotator, AdvancedRotator,
MusicBlock, //256 MusicBlock, //256
PlasmaCannonBlock, PlasmaCannonBlock,
QuantumRiflePickup = 300,
QuantumRifleAmmoPickup,
MagmaRockCube=777, MagmaRockCube=777,
MagmaRockCubeSliced, MagmaRockCubeSliced,
MagmaRockSlope, MagmaRockSlope,

View file

@ -0,0 +1,41 @@
using Gamecraft.Damage;
using RobocraftX.Common;
using Svelto.ECS;
namespace GamecraftModdingAPI
{
/// <summary>
/// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints.
/// </summary>
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<HealthEntityComponent>(Id).initialHealth;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value;
}
public float CurrentHealth
{
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value;
}
public float HealthMultiplier
{
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value;
}
}
}

View file

@ -3,6 +3,7 @@ using Svelto.ECS;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEngine; using UnityEngine;
using Gamecraft.Damage;
using RobocraftX.Common; using RobocraftX.Common;
using RobocraftX.Physics; using RobocraftX.Physics;
@ -15,6 +16,14 @@ namespace GamecraftModdingAPI
{ {
public EGID Id { get; } public EGID Id { get; }
/// <summary>
/// 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.
/// </summary>
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) public SimBody(EGID id)
{ {
Id = id; Id = id;
@ -24,6 +33,11 @@ namespace GamecraftModdingAPI
{ {
} }
internal SimBody(uint id, uint clusterID) : this(id)
{
clusterId = clusterID;
}
/// <summary> /// <summary>
/// The position of this body. When setting the position, update the position of the connected bodies as well, /// The position of this body. When setting the position, update the position of the connected bodies as well,
/// otherwise unexpected forces may arise. /// otherwise unexpected forces may arise.
@ -70,6 +84,29 @@ namespace GamecraftModdingAPI
//set => GetStruct().physicsMass.CenterOfMass = value; //set => GetStruct().physicsMass.CenterOfMass = value;
} }
public float Volume
{
get => GetStruct().volume;
}
public float InitialHealth
{
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value;
}
public float CurrentHealth
{
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value;
}
public float HealthMultiplier
{
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier;
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value;
}
/// <summary> /// <summary>
/// Whether the body can be moved or static. /// Whether the body can be moved or static.
/// </summary> /// </summary>

View file

@ -268,6 +268,16 @@ namespace GamecraftModdingAPI.Tests
}) })
.Build(); .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); GameClient.SetDebugInfo("InstalledMods", InstalledMods);
Block.Placed += (sender, args) => Block.Placed += (sender, args) =>
Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID);

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Text;
using System.Text.Formatting; using System.Text.Formatting;
using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Engines;
@ -46,9 +47,9 @@ namespace GamecraftModdingAPI.Utility
var array = new CodeInstruction[] var array = new CodeInstruction[]
{ {
new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer
new CodeInstruction(OpCodes.Call, ((Action<StringBuffer>)AddInfo).Method) new CodeInstruction(OpCodes.Call, ((Action<StringBuilder>)AddInfo).Method)
}; };
list.InsertRange(index, array); list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld
} }
catch (Exception e) catch (Exception e)
{ {
@ -58,13 +59,15 @@ namespace GamecraftModdingAPI.Utility
return list; return list;
} }
public static void AddInfo(StringBuffer sb) public static void AddInfo(StringBuilder sb)
{ {
foreach (var info in _extraInfo) foreach (var info in _extraInfo)
{ {
try try
{ {
sb.Append(info.Value() + "\n"); string text = info.Value().Trim();
if (text.Length != 0)
sb.Append(text + "\n");
} }
catch (Exception e) catch (Exception e)
{ {