Netcode Bootstrap

This commit is contained in:
Luis Gonzalez
2026-05-31 14:27:52 -07:00
parent 99d8d2d2a9
commit 7fa77ce821
1813 changed files with 2921554 additions and 84 deletions
@@ -0,0 +1,37 @@
using Unity.Entities;
using UnityEngine;
////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public class ModularRigAuthoring: MonoBehaviour
{
public GameObject skinnedMeshRootBone;
public GameObject[] rigParts;
////////////////////////////////////////////////////////////////////////////////////////
class ModularRigBaker: Baker<ModularRigAuthoring>
{
public override void Bake(ModularRigAuthoring a)
{
var e = GetEntity(a, TransformUsageFlags.Renderable);
foreach (var rp in a.rigParts)
{
GetEntity(rp, TransformUsageFlags.Dynamic);
}
var mrps = AddBuffer<ModularRigPartComponent>(e);
for (var i = 0; i < (int)ModularBodyPart.Total; ++i)
{
var mrpc = new ModularRigPartComponent()
{
bodyPart = (ModularBodyPart)i,
currentPartIndex = -1
};
mrps.Add(mrpc);
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 47e513d2e2aa40d45b5d220cdab2254a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/23. Runtime Skinned Mesh Swap/Scripts/ModularRigAuthoring.cs
uploadId: 897522
@@ -0,0 +1,35 @@
using Unity.Collections;
using Unity.Entities;
////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public enum ModularBodyPart
{
Head,
Body,
LeftArm,
RightArm,
Total
}
////////////////////////////////////////////////////////////////////////////////////////
public struct SwitchableBodyPartComponent: IComponentData
{
public ModularBodyPart bodyPart;
public FixedString64Bytes name;
}
////////////////////////////////////////////////////////////////////////////////////////
public struct ModularRigPartComponent: IBufferElementData
{
public ModularBodyPart bodyPart;
public int currentPartIndex;
public FixedList64Bytes<Entity> partsList;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3907b60eb8eed1b4881509fc8e9f7b44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/23. Runtime Skinned Mesh Swap/Scripts/ModularRigComponents.cs
uploadId: 897522
@@ -0,0 +1,128 @@
using Rukhanka.Toolbox;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;
////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public partial class ModularRigInitPartsSystem: SystemBase
{
EntityQuery modularRigQuery, switchableBodyPartsQuery;
BufferTypeHandle<ModularRigPartComponent> modularRigBufAccessor;
EntityTypeHandle entityTypeHandle;
////////////////////////////////////////////////////////////////////////////////////////
protected override void OnCreate()
{
modularRigQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<ModularRigPartComponent>()
.Build(EntityManager);
switchableBodyPartsQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<SwitchableBodyPartComponent>()
.WithOptions(EntityQueryOptions.IncludePrefab)
.Build(EntityManager);
modularRigBufAccessor = GetBufferTypeHandle<ModularRigPartComponent>();
}
////////////////////////////////////////////////////////////////////////////////////////
void InstantiateSkinnedPart(Entity prefabRoot, Entity animatedEntity, EntityCommandBuffer ecb, bool initDisabled)
{
if (!SystemAPI.HasComponent<SkinnedMeshRendererComponent>(prefabRoot))
return;
BurstAssert.IsTrue(!SystemAPI.HasBuffer<LinkedEntityGroup>(prefabRoot), "LEG should not be on skinned mesh entity");
var smrInstance = ecb.Instantiate(prefabRoot);
var p = new Parent();
p.Value = animatedEntity;
ecb.SetComponent(smrInstance, p);
var smr = EntityManager.GetComponentData<SkinnedMeshRendererComponent>(prefabRoot);
p.Value = animatedEntity;
smr.animatedRigEntity = animatedEntity;
smr.rootBoneIndexInRig = EntityManager.GetComponentData<AnimatorEntityRefComponent>(p.Value).boneIndexInAnimationRig;
ecb.SetComponent(smrInstance, smr);
if (initDisabled)
ecb.AddComponent<Disabled>(smrInstance);
}
////////////////////////////////////////////////////////////////////////////////////////
protected override unsafe void OnUpdate()
{
if (switchableBodyPartsQuery.IsEmpty || modularRigQuery.IsEmpty)
return;
var ecb = new EntityCommandBuffer(Allocator.Temp);
var chunks = modularRigQuery.ToArchetypeChunkArray(Allocator.Temp);
modularRigBufAccessor.Update(this);
entityTypeHandle.Update(this);
// The main idea is to define set of replaceable skinned mesh renderers in separate prefab. During instantiation of an animated entity that
// want to use them, copy all parts (represented as entities) to own hierarchy and switch them in runtime using 'Disabled' component
// Things is bit complicated because skinned mesh renderer in entity representation consists of main entity (corresponds to the original skinned mesh GameObject),
// and one or more render entities that are create during baking process (one for each submesh).
foreach (var (sbp, e) in SystemAPI.Query<SwitchableBodyPartComponent>().WithEntityAccess().WithOptions(EntityQueryOptions.IncludePrefab))
{
// Loop over all modular animated entities
for (var k = 0; k < chunks.Length; ++k)
{
var c = chunks[k];
var mrba = c.GetBufferAccessor(ref modularRigBufAccessor);
var processedEntities = c.GetEntityDataPtrRO(entityTypeHandle);
for (var l = 0; l < c.Count; ++l)
{
var mrbArr = mrba[l];
var processedEntity = processedEntities[l];
for (var m = 0; m < mrbArr.Length; ++m)
{
ref var mrb = ref mrbArr.ElementAt(m);
if (mrb.bodyPart == sbp.bodyPart)
{
// Instantiate copy of SMR entities and attach them to the
Debug.Log($"Adding part {e} as {mrb.bodyPart}");
InstantiateSkinnedPart(e, processedEntity, ecb, mrb.currentPartIndex >= 0);
mrb.currentPartIndex = 0;
// We cannot add created smr instance reference here because entity is still deferred.
// Need to make separate loop after command buffer playback
}
}
}
}
ecb.RemoveComponent<SwitchableBodyPartComponent>(e);
}
ecb.Playback(EntityManager);
// Loop one more time but this time we are processing already instantiated entities
// We need to populate parts list
ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (var (sbp, asmc, e) in SystemAPI.Query<SwitchableBodyPartComponent, SkinnedMeshRendererComponent>().WithEntityAccess().WithOptions(EntityQueryOptions.IncludeDisabledEntities))
{
var mrpBuf = EntityManager.GetBuffer<ModularRigPartComponent>(asmc.animatedRigEntity);
for (int i = 0; i < mrpBuf.Length; ++i)
{
ref var mrp = ref mrpBuf.ElementAt(i);
if (mrp.bodyPart == sbp.bodyPart)
{
mrp.partsList.Add(e);
}
}
ecb.RemoveComponent<SwitchableBodyPartComponent>(e);
}
ecb.Playback(EntityManager);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0c1810384aab200418da5b38e679bc21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/23. Runtime Skinned Mesh Swap/Scripts/ModularRigInitPartsSystem.cs
uploadId: 897522
@@ -0,0 +1,30 @@
using TMPro;
using Unity.Entities;
using UnityEngine;
////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
[RequireComponent(typeof(SkinnedMeshRenderer))]
public class SwitchableBodyPartAuthoring: MonoBehaviour
{
public ModularBodyPart bodyPart;
////////////////////////////////////////////////////////////////////////////////////////
class SwitchableBodyPartBaker: Baker<SwitchableBodyPartAuthoring>
{
public override void Bake(SwitchableBodyPartAuthoring a)
{
var e = GetEntity(a, TransformUsageFlags.Renderable);
var sbp = new SwitchableBodyPartComponent()
{
bodyPart = a.bodyPart,
name = a.name,
};
AddComponent(e, sbp);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f11387011a1d8ff40aafcc6545ca903b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/23. Runtime Skinned Mesh Swap/Scripts/SwitchableBodyPartAuthoring.cs
uploadId: 897522