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

277 行
11 KiB

using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using Unity.Entities;
using Unity.NetCode;
using Unity.Sample.Core;
public class PlayerModuleClient
{
// Number of commands the client stores - also maximum number of predictive steps the client can take
public const int commandClientBufferSize = 32;
// Placed on player entities on client that are controlled locally
public struct LocalOwnedPlayer : IComponentData
{}
public struct FakeLocalPlayer : IComponentData
{}
public PlayerModuleClient(World world)
{
m_world = world;
#pragma warning disable 618
// we're keeping World.Active until we can properly remove them all
var defaultWorld = World.Active;
try
{
World.Active = m_world;
m_settings = Resources.Load<PlayerModuleSettings>("PlayerModuleSettings");
m_HandlePlayerCameraControlSpawn = m_world.CreateSystem<PlayerCameraControl.HandlePlayerCameraControlSpawn>();
m_UpdatePlayerCameras = m_world.CreateSystem<PlayerCameraControl.UpdatePlayerCameras>();
m_ResolvePlayerReference = m_world.CreateSystem<ResolvePlayerReference>();
m_ResolvePlayerCharacterReference = m_world.CreateSystem<ResolvePlayerCharacterReference>();
m_UpdateServerEntityComponent = m_world.CreateSystem<UpdateServerEntityComponent>();
}
finally
{
World.Active = defaultWorld;
}
#pragma warning restore 618
}
public void Shutdown()
{
Resources.UnloadAsset(m_settings);
if (World.AllWorlds.Contains(m_world))
{
m_world.DestroySystem(m_HandlePlayerCameraControlSpawn);
m_world.DestroySystem(m_UpdatePlayerCameras);
m_world.DestroySystem(m_ResolvePlayerCharacterReference);
m_world.DestroySystem(m_ResolvePlayerReference);
m_world.DestroySystem(m_UpdateServerEntityComponent);
}
if (m_LocalPlayer != Entity.Null)
PrefabAssetManager.DestroyEntity(m_world.EntityManager, m_LocalPlayer);
}
public Entity RegisterLocalPlayer(int playerId)
{
m_LocalPlayer = PrefabAssetManager.CreateEntity(m_world.EntityManager,m_settings.localPlayerPrefab);
var query = m_world.EntityManager.CreateEntityQuery(typeof(ThinClientComponent));
if (query.CalculateEntityCount() == 1)
m_world.EntityManager.AddComponent<FakeLocalPlayer>(m_LocalPlayer);
var localPlayerState = m_world.EntityManager.GetComponentData<LocalPlayer>(m_LocalPlayer);
localPlayerState.playerId = playerId;
localPlayerState.command.lookPitch = 90;
m_world.EntityManager.SetComponentData(m_LocalPlayer, localPlayerState);
m_ResolvePlayerReference.SetLocalPlayer(m_LocalPlayer);
m_world.EntityManager.GetBuffer<UserCommand>(m_LocalPlayer).Clear();
// Find the correct thing
var q = m_world.EntityManager.CreateEntityQuery(ComponentType.ReadWrite<CommandTargetComponent>(),
ComponentType.ReadWrite<NetworkStreamConnection>(), ComponentType.ReadWrite<NetworkIdComponent>());
var ents = q.ToEntityArray(Allocator.TempJob);
var ids = q.ToComponentDataArray<NetworkIdComponent>(Allocator.TempJob);
for (int i = 0; i < ents.Length; ++i)
{
if (ids[i].Value == playerId)
{
UnityEngine.Debug.Log("Assign command on client");
m_world.EntityManager.SetComponentData(ents[i], new CommandTargetComponent{targetEntity = m_LocalPlayer});
}
}
ents.Dispose();
ids.Dispose();
return m_LocalPlayer;
}
public void SampleInput(World world, bool userInputEnabled, float deltaTime, int renderTick)
{
SampleInput(world, m_LocalPlayer, userInputEnabled, deltaTime, renderTick);
}
public static void SampleInput(World world, Entity localPlayer, bool userInputEnabled, float deltaTime, int renderTick)
{
var localPlayerState = world.EntityManager.GetComponentData<LocalPlayer>(localPlayer);
// Only sample input when cursor is locked to avoid affecting multiple clients running on same machine (TODO: find better handling of selected window)
if (userInputEnabled)
InputSystem.AccumulateInput(ref localPlayerState.command, deltaTime);
else
InputSystem.ClearInput(ref localPlayerState.command); // make sure no keys are stuck in 'down' when user input disabled
if (m_debugMove.IntValue == 1)
{
localPlayerState.command.moveMagnitude = 1;
localPlayerState.command.lookYaw += 70 * deltaTime;
}
if (m_debugMove.IntValue == 2 || world.EntityManager.HasComponent<FakeLocalPlayer>(localPlayer))
{
localPlayerState.m_debugMoveDuration += deltaTime;
var fireDuration = 2.0f;
var maxTurn = 70.0f;
if (localPlayerState.m_debugMoveDuration > localPlayerState.m_debugMovePhaseDuration)
{
localPlayerState.m_debugMoveDuration = 0;
localPlayerState.m_debugMovePhaseDuration = 4 + 2 * Random.value;
localPlayerState.m_debugMoveTurnSpeed = maxTurn * 0.9f + Random.value * maxTurn * 0.1f;
localPlayerState.m_debugMoveMag = Random.value > 0.5f ? 1.0f : 0.0f;
}
localPlayerState.command.moveMagnitude = localPlayerState.m_debugMoveMag;
localPlayerState.command.lookYaw += localPlayerState.m_debugMoveTurnSpeed * deltaTime;
localPlayerState.command.lookYaw = localPlayerState.command.lookYaw % 360;
while (localPlayerState.command.lookYaw < 0.0f)
localPlayerState.command.lookYaw += 360.0f;
var firePrimary = localPlayerState.m_debugMoveDuration < fireDuration;
//localPlayerState.command.buttons.Set(UserCommand.Button.PrimaryFire, firePrimary);
//localPlayerState.command.buttons.Set(UserCommand.Button.SecondaryFire, !firePrimary);
//localPlayerState.command.buttons.Set(UserCommand.Button.Jump, localPlayerState.m_debugMoveDuration < jumpDuration);
}
localPlayerState.command.renderTick = renderTick;
world.EntityManager.SetComponentData(localPlayer, localPlayerState);
}
public void ResetInput(bool userInputEnabled)
{
var localPlayerState = m_world.EntityManager.GetComponentData<LocalPlayer>(m_LocalPlayer);
// Clear keys and resample to make sure released keys gets detected.
// Pass in 0 as deltaTime to make mouse input and view stick do nothing
InputSystem.ClearInput(ref localPlayerState.command);
if (userInputEnabled)
InputSystem.AccumulateInput(ref localPlayerState.command, 0.0f);
m_world.EntityManager.SetComponentData(m_LocalPlayer, localPlayerState);
}
public void HandleCommandReset()
{
var localPlayerState = m_world.EntityManager.GetComponentData<LocalPlayer>(m_LocalPlayer);
if (localPlayerState.playerEntity == Entity.Null)
return;
var playerState = m_world.EntityManager.GetComponentData<Player.State>(localPlayerState.playerEntity);
if (playerState.controlledEntity == Entity.Null)
return;
var controlledEntity = playerState.controlledEntity;
var commandComponent = m_world.EntityManager.GetComponentData<PlayerControlled.State>(controlledEntity);
if (commandComponent.resetCommandTick > commandComponent.lastResetCommandTick)
{
commandComponent.lastResetCommandTick = commandComponent.resetCommandTick;
m_world.EntityManager.SetComponentData(controlledEntity, commandComponent);
localPlayerState.command.lookYaw = commandComponent.resetCommandLookYaw;
localPlayerState.command.lookPitch = commandComponent.resetCommandLookPitch;
}
m_world.EntityManager.SetComponentData(m_LocalPlayer, localPlayerState);
}
public void ResolveReferenceFromLocalPlayerToPlayer()
{
m_ResolvePlayerCharacterReference.Update();
var localPlayerState = m_world.EntityManager.GetComponentData<LocalPlayer>(m_LocalPlayer);
if (localPlayerState.playerEntity == Entity.Null)
m_ResolvePlayerReference.Update();
}
public void HandleControlledEntityChanged()
{
m_UpdateServerEntityComponent.Update();
}
public void StoreCommand(int tick)
{
StoreCommand(m_world, m_LocalPlayer, tick);
}
public static void StoreCommand(World world, Entity localPlayer, int tick)
{
var localPlayerState = world.EntityManager.GetComponentData<LocalPlayer>(localPlayer);
if (localPlayerState.playerEntity == Entity.Null && !world.EntityManager.HasComponent<FakeLocalPlayer>(localPlayer))
return;
var buf = world.EntityManager.GetBuffer<UserCommand>(localPlayer);
localPlayerState.command.checkTick = tick;
localPlayerState.command.tick = world.GetExistingSystem<ClientSimulationSystemGroup>().ServerTick;
buf.AddCommandData(localPlayerState.command);
world.EntityManager.SetComponentData(localPlayer, localPlayerState);
}
public void RetrieveCommand(uint tick)
{
var localPlayerState = m_world.EntityManager.GetComponentData<LocalPlayer>(m_LocalPlayer);
GameDebug.Assert(localPlayerState.playerEntity != null, "No player state set");
if (localPlayerState.controlledEntity == Entity.Null)
return;
if (!m_world.EntityManager.HasComponent<PlayerControlled.State>(localPlayerState.controlledEntity))
return;
var buf = m_world.EntityManager.GetBuffer<UserCommand>(m_LocalPlayer);
var userCommand = m_world.EntityManager.GetComponentData<PlayerControlled.State>(localPlayerState.controlledEntity);
// Normally we can expect commands to be present, but if client has done hardcatchup commands might not have been generated yet
// so we just use the defaultCommand
var command = UserCommand.defaultCommand;
var found = buf.GetDataAtTick(tick, out command);
//GameDebug.Assert(found, "Failed to find command for tick:{0}", tick);
userCommand.prevCommand = userCommand.command;
userCommand.command = command;
m_world.EntityManager.SetComponentData(localPlayerState.controlledEntity, userCommand);
}
public void HandleSpawn()
{
m_HandlePlayerCameraControlSpawn.Update();
}
public void CameraUpdate()
{
m_UpdatePlayerCameras.Update();
}
readonly PlayerModuleSettings m_settings;
readonly World m_world;
Entity m_LocalPlayer;
readonly PlayerCameraControl.HandlePlayerCameraControlSpawn m_HandlePlayerCameraControlSpawn;
readonly PlayerCameraControl.UpdatePlayerCameras m_UpdatePlayerCameras;
readonly ResolvePlayerReference m_ResolvePlayerReference;
readonly ResolvePlayerCharacterReference m_ResolvePlayerCharacterReference;
readonly UpdateServerEntityComponent m_UpdateServerEntityComponent;
#pragma warning disable 649
[ConfigVar(Name = "debugmove", DefaultValue = "0", Description = "Should client perform debug movement")]
static ConfigVar m_debugMove;
#pragma warning restore 649
float m_debugMoveDuration;
float m_debugMovePhaseDuration;
float m_debugMoveTurnSpeed;
float m_debugMoveMag;
}