/// <summary> /// Add and remove multiple component to an entity /// </summary> /// <param name="entityHandle"></param> /// <param name="componentType"></param> /// <returns></returns> public void AddRemoveMultipleComponent(GameEntityHandle entityHandle, Span <ComponentType> addSpan, Span <ComponentType> removeSpan) { ThrowOnInvalidHandle(entityHandle); var updateArch = false; foreach (ref readonly var componentType in addSpan) { var componentBoard = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType); var cRef = new ComponentReference(componentType, GameWorldLL.CreateComponent(componentBoard)); updateArch |= GameWorldLL.AssignComponent(componentBoard, cRef, Boards.Entity, entityHandle); GameWorldLL.SetOwner(componentBoard, cRef, entityHandle); } foreach (ref readonly var componentType in removeSpan) { updateArch |= GameWorldLL.RemoveComponentReference(GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType), componentType, Boards.Entity, entityHandle); } if (updateArch) { GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); } }
/// <summary> /// Get the reference to a component data from an entity /// </summary> /// <param name="entityHandle"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> /// <exception cref="InvalidOperationException"></exception> public ref T GetComponentData <T>(GameEntityHandle entityHandle) where T : struct, IComponentData { ThrowOnInvalidHandle(entityHandle); var componentType = AsComponentType <T>().Id; var board = Boards.ComponentType.ComponentBoardColumns[(int)componentType]; if (board is TagComponentBoard) { return(ref TagComponentBoard.Default <T> .V); } if (!(board is SingleComponentBoard componentColumn)) { throw new InvalidOperationException($"A board made from an {nameof(IComponentData)} should be a {nameof(SingleComponentBoard)}"); } #if DEBUG if (!HasComponent(entityHandle, new ComponentType(componentType))) { var msg = $"{Safe(entityHandle)} has no {Boards.ComponentType.NameColumns[(int) componentType]}. Existing:\n"; var componentList = Boards.Archetype.GetComponentTypes(GetArchetype(entityHandle).Id); foreach (var comp in componentList) { msg += $" [{comp}] {Boards.ComponentType.NameColumns[(int) comp]}\n"; } throw new InvalidOperationException(msg); } #endif return(ref componentColumn.AsSpan <T>()[Boards.Entity.GetComponentColumn(componentType)[(int)entityHandle.Id].Assigned]);
public ComponentReference Copy(GameEntityHandle from, GameEntityHandle to, ComponentType componentType) { ThrowOnInvalidHandle(from); ThrowOnInvalidHandle(to); if (!HasComponent(from, componentType)) { throw new InvalidOperationException(); } var fromMetadata = GetComponentMetadata(from, componentType); var toRef = AddComponent(to, componentType); var componentBoard = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType); switch (componentBoard) { case SingleComponentBoard singleComponentBoard: singleComponentBoard.ReadRaw(fromMetadata.Id) .CopyTo(singleComponentBoard.ReadRaw(toRef.Id)); break; case BufferComponentBoard bufferComponentBoard: { var toBuffer = bufferComponentBoard.AsSpan()[(int)toRef.Id]; toBuffer.Clear(); toBuffer.AddRange(bufferComponentBoard.AsSpan()[(int)fromMetadata.Id]); break; } } return(toRef); }
public GameEntityHandle CreateEntity() { var handle = new GameEntityHandle(Boards.Entity.CreateRow()); GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, handle); return(handle); }
/// <summary> /// Assure that an entity has the components. If an entity already possess one of them, it will not get replaced. /// </summary> /// <param name="entityHandle"></param> /// <param name="componentTypeSpan"></param> public void AssureComponents(GameEntityHandle entityHandle, Span <ComponentType> componentTypeSpan) { var updateArchetype = false; var entityBoard = Boards.Entity; foreach (ref readonly var componentType in componentTypeSpan) { // TODO: support for shared component if (entityBoard.GetComponentColumn(componentType.Id)[(int)entityHandle.Id].Valid) { continue; } var componentBoard = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType); var cRef = new ComponentReference(componentType, GameWorldLL.CreateComponent(componentBoard)); GameWorldLL.AssignComponent(componentBoard, cRef, Boards.Entity, entityHandle); GameWorldLL.SetOwner(componentBoard, cRef, entityHandle); updateArchetype = true; } if (updateArchetype) { GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); } }
/// <summary> /// Set if a child entity should be linked to an owner entity. If the owner get removed, the child will too. /// </summary> /// <param name="child"></param> /// <param name="owner"></param> /// <param name="isLinked"></param> /// <returns>Return if the linking state has been changed</returns> public bool Link(GameEntityHandle child, GameEntityHandle owner, bool isLinked) { ThrowOnInvalidHandle(child); ThrowOnInvalidHandle(owner); return(isLinked ? Boards.Entity.AddLinked(owner.Id, child.Id) : Boards.Entity.RemoveLinked(owner.Id, child.Id)); }
public GameEntity Safe(GameEntityHandle handle) { ThrowOnInvalidHandle(handle); unchecked { return(new GameEntity(handle.Id, Boards.Entity.VersionColumn[(int)handle.Id])); } }
/// <summary> /// Assign an existing component to an entity /// </summary> /// <param name="entityHandle"></param> /// <param name="component"></param> public void AssignComponent(GameEntityHandle entityHandle, ComponentReference component) { ThrowOnInvalidHandle(entityHandle); var board = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, component.Type); GameWorldLL.AssignComponent(board, component, Boards.Entity, entityHandle); GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); }
public ComponentReference GetComponentReference <T>(GameEntityHandle entityHandle) where T : struct, IEntityComponent { ThrowOnInvalidHandle(entityHandle); var componentType = AsComponentType <T>(); return(new ComponentReference(componentType, Boards.Entity.GetComponentColumn(componentType.Id)[(int)entityHandle.Id].Id)); }
public void ThrowOnInvalidHandle(GameEntityHandle handle) { if (handle.Id == 0) { throw new InvalidOperationException("You've passed an invalid handle"); } if (Boards.Entity.ArchetypeColumn[(int)handle.Id].Id == 0) { throw new InvalidOperationException($"The GameWorld does not contains a handle with id '{handle.Id}'"); } }
/// <summary> /// Remove a component from an entity. /// </summary> /// <param name="entityHandle">The entity</param> /// <param name="componentType">The component type</param> /// <returns>True if the component was removed, false if it did not exist.</returns> public bool RemoveComponent(GameEntityHandle entityHandle, ComponentType componentType) { ThrowOnInvalidHandle(entityHandle); if (GameWorldLL.RemoveComponentReference(GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType), componentType, Boards.Entity, entityHandle)) { GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); return(true); } return(false); }
/// <summary> /// Add multiple component to an entity /// </summary> /// <param name="entityHandle"></param> /// <param name="componentType"></param> /// <remarks> /// If you wish to not replace existing components, use <see cref="AssureComponents"/> (a bit slower than this method) /// </remarks> public void AddMultipleComponent(GameEntityHandle entityHandle, Span <ComponentType> componentTypeSpan) { ThrowOnInvalidHandle(entityHandle); foreach (ref readonly var componentType in componentTypeSpan) { var componentBoard = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType); var cRef = new ComponentReference(componentType, GameWorldLL.CreateComponent(componentBoard)); GameWorldLL.AssignComponent(componentBoard, cRef, Boards.Entity, entityHandle); GameWorldLL.SetOwner(componentBoard, cRef, entityHandle); } GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); }
public void RemoveEntity(GameEntityHandle entityHandle) { ThrowOnInvalidHandle(entityHandle); foreach (ref readonly var componentType in Boards.ComponentType.Registered) { RemoveComponent(entityHandle, componentType); } var children = Boards.Entity.GetLinkedEntities(entityHandle.Id); var childrenLength = children.Length; for (var ent = 0; ent < childrenLength; ent++) { var linkedEntity = children[ent]; if (Contains(linkedEntity)) { RemoveEntity(linkedEntity); ent--; childrenLength--; } } var parents = Boards.Entity.GetLinkedParents(entityHandle.Id); var parentLength = parents.Length; for (var ent = 0; ent < parentLength; ent++) { var parent = parents[ent]; if (Boards.Entity.RemoveLinked(parent.Id, entityHandle.Id)) { ent--; parentLength--; } } var archetype = GetArchetype(entityHandle); if (archetype.Id > 0) { Boards.Archetype.RemoveEntity(archetype.Id, entityHandle.Id); // Reset archetype of this ID. // Since we share the total entity span on clients, the client should know that the entity is deleted via its archetype Boards.Entity.ArchetypeColumn[(int)entityHandle.Id] = default; } Boards.Entity.DeleteRow(entityHandle.Id); }
/// <summary> /// Add a component to an entity /// </summary> /// <param name="entityHandle"></param> /// <param name="componentType"></param> /// <returns></returns> public ComponentReference AddComponent(GameEntityHandle entityHandle, ComponentType componentType) { ThrowOnInvalidHandle(entityHandle); var componentBoard = GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType); var cRef = new ComponentReference(componentType, GameWorldLL.CreateComponent(componentBoard)); GameWorldLL.SetOwner(componentBoard, cRef, entityHandle); // Only update archetype if this is a new component to the entity, and not just an update if (GameWorldLL.AssignComponent(componentBoard, cRef, Boards.Entity, entityHandle)) { GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); } return(cRef); }
/// <summary> /// Remove a component from an entity. /// </summary> /// <param name="entityHandle">The entity</param> /// <param name="componentType">The component type</param> /// <returns>True if the component was removed, false if it did not exist.</returns> public bool RemoveMultipleComponent(GameEntityHandle entityHandle, Span <ComponentType> componentTypeSpan) { ThrowOnInvalidHandle(entityHandle); var b = true; foreach (ref readonly var componentType in componentTypeSpan) { b &= GameWorldLL.RemoveComponentReference(GameWorldLL.GetComponentBoardBase(Boards.ComponentType, componentType), componentType, Boards.Entity, entityHandle); } if (b) { GameWorldLL.UpdateArchetype(Boards.Archetype, Boards.ComponentType, Boards.Entity, entityHandle); } return(b); }
/// <summary> /// Check whether or not an entity has a component /// </summary> /// <param name="entityHandle"></param> /// <param name="componentType"></param> /// <returns></returns> public bool HasComponent(GameEntityHandle entityHandle, ComponentType componentType) { var recursionLeft = RecursionLimit; var originalEntity = entityHandle; while (recursionLeft-- > 0) { var link = Boards.Entity.GetComponentColumn(componentType.Id)[(int)entityHandle.Id]; if (link.IsShared) { entityHandle = new GameEntityHandle(link.Entity); continue; } return(link.Id > 0); } throw new InvalidOperationException($"HasComponent - Recursion limit reached with '{originalEntity}' and component (backing: {componentType})"); }
public void GetComponentOf <TList>(GameEntityHandle entityHandle, ComponentType baseType, TList list) where TList : IList <ComponentReference> { ThrowOnInvalidHandle(entityHandle); var archetype = GetArchetype(entityHandle); foreach (var componentTypeId in Boards.Archetype.GetComponentTypes(archetype.Id)) { if (Boards.ComponentType.ParentTypeColumns[(int)componentTypeId] != baseType) { continue; } var componentType = new ComponentType(componentTypeId); var metadata = GetComponentMetadata(entityHandle, componentType); if (metadata.Null) { continue; } list.Add(new ComponentReference(componentType, metadata.Id)); } }
public EntityArchetype GetArchetype(GameEntityHandle entityHandle) { return(Boards.Entity.ArchetypeColumn[(int)entityHandle.Id]); }
/// <summary> /// Add a component to an entity /// </summary> /// <param name="entityHandle"></param> /// <param name="data"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public ComponentReference AddComponent <T>(GameEntityHandle entityHandle, in T data = default)
/// <summary> /// Whether or not this entity handle is valid in the boards. /// </summary> public bool Contains(GameEntityHandle entityHandle) { return(entityHandle.Id < Boards.Entity.ArchetypeColumn.Length && Boards.Entity.ArchetypeColumn[(int)entityHandle.Id].Id > 0); }
/// <summary> /// Check whether or not an entity has a component /// </summary> /// <param name="entityHandle"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public bool HasComponent <T>(GameEntityHandle entityHandle) where T : struct, IEntityComponent { return(HasComponent(entityHandle, AsComponentType <T>())); }
public EntityBoardContainer.ComponentMetadata GetComponentMetadata(GameEntityHandle entityHandle, ComponentType componentType) { ThrowOnInvalidHandle(entityHandle); return(Boards.Entity.GetComponentColumn(componentType.Id)[(int)entityHandle.Id]); }