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

298 行
10 KiB

using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Sample.Core;
using UnityEngine;
using UnityEngine.Profiling;
public struct CharacterSpawnRequest : IComponentData
{
public int characterType;
public Vector3 position;
public Quaternion rotation;
public Entity playerEntity;
private CharacterSpawnRequest(int characterType, Vector3 position, Quaternion rotation, Entity playerEntity)
{
this.characterType = characterType;
this.position = position;
this.rotation = rotation;
this.playerEntity = playerEntity;
}
public static void Create(EntityCommandBuffer commandBuffer, int characterType, Vector3 position, Quaternion rotation, Entity playerEntity)
{
var data = new CharacterSpawnRequest(characterType, position, rotation, playerEntity);
Entity entity = commandBuffer.CreateEntity();
commandBuffer.AddComponent(entity, data);
}
}
public struct CharacterDespawnRequest : IComponentData
{
public Entity characterEntity;
public static void Create(World world, Entity characterEntity)
{
var data = new CharacterDespawnRequest()
{
characterEntity = characterEntity,
};
var entity = world.EntityManager.CreateEntity(typeof(CharacterDespawnRequest));
world.EntityManager.SetComponentData(entity, data);
}
public static void Create(EntityCommandBuffer commandBuffer, Entity characterEntity)
{
var data = new CharacterDespawnRequest()
{
characterEntity = characterEntity,
};
Entity entity = commandBuffer.CreateEntity();
commandBuffer.AddComponent(entity, data);
}
}
[DisableAutoCreation]
[UpdateBefore(typeof(HandleCharacterSpawn))]
public class HandleCharacterSpawnRequests : ComponentSystem
{
EntityQuery SpawnGroup;
protected override void OnCreate()
{
base.OnCreate();
SpawnGroup = GetEntityQuery(typeof(CharacterSpawnRequest));
}
protected override void OnUpdate()
{
var requestArray = SpawnGroup.ToComponentDataArray<CharacterSpawnRequest>(Allocator.Persistent);
if (requestArray.Length == 0)
{
requestArray.Dispose();
return;
}
var requestEntityArray = SpawnGroup.ToEntityArray(Allocator.Persistent);
// Copy requests as spawning will invalidate Group
var spawnRequests = new CharacterSpawnRequest[requestArray.Length];
for (var i = 0; i < requestArray.Length; i++)
{
spawnRequests[i] = requestArray[i];
PostUpdateCommands.DestroyEntity(requestEntityArray[i]);
}
for (var i = 0; i < spawnRequests.Length; i++)
{
var request = spawnRequests[i];
var playerState = EntityManager.GetComponentData<Player.State>(request.playerEntity);
var charEntity = SpawnCharacter( playerState.playerId, request.position, request.rotation, request.characterType);
GameDebug.Log(World, Character.ShowLifetime, "Spawning character:{0} ", charEntity);
//We cannot serialize references yet so we hook up manually on client side based on PlayerId.
//but we set it here none the less for our server side uses if any
playerState.controlledEntity = charEntity;
EntityManager.SetComponentData(request.playerEntity,playerState);
}
requestEntityArray.Dispose();
requestArray.Dispose();
}
List<Entity> abilityList = new List<Entity>(16);
public Entity SpawnCharacter(int playerId, Vector3 position, Quaternion rotation,
int heroIndex)
{
var heroRegistry = HeroRegistry.GetRegistry(EntityManager);
var heroCount = heroRegistry.Value.Heroes.Length;
heroIndex = Mathf.Clamp(heroIndex, 0,heroCount-1);
var charEntity = PrefabAssetManager.CreateEntity(EntityManager, heroRegistry.Value.Heroes[heroIndex].characterPrefab);
var charSettings = EntityManager.GetComponentData<Character.Settings>(charEntity);
Character.TeleportTo(ref charSettings, position, rotation);
PostUpdateCommands.SetComponent(charEntity,charSettings);
var charRepAll = EntityManager.GetComponentData<Character.ReplicatedData>(charEntity);
charRepAll.heroTypeIndex = heroIndex;
PostUpdateCommands.SetComponent(charEntity,charRepAll);
PostUpdateCommands.SetComponent(charEntity,new Player.OwnerPlayerId
{
Value = playerId,
});
// TODO (mogensh) move this to inventory code (server part)
// Spawn items in inventory
var itemCount = heroRegistry.Value.Heroes[heroIndex].Items.Length;
for(int nItem=0;nItem<itemCount;nItem++)
{
var entry = heroRegistry.Value.Heroes[heroIndex].Items[nItem];
if (!entry.asset.IsSet())
continue;
var itemEntity = PrefabAssetManager.CreateEntity(EntityManager, entry.asset);
var itemState = EntityManager.GetComponentData<Item.InputState>(itemEntity);
itemState.owner = charEntity;
itemState.slot = entry.slot;
itemState.playerId = playerId;
PostUpdateCommands.SetComponent(itemEntity,itemState);
}
return charEntity;
}
}
[DisableAutoCreation]
[UpdateBefore(typeof(HandleCharacterDespawn))]
public class HandleCharacterDespawnRequests : ComponentSystem
{
EntityQuery DespawnGroup;
protected override void OnCreate()
{
base.OnCreate();
DespawnGroup = GetEntityQuery(typeof(CharacterDespawnRequest));
}
protected override void OnUpdate()
{
var requestArray = DespawnGroup.ToComponentDataArray<CharacterDespawnRequest>(Allocator.Persistent);
if (requestArray.Length == 0)
{
requestArray.Dispose();
return;
}
Profiler.BeginSample("HandleCharacterDespawnRequests");
var requestEntityArray = DespawnGroup.ToEntityArray(Allocator.Persistent);
for (var i = 0; i < requestArray.Length; i++)
{
var request = requestArray[i];
GameDebug.Assert(EntityManager.HasComponent<Character.State>(request.characterEntity), "Character despawn requst entity is not a character");
Inventory.Server_DestroyAll(EntityManager, PostUpdateCommands, request.characterEntity);
GameDebug.Log(World, Character.ShowLifetime, "Despawning character:{0}", request.characterEntity);
PrefabAssetManager.DestroyEntity(EntityManager,request.characterEntity);
PostUpdateCommands.DestroyEntity(requestEntityArray[i]);
if(Character.ShowLifetime.IntValue > 0)
AnimationGraphHelper.DumpState(World);
}
requestEntityArray.Dispose();
requestArray.Dispose();
Profiler.EndSample();
}
}
[DisableAutoCreation]
[UpdateInGroup(typeof(HandleDamageSystemGroup))]
[UpdateAfter(typeof(DamageManager))]
[AlwaysSynchronizeSystem]
public class HandleDamage : JobComponentSystem
{
private EntityQuery TimeQuery;
protected override void OnCreate()
{
TimeQuery = GetEntityQuery(ComponentType.ReadOnly<GlobalGameTime>());
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps.Complete();
var globalTime = TimeQuery.GetSingleton<GlobalGameTime>();
var damageHistoryDataFromEntity = GetComponentDataFromEntity<DamageHistoryData>(false);
Entities
.ForEach((Entity entity, DynamicBuffer<DamageEvent> damageBuffer, ref HealthStateData healthState, ref HitColliderOwner.State collOwner, ref Character.PredictedData charPredictedState) =>
{
if (healthState.health <= 0)
return;
var isDamaged = false;
var impulseVec = Vector3.zero;
var damage = 0.0f;
var damageVec = Vector3.zero;
// Apply hitcollider damage events
for (var eventIndex = 0; eventIndex < damageBuffer.Length; eventIndex++)
{
isDamaged = true;
var damageEvent = damageBuffer[eventIndex];
//GameDebug.Log(string.Format("ApplyDamage. Target:{0} Instigator:{1} Dam:{2}", healthState.name, m_world.GetGameObjectFromEntity(damageEvent.instigator), damageEvent.damage ));
healthState.ApplyDamage(damageEvent, globalTime.gameTime.tick);
impulseVec += damageEvent.Direction * damageEvent.Impulse;
damageVec += damageEvent.Direction * damageEvent.Damage;
damage += damageEvent.Damage;
//damageHistory.ApplyDamage(ref damageEvent, m_world.worldTime.tick);
if (damageHistoryDataFromEntity.HasComponent(damageEvent.Instigator))
{
var instigatorDamageHistory = damageHistoryDataFromEntity[damageEvent.Instigator];
if (globalTime.gameTime.tick > instigatorDamageHistory.inflictedDamage.tick)
{
instigatorDamageHistory.inflictedDamage.tick = globalTime.gameTime.tick;
instigatorDamageHistory.inflictedDamage.lethal = 0;
}
if (healthState.health <= 0)
instigatorDamageHistory.inflictedDamage.lethal = 1;
damageHistoryDataFromEntity[damageEvent.Instigator] = instigatorDamageHistory;
}
collOwner.collisionEnabled = healthState.health > 0 ? 1 : 0;
}
damageBuffer.Clear();
// TODO (mogensh) make sure damagebuffer also is cleared on clients
if (isDamaged)
{
var damageImpulse = impulseVec.magnitude;
var damageDir = damageImpulse > 0 ? impulseVec.normalized : damageVec.normalized;
charPredictedState.damageTick = globalTime.gameTime.tick;
charPredictedState.damageDirection = damageDir;
charPredictedState.damageImpulse = damageImpulse;
if (healthState.health <= 0)
{
// var ragdollState = EntityManager.GetComponentData<RagdollStateData>(entity);
// ragdollState.ragdollActive = 1;
// ragdollState.impulse = impulseVec;
// EntityManager.SetComponentData(entity, ragdollState);
}
}
}).Run();
return default;
}
}