First commit on my server, yey!

This commit is contained in:
Sebastian Bularca
2026-03-19 18:12:07 +01:00
parent 5139ec2cec
commit fedd1961a0
602 changed files with 101587 additions and 6 deletions

View File

@@ -0,0 +1,12 @@
using Nox.Game.UI;
using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "GameModePrefabs", menuName = "Nox/AdventureMapPrefabs")]
public class AdventureModePrefabs: ScenePrefabs {
public GuiReferences guiReferencesPrefab;
public MapReference mapReferencePrefab;
public MapLocationsReference mapLocationsReferencePrefab;
public PartyReference partyReferencePrefab;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e7cce6bb84bb20741a560389ab887769

View File

@@ -0,0 +1,174 @@
using Jovian.SaveSystem;
using Jovian.ZoneSystem;
using Nox.Core;
using Nox.Platform;
using Nox.Game.UI;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using PlayMode = Nox.Core.PlayMode;
namespace Nox.Game {
public class AdventureData {
public bool isPartyMoving;
public int currentDay = 0;
public int suppliesAvailable = -1;
public float currentTime = -1f;
public DayPhase currentDayPhase = DayPhase.Morning;
}
public class AdventurePlayMode : IPlayMode {
private readonly PlatformSettings platformSettings;
private readonly PlayModeSettings bootstrapSettings;
private readonly GameDataState gameDataState;
private readonly ISaveSystem saveSystem;
private PartyData partyData;
private AdventureData adventureData;
private AdventureModePrefabs scenePrefabs;
private ICameraController cameraController;
private MapReference mapRef;
private PartyMovementHandler partyMovementHandler;
private PartyReference partyRef;
private MapLocationsReference mapLocationsReference;
private InputSystem_Actions inputActions;
private AdventureView adventureView;
private ZoneSystem zoneSystem;
private GuiReferences guiReferences;
private AdventureSettings adventureSettings;
private TimeHandler timeHandler;
private PartyInventoryHandler partyInventoryHandler;
public AdventurePlayMode(
PlatformSettings platformSettings,
PartyData partyData,
PlayModeSettings bootstrapSettings,
GameDataState gameDataState,
ISaveSystem saveSystem,
AdventureSettings adventureSettings,
AdventureData adventureData) {
this.platformSettings = platformSettings;
this.partyData = partyData;
this.bootstrapSettings = bootstrapSettings;
this.gameDataState = gameDataState;
this.saveSystem = saveSystem;
this.adventureSettings = adventureSettings;
this.adventureData = adventureData;
}
public bool IsGameModeInitialized { get; private set; }
public void EnterPlayMode() {
inputActions = platformSettings.inputSettings.inputActions;
if(IsGameModeInitialized) {
inputActions.Player.Enable();
inputActions.UI.PauseMenu.Enable();
partyMovementHandler.ConsumeNextClick();
return;
}
Addressables.LoadSceneAsync(bootstrapSettings.gameModeData.FirstOrDefault(g => g.playMode == PlayMode.Adventure)?.scene)
.WaitForCompletion().ActivateAsync().completed += InitializeGameMode;
}
private void InitializeGameMode(AsyncOperation obj) {
inputActions.Player.Enable();
inputActions.UI.PauseMenu.Enable();
Debug.Log("Entering Adventure Play Mode");
if(partyData == null) {
var sessions = saveSystem.GetAllSessions().OrderByDescending(s => s.lastSaveDateUtc).ToList();
if(sessions.Count == 0) {
return;
}
var latestSession = sessions[0];
var slots = saveSystem.GetSlots(latestSession.sessionId).OrderByDescending(s => s.timestampUtc).ToList();
if(slots.Count == 0) {
return;
}
var latestSlot = slots[0];
var saveData = saveSystem.Load<NoxSaveData>(latestSlot);
Debug.Log($"Loaded save {latestSlot.DisplayLabel}");
if(saveData == null) {
Debug.LogError("Failed to load save data");
return;
}
NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData);
Debug.LogWarning("AdventurePlayMode started from the Adventure Scene. Loading the last Autosave");
}
scenePrefabs ??= Addressables.LoadAssetAsync<AdventureModePrefabs>("AdventureMapPrefabs").WaitForCompletion();
mapRef ??= Object.FindFirstObjectByType<MapReference>();
partyRef ??= Object.FindFirstObjectByType<PartyReference>();
if(partyRef && gameDataState.savedPartyPosition.HasValue) {
partyRef.transform.position = gameDataState.savedPartyPosition.Value;
}
mapLocationsReference ??= Object.FindFirstObjectByType<MapLocationsReference>();
if(!mapRef) {
mapRef ??= Object.Instantiate(scenePrefabs.mapReferencePrefab);
}
cameraController ??= new CameraController(platformSettings, mapRef);
cameraController.Initialize();
if(adventureData.suppliesAvailable == -1) {
adventureData.suppliesAvailable = adventureSettings.maxSupplies;
}
if(Mathf.Approximately(adventureData.currentTime, -1f)) {
adventureData.currentTime = 0.25f;
}
partyInventoryHandler ??= new PartyInventoryHandler(adventureData, adventureSettings);
partyInventoryHandler.Initialize();
timeHandler ??= new TimeHandler(adventureSettings, adventureData);
zoneSystem ??= new ZoneSystem(mapRef.zonesObjectHolder);
partyMovementHandler ??= new PartyMovementHandler(partyRef, cameraController, mapLocationsReference, platformSettings.inputSettings, zoneSystem, adventureData, adventureSettings);
partyMovementHandler.Initialize();
guiReferences ??= Object.FindFirstObjectByType<GuiReferences>();
adventureView ??= new AdventureView(gameDataState, guiReferences, inputActions, adventureData, adventureSettings);
adventureView.Initialize();
IsGameModeInitialized = true;
}
public void Tick() {
if(!IsGameModeInitialized) {
return;
}
timeHandler.Tick();
partyInventoryHandler.Tick();
partyMovementHandler.Tick();
adventureView.Tick();
if(inputActions.UI.PauseMenu.WasPerformedThisFrame()) {
gameDataState.ChangePlayMode(PlayMode.PauseMenu);
}
}
public void LateTick() {
if(!IsGameModeInitialized) {
return;
}
cameraController.Tick();
}
public NoxSavedDataSet CaptureNoxSaveData() {
return new NoxSavedDataSet {
activePlayMode = PlayMode.Adventure,
partyData = partyData,
partyPosition = partyRef ? SerializableVector3.FromVector3(partyRef.transform.position) : SerializableVector3.Zero
};
}
public void ExitGameMode() {
inputActions.Player.Disable();
inputActions.UI.PauseMenu.Disable();
}
public void Dispose() {
cameraController.Dispose();
partyMovementHandler.Dispose();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eb1c247bb12a45a587e8ae7d013038d7
timeCreated: 1771156737

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "AdventureSettings", menuName = "Nox/AdventureSettings")]
public class AdventureSettings : ScriptableObject {
public int dayLength = 10;
public int maxSupplies = 20;
[Header("Party Data")]
public float partyBaseSpeed = 3f;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1d2424482c4843c0b7a33a9cc67411b2
timeCreated: 1771786400

View File

@@ -0,0 +1,31 @@
using Nox.Core;
using Nox.Platform;
using UnityEngine;
namespace Nox.Game {
public class CombatPlayMode : IPlayMode {
private readonly PlatformSettings platformSettings;
private readonly PartyData partyData;
public CombatPlayMode(PlatformSettings platformSettings, PartyData partyData) {
this.platformSettings = platformSettings;
this.partyData = partyData;
}
public bool IsGameModeInitialized { get; private set; }
public void EnterPlayMode() {
if(partyData == null) {
Debug.LogWarning("CombatPlayMode started without PartyData.");
}
Debug.Log("Entering Combat Play Mode");
IsGameModeInitialized = true;
}
public void Tick() { }
public void LateTick() { }
public void ExitGameMode() { }
public void Dispose() { }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 087dc559ae894cd8b9a9dee5c6e3b64c
timeCreated: 1772367690

View File

@@ -0,0 +1,10 @@
#nullable enable
namespace Nox.Game.UI {
public interface IMenuView {
void Initialize();
void Show();
void Hide();
void Tick();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e99c535c23cc449984dcd145f4c1bec8
timeCreated: 1772374016

View File

@@ -0,0 +1,10 @@
using TMPro;
using UnityEngine;
namespace Nox.Game {
public class MapLocation : MonoBehaviour {
public SpriteRenderer icon;
public SpriteRenderer highlight;
public TextMeshProUGUI nameText;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 436b68ae9b9d347469b78e52a5aa7b53

View File

@@ -0,0 +1,7 @@
using UnityEngine;
namespace Nox.Game {
public class MapLocationsReference : MonoBehaviour {
public NoxLocationInfo [] mapLocations;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bdd66cc132efc3640b46bf53dedcbcb4

View File

@@ -0,0 +1,9 @@
using Jovian.ZoneSystem;
using UnityEngine;
namespace Nox.Game {
public class MapReference : MonoBehaviour {
public GameObject mapPlane;
public ZonesObjectHolder zonesObjectHolder;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7c173f913efc6004faf5dd75e96b32fe

View File

@@ -0,0 +1,21 @@
using System;
using UnityEngine;
namespace Nox.Game {
public enum NoxMapLocations {
None,
City1,
City2,
Village1,
Village2,
Ruin1,
Ruin2
}
[Serializable]
public class NoxLocationInfo {
public NoxMapLocations locationId;
public MapLocation mapLocation;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 535e7fdf7ddb4c1f9edf7254c3bb0acd
timeCreated: 1771763769

View File

@@ -0,0 +1,25 @@
namespace Nox.Game {
public class PartyInventoryHandler {
private readonly AdventureData adventureData;
private readonly AdventureSettings adventureSettings;
private int currentDay;
public PartyInventoryHandler(AdventureData adventureData, AdventureSettings adventureSettings) {
this.adventureData = adventureData;
this.adventureSettings = adventureSettings;
}
public void Initialize() {
currentDay = adventureData.currentDay;
}
public void Tick() {
if(currentDay != adventureData.currentDay) {
currentDay = adventureData.currentDay;
if(adventureData.suppliesAvailable > 0) {
adventureData.suppliesAvailable--;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c4a1ab7b529042ca8bf42714b383f918
timeCreated: 1773614576

View File

@@ -0,0 +1,160 @@
using Jovian.ZoneSystem;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace Nox.Game {
public class PartyMovementHandler {
private readonly PartyReference partyReference;
private readonly ICameraController cameraController;
private readonly InputSystem_Actions inputActions;
private readonly MapLocationsReference mapLocationsReference;
private readonly ZoneSystem zoneSystem;
private readonly AdventureSettings adventureSettings;
private readonly float maxDistance = 100f;
private AdventureData adventureData;
private bool partyCanMove;
private Vector3 targetPosition;
private bool shouldHover;
private MapLocation currentSelectedPoi;
private string previousZoneId;
private bool hasClicked;
private bool skipNextClick;
public LayerMask clickToMoveMask = LayerMask.GetMask("Clickable");
public LayerMask hoverOverMask = LayerMask.GetMask("Hoverable");
public PartyMovementHandler(
PartyReference partyReference,
ICameraController cameraController,
MapLocationsReference mapLocationsReference,
Input.InputSettings inputSettings,
ZoneSystem zoneSystem,
AdventureData adventureData,
AdventureSettings adventureSettings) {
this.partyReference = partyReference;
this.cameraController = cameraController;
this.mapLocationsReference = mapLocationsReference;
this.zoneSystem = zoneSystem;
this.adventureData = adventureData;
this.adventureSettings = adventureSettings;
inputActions = inputSettings.inputActions;
}
public void Initialize() {
inputActions.Player.ClickOnMap.performed += OnClickOnMap;
}
public void ConsumeNextClick() {
skipNextClick = true;
}
private void OnClickOnMap(InputAction.CallbackContext obj) {
if(!obj.action.WasReleasedThisFrame()) {
return;
}
hasClicked = true;
}
private void HandleHoverableLocation(RaycastHit hitInfo) {
var go = hitInfo.collider.gameObject;
if(!go.transform.parent.TryGetComponent(out MapLocation mapLocation)) {
return;
}
currentSelectedPoi = mapLocation;
mapLocation.highlight.gameObject.SetActive(true);
}
private void HandleClickableLocation() {
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
if(!Physics.Raycast(ray, out var clickHit, maxDistance, clickToMoveMask, QueryTriggerInteraction.Ignore)) {
return;
}
if(!clickHit.collider.gameObject.transform.parent.TryGetComponent(out MapReference mapReference)) {
return;
}
//if(mapReference.ValidateMoveLocation(hitInfoPoint)) {
targetPosition = clickHit.point;
partyCanMove = true;
//}
}
public void Tick() {
HandleHover();
if(hasClicked) {
hasClicked = false;
// should it skip next click to avoid click-through from the pause menu?
if(skipNextClick) {
skipNextClick = false;
return;
}
if(EventSystem.current.IsPointerOverGameObject()) {
return;
}
HandleClickableLocation();
}
if(!partyCanMove) {
adventureData.isPartyMoving = false;
return;
}
if(Vector3.Distance(partyReference.transform.position, targetPosition) < 0.05f) {
partyReference.transform.position = targetPosition;
VerifyPointsOfInterest();
partyCanMove = false;
}
adventureData.isPartyMoving = true;
partyReference.transform.position = Vector3.MoveTowards(new Vector3(partyReference.transform.position.x, 0, partyReference.transform.position.z), targetPosition, Time.deltaTime * adventureSettings.partyBaseSpeed);
VerifyZones(partyReference.transform.position);
}
private void HandleHover() {
if(EventSystem.current.IsPointerOverGameObject()) {
return;
}
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
if(Physics.Raycast(ray, out var hoverHit, maxDistance, hoverOverMask, QueryTriggerInteraction.Ignore)) {
HandleHoverableLocation(hoverHit);
}
else {
currentSelectedPoi?.highlight.gameObject.SetActive(false);
currentSelectedPoi = null;
}
}
private void VerifyZones(Vector3 position) {
var zoneContext = zoneSystem.QueryZone(position);
var currentZoneId = zoneContext.resolvedZoneId;
if(currentZoneId != previousZoneId) {
if(!string.IsNullOrEmpty(currentZoneId)) {
Debug.Log($"Entered zone: {currentZoneId} (encounter: {zoneContext.encounterTableId}, safe: {zoneContext.isSafe})");
}
else if(!string.IsNullOrEmpty(previousZoneId)) {
Debug.Log($"Left zone: {previousZoneId}");
}
previousZoneId = currentZoneId;
}
}
private void VerifyPointsOfInterest() {
foreach(var location in mapLocationsReference.mapLocations) {
if(Vector3.Distance(location.mapLocation.transform.position, partyReference.transform.position) < 0.4f) {
Debug.Log($"Arrived at {location.locationId}");
break;
}
}
}
public void Dispose() {
inputActions.Player.ClickOnMap.performed -= OnClickOnMap;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d2f697207298f2242aa2a8d36ef6a9b4

View File

@@ -0,0 +1,47 @@
#nullable enable
using Nox.Core;
using Nox.Platform;
using Nox.Game.UI;
using UnityEngine;
namespace Nox.Game {
public class PauseMenuPlayMode : IPlayMode {
private readonly PlatformSettings platformSettings;
private readonly GameDataState gameDataState;
private PauseMenuReferences? pauseMenuReference;
private readonly IMenuView? pauseMenuView;
private readonly InputSystem_Actions inputActions;
public PauseMenuPlayMode(PlatformSettings platformSettings, GameDataState gameDataState, IMenuView pauseMenuView) {
this.platformSettings = platformSettings;
this.gameDataState = gameDataState;
this.pauseMenuView = pauseMenuView;
inputActions = platformSettings.inputSettings.inputActions;
inputActions.UI.Enable();
}
public bool IsGameModeInitialized { get; private set; }
public void EnterPlayMode() {
Debug.Log("Entering PauseMenu Play Mode");
pauseMenuView?.Initialize();
IsGameModeInitialized = true;
}
public void Tick() {
if(inputActions.UI.PauseMenu.WasPerformedThisFrame()) {
pauseMenuView?.Hide();
gameDataState.ChangePlayMode(gameDataState.PreviousPlayMode);
}
pauseMenuView?.Tick();
}
public void LateTick() { }
public void ExitGameMode() {
pauseMenuView?.Hide();
}
public void Dispose() {
inputActions.UI.Disable();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eab5b722cabf4ec7b79af55838d24ed4
timeCreated: 1772367657

View File

@@ -0,0 +1,31 @@
using Nox.Core;
using Nox.Platform;
using UnityEngine;
namespace Nox.Game {
public class RestPlayMode : IPlayMode {
private readonly PlatformSettings platformSettings;
private readonly PartyData partyData;
public RestPlayMode(PlatformSettings platformSettings, PartyData partyData) {
this.platformSettings = platformSettings;
this.partyData = partyData;
}
public bool IsGameModeInitialized { get; private set; }
public void EnterPlayMode() {
if(partyData == null) {
Debug.LogWarning("RestPlayMode started without PartyData.");
}
Debug.Log("Entering Rest Play Mode");
IsGameModeInitialized = true;
}
public void Tick() { }
public void LateTick() { }
public void ExitGameMode() { }
public void Dispose() { }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67cb7d9e318d474694bc0addab3e8511
timeCreated: 1772367678

View File

@@ -0,0 +1,58 @@
using UnityEngine;
namespace Nox.Game {
public enum DayPhase {
Midnight,
Dawn,
Morning,
Afternoon,
Dusk,
Night
}
public class TimeHandler {
private readonly AdventureSettings adventureSettings;
private readonly AdventureData adventureData;
private float localTime;
private static readonly (float start, DayPhase phase)[] PhaseThresholds = {
(0.00f, DayPhase.Midnight),
(0.05f, DayPhase.Night),
(0.17f, DayPhase.Dawn),
(0.25f, DayPhase.Morning),
(0.50f, DayPhase.Afternoon),
(0.75f, DayPhase.Dusk),
(0.90f, DayPhase.Night),
};
public TimeHandler(AdventureSettings adventureSettings, AdventureData adventureData) {
this.adventureSettings = adventureSettings;
this.adventureData = adventureData;
localTime = adventureData.currentTime * adventureSettings.dayLength;
}
public void Tick() {
if (!adventureData.isPartyMoving) return;
localTime += Time.deltaTime;
if (localTime >= adventureSettings.dayLength) {
localTime -= adventureSettings.dayLength;
adventureData.currentDay++;
}
adventureData.currentTime = localTime / adventureSettings.dayLength;
adventureData.currentDayPhase = GetPhase(adventureData.currentTime);
}
private static DayPhase GetPhase(float t) {
var phase = DayPhase.Midnight;
foreach (var (start, p) in PhaseThresholds) {
if (t >= start) phase = p;
else break;
}
return phase;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 071a61f838db8e640b460ce029a8d5a5

View File

@@ -0,0 +1,31 @@
using Nox.Core;
using Nox.Platform;
using UnityEngine;
namespace Nox.Game {
public class TownPlayMode : IPlayMode {
private readonly PlatformSettings platformSettings;
private readonly PartyData partyData;
public TownPlayMode(PlatformSettings platformSettings, PartyData partyData) {
this.platformSettings = platformSettings;
this.partyData = partyData;
}
public bool IsGameModeInitialized { get; private set; }
public void EnterPlayMode() {
if(partyData == null) {
Debug.LogWarning("TownPlayMode started without PartyData.");
}
Debug.Log("Entering Town Play Mode");
IsGameModeInitialized = true;
}
public void Tick() { }
public void LateTick() { }
public void ExitGameMode() { }
public void Dispose() { }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bd57598925a54bad93fe730e15023d94
timeCreated: 1772367666