Skip to content

Instantly share code, notes, and snippets.

@jlreymendez
Last active March 9, 2022 16:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlreymendez/c2f441aaf6ac7b5f233ecd990314e9cc to your computer and use it in GitHub Desktop.
Save jlreymendez/c2f441aaf6ac7b5f233ecd990314e9cc to your computer and use it in GitHub Desktop.
using System;
using Svelto.Common;
using Svelto.DataStructures;
namespace Svelto.ECS
{
public static class ExclusiveBuildGroupExtensions
{
internal static FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>
_removeTransitions =
new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>();
internal static FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>
_addTransitions =
new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>();
internal static FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>
_swapTransitions =
new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>>();
public static void SetTagAddition<T>
(this ExclusiveBuildGroup group, ExclusiveBuildGroup target, bool setReverse = true) where T : GroupTag<T>
{
if (_addTransitions.TryGetValue(@group, out var transitions) == false)
{
transitions = new FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>();
_addTransitions[@group] = transitions;
}
var type = new RefWrapper<Type>(typeof(T));
transitions[type] = target;
if (setReverse)
{
SetTagRemoval<T>(target, group, false);
}
}
public static void SetTagRemoval<T>
(this ExclusiveBuildGroup group, ExclusiveBuildGroup target, bool setReverse = true) where T : GroupTag<T>
{
if (_removeTransitions.TryGetValue(@group, out var transitions) == false)
{
transitions = new FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>();
_removeTransitions[@group] = transitions;
}
var type = new RefWrapper<Type>(typeof(T));
transitions[type] = target;
if (setReverse)
{
SetTagAddition<T>(target, group, false);
}
}
public static void SetTagSwap<TRemove, TAdd>
(this ExclusiveBuildGroup group, ExclusiveBuildGroup target, bool setReverse = true)
where TRemove : GroupTag<TRemove> where TAdd : GroupTag<TAdd>
{
if (_swapTransitions.TryGetValue(@group, out var transitions) == false)
{
transitions = new FasterDictionary<RefWrapper<Type>, ExclusiveBuildGroup>();
_swapTransitions[group] = transitions;
}
var type = new RefWrapper<Type>(typeof(TAdd));
transitions[type] = target;
// To avoid needing to check if the group already has the tag when swapping (prevent ecs exceptions).
// The current groups adds the removed tag pointing to itself.
type = new RefWrapper<Type>(typeof(TRemove));
transitions[type] = group;
if (setReverse)
{
SetTagSwap<TAdd, TRemove>(target, group, false);
}
}
}
}
using System;
using Svelto.Common;
using Svelto.DataStructures;
namespace Svelto.ECS
{
public static class ExclusiveGroupStructExtensions
{
public static ExclusiveBuildGroup RemoveTag<T>(this ExclusiveGroupStruct group) where T : GroupTag<T>
{
if (ExclusiveBuildGroupExtensions._removeTransitions.TryGetValue(@group, out var transitions))
{
var type = new RefWrapper<Type>(typeof(T));
if (transitions.TryGetValue(type, out var result))
{
return result;
}
}
throw new ECSException("No remove transition found for type "
.FastConcat(typeof(T).ToString())
.FastConcat(" in group ").FastConcat(@group.ToString())
);
}
public static ExclusiveBuildGroup AddTag<T>(this ExclusiveGroupStruct group) where T : GroupTag<T>
{
if (ExclusiveBuildGroupExtensions._addTransitions.TryGetValue(group, out var transitions))
{
var type = new RefWrapper<Type>(typeof(T));
if (transitions.TryGetValue(type, out var result))
{
return result;
}
}
throw new ECSException("No add transition found for type "
.FastConcat(typeof(T).ToString())
.FastConcat(" in group ").FastConcat(@group.ToString())
);
}
public static ExclusiveBuildGroup SwapTag<TTarget>(this ExclusiveGroupStruct group)
where TTarget : GroupTag<TTarget>
{
var type = new RefWrapper<Type>(typeof(TTarget));
if (ExclusiveBuildGroupExtensions._swapTransitions.TryGetValue(@group, out var transitions))
{
if (transitions.TryGetValue(type, out var result))
{
return result;
}
}
throw new ECSException("No swap transition found for type "
.FastConcat(typeof(TTarget).ToString())
.FastConcat(" in group ").FastConcat(@group.ToString())
);
}
}
}
@Ujinjinjin
Copy link

Hi! I've been following your discussion on discord and have just a few questions on how to use this snippet properly:

  1. Did I get the idea right: this snippet allows us to swap group tags (from current to target) even if target combination of tags not declared in groups class (like GameGroups.cs in Doofuses iteration 3 example)? If so:
  2. On discord you wrote:

The specialized engines define the swaps like this:
GroupCompound<SHIP, AI>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, AI>.BuildGroup);
GroupCompound<SHIP, PLAYER>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, PLAYER>.BuildGroup);

And any engine can do this:
var targetGroup = egid.groupID.GetSwapTag<SUNK_SHIP, SHIP>();
_functions.SwapEntityGroup<ShipEntityDescriptor>(egid, targetGroup);

by specialized / any did you mean not abstract / abstract or something else?

  1. When _removeTransitions, _addTransitions, _swapTransitions should be filled?

@jlreymendez
Copy link
Author

Hey!

1- Yeah, it would allow you to swap to targets that are not directly declared in a group class. In reality you are declaring them when you declare the SetTagSwap, SetTagAddition and SetTagRemoval.

2- Yes, correct by specialized I mean something not abstract, an engine that knows all the tags that apply to an entity. Thus it would allow you to create a comprehensive list of the swaps like you see in that code. Remember that when you do SetTagSwap<SHIP, SUNK_SHIP> the reverse will also be declared automatically.

This is the latest from that code you shared:


            // Register possible transitions.
            GroupCompound<SHIP, AI, PIRATE>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, AI, PIRATE>.BuildGroup);
            GroupCompound<SHIP, AI, MERCHANT>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, AI, MERCHANT>.BuildGroup);
            GroupCompound<SHIP, AI, NORMAL>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, AI, NORMAL>.BuildGroup);

            GroupCompound<SHIP, PLAYER>.BuildGroup.SetTagSwap<SHIP, SUNK_SHIP>(GroupCompound<SUNK_SHIP, PLAYER>.BuildGroup);

3- You would fill them at initialization time, I did it in the Ready() of the engine before entering the game loop. But you could do it in the constructor of the engine. Wherever you find it appropriate before you need to start swapping or changing tags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment