371 lines
No EOL
15 KiB
C#
371 lines
No EOL
15 KiB
C#
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Cinemachine;
|
|
using MessagePack;
|
|
using TMPro;
|
|
using UniRx;
|
|
using UnityEngine;
|
|
using Unity.Mathematics;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.UI;
|
|
using static Unity.Mathematics.math;
|
|
using float2 = Unity.Mathematics.float2;
|
|
|
|
public class ActionGameManager : MonoBehaviour
|
|
{
|
|
public GameSettings Settings;
|
|
public SectorRenderer SectorRenderer;
|
|
// public MapView MapView;
|
|
public CinemachineVirtualCamera DockCamera;
|
|
public CinemachineVirtualCamera FollowCamera;
|
|
public GameObject GameplayUI;
|
|
public MenuPanel Menu;
|
|
public MapRenderer MenuMap;
|
|
public InventoryMenu Inventory;
|
|
public InventoryPanel ShipPanel;
|
|
public ConfirmationDialog ConfirmationDialog;
|
|
public float2 Sensitivity;
|
|
|
|
//public PlayerInput Input;
|
|
|
|
// private CinemachineFramingTransposer _transposer;
|
|
// private CinemachineComposer _composer;
|
|
private DirectoryInfo _filePath;
|
|
private bool _editMode;
|
|
private float _time;
|
|
private AetheriaInput _input;
|
|
private int _zoomLevelIndex;
|
|
private Ship _currentShip;
|
|
private ShipInput _shipInput;
|
|
private float2 _shipYawPitch;
|
|
private float3 _viewDirection;
|
|
private Transform _lookAt;
|
|
public List<Ship> PlayerShips { get; } = new List<Ship>();
|
|
|
|
public DatabaseCache ItemData { get; private set; }
|
|
public ItemManager ItemManager { get; private set; }
|
|
public Zone Zone { get; private set; }
|
|
|
|
|
|
void Start()
|
|
{
|
|
// _transposer = DockCamera.GetCinemachineComponent<CinemachineFramingTransposer>();
|
|
// _composer = DockCamera.GetCinemachineComponent<CinemachineComposer>();
|
|
_lookAt = new GameObject().transform;
|
|
|
|
ConsoleController.MessageReceiver = this;
|
|
_filePath = new DirectoryInfo(Application.dataPath).Parent.CreateSubdirectory("GameData");
|
|
ItemData = new DatabaseCache();
|
|
ItemData.Load(_filePath.FullName);
|
|
ItemManager = new ItemManager(ItemData, Settings.GameplaySettings, Debug.Log);
|
|
|
|
var zoneFile = Path.Combine(_filePath.FullName, "Home.zone");
|
|
|
|
// If the game has already been run, there will be a Home file containing a ZonePack; if not, generate one
|
|
var zonePack = File.Exists(zoneFile) ?
|
|
MessagePackSerializer.Deserialize<ZonePack>(File.ReadAllBytes(zoneFile)):
|
|
ZoneGenerator.GenerateZone(
|
|
settings: Settings.ZoneSettings,
|
|
// mapLayers: Context.MapLayers,
|
|
// resources: Context.Resources,
|
|
mass: Settings.DefaultZoneMass,
|
|
radius: Settings.DefaultZoneRadius
|
|
);
|
|
|
|
Zone = new Zone(Settings.PlanetSettings, zonePack);
|
|
SectorRenderer.ItemManager = ItemManager;
|
|
SectorRenderer.LoadZone(Zone);
|
|
|
|
_input = new AetheriaInput();
|
|
_input.Player.Enable();
|
|
_input.Global.Enable();
|
|
_input.UI.Enable();
|
|
|
|
_zoomLevelIndex = Settings.DefaultMinimapZoom;
|
|
_input.Player.MinimapZoom.performed += context =>
|
|
{
|
|
_zoomLevelIndex = (_zoomLevelIndex + 1) % Settings.MinimapZoomLevels.Length;
|
|
SectorRenderer.MinimapDistance = Settings.MinimapZoomLevels[_zoomLevelIndex];
|
|
};
|
|
|
|
_input.Global.MapToggle.performed += context =>
|
|
{
|
|
if (Menu.gameObject.activeSelf && Menu.CurrentTab == MenuTab.Map)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
_input.Player.Enable();
|
|
Menu.gameObject.SetActive(false);
|
|
GameplayUI.SetActive(true);
|
|
return;
|
|
}
|
|
|
|
Cursor.lockState = CursorLockMode.None;
|
|
_input.Player.Disable();
|
|
GameplayUI.SetActive(false);
|
|
Menu.ShowTab(MenuTab.Map);
|
|
MenuMap.Position = _currentShip.Position;
|
|
};
|
|
|
|
_input.Global.Inventory.performed += context =>
|
|
{
|
|
if (Menu.gameObject.activeSelf && Menu.CurrentTab == MenuTab.Inventory)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
_input.Player.Enable();
|
|
Menu.gameObject.SetActive(false);
|
|
GameplayUI.SetActive(true);
|
|
return;
|
|
}
|
|
|
|
Cursor.lockState = CursorLockMode.None;
|
|
_input.Player.Disable();
|
|
Menu.ShowTab(MenuTab.Inventory);
|
|
GameplayUI.SetActive(false);
|
|
var cargo = _currentShip.CargoBays.FirstOrDefault();
|
|
if (cargo != null)
|
|
{
|
|
Inventory.GetPanel.Display(cargo);
|
|
}
|
|
else Inventory.GetPanel.Clear();
|
|
Inventory.GetPanel.Display(_currentShip);
|
|
};
|
|
|
|
_input.Global.Dock.performed += context =>
|
|
{
|
|
if (_currentShip.Parent == null) Dock();
|
|
else Undock();
|
|
};
|
|
|
|
// ConsoleController.AddCommand("editmode", _ => ToggleEditMode());
|
|
ConsoleController.AddCommand("savezone", args =>
|
|
{
|
|
if (args.Length > 0)
|
|
Zone.Data.Name = args[0];
|
|
SaveZone();
|
|
});
|
|
|
|
var stationType = ItemData.GetAll<HullData>().First(x=>x.HullType==HullType.Station);
|
|
var stationHull = ItemManager.CreateInstance(stationType, 0, 1) as EquippableItem;
|
|
var stationParent = Zone.PlanetInstances.Values.OrderByDescending(p => p.BodyData.Mass.Value).ElementAt(3);
|
|
var parentOrbit = stationParent.Orbit.Data.ID;
|
|
var parentPos = Zone.GetOrbitPosition(parentOrbit);
|
|
var stationPos = parentPos + ItemManager.Random.NextFloat2Direction() * stationParent.GravityWellRadius.Value * .1f;
|
|
var stationOrbit = Zone.CreateOrbit(parentOrbit, stationPos);
|
|
var station = new OrbitalEntity(ItemManager, Zone, stationHull, stationOrbit.ID);
|
|
Zone.Entities.Add(station);
|
|
var dockingBayData = ItemData.GetAll<DockingBayData>().First();
|
|
var dockingBay = ItemManager.CreateInstance(dockingBayData, 1, 1) as EquippableItem;
|
|
station.TryEquip(dockingBay);
|
|
station.Active = true;
|
|
|
|
var hullType = ItemData.GetAll<HullData>().First(x=>x.HullType==HullType.Ship);
|
|
var shipHull = ItemManager.CreateInstance(hullType, 0, 1) as EquippableItem;
|
|
var ship = new Ship(ItemManager, Zone, shipHull);
|
|
PlayerShips.Add(ship);
|
|
_currentShip = ship;
|
|
|
|
var thrusterData = ItemData.GetAll<GearData>().First(x => x.HardpointType == HardpointType.Thruster && x.Shape.Height == 1);
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
ship.TryEquip(ItemManager.CreateInstance(thrusterData, .5f, 1) as EquippableItem);
|
|
//dockingCargo.TryStore(ItemManager.CreateInstance(thrusterData, .5f, 1));
|
|
}
|
|
|
|
var reactorData = ItemData.GetAll<GearData>().First(x => x.HardpointType == HardpointType.Reactor && x.Shape.Height == 2);
|
|
ship.TryEquip(ItemManager.CreateInstance(reactorData, .5f, 1) as EquippableItem);
|
|
|
|
var cockpitData = ItemData.GetAll<GearData>().First(x => x.Behaviors.Any(b=>b is CockpitData));
|
|
ship.TryEquip(ItemManager.CreateInstance(cockpitData, .5f, 1) as EquippableItem);
|
|
//dockingCargo.TryStore(ItemManager.CreateInstance(reactorData, .5f, 1));
|
|
|
|
Dock();
|
|
|
|
// MapButton.onClick.AddListener(() =>
|
|
// {
|
|
// if (_currentMenuTabButton == MapPanel) return;
|
|
//
|
|
// _currentMenuTabButton.GetComponent<TextMeshProUGUI>().color = Color.white;
|
|
// _currentMenuTabButton = MapButton;
|
|
// });
|
|
//
|
|
//InventoryPanel.Display(ItemManager, entity);
|
|
}
|
|
|
|
public void Dock()
|
|
{
|
|
if (_currentShip.Parent != null) return;
|
|
foreach (var entity in Zone.Entities.ToArray())
|
|
{
|
|
if (lengthsq(entity.Position - _currentShip.Position) <
|
|
Settings.GameplaySettings.DockingDistance * Settings.GameplaySettings.DockingDistance)
|
|
{
|
|
var bay = entity.TryDock(_currentShip);
|
|
if (bay != null)
|
|
{
|
|
DockCamera.enabled = true;
|
|
FollowCamera.enabled = false;
|
|
_currentShip.Active = false;
|
|
var orbital = (OrbitalEntity) entity;
|
|
DockCamera.Follow = SectorRenderer.Orbitals[orbital];
|
|
var parentOrbit = Zone.Orbits[orbital.OrbitData].Data.Parent;
|
|
var parentPlanet = SectorRenderer.Planets[Zone.Planets.FirstOrDefault(p => p.Value.Orbit == parentOrbit).Key];
|
|
DockCamera.LookAt = parentPlanet.Body.transform;
|
|
Menu.ShowTab(MenuTab.Inventory);
|
|
Inventory.GetPanel.Display(bay);
|
|
Inventory.GetPanel.Display(_currentShip);
|
|
_shipInput = null;
|
|
Cursor.lockState = CursorLockMode.None;
|
|
_input.Player.Disable();
|
|
GameplayUI.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Undock()
|
|
{
|
|
if (_currentShip.Parent == null) return;
|
|
if (_currentShip.GetBehavior<Cockpit>() == null)
|
|
{
|
|
ConfirmationDialog.Title.text = "Can't undock. Missing cockpit component!";
|
|
ConfirmationDialog.Show();
|
|
}
|
|
else if (_currentShip.GetBehavior<Thruster>() == null)
|
|
{
|
|
ConfirmationDialog.Title.text = "Can't undock. Missing thruster component!";
|
|
ConfirmationDialog.Show();
|
|
}
|
|
else if (_currentShip.GetBehavior<Reactor>() == null)
|
|
{
|
|
ConfirmationDialog.Title.text = "Can't undock. Missing reactor component!";
|
|
ConfirmationDialog.Show();
|
|
}
|
|
else if (_currentShip.Parent.TryUndock(_currentShip))
|
|
{
|
|
Menu.gameObject.SetActive(false);
|
|
_currentShip.Active = true;
|
|
_shipInput = new ShipInput(_input.Player, _currentShip);
|
|
DockCamera.enabled = false;
|
|
FollowCamera.enabled = true;
|
|
FollowCamera.LookAt = _lookAt;
|
|
FollowCamera.Follow = SectorRenderer.Ships[_currentShip].Transform;
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
GameplayUI.SetActive(true);
|
|
_input.Player.Enable();
|
|
ShipPanel.Display(_currentShip);
|
|
}
|
|
else
|
|
{
|
|
ConfirmationDialog.Title.text = "Can't undock. Must empty docking bay!";
|
|
ConfirmationDialog.Show();
|
|
}
|
|
}
|
|
|
|
public void SaveZone() => File.WriteAllBytes(
|
|
Path.Combine(_filePath.FullName, $"{Zone.Data.Name}.zone"), MessagePackSerializer.Serialize(Zone.Pack()));
|
|
|
|
// public void ToggleEditMode()
|
|
// {
|
|
// _editMode = !_editMode;
|
|
// FollowCamera.gameObject.SetActive(!_editMode);
|
|
// TopDownCamera.gameObject.SetActive(_editMode);
|
|
// }
|
|
|
|
public IEnumerable<EquippedCargoBay> AvailableCargoBays()
|
|
{
|
|
if (_currentShip.Parent != null)
|
|
{
|
|
foreach (var bay in _currentShip.Parent.DockingBays)
|
|
{
|
|
if (PlayerShips.Contains(bay.DockedShip)) yield return bay;
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<Ship> AvailableShips()
|
|
{
|
|
if (_currentShip.Parent != null)
|
|
{
|
|
foreach (var ship in PlayerShips)
|
|
{
|
|
if (_currentShip.Parent.Children.Contains(ship)) yield return ship;
|
|
}
|
|
}
|
|
else
|
|
yield return _currentShip;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if(!_editMode)
|
|
{
|
|
_time += Time.deltaTime;
|
|
ItemManager.Time = Time.time;
|
|
if(_shipInput!=null)
|
|
{
|
|
var look = _input.Player.Look.ReadValue<Vector2>();
|
|
_shipYawPitch = float2(_shipYawPitch.x + look.x * Sensitivity.x, clamp(_shipYawPitch.y + look.y * Sensitivity.y, -.45f * PI, .45f * PI));
|
|
_viewDirection = mul(float3(0, 0, 1), Unity.Mathematics.float3x3.Euler(float3(_shipYawPitch.yx, 0), RotationOrder.YXZ));
|
|
_lookAt.position = SectorRenderer.Ships[_currentShip].Transform.position + (Vector3) _viewDirection * 100;
|
|
_shipInput.DesiredOrientation = _viewDirection.xz;
|
|
_shipInput.Update();
|
|
}
|
|
}
|
|
Zone.Update(_time, Time.deltaTime);
|
|
SectorRenderer.Time = _time;
|
|
}
|
|
}
|
|
|
|
public class ShipInput
|
|
{
|
|
private AetheriaInput.PlayerActions _input;
|
|
private Ship _ship;
|
|
private Thruster[] _allThrusters;
|
|
private Thruster[] _forwardThrusters;
|
|
private Thruster[] _reverseThrusters;
|
|
private Thruster[] _rightThrusters;
|
|
private Thruster[] _leftThrusters;
|
|
private Thruster[] _clockwiseThrusters;
|
|
private Thruster[] _counterClockwiseThrusters;
|
|
|
|
public float2 DesiredOrientation { get; set; }
|
|
public float DesiredPitch { get; set; }
|
|
|
|
public ShipInput(AetheriaInput.PlayerActions input, Ship ship)
|
|
{
|
|
_input = input;
|
|
_ship = ship;
|
|
_allThrusters = ship.GetBehaviors<Thruster>().ToArray();
|
|
_forwardThrusters = _allThrusters.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.Reversed).ToArray();
|
|
_reverseThrusters = _allThrusters.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.None).ToArray();
|
|
_rightThrusters = _allThrusters.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.CounterClockwise).ToArray();
|
|
_leftThrusters = _allThrusters.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.Clockwise).ToArray();
|
|
_counterClockwiseThrusters = _allThrusters.Where(x => x.Torque < -.05f).ToArray();
|
|
_clockwiseThrusters = _allThrusters.Where(x => x.Torque > .05f).ToArray();
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
var move = _input.Move.ReadValue<Vector2>();
|
|
|
|
foreach (var thruster in _allThrusters) thruster.Axis = 0;
|
|
foreach (var thruster in _rightThrusters) thruster.Axis += move.x;
|
|
foreach (var thruster in _leftThrusters) thruster.Axis += -move.x;
|
|
foreach (var thruster in _forwardThrusters) thruster.Axis += move.y;
|
|
foreach (var thruster in _reverseThrusters) thruster.Axis += -move.y;
|
|
|
|
var deltaRot = dot(normalize(DesiredOrientation), normalize(_ship.Direction).Rotate(ItemRotation.Clockwise));
|
|
if (abs(deltaRot) < .01) deltaRot = 0;
|
|
deltaRot = pow(abs(deltaRot), .5f) * sign(deltaRot);
|
|
|
|
foreach (var thruster in _clockwiseThrusters) thruster.Axis += deltaRot;
|
|
foreach (var thruster in _counterClockwiseThrusters) thruster.Axis += -deltaRot;
|
|
}
|
|
} |