该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

304 行
12 KiB

using Unity.Animation;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Sample.Core;
using Unity.Transforms;
using UnityEngine;
public class PartOwner
{
public struct Visible : IComponentData
{}
public struct RegistryAsset : IComponentData
{
public RegistryAsset(WeakAssetReference value)
{
Value = value;
}
public WeakAssetReference Value;
}
public struct InputState : IComponentData //, IReplicatedComponent
{
public static InputState Default => new InputState { };
public uint PackedPartIds;
// public static IReplicatedComponentSerializerFactory CreateSerializerFactory()
// {
// return new ReplicatedComponentSerializerFactory<InputState>();
// }
//
// public void Serialize(ref SerializeContext context, ref NetworkWriter writer)
// {
// writer.WriteUInt32("parts",PackedPartIds);
// }
//
// public void Deserialize(ref SerializeContext context, ref NetworkReader reader)
// {
// PackedPartIds = reader.ReadUInt32();
// }
}
struct State : ISystemStateComponentData
{
public static State Default => new State { currentLOD = -1, };
public uint CurrentPackedPartIds;
public int currentLOD;
public BlobAssetReference<RigDefinition> currentRig;
}
struct PartElement : ISystemStateBufferElementData
{
public static PartElement Default => new PartElement();
public Entity PartEntity;
public int PartId;
public WeakAssetReference Asset;
}
[UpdateInGroup(typeof(PartSystemUpdateGroup))]
class Initialization : ComponentSystem
{
protected override void OnUpdate()
{
Entities.WithNone<State>().ForEach((Entity entity, ref RegistryAsset registryAsset) =>
{
GameDebug.Log(World, Part.ShowLifetime, "Initializing PartOwner:{0}", entity);
var registry = PartRegistry.GetPartRegistry(World, registryAsset.Value);
var categoryCount = registry.Value.GetCategoryCount();
var buffer = PostUpdateCommands.AddBuffer<PartElement>(entity);
for(int i=0;i<categoryCount;i++)
buffer.Add(PartElement.Default);
PostUpdateCommands.AddComponent(entity,State.Default);
});
Entities.WithNone<InputState>().ForEach((Entity entity, ref State state) =>
{
GameDebug.Log(World,Part.ShowLifetime, "Deinitializing PartOwner:{0}", entity);
var partBuffer = EntityManager.GetBuffer<PartElement>(entity);
for (int i = 0; i < partBuffer.Length; i++)
{
if (partBuffer[i].PartEntity != Entity.Null)
{
PostUpdateCommands.DestroyEntity(partBuffer[i].PartEntity);
GameDebug.Log(Part.ShowLifetime, " destroying part:{0}", partBuffer[i].PartEntity);
}
}
PostUpdateCommands.RemoveComponent<State>(entity);
PostUpdateCommands.RemoveComponent<PartElement>(entity);
});
}
}
[UpdateInGroup(typeof(PartSystemUpdateGroup))]
[UpdateAfter(typeof(Initialization))]
public class Update : ComponentSystem
{
private Camera MainCamera;
protected override void OnCreate()
{
base.OnCreate();
}
protected override void OnUpdate()
{
// Camera.main may not be available when the system is created, so need this to set it for the first time
if (MainCamera == null)
{
if (Camera.main != null)
{
MainCamera = Camera.main;
}
else
{
GameDebug.LogWarning("PartOwner update: No camera.main");
return;
}
}
var camPos = (float3) MainCamera.transform.position;
// TODO: Jobified ForEach blocked by PrefabAssetRegistry.CreateEntity
Entities.ForEach((Entity partOwnerEntity, ref Translation translation, ref RegistryAsset registryAsset, ref InputState inputState,
ref State state) =>
{
var registry = PartRegistry.GetPartRegistry(World, registryAsset.Value);
// Calc lod
var charPos = translation.Value;
var dist = math.distance(camPos, charPos);
var newLod = -1;
// TODO (mogensh) add threshold that needs to be passed before change (so it does not flicker)
for (int lod = 0; lod < registry.Value.LODLevels.Length; lod++)
{
if (dist <= registry.Value.LODLevels[lod].EndDist)
{
newLod = lod;
break;
}
}
// TODO (mogensh) hack: force LOD 0
newLod = 0;
// Handle out of lod distance specifically
if (newLod == -1)
{
if (state.currentLOD != newLod)
{
state.currentLOD = newLod;
GameDebug.Log(Part.ShowLifetime, "Out of LOD distance");
var partBuf = EntityManager.GetBuffer<PartElement>(partOwnerEntity)
.ToNativeArray(Allocator.Temp);
var partOutBuf = PostUpdateCommands.SetBuffer<PartElement>(partOwnerEntity);
partOutBuf.ResizeUninitialized(partBuf.Length);
for (int j = 0; j < partBuf.Length; j++)
{
var partElement = partBuf[j];
// Destroy old part
if (partElement.PartId != 0)
{
if (partElement.PartEntity != Entity.Null)
{
GameDebug.Log(Part.ShowLifetime, "Destroying part. Category:{0} partId:{1}", j,
partElement.PartId);
PostUpdateCommands.DestroyEntity(partElement.PartEntity);
}
partElement.PartEntity = Entity.Null;
partElement.PartId = 0;
partElement.Asset = WeakAssetReference.Default;
}
partOutBuf[j] = partElement;
}
PostUpdateCommands.SetComponent(partOwnerEntity, state);
}
return;
}
var newRig = BlobAssetReference<RigDefinition>.Null;
if (EntityManager.HasComponent<SharedRigDefinition>(partOwnerEntity))
{
newRig = EntityManager.GetSharedComponentData<SharedRigDefinition>(partOwnerEntity).Value;
}
// Change bodypart if LOD or rig changed
var packedPartIds = inputState.PackedPartIds;
if (packedPartIds != state.CurrentPackedPartIds ||
newLod != state.currentLOD ||
(newRig != BlobAssetReference<RigDefinition>.Null && newRig != state.currentRig))
{
var partBuf = EntityManager.GetBuffer<PartElement>(partOwnerEntity).ToNativeArray(Allocator.Temp);
var partIds = new NativeArray<int>(partBuf.Length, Allocator.Temp);
registry.Value.UnpackPartsList(inputState.PackedPartIds, partIds);
GameDebug.Log(World, Part.ShowLifetime, "Property changed. Lod:{0}", newLod);
var partOutBuf = PostUpdateCommands.SetBuffer<PartElement>(partOwnerEntity);
partOutBuf.ResizeUninitialized(partBuf.Length);
for (int j = 0; j < partBuf.Length; j++)
{
var partId = partIds[j];
var partElement = partBuf[j];
// Find new asset given the new properties
var asset = new WeakAssetReference();
if (partId > 0)
{
var skeletonHash = newRig.IsCreated ? newRig.Value.GetHashCode() : 0;
var found = registry.Value.FindAsset(j, partId, skeletonHash, newLod, ref asset);
if (!found)
GameDebug.Log(World, Part.ShowLifetime,
"Failed to find valid part. Category:{0} PartId:{1}", j, partId);
}
// No change if asset has not changed
if (partElement.Asset == asset)
{
partOutBuf[j] = partElement;
continue;
}
// Destroy old part
if (partElement.PartId != 0)
{
if (partElement.PartEntity != Entity.Null)
{
GameDebug.Log(World, Part.ShowLifetime, "Destroying part. Category:{0} partId:", j,
partElement.PartId);
PostUpdateCommands.DestroyEntity(partElement.PartEntity);
}
partElement.PartEntity = Entity.Null;
partElement.PartId = 0;
partElement.Asset = WeakAssetReference.Default;
}
// Create new part
if (partId != 0 && asset.IsSet())
{
partElement.PartEntity = PrefabAssetManager.CreateEntity(EntityManager, asset);
partElement.PartId = partId;
partElement.Asset = asset;
if (partElement.PartEntity != Entity.Null)
{
GameDebug.Log(World, Part.ShowLifetime,
"Creating part. Owner:{0} Cat:{1} PartId:{2} Asset:{3} part:{4}", partOwnerEntity,
j, partId, asset.ToGuidStr(), partElement.PartEntity);
var part = Part.Owner.Default;
part.Value = partOwnerEntity;
PostUpdateCommands.SetComponent(partElement.PartEntity, part);
// TODO (mogensh) add "static" property on owner (or get somehow). If static just set world transform
PostUpdateCommands.AddComponent(partElement.PartEntity,
new Parent {Value = partOwnerEntity});
PostUpdateCommands.AddComponent(partElement.PartEntity, new LocalToParent());
}
else
{
GameDebug.LogError("Failed to create part. Asset:" + asset.ToGuidStr());
}
}
partOutBuf[j] = partElement;
}
state.CurrentPackedPartIds = packedPartIds;
state.currentRig = newRig;
state.currentLOD = newLod;
PostUpdateCommands.SetComponent(partOwnerEntity, state);
}
});
}
}
}