C#:
using Facepunch;
using Network;
using Network.Visibility;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
[Info("HeliCommander", "k1lly0u", "0.3.4")]
[Description("Custom controllers and options for all types of helicopters")]
class HeliCommander : RustPlugin {
#region Fields
[PluginReference]
Plugin Clans, Friends, RandomSpawns, Spawns;
private RestoreData restoreData;
private Dictionary<ulong, double> userCooldowns = new Dictionary<ulong, double>();
private DynamicConfigFile restorationdata, cooldowns;
private List<BaseController> spawnedHelis = new List<BaseController>();
private List<BaseController> saveableHelis = new List<BaseController>();
private static Controls Control;
private static RaycastHit raycastHit;
private const string UH1Y_PREFAB = "assets/prefabs/npc/patrol helicopter/patrolhelicopter.prefab";
private const string CH47_PREFAB = "assets/prefabs/npc/ch47/ch47.entity.prefab";
private const string MINI_PREFAB = "assets/content/vehicles/minicopter/minicopter.entity.prefab";
private const string TRANS_PREFAB = "assets/content/vehicles/scrap heli carrier/scraptransporthelicopter.prefab";
private const string CHAIR_PREFAB = "assets/prefabs/vehicle/seats/passenger.prefab";
private const string FUEL_STORAGE = "assets/content/vehicles/minicopter/subents/fuel_storage.prefab";
private const string ROCKET_NORMAL_PREFAB = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
private const string ROCKET_NAPALM_PREFAB = "assets/prefabs/ammo/rocket/rocket_fire.prefab";
private const string ROCKET_HV_PREFAB = "assets/prefabs/ammo/rocket/rocket_hv.prefab";
private const string UI_HEALTH = "HCUI_Health";
private const string UI_AMMO_MG = "HCUI_Ammo_MG";
private const string UI_AMMO_ROCKET = "HCUI_Ammo_Rocket";
private const string UI_FUEL = "HCUI_Fuel";
private const string UI_AIM = "HCUI_Aim";
private const string USE_PERMISSION = "helicommander.use.";
private const string BUILD_PERMISSION = "helicommander.canbuild.";
private const string SPAWN_PERMISSION = "helicommander.canspawn.";
private const string COOLDOWN_PERMISSION = "helicommander.ignorecooldown.";
private const string PASSENGER_PERMISSION = "helicommander.passenger.";
private static GameObjectRef FUEL_STORAGE_REF;
#endregion
#region Oxide Hooks
private void Loaded() {
Unsubscribe(nameof(OnEntitySpawned));
foreach (HelicopterType type in Enum.GetValues(typeof(HelicopterType)) as HelicopterType[]) {
if (type == HelicopterType.Invalid) continue;
permission.RegisterPermission(string.Concat(BUILD_PERMISSION, type), this);
permission.RegisterPermission(string.Concat(SPAWN_PERMISSION, type), this);
permission.RegisterPermission(string.Concat(USE_PERMISSION, type), this);
permission.RegisterPermission(string.Concat(PASSENGER_PERMISSION, type), this);
permission.RegisterPermission(string.Concat(COOLDOWN_PERMISSION, type), this);
}
lang.RegisterMessages(Messages, this);
GetMessage = Message;
Control = new Controls();
}
private void OnServerInitialized() {
FUEL_STORAGE_REF = GameManager.server.FindPrefab("assets/content/vehicles/minicopter/minicopter.entity.prefab").GetComponent<MiniCopter>().fuelStoragePrefab;
LoadData();
if (Configuration.Mini.Convert || Configuration.Transport.Convert) Subscribe(nameof(OnEntitySpawned));
restoreData.RestoreVehicles(SpawnAtLocation);
timer.In(5, () => CheckForSpawns(HelicopterType.CH47));
timer.In(10, () => CheckForSpawns(HelicopterType.UH1Y));
timer.In(15, () => CheckForSpawns(HelicopterType.Mini));
timer.In(20, () => CheckForSpawns(HelicopterType.Transport));
}
private void OnEntitySpawned(MiniCopter miniCopter) {
if (miniCopter == null) return;
if ((miniCopter is ScrapTransportHelicopter && !Configuration.Transport.Convert) || !Configuration.Mini.Convert) return;
if (!miniCopter.GetComponent<BaseController>() && !restoreData.HasRestoreData(miniCopter.net.ID)) {
NextTick(() => {
if (miniCopter == null || miniCopter.GetComponent<BaseController>()) return;
MiniController controller = miniCopter is ScrapTransportHelicopter ? miniCopter.gameObject.AddComponent<TransportController>() : miniCopter.gameObject.AddComponent<MiniController>();
saveableHelis.Add(controller);
}
);
}
}
private void OnSamSiteTargetScan(SamSite samsite, List<SamSite.ISamSiteTarget> list) {
if (spawnedHelis.Count == 0 && saveableHelis.Count == 0) return;
for (int i = 0; i < spawnedHelis.Count; i++) {
BaseController baseController = spawnedHelis[i];
if (!(baseController is CH47Controller) && !(baseController is UH1YController)) continue;
if (Vector3.Distance(baseController.Transform.position, samsite.transform.position) < SamSite.targetTypeVehicle.scanRadius) list.Add(baseController as SamSite.ISamSiteTarget);
}
for (int i = 0; i < saveableHelis.Count; i++) {
BaseController baseController = saveableHelis[i];
if (!(baseController is CH47Controller) && !(baseController is UH1YController)) continue;
if (Vector3.Distance(baseController.Transform.position, samsite.transform.position) < SamSite.targetTypeVehicle.scanRadius) list.Add(baseController as SamSite.ISamSiteTarget);
}
}
private object CanConvertToPilotEject(BaseHelicopter baseHelicopter) => baseHelicopter != null && baseHelicopter.GetComponent<UH1YController>() != null ? (object)false : null;
private void OnEntityKill(BaseNetworkable baseNetworkable) {
BaseController baseController = baseNetworkable.GetComponent<BaseController>();
if (baseController != null) {
baseController.EjectAllPlayers();
spawnedHelis.Remove(baseController);
saveableHelis.Remove(baseController);
}
}
private void OnEntityTakeDamage(BaseCombatEntity baseCombatEntity, HitInfo hitInfo) {
if (baseCombatEntity == null || hitInfo == null) return;
BaseController baseController = baseCombatEntity.GetComponent<BaseController>();
if (baseController != null) {
baseController.ManageDamage(hitInfo);
return;
}
}
private void OnHammerHit(BasePlayer player, HitInfo hitInfo) {
if (player == null || hitInfo == null || hitInfo.HitEntity == null) return;
BaseController baseController = hitInfo.HitEntity.GetComponent<BaseController>();
if (baseController != null) baseController.TryRepair(player);
}
private void OnPlayerInput(BasePlayer player, InputState inputState) {
if (player == null) return;
if (Control.JustPressed(player, BUTTON.USE)) {
if (Physics.SphereCast(player.eyes.position, 0.5f, Quaternion.Euler(player.serverInput.current.aimAngles) * Vector3.forward, out raycastHit, 3f)) {
BaseController baseController = raycastHit.collider.GetComponentInParent<BaseController>();
if (baseController != null && baseController.Type == HelicopterType.UH1Y) {
if (!baseController.IsOccupant(player)) {
BaseVehicle.MountPointInfo mountPointInfo = baseController.GetIdealMountPoint(player);
if (mountPointInfo != null && CanMountHelicopter(baseController, mountPointInfo, player) == null) {
ForceMountPlayerTo(player, mountPointInfo.mountable, baseController);
}
}
}
}
return;
}
if (Control.JustPressed(player, Controls.Type.Inventory)) {
if (Physics.SphereCast(player.eyes.position, 0.5f, Quaternion.Euler(player.serverInput.current.aimAngles) * Vector3.forward, out raycastHit, 3f)) {
BaseController baseController = raycastHit.collider.GetComponentInParent<BaseController>();
if (baseController != null && baseController.Config.Inventory.Enabled && baseController.Commander == null && !baseController.IsOccupant(player)) {
baseController.OpenInventory(player);
}
}
return;
}
if (Control.JustPressed(player, Controls.Type.FuelTank)) {
if (Physics.SphereCast(player.eyes.position, 0.5f, Quaternion.Euler(player.serverInput.current.aimAngles) * Vector3.forward, out raycastHit, 3f)) {
BaseController baseController = raycastHit.collider.GetComponentInParent<BaseController>();
if (baseController != null && baseController.ConsumeFuel && baseController.Commander == null && !baseController.IsOccupant(player)) {
if ((int)baseController.Type < 3) {
baseController.OpenFuel(player);
}
}
}
return;
}
}
private void OnServerSave() {
restoreData.Clear();
for (int i = saveableHelis.Count - 1; i >= 0; i--) {
BaseController controller = saveableHelis[i];
BaseCombatEntity baseCombatEntity = controller.GetEntity();
if (controller == null || baseCombatEntity == null || !baseCombatEntity.IsValid() || baseCombatEntity.IsDestroyed) {
saveableHelis.RemoveAt(i);
continue;
}
restoreData.AddData(controller);
}
SaveData();
}
private void Unload() {
BaseController[] baseControllers = UnityEngine.Object.FindObjectsOfType<BaseController>();
if (baseControllers != null) {
foreach (BaseController baseController in baseControllers) {
BaseCombatEntity baseCombatEntity = baseController.GetEntity();
UnityEngine.Object.DestroyImmediate(baseController);
if (baseCombatEntity != null && !baseCombatEntity.IsDestroyed) baseCombatEntity.Kill(BaseNetworkable.DestroyMode.None);
}
}
foreach (BasePlayer player in BasePlayer.activePlayerList) DestroyAllUI(player);
Configuration = null;
}
private object CanMountHelicopter(BaseController baseController, BaseVehicle.MountPointInfo mountPointInfo, BasePlayer player) {
if (baseController != null) {
if (player.isMounted) return false;
if (baseController.MountLocked) return false;
if (baseController.IsDying) return false;
bool canPilot = permission.UserHasPermission(player.UserIDString, string.Concat(USE_PERMISSION, baseController.Type));
bool canPassenger = permission.UserHasPermission(player.UserIDString, string.Concat(PASSENGER_PERMISSION, baseController.Type));
if (!canPilot && !canPassenger) {
SendReply(player, Message("nopermission", player.userID));
return false;
}
if (mountPointInfo != null) {
if (mountPointInfo.isDriver) {
if (!canPilot) {
SendReply(player, Message("noflypermission", player.userID));
return false;
}
return null;
}
else {
if (baseController.Config.Passengers.Enabled) {
if (baseController.Commander == null) return null;
else {
if (!baseController.Config.Passengers.UseFriends && !baseController.Config.Passengers.UseClans) return null;
if (IsFriendlyPlayer(baseController.Commander.userID, player.userID, baseController.Type)) return null;
SendReply(player, Message("not_friend", player.userID));
return false;
}
}
else {
SendReply(player, Message("passenger_not_enabled", player.userID));
return false;
}
}
}
}
return null;
}
private object CanMountEntity(BasePlayer player, BaseMountable baseMountable) {
BaseController baseController = baseMountable.GetParentEntity()?.GetComponent<BaseController>();
if (baseController != null && !baseController.IsOccupant(player)) {
BaseVehicle.MountPointInfo mountPointInfo = baseController.FindMountPointOf(baseMountable);
if (mountPointInfo != null) return CanMountHelicopter(baseController, mountPointInfo, player);
}
return null;
}
private void OnPlayerDismountFailed(BasePlayer player, BaseMountable baseMountable) {
BaseEntity parentEntity = baseMountable.GetParentEntity();
if (parentEntity != null && !parentEntity.IsDestroyed) {
BaseController baseController = parentEntity.GetComponentInParent<BaseController>();
if (baseController != null) {
if (baseController.MountLocked) return;
if (baseController.Type == HelicopterType.UH1Y) ForceDismountPlayerFrom(player, baseMountable, baseController);
}
}
}
private object CanDismountEntity(BasePlayer player, BaseMountable baseMountable) {
BaseEntity parentEntity = baseMountable.GetParentEntity();
if (parentEntity != null && !parentEntity.IsDestroyed) {
BaseController baseController = parentEntity.GetComponentInParent<BaseController>();
if (baseController != null) {
if (baseController.MountLocked) return false;
if (baseController.Type == HelicopterType.UH1Y) {
ForceDismountPlayerFrom(player, baseMountable, baseController);
return false;
}
}
}
return null;
}
private void OnEntityMounted(BaseMountable baseMountable, BasePlayer player) {
BaseEntity parentEntity = baseMountable.GetParentEntity();
if (parentEntity != null && !parentEntity.IsDestroyed) {
BaseController baseController = parentEntity.GetComponentInParent<BaseController>();
if (baseController != null) {
baseController.OnPlayerMounted(baseMountable, player);
}
}
}
private void OnEntityDismounted(BaseMountable baseMountable, BasePlayer player) {
BaseEntity parentEntity = baseMountable.GetParentEntity();
if (parentEntity != null && !parentEntity.IsDestroyed) {
BaseController baseController = parentEntity.GetComponentInParent<BaseController>();
if (baseController != null) {
baseController.OnPlayerDismounted(baseMountable, player);
DestroyAllUI(player);
}
}
}
#endregion
#region Functions
private static T ParseType<T>(string type) {
try {
T value = (T)Enum.Parse(typeof(T), type, true);
if (Enum.IsDefined(typeof(T), value)) return value;
}
catch {
if (typeof(T) == typeof(BUTTON)) Debug.LogError($"INVALID CONFIG OPTION DETECTED! The value \"{type}\" is an incorrect selection.\nAvailable options are: {Enum.GetNames(typeof(T)).ToSentence()}");
return default(T);
}
return default(T);
}
private class Controls {
private Hash<Type, BUTTON> _controls = new Hash<Type, BUTTON>();
public Controls() {
_controls[Type.Lights] = ParseType<BUTTON>(Configuration.Buttons.Lights);
_controls[Type.Inventory] = ParseType<BUTTON>(Configuration.Buttons.Inventory);
_controls[Type.MG] = ParseType<BUTTON>(Configuration.Buttons.MG);
_controls[Type.Rockets] = ParseType<BUTTON>(Configuration.Buttons.Rockets);
_controls[Type.PitchF] = ParseType<BUTTON>(Configuration.Buttons.PitchForward);
_controls[Type.PitchB] = ParseType<BUTTON>(Configuration.Buttons.PitchBackward);
_controls[Type.RollL] = ParseType<BUTTON>(Configuration.Buttons.RollLeft);
_controls[Type.RollR] = ParseType<BUTTON>(Configuration.Buttons.RollRight);
_controls[Type.ThrottleUp] = ParseType<BUTTON>(Configuration.Buttons.ThrottleUp);
_controls[Type.ThrottleDown] = ParseType<BUTTON>(Configuration.Buttons.ThrottleDown);
_controls[Type.FuelTank] = ParseType<BUTTON>(Configuration.Buttons.FuelTank);
_controls[Type.LockYaw] = ParseType<BUTTON>(Configuration.Buttons.LockYaw);
}
public bool IsDown(BasePlayer player, Type commandType) {
BUTTON button = _controls[commandType];
return player.serverInput.WasJustPressed(button) || player.serverInput.IsDown(button);
}
public bool IsDown(BasePlayer player, BUTTON button) {
return player.serverInput.WasJustPressed(button) || player.serverInput.IsDown(button);
}
public bool JustPressed(BasePlayer player, Type commandType) {
return player.serverInput.WasJustPressed(_controls[commandType]);
}
public bool JustPressed(BasePlayer player, BUTTON button) {
return player.serverInput.WasJustPressed(button);
}
public BUTTON GetButtonOf(Type type) => _controls[type];
public enum Type {
Lights, Inventory, MG, Rockets, RollL, RollR, PitchF, PitchB, ThrottleUp, ThrottleDown, LockYaw, FuelTank
}
}
private void CheckForSpawns(HelicopterType type) {
ConfigData.BaseHelicopter config = type == HelicopterType.CH47 ? Configuration.CH47 : type == HelicopterType.Transport ? Configuration.Transport as ConfigData.BaseHelicopter : type == HelicopterType.Mini ? Configuration.Mini as ConfigData.BaseHelicopter : Configuration.UH1Y;
if (config.Spawnable.Enabled) {
if ((spawnedHelis.Count + saveableHelis.Count) < config.Spawnable.Max) {
object position = null;
if (config.Spawnable.RandomSpawns) {
if (!RandomSpawns) {
PrintError("RandomSpawns can not be found! Unable to autospawn helicopters");
return;
}
object success = RandomSpawns.Call("GetSpawnPoint");
if (success != null) position = (Vector3)success;
else PrintError("Unable to find a valid spawnpoint from RandomSpawns");
}
else {
if (string.IsNullOrEmpty(config.Spawnable.Spawnfile)) return;
if (!Spawns) {
PrintError("Spawns Database can not be found! Unable to autospawn helicopters");
return;
}
object success = Spawns.Call("GetSpawnsCount", config.Spawnable.Spawnfile);
if (success is string) {
PrintError($"An invalid {type} spawnfile has been set in the config.Unable to autospawn helicopters : " + (string)success);
return;
}
success = Spawns.Call("GetRandomSpawn", config.Spawnable.Spawnfile);
if (success is string) {
PrintError((string)success);
return;
}
else position = (Vector3)success;
}
if (position != null) {
int count = 0;
switch (type) {
case HelicopterType.UH1Y : {
List<BaseHelicopter> entities = Facepunch.Pool.GetList<BaseHelicopter>();
Vis.Entities((Vector3)position, 5f, entities);
count = entities.Count;
Facepunch.Pool.FreeList(ref entities);
if (count > 0) {
timer.In(10, () => CheckForSpawns(type));
return;
}
else SpawnAtLocation((Vector3)position, Quaternion.identity, type, config.Spawnable.Save);
}
break;
case HelicopterType.CH47 : {
List<CH47Helicopter> entities = Facepunch.Pool.GetList<CH47Helicopter>();
Vis.Entities((Vector3)position, 5f, entities);
count = entities.Count;
Facepunch.Pool.FreeList(ref entities);
if (count > 0) {
timer.In(10, () => CheckForSpawns(type));
return;
}
else SpawnAtLocation((Vector3)position, Quaternion.identity, type, config.Spawnable.Save);
}
break;
case HelicopterType.Transport : case HelicopterType.Mini : {
List<MiniCopter> entities = Facepunch.Pool.GetList<MiniCopter>();
Vis.Entities((Vector3)position, 5f, entities);
count = entities.Count;
Facepunch.Pool.FreeList(ref entities);
if (count > 0) {
timer.In(10, () => CheckForSpawns(type));
return;
}
else SpawnAtLocation((Vector3)position, Quaternion.identity, type, config.Spawnable.Save);
}
break;
}
}
}
timer.In(config.Spawnable.Time, () => CheckForSpawns(type));
}
}
private double GrabCurrentTime() => DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
private string FormatTime(double time) {
TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
var days = dateDifference.Days;
var hours = dateDifference.Hours;
hours += (days * 24);
var mins = dateDifference.Minutes;
var secs = dateDifference.Seconds;
return string.Format("{0:00}:{1:00}:{2:00}", hours, mins, secs);
}
private string GetPrefabPath(HelicopterType type) {
switch (type) {
case HelicopterType.UH1Y : return UH1Y_PREFAB;
case HelicopterType.CH47 : return CH47_PREFAB;
case HelicopterType.Mini : return MINI_PREFAB;
case HelicopterType.Transport : return TRANS_PREFAB;
case HelicopterType.Invalid : default : return string.Empty;
}
}
private int GetCooldown(HelicopterType type) {
switch (type) {
case HelicopterType.UH1Y : return Configuration.UH1Y.Spawnable.Cooldown;
case HelicopterType.CH47 : return Configuration.CH47.Spawnable.Cooldown;
case HelicopterType.Mini : return Configuration.Mini.Spawnable.Cooldown;
case HelicopterType.Transport : return Configuration.Transport.Spawnable.Cooldown;
case HelicopterType.Invalid : default : return 0;
}
}
private List<ConfigData.BaseHelicopter.BuildOptions.BuildOption> GetBuildCosts(HelicopterType type) {
switch (type) {
case HelicopterType.UH1Y : return Configuration.UH1Y.Build.Costs;
case HelicopterType.CH47 : return Configuration.CH47.Build.Costs;
case HelicopterType.Mini : return Configuration.Mini.Build.Costs;
case HelicopterType.Transport : return Configuration.Transport.Build.Costs;
case HelicopterType.Invalid : default : return new List<ConfigData.BaseHelicopter.BuildOptions.BuildOption>();
}
}
private bool HasBuildCooldown(HelicopterType type) {
switch (type) {
case HelicopterType.UH1Y : return Configuration.UH1Y.Build.Cooldown;
case HelicopterType.CH47 : return Configuration.CH47.Build.Cooldown;
case HelicopterType.Mini : return Configuration.Mini.Build.Cooldown;
case HelicopterType.Transport : return Configuration.Transport.Build.Cooldown;
case HelicopterType.Invalid : default : return true;
}
}
private static BaseMountable SpawnMountPoint(BaseVehicle.MountPointInfo mountToSpawn, Model model, BaseCombatEntity parent) {
Vector3 localForward = Quaternion.Euler(mountToSpawn.rot) * Vector3.forward;
Vector3 position = mountToSpawn.pos;
Vector3 localUp = Vector3.up;
if (!string.IsNullOrEmpty(mountToSpawn.bone)) {
position = model.FindBone(mountToSpawn.bone).transform.position + parent.transform.TransformDirection(mountToSpawn.pos);
localForward = parent.transform.TransformDirection(localForward);
localUp = parent.transform.up;
}
BaseMountable baseMountable = GameManager.server.CreateEntity(CHAIR_PREFAB, position, Quaternion.LookRotation(localForward, localUp), true) as BaseMountable;
if (baseMountable != null) {
if (string.IsNullOrEmpty(mountToSpawn.bone)) baseMountable.SetParent(parent, false, false);
else baseMountable.SetParent(parent, mountToSpawn.bone, true, true);
baseMountable.Spawn();
mountToSpawn.mountable = baseMountable;
}
return baseMountable;
}
#endregion
#region Component
public enum HelicopterType {
Invalid, UH1Y, CH47, Mini, Transport
}
private abstract class BaseController : MonoBehaviour {
internal virtual HelicopterType Type => HelicopterType.Invalid;
internal virtual ConfigData.BaseHelicopter Config {
get;
}
protected ConfigData.BaseHelicopter.MovementSettings Movement {
get;
set;
}
internal EntityFuelSystem FuelSystem {
get;
set;
}
internal ItemContainer Inventory {
get;
private set;
}
protected Rigidbody Rigidbody {
get;
set;
}
internal Transform Transform {
get;
set;
}
internal BasePlayer Commander {
get {
return _commander;
}
set {
_commander = value;
OnCommanderSet(value);
}
}
internal abstract bool UseCustomControls {
get;
}
internal bool MountLocked {
get;
set;
}
private BasePlayer _commander;
protected List<BaseVehicle.MountPointInfo> mountPoints = Pool.GetList<BaseVehicle.MountPointInfo>();
protected List<BasePlayer> occupants = Pool.GetList<BasePlayer>();
internal int OccupantCount => occupants.Count;
internal bool IsDying {
get;
private set;
}
protected virtual void OnDestroy() {
EjectAllPlayers();
DestroyAllMounts();
Pool.FreeList(ref mountPoints);
Pool.FreeList(ref occupants);
}
internal abstract BaseCombatEntity GetEntity();
internal abstract bool IsGrounded();
internal bool IsNearGround() {
const int GROUND_LAYER = 1 << 16 | 1 << 21 | 1 << 23;
return Physics.Raycast(new Ray(Transform.position, Vector3.down), 1f, GROUND_LAYER);
}
protected virtual void UpdateAimTarget() {
}
protected virtual void ToggleLights() {
}
#region Mounting
internal bool IsOccupant(BasePlayer player) => occupants.Contains(player);
internal List<BasePlayer> GetOccupants() => occupants;
internal virtual void CreateMountPoints() {
}
internal BaseVehicle.MountPointInfo FindMountPointOf(BaseMountable baseMountable) {
for (int i = 0; i < mountPoints.Count; i++) {
BaseVehicle.MountPointInfo mountPointInfo = mountPoints[i];
if (mountPointInfo.mountable == baseMountable) return mountPointInfo;
}
return null;
}
internal BaseVehicle.MountPointInfo FindMountPoint(Func<BaseVehicle.MountPointInfo, bool> func) {
for (int i = 0; i < mountPoints.Count; i++) {
BaseVehicle.MountPointInfo mountPointInfo = mountPoints[i];
if (func(mountPointInfo)) return mountPointInfo;
}
return null;
}
internal virtual void OnPlayerMounted(BaseMountable baseMountable, BasePlayer player) {
bool isDriver = FindMountPointOf(baseMountable).isDriver;
if (isDriver) {
string message = UseCustomControls ? string.Format(GetMessage((int)Type > 2 ? "controls_new_mini" : "controls_new", player.userID), Control.GetButtonOf(Controls.Type.PitchF), Control.GetButtonOf(Controls.Type.PitchB), Control.GetButtonOf(Controls.Type.RollL), Control.GetButtonOf(Controls.Type.RollR), Control.GetButtonOf(Controls.Type.ThrottleUp), Control.GetButtonOf(Controls.Type.ThrottleDown), Control.GetButtonOf(Controls.Type.LockYaw)) : string.Empty;
player.ChatMessage(message);
message = Type == HelicopterType.CH47 || Type == HelicopterType.Transport ? $"{string.Format(GetMessage("toggle_lights", player.userID), Configuration.Buttons.Lights)}\n" : string.Empty;
if (this is UH1YController) {
if ((this as UH1YController).GetWeapons()?.Rocket.Enabled ?? false) message += $"{string.Format(GetMessage("fire_rocket", player.userID), Configuration.Buttons.Rockets)}\n";
if ((this as UH1YController).GetWeapons()?.MG.Enabled ?? false) message += $"{string.Format(GetMessage("fire_mg", player.userID), Configuration.Buttons.MG)}\n";
}
if (Inventory != null) message += $"{string.Format(GetMessage("access_inventory", player.userID), Configuration.Buttons.Inventory)}\n";
if (ConsumeFuel && GetFuelItem() != null) {
if ((int)Type < 3) message += $"{string.Format(GetMessage("access_fuel", player.userID), Control.GetButtonOf(Controls.Type.FuelTank))}\n";
message += $"{string.Format(GetMessage("fuel_type", player.userID), GetFuelItem().displayName.english)}";
}
if (!string.IsNullOrEmpty(message)) player.ChatMessage(message);
if (Config.Repair.Enabled && GetRepairItem() != null) player.ChatMessage(string.Format(GetMessage("repairhelp", player.userID), Config.Repair.Amount, GetRepairItem().displayName.english));
}
else {
string message = string.Empty;
if (Inventory != null) message += $"{string.Format(GetMessage("access_inventory", player.userID), Control.GetButtonOf(Controls.Type.Inventory))}\n";
if (ConsumeFuel && GetFuelItem() != null) {
if ((int)Type < 3) message += $"{string.Format(GetMessage("access_fuel", player.userID), Control.GetButtonOf(Controls.Type.FuelTank))}\n";
message += $"{string.Format(GetMessage("fuel_type", player.userID), GetFuelItem().displayName.english)}";
}
if (!string.IsNullOrEmpty(message)) player.ChatMessage(message);
}
OnEntityMounted(player, isDriver);
}
internal virtual void OnEntityMounted(BasePlayer player, bool isDriver) {
occupants.Add(player);
if (isDriver) {
Commander = player;
if ((int)Type < 3) {
CreateHealthUI(player, this);
if (ConsumeFuel) UpdateFuelUI();
}
}
}
internal virtual void OnPlayerDismounted(BaseMountable mountable, BasePlayer player) {
if (player == Commander) Commander = null;
occupants.Remove(player);
DestroyAllUI(player);
}
protected virtual void OnCommanderSet(BasePlayer player) {
}
internal virtual void EjectAllPlayers() {
if (mountPoints != null) {
for (int i = 0; i < mountPoints.Count; i++) mountPoints[i].mountable.DismountAllPlayers();
}
}
protected abstract void DestroyAllMounts();
internal BaseVehicle.MountPointInfo GetIdealMountPoint(BasePlayer player) {
BaseVehicle.MountPointInfo mountPointInfo = null;
float closestDistance = float.PositiveInfinity;
foreach (BaseVehicle.MountPointInfo mountPoint in mountPoints) {
if (mountPoint.mountable.IsMounted()) continue;
float distance = Vector3.Distance(mountPoint.mountable.mountAnchor.position, player.transform.position);
if (distance > closestDistance) continue;
mountPointInfo = mountPoint;
closestDistance = distance;
}
return mountPointInfo;
}
internal class DriverMount : MonoBehaviour {
private BaseMountable baseMountable;
private void Awake() {
baseMountable = GetComponent<BaseMountable>();
InvokeHandler.InvokeRepeating(baseMountable, UpdateHeldItems, 0.5f, 0.5f);
}
public void UpdateHeldItems() {
if (baseMountable._mounted == null) return;
Item item = baseMountable._mounted.GetActiveItem();
if (item == null || item.GetHeldEntity() == null) return;
int slot = item.position;
item.SetParent(null);
item.MarkDirty();
InvokeHandler.Invoke(baseMountable, () => {
if (item == null) return;
item.SetParent(baseMountable._mounted.inventory.containerBelt);
item.position = slot;
item.MarkDirty();
}
, 0.15f);
}
}
#endregion
#region Inventory
protected void InitializeInventory() {
if (Config.Inventory.Enabled) {
Inventory = new ItemContainer();
Inventory.ServerInitialize(null, Config.Inventory.Size);
if ((int)Inventory.uid == 0) Inventory.GiveUID();
}
}
internal virtual void OpenInventory(BasePlayer player) {
}
internal void DropInventory() {
if (Inventory == null) return;
Inventory.Drop("assets/prefabs/misc/item drop/item_drop.prefab", (Transform.position + new Vector3(0f, 1.5f, 0f)) + (UnityEngine.Random.onUnitSphere * UnityEngine.Random.Range(2f, 3f)), Quaternion.identity);
}
#endregion
#region Fuel
private float lastFuelAmount;
private bool fuelDisabled = false;
internal bool ConsumeFuel => Config.Fuel.Enabled && !fuelDisabled;
protected abstract ItemDefinition GetFuelItem();
protected virtual void InitializeFuel() {
}
protected void CreateFuelSystem() {
StorageContainer fuelStorage = GameManager.server.CreateEntity(FUEL_STORAGE, Transform.position, Quaternion.identity, true) as StorageContainer;
fuelStorage.SetParent(GetEntity(), false, true);
fuelStorage.transform.localPosition = Vector3.zero;
fuelStorage.GetComponent<Collider>().enabled = false;
fuelStorage.Spawn();
FuelSystem = new EntityFuelSystem(true, FUEL_STORAGE_REF, new List<BaseEntity>());
FuelSystem.fuelStorageInstance.Set(fuelStorage);
ItemContainer itemContainer = FuelSystem.GetFuelContainer().inventory;
itemContainer.onlyAllowedItems = new ItemDefinition[] {
GetFuelItem()
}
;
if (!Config.Fuel.Enabled) itemContainer.SetFlag(ItemContainer.Flag.IsLocked, true);
else if (Config.Fuel.GiveFuel) ItemManager.Create(GetFuelItem(), UnityEngine.Random.Range(Config.Fuel.FuelAmountMin, Config.Fuel.FuelAmountMax)).MoveToContainer(itemContainer);
}
internal virtual void OpenFuel(BasePlayer player) {
}
internal void DropFuel() {
StorageContainer storageContainer = FuelSystem.GetFuelContainer();
if (storageContainer == null) return;
storageContainer.inventory.Drop("assets/prefabs/misc/item drop/item_drop.prefab", (Transform.position + new Vector3(0f, 1.5f, 0f)) + (UnityEngine.Random.onUnitSphere * UnityEngine.Random.Range(2f, 3f)), Quaternion.identity);
}
protected void UpdateFuelUI() {
if (Commander != null) {
int currentFuelAmount = FuelSystem.GetFuelAmount();
if (currentFuelAmount != lastFuelAmount) {
CreateFuelUI(Commander, this, currentFuelAmount);
lastFuelAmount = currentFuelAmount;
}
InvokeHandler.Invoke(this, UpdateFuelUI, 1f);
}
}
internal void SetFuelRequirement(bool fuelEnabled) {
fuelDisabled = !fuelEnabled;
if (Commander != null) DestroyUI(Commander, UI_FUEL);
}
#endregion
#region Repair
protected abstract ItemDefinition GetRepairItem();
internal void TryRepair(BasePlayer player) {
BaseCombatEntity baseCombatEntity = GetEntity();
if (baseCombatEntity != null && Config.Repair.Enabled) {
if (baseCombatEntity.health < baseCombatEntity.MaxHealth()) {
ItemDefinition repairItem = GetRepairItem();
if (repairItem == null) {
Debug.Log($"[HeliCommander] Attempted repair for type {GetType()} but invalid repair item set in config");
return;
}
if (player.inventory.GetAmount(repairItem.itemid) < Config.Repair.Amount) {
player.ChatMessage(string.Format(GetMessage("noresources", player.userID), Config.Repair.Amount, repairItem.displayName.english));
return;
}
player.inventory.Take(null, repairItem.itemid, Config.Repair.Amount);
baseCombatEntity.Heal(Config.Repair.Damage);
player.Command("note.inv", new object[] {
repairItem.itemid, Config.Repair.Amount * -1
}
);
}
else player.ChatMessage(GetMessage("fullhealth", player.userID));
}
}
#endregion
#region Death
internal void ManageDamage(HitInfo info) {
if (IsDying) return;
if (IsDead()) {
OnDeath();
return;
}
foreach (KeyValuePair<DamageType, float> damageType in Config.Damage.Modifiers) {
if (info.damageTypes.Has(damageType.Key)) {
info.damageTypes.Scale(damageType.Key, damageType.Value);
}
}
if (Type == HelicopterType.Mini || Type == HelicopterType.Transport) return;
foreach (BasePlayer occupant in occupants) CreateHealthUI(occupant, this);
}
protected void StopToDie() {
enabled = false;
IsDying = true;
Rigidbody.velocity = Vector3.zero;
EjectAllPlayers();
GetEntity().Invoke(OnDeath, 5f);
}
protected virtual bool IsDead() => false;
protected virtual void OnDeath() {
enabled = false;
IsDying = true;
EjectAllPlayers();
if (Config.Inventory.DropInv && Inventory != null) DropInventory();
}
#endregion
}
private abstract class BaseController<T> : BaseController where T : BaseCombatEntity {
public T Component {
get;
private set;
}
private bool isInvincible;
protected bool isGrounded = false;
protected HelicopterInput input = new HelicopterInput();
#region Initialization
protected virtual void Awake() {
Component = GetComponent<T>();
Transform = Component.transform;
isInvincible = true;
InvokeHandler.Invoke(this, () => {
isInvincible = false;
}
, 3f);
InitializeSettings();
InitializeInventory();
InitializeFuel();
CreateMountPoints();
}
protected virtual void InitializeSettings() {
Movement = Config.Movement;
Component.InitializeHealth(Config.Damage.Health, Config.Damage.Health);
Component.SendNetworkUpdate();
}
internal override BaseCombatEntity GetEntity() => Component;
#endregion
#region Inventory
internal override void OpenInventory(BasePlayer player) {
if (Config.Inventory.Enabled && Inventory != null) OpenContainer(player, Inventory);
}
private void OpenContainer(BasePlayer player, ItemContainer container) {
player.inventory.loot.Clear();
player.inventory.loot.entitySource = Component;
player.inventory.loot.itemSource = null;
player.inventory.loot.AddContainer(container);
player.inventory.loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "generic");
player.SendNetworkUpdate();
}
#endregion
#region Fuel
internal override void OpenFuel(BasePlayer player) {
if (ConsumeFuel) OpenContainer(player, FuelSystem.GetFuelContainer().inventory);
}
#endregion
#region Movement
private void FixedUpdate() {
if (WaterLevel.Factor(Component.WorldSpaceBounds().ToBounds()) > 0.7f) {
StopToDie();
return;
}
if (!UseCustomControls) return;
OnFixedUpdate();
if (Vector3.Dot(Component.transform.up, Vector3.up) < 0) {
StopToDie();
return;
}
MovementUpdate();
if (IsEngineOn() && (Commander == null || (ConsumeFuel && !FuelSystem.HasFuel()))) EngineOff();
if (IsEngineOn() && ConsumeFuel) FuelSystem.TryUseFuel(Time.fixedDeltaTime, IsGrounded() ? Config.Fuel.Consumption * 0.1f : Config.Fuel.Consumption);
}
private void MovementUpdate() {
if (input.lights) ToggleLights();
if (ConsumeFuel && !FuelSystem.HasFuel()) return;
if (IsGrounded()) ApplyForceAtWheels();
if (IsEngineOn() && !(IsGrounded() && input.throttle < 0f)) {
LiftForce();
TiltForce();
YawForce();
}
}
protected virtual void OnFixedUpdate() {
}
private void LateUpdate() {
if (!UseCustomControls) return;
float levelPitch = pitchRoll.y > 0f ? -Time.deltaTime : pitchRoll.y < 0f ? Time.deltaTime : 0f;
float levelRoll = pitchRoll.x > 0f ? -Time.deltaTime : pitchRoll.x < 0f ? Time.deltaTime : 0f;
if (Commander == null) {
input.Clear();
pitchRoll.x = Mathf.Clamp(pitchRoll.x + levelPitch, -1f, 1f);
pitchRoll.y = Ma
// ... [Code preview truncated due to length. Full source in attached file] ...