C#:
using Newtonsoft.Json;
using Oxide.Core;
using System.Collections.Generic;
namespace Oxide.Plugins
{
[Info("Drone Hover", "WhiteThunder", "1.0.6")]
[Description("Allows RC drones to hover in place when a player disconnects control at a computer station.")]
internal class DroneHover : CovalencePlugin
{
#region Fields
private const string PermissionUse = "dronehover.use";
private readonly object False = false;
private StoredData _pluginData;
#endregion
#region Hooks
private void Init()
{
_pluginData = StoredData.Load();
permission.RegisterPermission(PermissionUse, this);
}
private void Unload()
{
OnServerSave();
}
private void OnServerInitialized()
{
if (_pluginData.HoveringDrones == null)
return;
foreach (var entity in RemoteControlEntity.allControllables)
{
var drone = entity as Drone;
if (drone != null && _pluginData.HoveringDrones.Contains(drone.net.ID.Value))
{
MaybeStartDroneHover(drone, null);
}
}
}
private void OnServerSave()
{
_pluginData.Save();
}
private void OnNewSave()
{
_pluginData = StoredData.Clear();
}
private void OnBookmarkControlStarted(ComputerStation station, BasePlayer player, string bookmarkName, Drone drone)
{
if (!RCUtils.HasFakeController(drone))
return;
RCUtils.RemoveController(drone);
RCUtils.RemoveViewer(drone, player);
RCUtils.AddViewer(drone, player);
station.SetFlagLocal(ComputerStation.Flag_HasFullControl, true);
station.SendNetworkUpdateImmediate();
}
private void OnBookmarkControlEnded(ComputerStation station, BasePlayer player, Drone drone)
{
OnDroneControlEnded(drone, player);
}
private void OnEntityKill(Drone drone)
{
_pluginData.HoveringDrones.Remove(drone.net.ID.Value);
}
// This hook is exposed by plugin: Remover Tool (RemoverTool).
private object canRemove(BasePlayer player, Drone drone)
{
// Null check since somebody reported this method was somehow throwing NREs.
if (drone == null)
return null;
if (drone.IsBeingControlled)
return False;
return null;
}
// This hook is exposed by plugin: Ridable Drones (RidableDrones).
private void OnDroneControlEnded(Drone drone, BasePlayer player)
{
if (drone == null)
return;
MaybeStartDroneHover(drone, player);
}
#endregion
#region Helpers
private static class RCUtils
{
public static bool HasFakeController(IRemoteControllable controllable)
{
return controllable.ControllingViewerId?.SteamId == 0;
}
public static void RemoveController(IRemoteControllable controllable)
{
var controllerId = controllable.ControllingViewerId;
if (controllerId.HasValue)
{
controllable.StopControl(controllerId.Value);
}
}
public static bool AddViewer(IRemoteControllable controllable, BasePlayer player)
{
return controllable.InitializeControl(new CameraViewerId(player.userID, 0));
}
public static void RemoveViewer(IRemoteControllable controllable, BasePlayer player)
{
controllable.StopControl(new CameraViewerId(player.userID, 0));
}
public static bool AddFakeViewer(IRemoteControllable controllable)
{
return controllable.InitializeControl(new CameraViewerId());
}
}
private bool HoverWasBlocked(Drone drone, BasePlayer formerPilot)
{
var hookResult = Interface.CallHook("OnDroneHoverStart", drone, formerPilot);
return hookResult is bool && (bool)hookResult == false;
}
private bool ShouldHover(Drone drone, BasePlayer formerPilot)
{
if (drone.IsBeingControlled || drone.isGrounded)
return false;
if (formerPilot != null && !permission.UserHasPermission(formerPilot.UserIDString, PermissionUse))
return false;
if (HoverWasBlocked(drone, formerPilot))
return false;
return true;
}
private void MaybeStartDroneHover(Drone drone, BasePlayer formerPilot)
{
if (!ShouldHover(drone, formerPilot))
{
_pluginData.HoveringDrones.Remove(drone.net.ID.Value);
return;
}
RCUtils.AddFakeViewer(drone);
drone.currentInput.Reset();
_pluginData.HoveringDrones.Add(drone.net.ID.Value);
Interface.CallHook("OnDroneHoverStarted", drone, formerPilot);
}
#endregion
#region Data
private class StoredData
{
[JsonProperty("HoveringDrones")]
public HashSet<ulong> HoveringDrones = new HashSet<ulong>();
public static StoredData Load() =>
Interface.Oxide.DataFileSystem.ReadObject<StoredData>(nameof(DroneHover)) ?? new StoredData();
public static StoredData Clear() => new StoredData().Save();
public StoredData Save()
{
Interface.Oxide.DataFileSystem.WriteObject(nameof(DroneHover), this);
return this;
}
}
#endregion
}
}