stuff
This commit is contained in:
52
Assets/jelycho/Code/ActorSpawner.cs
Normal file
52
Assets/jelycho/Code/ActorSpawner.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Simulation;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootReality.jelycho {
|
||||
public class ActorSpawner : Actor {
|
||||
static readonly Logger s_Logger = new Logger(nameof(ActorSpawner));
|
||||
|
||||
[SerializeField] AssetReferenceGameObject m_ActorPrefabReference;
|
||||
|
||||
[TriInspector.InfoBox("If empty will use this object transform as spawn point.")]
|
||||
[SerializeField] Transform[] m_SpawnPoints;
|
||||
|
||||
protected override IActorData CreateActorData() {
|
||||
return new NoActorData();
|
||||
}
|
||||
|
||||
protected override void OnActorCommandServer(ActorCommand actorCommand) {
|
||||
base.OnActorCommandServer(actorCommand);
|
||||
|
||||
if (actorCommand.CommandID == (ushort) ActorSpawnerCommands.SpawnActor) {
|
||||
(Vector3 spawnPoint, Quaternion spawnRotation) = GetSpawnPoint();
|
||||
RR.SpawnActor(m_ActorPrefabReference, spawnPoint, spawnRotation);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnActor() {
|
||||
if (m_ActorPrefabReference == null) {
|
||||
s_Logger.Error("ActorPrefabReference is not set. Cannot spawn actor.");
|
||||
return;
|
||||
}
|
||||
|
||||
SendActorCommand((ushort) ActorSpawnerCommands.SpawnActor);
|
||||
}
|
||||
|
||||
(Vector3, Quaternion) GetSpawnPoint() {
|
||||
if (m_SpawnPoints.Length == 0) {
|
||||
return (transform.position, transform.rotation);
|
||||
}
|
||||
|
||||
int index = Random.Range(0, m_SpawnPoints.Length);
|
||||
return (m_SpawnPoints[index].position, m_SpawnPoints[index].rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActorSpawnerCommands : ushort {
|
||||
None = 0x0000,
|
||||
SpawnActor = 0x0001,
|
||||
}
|
||||
}
|
||||
3
Assets/jelycho/Code/ActorSpawner.cs.meta
Normal file
3
Assets/jelycho/Code/ActorSpawner.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96676410d3db4402b69bc504218db929
|
||||
timeCreated: 1752274642
|
||||
@@ -7,6 +7,9 @@ using UnityEngine.Events;
|
||||
namespace RebootReality.jelycho {
|
||||
public class ButtonActor : Actor, IInteractable {
|
||||
[SerializeField] Transform m_Graphics;
|
||||
[SerializeField] float m_CooldownDuration = 0.5f;
|
||||
|
||||
DateTime m_LastPressTime;
|
||||
|
||||
public UnityEvent pressed = new UnityEvent();
|
||||
|
||||
@@ -16,6 +19,12 @@ namespace RebootReality.jelycho {
|
||||
|
||||
protected override void OnActorCommandServer(ActorCommand actorCommand) {
|
||||
if (actorCommand.CommandID == (ushort) ButtonActorCommands.Press) {
|
||||
if (DateTime.UtcNow - m_LastPressTime < TimeSpan.FromSeconds(m_CooldownDuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastPressTime = DateTime.UtcNow;
|
||||
|
||||
SendActorEvent((ushort) ButtonActorEvents.Pressed);
|
||||
pressed?.Invoke();
|
||||
}
|
||||
|
||||
21
Assets/jelycho/Code/Enemies/ZombieActor.cs
Normal file
21
Assets/jelycho/Code/Enemies/ZombieActor.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using RebootKit.Engine.Simulation;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootReality.jelycho.Enemies {
|
||||
public class ZombieActorData : IActorData {
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
}
|
||||
}
|
||||
|
||||
public class ZombieActor : Actor {
|
||||
[SerializeField] Animator m_Animator;
|
||||
|
||||
protected override IActorData CreateActorData() {
|
||||
return new ZombieActorData();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/jelycho/Code/Enemies/ZombieActor.cs.meta
Normal file
3
Assets/jelycho/Code/Enemies/ZombieActor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82c11d5cbdd64c2ab63010901162299e
|
||||
timeCreated: 1752364002
|
||||
@@ -60,6 +60,24 @@ namespace RebootReality.jelycho.Items {
|
||||
s_Logger.Error($"Item {actor.name} is not in the inventory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
public ItemActor TryDropOne(int slotIndex) {
|
||||
if (slotIndex < 0 || slotIndex >= m_Items.Length) {
|
||||
s_Logger.Error($"Slot index {slotIndex} is out of range.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_Items[slotIndex].Actors.Count == 0) {
|
||||
s_Logger.Error($"No items in slot {slotIndex} to drop.");
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemActor actor = m_Items[slotIndex].Actors[0];
|
||||
m_Items[slotIndex].Actors.RemoveAt(0);
|
||||
OnItemDropped?.Invoke(actor);
|
||||
OnSlotUpdated?.Invoke(slotIndex);
|
||||
return actor;
|
||||
}
|
||||
|
||||
public int GetQuantity(int slotIndex) {
|
||||
if (slotIndex < 0 || slotIndex >= m_Items.Length) {
|
||||
@@ -78,7 +96,6 @@ namespace RebootReality.jelycho.Items {
|
||||
return m_Items[slotIndex].Actors[0];
|
||||
}
|
||||
|
||||
s_Logger.Error($"No items in slot {slotIndex}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootReality.jelycho.Items {
|
||||
public enum ItemType {
|
||||
Neutral = 0,
|
||||
Egg = 1,
|
||||
Sword = 2,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ItemConfig {
|
||||
public FixedString32Bytes itemID;
|
||||
public class ItemConfig {
|
||||
public ItemType itemType = ItemType.Neutral;
|
||||
public Sprite icon;
|
||||
|
||||
[MaxLength(32)] public string characterEquippedMountSlotName = "hand_right";
|
||||
|
||||
[Header("Chargeable")]
|
||||
public bool isChargeable = false;
|
||||
public float chargeDuration = 0.5f;
|
||||
public float chargeCooldown = 1.0f;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using RebootReality.jelycho.Player.HUD;
|
||||
using Unity.Collections;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Assertions;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
@@ -23,11 +24,11 @@ namespace RebootReality.jelycho.Main {
|
||||
|
||||
public class JelychoGame : Game {
|
||||
static readonly Logger s_Logger = new Logger(nameof(JelychoGame));
|
||||
|
||||
|
||||
[Header("Player")]
|
||||
[SerializeField] PlayerController m_PlayerControllerPrefab;
|
||||
[SerializeField] PlayerActor m_PlayerActorPrefab;
|
||||
|
||||
[SerializeField] AssetReferenceGameObject m_PlayerActorPrefab;
|
||||
|
||||
readonly List<PlayerState> m_PlayerStates = new List<PlayerState>();
|
||||
|
||||
void Awake() { }
|
||||
@@ -35,18 +36,19 @@ namespace RebootReality.jelycho.Main {
|
||||
public override void OnDestroy() {
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
|
||||
protected override void OnPlayerBecameReady(ulong clientID) {
|
||||
s_Logger.Info($"Player {clientID} became ready");
|
||||
|
||||
PlayerActor actor = Instantiate(m_PlayerActorPrefab);
|
||||
actor.name = $"PlayerActor_{clientID}";
|
||||
actor.NetworkObject.SpawnAsPlayerObject(clientID);
|
||||
if (IsServer) {
|
||||
PlayerActor actor =
|
||||
RR.SpawnActor(m_PlayerActorPrefab, Vector3.zero, Quaternion.identity) as PlayerActor;
|
||||
|
||||
PlayerState playerState = GetPlayerState(clientID);
|
||||
Assert.IsNotNull(playerState);
|
||||
playerState.Actor = actor;
|
||||
playerState.Controller.SetActorClientRpc(actor.NetworkObjectId);
|
||||
PlayerState playerState = GetPlayerState(clientID);
|
||||
Assert.IsNotNull(playerState);
|
||||
playerState.Actor = actor;
|
||||
playerState.Controller.PossessActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn() {
|
||||
@@ -119,7 +121,7 @@ namespace RebootReality.jelycho.Main {
|
||||
RR.WriteToConsole($" {worldConfigAsset.Config.name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[RCCMD("connect_dev", "Connects to a local server for development purposes")]
|
||||
public static void ConnectToLocalServer(string[] args) {
|
||||
RR.WriteToConsole("Connecting to server...");
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootReality.jelycho.Main;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace RebootReality.jelycho.MainMenu {
|
||||
public class MainMenuController : MonoBehaviour {
|
||||
const string k_ButtonPlay = "btn-play";
|
||||
const string k_ButtonSettings = "btn-settings";
|
||||
const string k_ButtonQuit = "btn-quit";
|
||||
const string k_ButtonHost = "rr-menu__main-btn-host";
|
||||
const string k_ButtonJoinLocalHost = "rr-menu__main-btn-join-localhost";
|
||||
const string k_ButtonSettings = "rr-menu__main-btn-settings";
|
||||
const string k_ButtonQuit = "rr-menu__main-btn-quit";
|
||||
|
||||
const string k_PanelMain = "panel-main";
|
||||
const string k_PanelSettings = "panel-settings";
|
||||
const string k_PanelMain = "rr-menu__panel-main";
|
||||
const string k_PanelSettings = "rr-menu__panel-settings";
|
||||
|
||||
[SerializeField] UIDocument m_Document;
|
||||
|
||||
void OnEnable() {
|
||||
VisualElement root = m_Document.rootVisualElement;
|
||||
|
||||
Button playButton = root.Q<Button>(k_ButtonPlay);
|
||||
Button hostButton = root.Q<Button>(k_ButtonHost);
|
||||
Button joinLocalhostButton = root.Q<Button>(k_ButtonJoinLocalHost);
|
||||
Button settingsButton = root.Q<Button>(k_ButtonSettings);
|
||||
Button quitButton = root.Q<Button>(k_ButtonQuit);
|
||||
|
||||
playButton.RegisterCallback<ClickEvent>(e => {
|
||||
hostButton.RegisterCallback<ClickEvent>(e => {
|
||||
RR.StartHost();
|
||||
RR.SetServerWorld("dev");
|
||||
});
|
||||
joinLocalhostButton.RegisterCallback<ClickEvent>(e => {
|
||||
RR.Connect();
|
||||
});
|
||||
|
||||
settingsButton.RegisterCallback<ClickEvent>(e => OpenSettings());
|
||||
quitButton.RegisterCallback<ClickEvent>(e => Application.Quit());
|
||||
|
||||
|
||||
@@ -1,33 +1,18 @@
|
||||
using System;
|
||||
using R3;
|
||||
using R3;
|
||||
using RebootKit.Engine.Extensions;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Simulation;
|
||||
using RebootKit.Engine.Simulation.Sensors;
|
||||
using RebootReality.jelycho.Items;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootReality.jelycho.Player {
|
||||
public struct PlayerActorState : INetworkSerializable {
|
||||
public Vector3 Position;
|
||||
public Vector3 Velocity;
|
||||
public float LookPitch;
|
||||
public float LookYaw;
|
||||
public bool IsGrounded;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter {
|
||||
serializer.SerializeValue(ref Position);
|
||||
serializer.SerializeValue(ref Velocity);
|
||||
serializer.SerializeValue(ref LookPitch);
|
||||
serializer.SerializeValue(ref LookYaw);
|
||||
serializer.SerializeValue(ref IsGrounded);
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerActor : NetworkBehaviour {
|
||||
public class PlayerActor : Actor {
|
||||
static readonly Logger s_Logger = new Logger(nameof(PlayerActor));
|
||||
|
||||
[SerializeField] Animator m_Animator;
|
||||
@@ -73,20 +58,25 @@ namespace RebootReality.jelycho.Player {
|
||||
[SerializeField] LayerMask m_BeaconPlacementLayerMask = 0;
|
||||
[SerializeField] float m_BeaconPlacementMaxDistance = 15.0f;
|
||||
[SerializeField] float m_NormalDotUpThreshold = 0.5f;
|
||||
|
||||
|
||||
[Header("Sensors")]
|
||||
[SerializeField] GenericSensor<IInteractable> m_InteractablesSensor;
|
||||
[SerializeField] SingleRaySensor<IInteractable> m_InteractablesSensor;
|
||||
|
||||
[Header("Network")]
|
||||
[SerializeField] float m_MinTeleportDistance = 0.5f;
|
||||
[SerializeField] float m_ItemPickupDistance = 2.0f;
|
||||
|
||||
bool m_IsSetupAsOwner = false;
|
||||
float m_SyncRemoteStateTimer = 0.0f;
|
||||
RemotePlayerActorState m_RemoteState;
|
||||
|
||||
PlayerActorState m_NetworkState;
|
||||
|
||||
[Header("Inventory")]
|
||||
[SerializeField] int m_InventorySize = 10;
|
||||
|
||||
public Inventory Inventory { get; private set; }
|
||||
|
||||
|
||||
ItemActor m_EquippedItem;
|
||||
|
||||
public ReactiveProperty<int> SelectedInventorySlot { get; private set; } = new ReactiveProperty<int>(0);
|
||||
|
||||
public float3 LookDirection {
|
||||
@@ -106,26 +96,418 @@ namespace RebootReality.jelycho.Player {
|
||||
}
|
||||
}
|
||||
|
||||
protected override IActorData CreateActorData() {
|
||||
return new PlayerActorData { };
|
||||
}
|
||||
|
||||
void Awake() {
|
||||
Inventory = new Inventory(m_InventorySize);
|
||||
|
||||
// @NOTE: By default player actor should be set up as remote
|
||||
SetupAsRemote();
|
||||
}
|
||||
|
||||
void Start() {
|
||||
m_CameraSpring.Initialize();
|
||||
}
|
||||
|
||||
void Update() {
|
||||
if (!IsSpawned) {
|
||||
|
||||
void OnEnable() {
|
||||
Inventory.OnItemPickedUp += OnItemPickedUp;
|
||||
Inventory.OnItemDropped += OnItemDropped;
|
||||
}
|
||||
|
||||
void OnDisable() {
|
||||
Inventory.OnItemPickedUp -= OnItemPickedUp;
|
||||
Inventory.OnItemDropped -= OnItemDropped;
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Actor
|
||||
//
|
||||
public override void ServerTick(float deltaTime) {
|
||||
base.ServerTick(deltaTime);
|
||||
|
||||
// Update actor data
|
||||
// PlayerActorData data = DataAs<PlayerActorData>();
|
||||
// IsDataDirty = true;
|
||||
|
||||
NativeArray<byte> remoteStateData = DataSerializationUtils.Serialize(m_RemoteState);
|
||||
SendActorEvent((ushort) PlayerActorEvents.UpdatedRemoteState, remoteStateData);
|
||||
}
|
||||
|
||||
public override void ClientTick(float deltaTime) {
|
||||
base.ClientTick(deltaTime);
|
||||
|
||||
if (m_IsSetupAsOwner) {
|
||||
TickCamera();
|
||||
UpdateAnimator(m_Locomotion.Velocity);
|
||||
SenseInteractable();
|
||||
|
||||
m_SyncRemoteStateTimer -= deltaTime;
|
||||
if (m_SyncRemoteStateTimer <= 0.0f) {
|
||||
m_SyncRemoteStateTimer = 1.0f / RR.TickRate.IndexValue;
|
||||
|
||||
RemotePlayerActorState remoteState = new RemotePlayerActorState {
|
||||
Position = transform.position,
|
||||
Velocity = m_Locomotion.Velocity,
|
||||
LookPitch = m_Camera.Pitch,
|
||||
LookYaw = m_Camera.Yaw,
|
||||
IsGrounded = m_Locomotion.IsGrounded
|
||||
};
|
||||
|
||||
NativeArray<byte> data = DataSerializationUtils.Serialize(remoteState);
|
||||
SendActorCommand((ushort) PlayerActorCommands.UpdateRemoteState, data);
|
||||
}
|
||||
} else {
|
||||
InterpolateActorState(deltaTime);
|
||||
}
|
||||
|
||||
TickCharacterRotation();
|
||||
}
|
||||
|
||||
protected override void OnActorCommandServer(ActorCommand actorCommand) {
|
||||
base.OnActorCommandServer(actorCommand);
|
||||
|
||||
// @TODO: SECURITY, Check if commands come from the owner
|
||||
|
||||
if (actorCommand.CommandID == (ushort) PlayerActorCommands.UpdateRemoteState) {
|
||||
RemotePlayerActorState remoteState = new RemotePlayerActorState();
|
||||
DataSerializationUtils.Deserialize(actorCommand.Data, ref remoteState);
|
||||
m_RemoteState = remoteState;
|
||||
} else if (actorCommand.CommandID == (ushort) PlayerActorCommands.PickupItem) {
|
||||
PlayerActorPickupItemCommand command = new PlayerActorPickupItemCommand();
|
||||
DataSerializationUtils.Deserialize(actorCommand.Data, ref command);
|
||||
|
||||
Actor itemActor = RR.FindSpawnedActor(command.ItemActorID);
|
||||
if (itemActor is ItemActor item) {
|
||||
if (math.distancesq(itemActor.transform.position, m_HeadBoneTransform.position) <=
|
||||
m_ItemPickupDistance * m_ItemPickupDistance) {
|
||||
if (Inventory.TryPickup(item)) {
|
||||
s_Logger.Info($"Item {item.name} picked up successfully by player {name}.");
|
||||
|
||||
UpdateEquippedItem();
|
||||
} else {
|
||||
s_Logger.Info($"Failed to pick up item {item.name}. Inventory is full.");
|
||||
}
|
||||
} else {
|
||||
s_Logger.Info($"Item actor {item.name} is too far away to pick up.");
|
||||
}
|
||||
} else {
|
||||
s_Logger.Error($"Item actor with ID {command.ItemActorID} not found.");
|
||||
}
|
||||
} else if (actorCommand.CommandID == (ushort) PlayerActorCommands.SelectItemSlot) {
|
||||
PlayerActorSelectItemSlotCommand command = new PlayerActorSelectItemSlotCommand();
|
||||
DataSerializationUtils.Deserialize(actorCommand.Data, ref command);
|
||||
|
||||
if (command.SlotIndex < 0 || command.SlotIndex >= Inventory.SlotsCount) {
|
||||
s_Logger.Error($"Invalid slot index {command.SlotIndex}. Must be between 0 and {Inventory.SlotsCount - 1}.");
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedInventorySlot.Value = command.SlotIndex;
|
||||
UpdateEquippedItem();
|
||||
} else if (actorCommand.CommandID == (ushort) PlayerActorCommands.DropItem) {
|
||||
PlayerActorDropItemCommand command = new PlayerActorDropItemCommand();
|
||||
DataSerializationUtils.Deserialize(actorCommand.Data, ref command);
|
||||
|
||||
if (command.Count == 1) {
|
||||
Inventory.TryDropOne(command.InventorySlotIndex);
|
||||
} else {
|
||||
s_Logger.Error("DropItem command with count != 1 is not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnActorEventClient(ActorEvent actorEvent) {
|
||||
base.OnActorEventClient(actorEvent);
|
||||
|
||||
if (actorEvent.EventID == (ushort) PlayerActorEvents.UpdatedRemoteState) {
|
||||
RemotePlayerActorState remoteState = new RemotePlayerActorState();
|
||||
DataSerializationUtils.Deserialize(actorEvent.Data, ref remoteState);
|
||||
m_RemoteState = remoteState;
|
||||
} else if (actorEvent.EventID == (ushort) PlayerActorEvents.PrimaryEquippedItemChanged) {
|
||||
PlayerActorPrimaryEquippedItemChangedEvent itemChangedEvent =
|
||||
new PlayerActorPrimaryEquippedItemChangedEvent();
|
||||
DataSerializationUtils.Deserialize(actorEvent.Data, ref itemChangedEvent);
|
||||
|
||||
if (itemChangedEvent.ItemActorID == 0) {
|
||||
m_EquippedItem = null;
|
||||
} else {
|
||||
Actor itemActor = RR.FindSpawnedActor(itemChangedEvent.ItemActorID);
|
||||
if (itemActor is ItemActor item) {
|
||||
s_Logger.Info($"Primary equipped item changed to {item.name} for player {name}.");
|
||||
m_EquippedItem = item;
|
||||
} else {
|
||||
s_Logger.Error($"Primary equipped item with ID {itemChangedEvent.ItemActorID} not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Controller API
|
||||
//
|
||||
public void SetSprint(bool isSprinting) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot set sprint state when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
m_Locomotion.SetSprint(isSprinting);
|
||||
}
|
||||
|
||||
public void Jump() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot jump when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
m_Locomotion.Jump();
|
||||
}
|
||||
|
||||
public void Look(Vector2 input) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot look when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
m_Camera.Rotate(input.x, input.y);
|
||||
}
|
||||
|
||||
public void SetMoveInput(Vector2 input) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot set move input when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsOwner) {
|
||||
OwnerTick();
|
||||
} else {
|
||||
RemoteTick();
|
||||
float3 direction = Quaternion.AngleAxis(m_Camera.Yaw, Vector3.up) *
|
||||
new float3(input.x, 0.0f, input.y);
|
||||
m_Locomotion.SetWishDirection(direction);
|
||||
}
|
||||
|
||||
public void StartDrag() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot start dragging when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Character rotation
|
||||
GameObject pickedGameObject = m_Camera.Sensor.Sense();
|
||||
if (pickedGameObject != null && pickedGameObject.TryGetComponent(out Rigidbody rigidbody)) {
|
||||
m_PhysicsDragger.Grab(rigidbody);
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDrag() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot stop dragging when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_PhysicsDragger.Drop();
|
||||
}
|
||||
|
||||
public void DropItem() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot drop item when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_EquippedItem != null) {
|
||||
PlayerActorDropItemCommand command = new PlayerActorDropItemCommand {
|
||||
InventorySlotIndex = SelectedInventorySlot.Value,
|
||||
Count = 1
|
||||
};
|
||||
SendActorCommand((ushort) PlayerActorCommands.DropItem, ref command);
|
||||
}
|
||||
}
|
||||
|
||||
public void PrimaryAction() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot perform primary action when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
// if (!IsOwner()) {
|
||||
// s_Logger.Error("Only the owner can perform primary actions.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (TryGetBeaconPosition(out Vector3 beaconPosition)) {
|
||||
// SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
|
||||
//
|
||||
// if (RR.World.Context is WorldContext worldContext) {
|
||||
// worldContext.BaseManager.TrySpawnBeacon(beaconPosition);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void SecondaryAction() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot perform secondary action when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_Animator.SetTrigger(AnimatorParamHashes.Block);
|
||||
}
|
||||
|
||||
public void Interact() {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot perform interaction when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TargetInteractable.Value is ItemActor itemActor) {
|
||||
Pickup(itemActor);
|
||||
} else if (m_TargetInteractable.Value is not null) {
|
||||
m_TargetInteractable.Value.Interact();
|
||||
// SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Owner
|
||||
//
|
||||
public void SetupAsOwner() {
|
||||
m_Camera.enabled = true;
|
||||
m_Camera.Camera.enabled = true;
|
||||
m_Locomotion.enabled = true;
|
||||
|
||||
if (TryGetComponent(out Rigidbody rbody)) {
|
||||
rbody.isKinematic = false;
|
||||
}
|
||||
|
||||
m_IsSetupAsOwner = true;
|
||||
}
|
||||
|
||||
void TickCamera() {
|
||||
// Camera Stuff
|
||||
m_Camera.Tick();
|
||||
|
||||
if (m_Locomotion.IsGrounded &&
|
||||
m_Locomotion.SpeedXZ >= m_Locomotion.runSpeed * m_EnableCameraBobbingPercentThreshold) {
|
||||
if (m_Locomotion.IsSprinting) {
|
||||
m_TargetCameraBobbing = m_SprintCameraBobbing;
|
||||
} else {
|
||||
m_TargetCameraBobbing = m_RunCameraBobbing;
|
||||
}
|
||||
} else {
|
||||
m_TargetCameraBobbing = m_IdleCameraBobbing;
|
||||
}
|
||||
|
||||
m_CurrentCameraBobbing = Mathf.MoveTowards(m_CurrentCameraBobbing,
|
||||
m_TargetCameraBobbing,
|
||||
m_CameraBobbingTransitionSpeed * Time.deltaTime);
|
||||
m_Camera.SetBobbing(m_CurrentCameraBobbing);
|
||||
|
||||
m_CameraSpring.UpdateSpring(Time.deltaTime,
|
||||
m_CharacterForwardTransform.up,
|
||||
m_CharacterForwardTransform.right,
|
||||
m_CharacterForwardTransform.forward);
|
||||
}
|
||||
|
||||
void SenseInteractable() {
|
||||
IInteractable interactable = m_InteractablesSensor.Sense();
|
||||
if (interactable != m_TargetInteractable.Value) {
|
||||
m_TargetInteractable.Value = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Remote
|
||||
//
|
||||
void SetupAsRemote() {
|
||||
m_Camera.enabled = false;
|
||||
m_Camera.Camera.enabled = false;
|
||||
m_Locomotion.enabled = false;
|
||||
|
||||
if (TryGetComponent(out Rigidbody rbody)) {
|
||||
rbody.isKinematic = true;
|
||||
}
|
||||
|
||||
m_IsSetupAsOwner = false;
|
||||
}
|
||||
|
||||
void InterpolateActorState(float deltaTime) {
|
||||
Vector3 targetPosition = m_RemoteState.Position;
|
||||
|
||||
if ((transform.position - m_RemoteState.Position).sqrMagnitude <
|
||||
m_MinTeleportDistance * m_MinTeleportDistance) {
|
||||
targetPosition = Vector3.MoveTowards(transform.position,
|
||||
m_RemoteState.Position,
|
||||
m_Locomotion.runSpeed * deltaTime);
|
||||
}
|
||||
|
||||
m_Locomotion.WarpTo(targetPosition);
|
||||
|
||||
m_Camera.Pitch = m_RemoteState.LookPitch;
|
||||
m_Camera.Yaw = m_RemoteState.LookYaw;
|
||||
|
||||
UpdateAnimator(m_RemoteState.Velocity);
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Server
|
||||
//
|
||||
void OnItemDropped(ItemActor item) {
|
||||
if (!RR.IsServer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateEquippedItem();
|
||||
|
||||
item.SetHidden(false);
|
||||
item.UnMount();
|
||||
|
||||
item.transform.position = m_HeadBoneTransform.position + m_HeadBoneTransform.forward * 1.0f;
|
||||
item.transform.rotation = Quaternion.LookRotation(m_HeadBoneTransform.forward, Vector3.up);
|
||||
}
|
||||
|
||||
void OnItemPickedUp(ItemActor item) {
|
||||
if (!RR.IsServer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.SetHidden(true);
|
||||
}
|
||||
|
||||
void UpdateEquippedItem() {
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can update selected item.");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemActor itemActor = Inventory.GetFirstItem(SelectedInventorySlot.Value);
|
||||
if (itemActor == m_EquippedItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_EquippedItem != null) {
|
||||
m_EquippedItem.SetHidden(true);
|
||||
}
|
||||
|
||||
m_EquippedItem = itemActor;
|
||||
|
||||
if (m_EquippedItem != null) {
|
||||
m_EquippedItem.SetHidden(false);
|
||||
m_EquippedItem.MountTo(this, "hand_right");
|
||||
}
|
||||
|
||||
PlayerActorPrimaryEquippedItemChangedEvent itemChangedEvent =
|
||||
new PlayerActorPrimaryEquippedItemChangedEvent {
|
||||
ItemActorID = m_EquippedItem != null ? m_EquippedItem.ActorID : 0
|
||||
};
|
||||
SendActorEvent((ushort) PlayerActorEvents.PrimaryEquippedItemChanged, ref itemChangedEvent);
|
||||
}
|
||||
|
||||
public void WarpTo(Vector3 position) {
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can warp players.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_Locomotion.WarpTo(position);
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Common
|
||||
//
|
||||
void TickCharacterRotation() {
|
||||
float3 targetCharacterForward = math.normalize(LookDirection.With(y: 0.0f));
|
||||
float3 currentCharacterForward = math.normalize(m_CharacterForwardTransform.forward.With(y: 0.0f));
|
||||
|
||||
@@ -167,220 +549,9 @@ namespace RebootReality.jelycho.Player {
|
||||
m_HeadAimTargetTransform.position = (float3) m_HeadBoneTransform.position + LookDirection * 5.0f;
|
||||
}
|
||||
|
||||
// @MARK: NetworkBehaviour callbacks
|
||||
public override void OnNetworkSpawn() {
|
||||
base.OnNetworkSpawn();
|
||||
|
||||
if (IsServer) {
|
||||
Inventory.OnItemPickedUp += OnItemPickedUp;
|
||||
Inventory.OnItemDropped += OnItemDropped;
|
||||
}
|
||||
|
||||
if (IsOwner) {
|
||||
SetupAsOwner();
|
||||
|
||||
RR.ClientTick += SyncActorState;
|
||||
} else {
|
||||
SetupAsRemote();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn() {
|
||||
base.OnNetworkDespawn();
|
||||
|
||||
if (IsServer) {
|
||||
Inventory.OnItemPickedUp -= OnItemPickedUp;
|
||||
Inventory.OnItemDropped -= OnItemDropped;
|
||||
}
|
||||
|
||||
if (IsOwner) {
|
||||
RR.ClientTick -= SyncActorState;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGainedOwnership() {
|
||||
base.OnGainedOwnership();
|
||||
SetupAsOwner();
|
||||
}
|
||||
|
||||
public override void OnLostOwnership() {
|
||||
base.OnLostOwnership();
|
||||
SetupAsRemote();
|
||||
}
|
||||
|
||||
// @MARK: API to be used by owner
|
||||
public void SetSprint(bool isSprinting) {
|
||||
m_Locomotion.SetSprint(isSprinting);
|
||||
}
|
||||
|
||||
public void Jump() {
|
||||
m_Locomotion.Jump();
|
||||
}
|
||||
|
||||
public void Look(Vector2 input) {
|
||||
m_Camera.Rotate(input.x, input.y);
|
||||
}
|
||||
|
||||
public void SetMoveInput(Vector2 input) {
|
||||
float3 direction = Quaternion.AngleAxis(m_Camera.Yaw, Vector3.up) *
|
||||
new float3(input.x, 0.0f, input.y);
|
||||
m_Locomotion.SetWishDirection(direction);
|
||||
}
|
||||
|
||||
public void StartDrag() {
|
||||
GameObject pickedGameObject = m_Camera.Sensor.Sense();
|
||||
if (pickedGameObject != null && pickedGameObject.TryGetComponent(out Rigidbody rigidbody)) {
|
||||
m_PhysicsDragger.Grab(rigidbody);
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDrag() {
|
||||
m_PhysicsDragger.Drop();
|
||||
}
|
||||
|
||||
public void PrimaryAction() {
|
||||
if (!IsOwner) {
|
||||
s_Logger.Error("Only the owner can perform primary actions.");
|
||||
return;
|
||||
}
|
||||
|
||||
// if (TryGetBeaconPosition(out Vector3 beaconPosition)) {
|
||||
// SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
|
||||
//
|
||||
// if (RR.World.Context is WorldContext worldContext) {
|
||||
// worldContext.BaseManager.TrySpawnBeacon(beaconPosition);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void SecondaryAction() {
|
||||
if (!IsOwner) {
|
||||
s_Logger.Error("Only the owner can perform secondary actions.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_Animator.SetTrigger(AnimatorParamHashes.Block);
|
||||
}
|
||||
|
||||
public void Interact() {
|
||||
if (!IsOwner) {
|
||||
s_Logger.Error("Only the owner can perform interactions.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TargetInteractable.Value is ItemActor itemActor) {
|
||||
Pickup(itemActor);
|
||||
} else if (m_TargetInteractable.Value is not null) {
|
||||
m_TargetInteractable.Value.Interact();
|
||||
SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
|
||||
}
|
||||
}
|
||||
|
||||
// @MARK: Owner
|
||||
void SetupAsOwner() {
|
||||
m_Camera.enabled = true;
|
||||
m_Camera.Camera.enabled = true;
|
||||
m_Locomotion.enabled = true;
|
||||
|
||||
if (TryGetComponent(out Rigidbody rbody)) {
|
||||
rbody.isKinematic = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OwnerTick() {
|
||||
// Camera Stuff
|
||||
m_Camera.Tick();
|
||||
|
||||
if (m_Locomotion.IsGrounded &&
|
||||
m_Locomotion.SpeedXZ >= m_Locomotion.runSpeed * m_EnableCameraBobbingPercentThreshold) {
|
||||
if (m_Locomotion.IsSprinting) {
|
||||
m_TargetCameraBobbing = m_SprintCameraBobbing;
|
||||
} else {
|
||||
m_TargetCameraBobbing = m_RunCameraBobbing;
|
||||
}
|
||||
} else {
|
||||
m_TargetCameraBobbing = m_IdleCameraBobbing;
|
||||
}
|
||||
|
||||
m_CurrentCameraBobbing = Mathf.MoveTowards(m_CurrentCameraBobbing,
|
||||
m_TargetCameraBobbing,
|
||||
m_CameraBobbingTransitionSpeed * Time.deltaTime);
|
||||
m_Camera.SetBobbing(m_CurrentCameraBobbing);
|
||||
|
||||
m_CameraSpring.UpdateSpring(Time.deltaTime,
|
||||
m_CharacterForwardTransform.up,
|
||||
m_CharacterForwardTransform.right,
|
||||
m_CharacterForwardTransform.forward);
|
||||
|
||||
|
||||
UpdateAnimator(m_Locomotion.Velocity);
|
||||
|
||||
IInteractable interactable = m_InteractablesSensor.Sense();
|
||||
if (interactable != m_TargetInteractable.Value) {
|
||||
m_TargetInteractable.Value = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
void SyncActorState() {
|
||||
PlayerActorState state = new PlayerActorState {
|
||||
Position = transform.position,
|
||||
LookPitch = m_Camera.Pitch,
|
||||
LookYaw = m_Camera.Yaw,
|
||||
IsGrounded = m_Locomotion.IsGrounded,
|
||||
Velocity = m_Locomotion.Velocity
|
||||
};
|
||||
|
||||
UpdatePlayerStateRpc(state);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.NotMe)]
|
||||
void UpdatePlayerStateRpc(PlayerActorState state) {
|
||||
if (IsOwner) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_NetworkState = state;
|
||||
}
|
||||
|
||||
// @MARK: Remote
|
||||
void SetupAsRemote() {
|
||||
m_Camera.enabled = false;
|
||||
m_Camera.Camera.enabled = false;
|
||||
m_Locomotion.enabled = false;
|
||||
|
||||
if (TryGetComponent(out Rigidbody rbody)) {
|
||||
rbody.isKinematic = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteTick() {
|
||||
Vector3 targetPosition = m_NetworkState.Position;
|
||||
|
||||
if ((transform.position - m_NetworkState.Position).sqrMagnitude <
|
||||
m_MinTeleportDistance * m_MinTeleportDistance) {
|
||||
targetPosition = Vector3.MoveTowards(transform.position,
|
||||
m_NetworkState.Position,
|
||||
m_Locomotion.runSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
m_Locomotion.WarpTo(targetPosition);
|
||||
|
||||
m_Camera.Pitch = m_NetworkState.LookPitch;
|
||||
m_Camera.Yaw = m_NetworkState.LookYaw;
|
||||
|
||||
UpdateAnimator(m_NetworkState.Velocity);
|
||||
}
|
||||
|
||||
// @MARK: Server
|
||||
void OnItemDropped(ItemActor item) {
|
||||
item.SetHidden(false);
|
||||
}
|
||||
|
||||
void OnItemPickedUp(ItemActor item) {
|
||||
item.SetHidden(true);
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Sensors
|
||||
//
|
||||
bool TryGetBeaconPosition(out Vector3 position) {
|
||||
Ray ray = new Ray(m_Camera.Camera.transform.position, m_Camera.Camera.transform.forward);
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, m_BeaconPlacementMaxDistance, m_BeaconPlacementLayerMask) &&
|
||||
@@ -393,69 +564,57 @@ namespace RebootReality.jelycho.Player {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @MARK: Networked methods
|
||||
[ServerRpc(RequireOwnership = false)]
|
||||
public void WarpToServerRpc(Vector3 position) {
|
||||
WarpToClientRpc(position);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void WarpToClientRpc(Vector3 position) {
|
||||
if (IsOwner) {
|
||||
m_Locomotion.WarpTo(position);
|
||||
} else {
|
||||
transform.position = position;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Inventory
|
||||
//
|
||||
void Pickup(ItemActor actor) {
|
||||
PickupItemRpc(actor.ActorID);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server)]
|
||||
void PickupItemRpc(ulong actorID) {
|
||||
Actor actor = RR.FindSpawnedActor(actorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {actorID} not found for pickup.");
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Cannot pick up items when not set up as owner.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (actor is ItemActor itemActor) {
|
||||
if (Inventory.TryPickup(itemActor)) {
|
||||
SetAnimatorTriggerRpc(AnimatorParamHashes.Attack);
|
||||
}
|
||||
}
|
||||
PlayerActorPickupItemCommand command = new PlayerActorPickupItemCommand {
|
||||
ItemActorID = actor.ActorID
|
||||
};
|
||||
SendActorCommand((ushort) PlayerActorCommands.PickupItem, ref command);
|
||||
}
|
||||
|
||||
|
||||
public void SelectPreviousItemSlot() {
|
||||
if (!IsOwner) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Only the owner can change inventory selection.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (SelectedInventorySlot.Value > 0) {
|
||||
SelectedInventorySlot.Value--;
|
||||
} else {
|
||||
SelectedInventorySlot.Value = Inventory.SlotsCount - 1;
|
||||
}
|
||||
|
||||
PlayerActorSelectItemSlotCommand command = new PlayerActorSelectItemSlotCommand();
|
||||
command.SlotIndex = SelectedInventorySlot.Value;
|
||||
SendActorCommand((ushort) PlayerActorCommands.SelectItemSlot, ref command);
|
||||
}
|
||||
|
||||
public void SelectNextItemSlot() {
|
||||
if (!IsOwner) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Only the owner can change inventory selection.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (SelectedInventorySlot.Value < Inventory.SlotsCount - 1) {
|
||||
SelectedInventorySlot.Value++;
|
||||
} else {
|
||||
SelectedInventorySlot.Value = 0;
|
||||
}
|
||||
|
||||
PlayerActorSelectItemSlotCommand command = new PlayerActorSelectItemSlotCommand();
|
||||
command.SlotIndex = SelectedInventorySlot.Value;
|
||||
SendActorCommand((ushort) PlayerActorCommands.SelectItemSlot, ref command);
|
||||
}
|
||||
|
||||
|
||||
public void SelectItemSlot(int slotIndex) {
|
||||
if (!IsOwner) {
|
||||
if (!m_IsSetupAsOwner) {
|
||||
s_Logger.Error("Only the owner can change inventory selection.");
|
||||
return;
|
||||
}
|
||||
@@ -466,13 +625,15 @@ namespace RebootReality.jelycho.Player {
|
||||
}
|
||||
|
||||
SelectedInventorySlot.Value = slotIndex;
|
||||
|
||||
PlayerActorSelectItemSlotCommand command = new PlayerActorSelectItemSlotCommand();
|
||||
command.SlotIndex = SelectedInventorySlot.Value;
|
||||
SendActorCommand((ushort) PlayerActorCommands.SelectItemSlot, ref command);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// @MARK: Animations
|
||||
[Rpc(SendTo.Everyone)]
|
||||
void SetAnimatorTriggerRpc(int hash) {
|
||||
m_Animator.SetTrigger(hash);
|
||||
}
|
||||
//
|
||||
|
||||
struct AnimatorParamHashes {
|
||||
public static readonly int VelocityForwardNormalized = Animator.StringToHash("VelocityForwardNormalized");
|
||||
@@ -507,4 +668,114 @@ namespace RebootReality.jelycho.Player {
|
||||
m_Animator.SetInteger(AnimatorParamHashes.Holding, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerActorData : IActorData {
|
||||
public void Serialize(FastBufferWriter writer) { }
|
||||
|
||||
public void Deserialize(FastBufferReader reader) { }
|
||||
}
|
||||
|
||||
public struct RemotePlayerActorState : IActorData {
|
||||
public Vector3 Position;
|
||||
public Vector3 Velocity;
|
||||
public float LookPitch;
|
||||
public float LookYaw;
|
||||
public bool IsGrounded;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(Position);
|
||||
writer.WriteValue(Velocity);
|
||||
writer.WriteValue(LookPitch);
|
||||
writer.WriteValue(LookYaw);
|
||||
writer.WriteValue(IsGrounded);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out Position);
|
||||
reader.ReadValue(out Velocity);
|
||||
reader.ReadValue(out LookPitch);
|
||||
reader.ReadValue(out LookYaw);
|
||||
reader.ReadValue(out IsGrounded);
|
||||
}
|
||||
}
|
||||
|
||||
// @MARK: Player Actor Commands
|
||||
enum PlayerActorCommands : ushort {
|
||||
None = 0x0000,
|
||||
UpdateRemoteState = 0x0001,
|
||||
PickupItem = 0x0002,
|
||||
DropItem = 0x0003,
|
||||
EquipItem = 0x0004,
|
||||
SelectItemSlot = 0x0005,
|
||||
}
|
||||
|
||||
struct PlayerActorPickupItemCommand : IActorData {
|
||||
public ulong ItemActorID;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(ItemActorID);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out ItemActorID);
|
||||
}
|
||||
}
|
||||
|
||||
struct PlayerActorDropItemCommand : IActorData {
|
||||
public int InventorySlotIndex;
|
||||
public int Count;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(InventorySlotIndex);
|
||||
writer.WriteValue(Count);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out InventorySlotIndex);
|
||||
reader.ReadValue(out Count);
|
||||
}
|
||||
}
|
||||
|
||||
struct PlayerActorEquipItemCommand : IActorData {
|
||||
public int InventorySlotIndex;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(InventorySlotIndex);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out InventorySlotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
struct PlayerActorSelectItemSlotCommand : IActorData {
|
||||
public int SlotIndex;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(SlotIndex);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out SlotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// @MARK: Player Actor Events
|
||||
enum PlayerActorEvents : ushort {
|
||||
None = 0x0000,
|
||||
PrimaryEquippedItemChanged = 0x0001,
|
||||
UpdatedRemoteState = 0x0002,
|
||||
}
|
||||
|
||||
struct PlayerActorPrimaryEquippedItemChangedEvent : IActorData {
|
||||
public ulong ItemActorID;
|
||||
|
||||
public void Serialize(FastBufferWriter writer) {
|
||||
writer.WriteValue(ItemActorID);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader) {
|
||||
reader.ReadValue(out ItemActorID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,10 @@
|
||||
using R3;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Simulation;
|
||||
using RebootReality.jelycho.Player.HUD;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.InputSystem;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
@@ -49,49 +48,48 @@ namespace RebootReality.jelycho.Player {
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void SetActorClientRpc(ulong networkObjectID) {
|
||||
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectID,
|
||||
out NetworkObject networkObject)) {
|
||||
m_Actor = networkObject.GetComponent<PlayerActor>();
|
||||
s_Logger.Info($"Found Player Actor NetworkObject ID: {networkObjectID}");
|
||||
protected override void OnPossessActor(Actor actor) {
|
||||
if (actor is PlayerActor playerActor) {
|
||||
m_Actor = playerActor;
|
||||
} else {
|
||||
s_Logger.Error($"Failed to find PlayerActor with NetworkObject ID: {networkObjectID}");
|
||||
m_Actor = null;
|
||||
}
|
||||
|
||||
if (m_Actor is null) {
|
||||
s_Logger.Error($"Tried to possess non-PlayerActor: {actor.GetType().Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsServer) {
|
||||
if (RR.World.Context is WorldContext worldContext) {
|
||||
m_Actor.WarpToServerRpc(worldContext.PlayerSpawnPoint.position);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsOwner) {
|
||||
m_Actor.SetupAsOwner();
|
||||
|
||||
m_OwnerActorDisposableBag.Dispose();
|
||||
m_OwnerActorDisposableBag = new DisposableBag();
|
||||
|
||||
m_Actor.TargetInteractable.Subscribe(interactable => {
|
||||
if (m_TargetInteractableLabelDisposable != null) {
|
||||
m_TargetInteractableLabelDisposable.Dispose();
|
||||
m_TargetInteractableLabelDisposable = null;
|
||||
}
|
||||
|
||||
if (interactable is MonoBehaviour mb) {
|
||||
if (interactable is Actor interactableActor) {
|
||||
m_TargetInteractableLabelDisposable =
|
||||
m_HUD.ObjectsLabels.CreateLabel(mb.transform, mb.name);
|
||||
m_HUD.ObjectsLabels.CreateLabel(interactableActor.transform,
|
||||
interactableActor.ActorName);
|
||||
}
|
||||
})
|
||||
.AddTo(ref m_OwnerActorDisposableBag);
|
||||
|
||||
m_HUD.SetPlayerActor(m_Actor);
|
||||
}
|
||||
|
||||
if (IsServer) {
|
||||
if (RR.World.Context is WorldContext worldContext) {
|
||||
m_Actor.WarpTo(worldContext.PlayerSpawnPoint.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void SetNullActorClientRpc() {
|
||||
protected override void OnUnpossessActor(Actor actor) {
|
||||
base.OnUnpossessActor(actor);
|
||||
|
||||
m_OwnerActorDisposableBag.Dispose();
|
||||
m_OwnerActorDisposableBag = new DisposableBag();
|
||||
m_Actor = null;
|
||||
@@ -126,6 +124,10 @@ namespace RebootReality.jelycho.Player {
|
||||
m_Actor.StopDrag();
|
||||
}
|
||||
|
||||
if (m_Config.dropItemActionReference.action.WasReleasedThisFrame()) {
|
||||
m_Actor.DropItem();
|
||||
}
|
||||
|
||||
if (m_Config.primaryActionReference.action.WasReleasedThisFrame()) {
|
||||
m_Actor.PrimaryAction();
|
||||
}
|
||||
@@ -137,7 +139,7 @@ namespace RebootReality.jelycho.Player {
|
||||
if (m_Config.interactActionReference.action.WasReleasedThisFrame()) {
|
||||
m_Actor.Interact();
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < m_Config.inventorySlotSelectActionReferences.Length; i++) {
|
||||
if (m_Config.inventorySlotSelectActionReferences[i].action.WasReleasedThisFrame()) {
|
||||
m_Actor.SelectItemSlot(i);
|
||||
@@ -163,10 +165,11 @@ namespace RebootReality.jelycho.Player {
|
||||
public InputActionReference jumpActionReference;
|
||||
public InputActionReference sprintActionReference;
|
||||
public InputActionReference dragObjectActionReference;
|
||||
public InputActionReference dropItemActionReference;
|
||||
public InputActionReference primaryActionReference;
|
||||
public InputActionReference secondaryActionReference;
|
||||
public InputActionReference interactActionReference;
|
||||
|
||||
|
||||
public InputActionReference[] inventorySlotSelectActionReferences;
|
||||
public InputActionReference inventorySlotChangeActionReference;
|
||||
}
|
||||
|
||||
@@ -97,13 +97,9 @@ namespace RebootReality.jelycho.Player {
|
||||
}
|
||||
|
||||
GUI.Label(new Rect(0, 0, Screen.width, Screen.height),
|
||||
$"Wish Direction: {m_WishDir}\n" +
|
||||
$"Is Grounded: {m_Motor.GroundingStatus.IsStableOnGround}\n" +
|
||||
$"Is Jump Requested: {m_IsJumpRequested}\n" +
|
||||
$"Is Grounded: {m_Motor.GroundingStatus.IsStableOnGround.ToString()}\n" +
|
||||
$"Motor Velocity: {m_Motor.Velocity}, magnitude: {m_Motor.Velocity.magnitude}\n" +
|
||||
$"Motor Base Velocity: {m_Motor.BaseVelocity}, magnitude: {m_Motor.BaseVelocity.magnitude}\n" +
|
||||
$"Last Velocity: {m_LastVelocity}, magnitude: {math.length(m_LastVelocity)}\n" +
|
||||
$"XZ Last Velocity: {m_LastVelocity.With(y: 0.0f).magnitude}",
|
||||
$"XZ Motor Velocity: {m_Motor.Velocity.With(y: 0.0f).magnitude}",
|
||||
s_debugLabelStyle);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using UnityEngine;
|
||||
|
||||
namespace RebootReality.jelycho.Player {
|
||||
[Serializable]
|
||||
public struct GenericSensor : ISensor {
|
||||
public struct SingleRaySensor : ISensor {
|
||||
[SerializeField] Transform m_Origin;
|
||||
[SerializeField] LayerMask m_LayerMask;
|
||||
[SerializeField] float m_MaxDistance;
|
||||
@@ -21,7 +21,7 @@ namespace RebootReality.jelycho.Player {
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct GenericSensor<T> : ISensor<T> where T : class {
|
||||
public class SingleRaySensor<T> : ISensor<T> where T : class {
|
||||
[SerializeField] Transform m_Origin;
|
||||
[SerializeField] LayerMask m_LayerMask;
|
||||
[SerializeField] float m_MaxDistance;
|
||||
Reference in New Issue
Block a user