working on inventory

This commit is contained in:
2025-07-11 14:40:23 +02:00
parent 0d69e37385
commit dc998d907c
81 changed files with 3468 additions and 231 deletions

View File

@@ -1,6 +1,5 @@
using System;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Services.Simulation.Sensors;
using RebootKit.Engine.Simulation.Sensors;
using RebootReality.jelycho.Main;
using Unity.Cinemachine;

View File

@@ -0,0 +1,41 @@
using System;
using RebootKit.Engine.Simulation.Sensors;
using UnityEngine;
namespace RebootReality.jelycho.Player {
[Serializable]
public struct GenericSensor : ISensor {
[SerializeField] Transform m_Origin;
[SerializeField] LayerMask m_LayerMask;
[SerializeField] float m_MaxDistance;
public GameObject Sense() {
Ray ray = new Ray(m_Origin.position, m_Origin.forward);
if (Physics.Raycast(ray, out RaycastHit hit, m_MaxDistance, m_LayerMask)) {
return hit.collider.gameObject;
}
return null;
}
}
[Serializable]
public struct GenericSensor<T> : ISensor<T> where T : class {
[SerializeField] Transform m_Origin;
[SerializeField] LayerMask m_LayerMask;
[SerializeField] float m_MaxDistance;
public T Sense() {
Ray ray = new Ray(m_Origin.position, m_Origin.forward);
if (Physics.Raycast(ray, out RaycastHit hit, m_MaxDistance, m_LayerMask)) {
if (hit.collider.TryGetComponent(out T component)) {
return component;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 584138e7a2834fbaa3f29d381ee6d0f5
timeCreated: 1752181704

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 433c5938a11248afa61f1ced56bd407d
timeCreated: 1752067932

View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using RebootKit.Engine.Main;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.UIElements;
namespace RebootReality.jelycho.Player.HUD {
public class ObjectsLabelsVC : MonoBehaviour {
[SerializeField] UIDocument m_Document;
[SerializeField] VisualTreeAsset m_LabelTemplate;
IObjectPool<LabelEntry> m_LabelPool;
readonly List<LabelEntry> m_ActiveLabels = new List<LabelEntry>();
void Awake() {
m_LabelPool = new ObjectPool<LabelEntry>(() => {
LabelEntry entry = new LabelEntry();
entry.Parent = this;
entry.Root = new VisualElement();
entry.Root.style.position = Position.Absolute;
entry.Root.style.visibility = Visibility.Hidden;
entry.Root.style.minWidth = 300;
entry.Root.style.height = 64;
m_LabelTemplate.CloneTree(entry.Root);
entry.Label = entry.Root.Q<Label>("player-hud__object-label");
m_Document.rootVisualElement.Add(entry.Root);
return entry;
},
entry => {
entry.Root.style.visibility = Visibility.Visible;
m_ActiveLabels.Add(entry);
},
entry => {
entry.Root.style.visibility = Visibility.Hidden;
m_ActiveLabels.RemoveSwapBack(entry);
},
entry => {
m_ActiveLabels.RemoveSwapBack(entry);
m_Document.rootVisualElement.Remove(entry.Root);
});
}
void Update() {
foreach (LabelEntry entry in m_ActiveLabels) {
Vector3 worldPosition = entry.TargetTransform.position;
Vector2 screenPosition = RR.MainCamera.WorldToScreenPoint(worldPosition);
entry.Root.style.left = screenPosition.x - entry.Root.contentRect.width * 0.5f;
entry.Root.style.top = Screen.height - screenPosition.y - entry.Root.contentRect.height * 0.5f;
}
}
public IDisposable CreateLabel(Transform targetTransform, string labelText) {
if (targetTransform == null) {
throw new ArgumentNullException(nameof(targetTransform));
}
LabelEntry entry = m_LabelPool.Get();
entry.TargetTransform = targetTransform;
entry.Label.text = labelText;
entry.Root.style.visibility = Visibility.Visible;
return entry;
}
class LabelEntry : IDisposable {
public ObjectsLabelsVC Parent;
public VisualElement Root;
public Label Label;
public Transform TargetTransform;
public void Dispose() {
Parent.m_LabelPool.Release(this);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42a4ccf83ed64ac58aef118275bd2414
timeCreated: 1752068186

View File

@@ -0,0 +1,45 @@
using System;
using R3;
using UnityEngine;
using UnityEngine.UIElements;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootReality.jelycho.Player.HUD {
public class PlayerHUD : MonoBehaviour {
static readonly Logger s_Logger = new Logger(nameof(PlayerHUD));
[SerializeField] UIDocument m_MainDocument;
[field: SerializeField] public ObjectsLabelsVC ObjectsLabels { get; private set; }
[field: SerializeField] public PlayerInventoryUI InventoryUI { get; private set; }
PlayerActor m_PlayerActor;
DisposableBag m_ActorBag;
void OnEnable() {
}
void OnDisable() {
InventoryUI.CleanUp();
m_ActorBag.Dispose();
}
public void SetPlayerActor(PlayerActor actor) {
m_ActorBag.Dispose();
if (actor == null) {
m_PlayerActor = null;
InventoryUI.CleanUp();
return;
}
m_ActorBag = new DisposableBag();
m_PlayerActor = actor;
InventoryUI.Configure(m_MainDocument.rootVisualElement.Q("player-hud__inventory-slots"), actor.Inventory);
actor.SelectedInventorySlot.Subscribe(x => {
InventoryUI.SetSelectedSlot(x);
}).AddTo(ref m_ActorBag);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e0712c9d21534362b219edf44601f57d
timeCreated: 1752067887

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using RebootReality.jelycho.Items;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UIElements;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootReality.jelycho.Player.HUD {
public class PlayerInventoryUI : MonoBehaviour {
static readonly Logger s_Logger = new Logger(nameof(PlayerInventoryUI));
[SerializeField] VisualTreeAsset m_InventorySlotTemplate;
Inventory m_Inventory;
VisualElement m_Root;
struct InventorySlot {
public VisualElement Root;
public VisualElement Slot;
public VisualElement Icon;
public Label QuantityLabel;
}
readonly List<InventorySlot> m_InventorySlots = new List<InventorySlot>();
public void Configure(VisualElement root, Inventory inventory) {
CleanUp();
m_Root = root;
m_Inventory = inventory;
m_Inventory.OnSlotUpdated += OnSlotUpdated;
m_Root.Clear();
for (int i = 0; i < m_Inventory.SlotsCount; i++) {
VisualElement slotRoot = m_InventorySlotTemplate.CloneTree();
m_Root.Add(slotRoot);
slotRoot .style.width = new StyleLength(new Length(72, LengthUnit.Pixel));
slotRoot.style.height = new StyleLength(new Length(72, LengthUnit.Pixel));
InventorySlot slot = new InventorySlot {
Root = slotRoot,
Slot = slotRoot.Q<VisualElement>("player-hud__inventory-slot"),
Icon = slotRoot.Q<VisualElement>("player-hud__inventory-slot-icon"),
QuantityLabel = slotRoot.Q<Label>("player-hud__inventory-slot-quantity"),
};
Assert.IsNotNull(slot.Root, "Slot root cannot be null");
Assert.IsNotNull(slot.Slot, "Slot element cannot be null");
Assert.IsNotNull(slot.Icon, "Slot icon cannot be null");
Assert.IsNotNull(slot.QuantityLabel, "Slot quantity label cannot be null");
m_InventorySlots.Add(slot);
OnSlotUpdated(i);
}
}
public void CleanUp() {
if (m_Root != null) {
m_Root.Clear();
m_Root = null;
}
if (m_Inventory != null) {
m_Inventory.OnSlotUpdated -= OnSlotUpdated;
m_Inventory = null;
}
m_InventorySlots.Clear();
}
public void SetSelectedSlot(int slotIndex) {
if (slotIndex < 0 || slotIndex >= m_InventorySlots.Count) {
s_Logger.Error($"Invalid slot index: {slotIndex}. Inventory has {m_InventorySlots.Count} slots.");
return;
}
for (int i = 0; i < m_InventorySlots.Count; i++) {
m_InventorySlots[i].Slot.EnableInClassList("inventory-slot-selected", i == slotIndex);
}
}
void OnSlotUpdated(int slotIndex) {
if (slotIndex < 0 || slotIndex >= m_InventorySlots.Count) {
s_Logger.Error($"Invalid slot index: {slotIndex}. Inventory has {m_InventorySlots.Count} slots.");
return;
}
int quantity = m_Inventory.GetQuantity(slotIndex);
if (quantity <= 0) {
m_InventorySlots[slotIndex].QuantityLabel.style.display = DisplayStyle.None;
m_InventorySlots[slotIndex].Icon.style.backgroundImage = null;
m_InventorySlots[slotIndex].Icon.style.display = DisplayStyle.None;
} else {
m_InventorySlots[slotIndex].QuantityLabel.style.display = DisplayStyle.Flex;
m_InventorySlots[slotIndex].QuantityLabel.text = quantity.ToString();
ItemActor itemActor = m_Inventory.GetFirstItem(slotIndex);
if (itemActor != null) {
m_InventorySlots[slotIndex].Icon.style.backgroundImage = new StyleBackground(itemActor.Config.icon);
m_InventorySlots[slotIndex].Icon.style.display = DisplayStyle.Flex;
} else {
m_InventorySlots[slotIndex].Icon.style.backgroundImage = null;
m_InventorySlots[slotIndex].Icon.style.display = DisplayStyle.None;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ffb52c4d0a3c4e17917100cbb52494ea
timeCreated: 1752183541

View File

@@ -1,9 +1,10 @@
using System;
using R3;
using RebootKit.Engine.Extensions;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Main;
using RebootKit.Engine.Services.Simulation;
using RebootKit.Engine.Simulation.Sensors;
using RebootKit.Engine.Simulation;
using RebootReality.jelycho.Items;
using Unity.Mathematics;
using Unity.Netcode;
using UnityEngine;
@@ -26,42 +27,6 @@ namespace RebootReality.jelycho.Player {
}
}
[Serializable]
public struct GenericSensor : ISensor {
[SerializeField] Transform m_Origin;
[SerializeField] LayerMask m_LayerMask;
[SerializeField] float m_MaxDistance;
public GameObject Sense() {
Ray ray = new Ray(m_Origin.position, m_Origin.forward);
if (Physics.Raycast(ray, out RaycastHit hit, m_MaxDistance, m_LayerMask)) {
return hit.collider.gameObject;
}
return null;
}
}
[Serializable]
public struct GenericSensor<T> : ISensor<T> where T : class {
[SerializeField] Transform m_Origin;
[SerializeField] LayerMask m_LayerMask;
[SerializeField] float m_MaxDistance;
public T Sense() {
Ray ray = new Ray(m_Origin.position, m_Origin.forward);
if (Physics.Raycast(ray, out RaycastHit hit, m_MaxDistance, m_LayerMask)) {
if (hit.collider.TryGetComponent(out T component)) {
return component;
}
}
return null;
}
}
public class PlayerActor : NetworkBehaviour {
static readonly Logger s_Logger = new Logger(nameof(PlayerActor));
@@ -115,6 +80,15 @@ namespace RebootReality.jelycho.Player {
[Header("Network")]
[SerializeField] float m_MinTeleportDistance = 0.5f;
PlayerActorState m_NetworkState;
[Header("Inventory")]
[SerializeField] int m_InventorySize = 10;
public Inventory Inventory { get; private set; }
public ReactiveProperty<int> SelectedInventorySlot { get; private set; } = new ReactiveProperty<int>(0);
public float3 LookDirection {
get {
float pitchRad = math.radians(-m_Camera.Pitch);
@@ -125,60 +99,21 @@ namespace RebootReality.jelycho.Player {
}
}
readonly ReactiveProperty<IInteractable> m_TargetInteractable = new ReactiveProperty<IInteractable>(null);
public ReadOnlyReactiveProperty<IInteractable> TargetInteractable {
get {
return m_TargetInteractable;
}
}
void Awake() {
Inventory = new Inventory(m_InventorySize);
}
void Start() {
m_CameraSpring.Initialize();
}
public override void OnNetworkSpawn() {
base.OnNetworkSpawn();
if (IsOwner) {
SetupAsLocalPlayer();
RR.ClientTick += OnClientTick;
} else {
SetupAsRemotePlayer();
}
}
public override void OnNetworkDespawn() {
base.OnNetworkDespawn();
if (IsOwner) {
RR.ClientTick -= OnClientTick;
}
}
void SetupAsLocalPlayer() {
m_Camera.enabled = true;
m_Camera.Camera.enabled = true;
m_Locomotion.enabled = true;
if (TryGetComponent(out Rigidbody rbody)) {
rbody.isKinematic = false;
}
}
void SetupAsRemotePlayer() {
m_Camera.enabled = false;
m_Camera.Camera.enabled = false;
m_Locomotion.enabled = false;
if (TryGetComponent(out Rigidbody rbody)) {
rbody.isKinematic = true;
}
}
public override void OnGainedOwnership() {
base.OnGainedOwnership();
SetupAsLocalPlayer();
}
public override void OnLostOwnership() {
base.OnLostOwnership();
SetupAsRemotePlayer();
}
void Update() {
if (!IsSpawned) {
return;
@@ -232,90 +167,48 @@ namespace RebootReality.jelycho.Player {
m_HeadAimTargetTransform.position = (float3) m_HeadBoneTransform.position + LookDirection * 5.0f;
}
void OwnerTick() {
// Camera Stuff
m_Camera.Tick();
// @MARK: NetworkBehaviour callbacks
public override void OnNetworkSpawn() {
base.OnNetworkSpawn();
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;
if (IsServer) {
Inventory.OnItemPickedUp += OnItemPickedUp;
Inventory.OnItemDropped += OnItemDropped;
}
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);
}
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);
}
void OnClientTick() {
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);
}
PlayerActorState m_NetworkState;
[Rpc(SendTo.NotMe)]
void UpdatePlayerStateRpc(PlayerActorState state) {
if (IsOwner) {
return;
}
SetupAsOwner();
m_NetworkState = state;
}
[ServerRpc(RequireOwnership = false)]
public void WarpToServerRpc(Vector3 position) {
WarpToClientRpc(position);
}
[ClientRpc]
void WarpToClientRpc(Vector3 position) {
if (IsOwner) {
m_Locomotion.WarpTo(position);
RR.ClientTick += SyncActorState;
} else {
transform.position = position;
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);
}
@@ -351,13 +244,13 @@ namespace RebootReality.jelycho.Player {
return;
}
if (TryGetBeaconPosition(out Vector3 beaconPosition)) {
SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
if (RR.World.Context is WorldContext worldContext) {
worldContext.BaseManager.TrySpawnBeacon(beaconPosition);
}
}
// if (TryGetBeaconPosition(out Vector3 beaconPosition)) {
// SetAnimatorTriggerRpc(AnimatorParamHashes.Throw);
//
// if (RR.World.Context is WorldContext worldContext) {
// worldContext.BaseManager.TrySpawnBeacon(beaconPosition);
// }
// }
}
public void SecondaryAction() {
@@ -375,28 +268,119 @@ namespace RebootReality.jelycho.Player {
return;
}
IInteractable interactable = m_InteractablesSensor.Sense();
if (interactable is not null) {
interactable.Interact();
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;
[Rpc(SendTo.Everyone)]
void SetAnimatorTriggerRpc(int hash) {
m_Animator.SetTrigger(hash);
if (TryGetComponent(out Rigidbody rbody)) {
rbody.isKinematic = false;
}
}
bool TryGetInteractable(out IInteractable interactable) {
GameObject pickedGameObject = m_Camera.Sensor.Sense();
if (pickedGameObject != null && pickedGameObject.TryGetComponent(out interactable)) {
return true;
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;
}
interactable = null;
return false;
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) &&
@@ -409,6 +393,87 @@ 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.");
return;
}
if (actor is ItemActor itemActor) {
if (Inventory.TryPickup(itemActor)) {
SetAnimatorTriggerRpc(AnimatorParamHashes.Attack);
}
}
}
public void SelectPreviousItemSlot() {
if (!IsOwner) {
s_Logger.Error("Only the owner can change inventory selection.");
return;
}
if (SelectedInventorySlot.Value > 0) {
SelectedInventorySlot.Value--;
} else {
SelectedInventorySlot.Value = Inventory.SlotsCount - 1;
}
}
public void SelectNextItemSlot() {
if (!IsOwner) {
s_Logger.Error("Only the owner can change inventory selection.");
return;
}
if (SelectedInventorySlot.Value < Inventory.SlotsCount - 1) {
SelectedInventorySlot.Value++;
} else {
SelectedInventorySlot.Value = 0;
}
}
public void SelectItemSlot(int slotIndex) {
if (!IsOwner) {
s_Logger.Error("Only the owner can change inventory selection.");
return;
}
if (slotIndex < 0 || slotIndex >= Inventory.SlotsCount) {
s_Logger.Error($"Invalid slot index {slotIndex}. Must be between 0 and {Inventory.SlotsCount - 1}.");
return;
}
SelectedInventorySlot.Value = slotIndex;
}
// @MARK: Animations
[Rpc(SendTo.Everyone)]
void SetAnimatorTriggerRpc(int hash) {
m_Animator.SetTrigger(hash);
}
struct AnimatorParamHashes {
public static readonly int VelocityForwardNormalized = Animator.StringToHash("VelocityForwardNormalized");
public static readonly int VelocityRightNormalized = Animator.StringToHash("VelocityRightNormalized");

View File

@@ -1,6 +1,8 @@
using System;
using R3;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Main;
using RebootReality.jelycho.Player.HUD;
using Unity.Mathematics;
using Unity.Netcode;
using UnityEngine;
@@ -15,6 +17,10 @@ namespace RebootReality.jelycho.Player {
[SerializeField] Config m_Config;
PlayerActor m_Actor;
PlayerHUD m_HUD;
DisposableBag m_OwnerActorDisposableBag = new DisposableBag();
IDisposable m_TargetInteractableLabelDisposable;
public override void OnNetworkSpawn() {
base.OnNetworkSpawn();
@@ -22,6 +28,8 @@ namespace RebootReality.jelycho.Player {
if (IsOwner) {
RR.Input.LockCursor();
RR.Input.EnableControls();
m_HUD = Instantiate(m_Config.playerHUDPrefab);
}
}
@@ -31,6 +39,13 @@ namespace RebootReality.jelycho.Player {
if (IsOwner) {
RR.Input.UnlockCursor();
RR.Input.DisableControls();
if (m_HUD != null) {
Destroy(m_HUD.gameObject);
m_HUD = null;
}
m_OwnerActorDisposableBag.Dispose();
}
}
@@ -54,10 +69,31 @@ namespace RebootReality.jelycho.Player {
m_Actor.WarpToServerRpc(worldContext.PlayerSpawnPoint.position);
}
}
if (IsOwner) {
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) {
m_TargetInteractableLabelDisposable =
m_HUD.ObjectsLabels.CreateLabel(mb.transform, mb.name);
}
})
.AddTo(ref m_OwnerActorDisposableBag);
m_HUD.SetPlayerActor(m_Actor);
}
}
[ClientRpc]
public void SetNullActorClientRpc() {
m_OwnerActorDisposableBag.Dispose();
m_OwnerActorDisposableBag = new DisposableBag();
m_Actor = null;
}
@@ -97,14 +133,31 @@ namespace RebootReality.jelycho.Player {
if (m_Config.secondaryActionReference.action.WasReleasedThisFrame()) {
m_Actor.SecondaryAction();
}
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);
}
}
float slotChangeAxis = m_Config.inventorySlotChangeActionReference.action.ReadValue<float>();
if (math.abs(slotChangeAxis) > 0.5f) {
if (slotChangeAxis > 0) {
m_Actor.SelectNextItemSlot();
} else {
m_Actor.SelectPreviousItemSlot();
}
}
}
[Serializable]
public class Config {
public PlayerHUD playerHUDPrefab;
public InputActionReference moveActionReference;
public InputActionReference lookActionReference;
public InputActionReference jumpActionReference;
@@ -113,6 +166,9 @@ namespace RebootReality.jelycho.Player {
public InputActionReference primaryActionReference;
public InputActionReference secondaryActionReference;
public InputActionReference interactActionReference;
public InputActionReference[] inventorySlotSelectActionReferences;
public InputActionReference inventorySlotChangeActionReference;
}
}