C#:
using System;
using System.Collections.Generic;
using Oxide.Core;
using Network;
using Network.Visibility;
using UnityEngine;
namespace Oxide.Plugins {
[Info("AdminSleigh", "k1lly0u", "0.1.5")]
class AdminSleigh : RustPlugin {
#region Fields
private readonly List<SleighController> m_Controllers = new List<SleighController>();
private const string SLEIGH_ENTITY = "assets/prefabs/misc/xmas/sleigh/santasleigh.prefab";
private const string CHAIR_PREFAB = "assets/prefabs/deployable/chair/chair.deployed.prefab";
private const string ITEM_SMALLPRESENT = "xmas.present.small";
private const string ITEM_MEDIUMPRESENT = "xmas.present.medium";
private const string ITEM_LARGEPRESENT = "xmas.present.large";
private const string CODELOCK_CRATE = "assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate_oilrig.prefab";
private const string USE_PERMISSION = "adminsleigh.use";
private static Func<string, ulong, string> m_GetMessage;
#endregion
#region Oxide Hooks
private void Loaded() {
permission.RegisterPermission(USE_PERMISSION, this);
}
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["Msg.LootTypeChanged"]
= "You have changed loot drop to <color=#ce422b>{0}</color>", ["Msg.PresentDropped"] = "You just dropped a <color=#ce422b>{0}</color>", ["Error.NoPermission"] = "You do not have permission to use this command", ["Error.Mounted"] = "You can not ride a sleigh when your are mounted", ["Help.Controls"] = "-- <color=#ce422b>AdminSleigh</color> - Controls --\n<color=#ce422b>Forward/Backward</color> - Accelerate and brake\n<color=#ce422b>Left/Right</color> - Turn Left and right\n<color=#ce422b>Fire1</color> - Drop Gift\n<color=#ce422b>Fire2</color> - Play Sound Effect\n<color=#ce422b>Jump</color> - Exit Sleigh\n<color=#ce422b>Reload</color> - Switch loot drop type"
}
, this);
m_GetMessage = new Func<string, ulong, string>(Message);
}
private void OnEntityDismounted(BaseMountable mountable, BasePlayer player) {
SleighController controller = mountable.GetComponentInParent<SleighController>();
if (controller != null) {
m_Controllers.Remove(controller);
UnityEngine.Object.Destroy(controller);
}
}
private void OnPlayerDisconnected(BasePlayer player) {
if (player.isMounted) {
BaseMountable mountable = player.GetMounted();
if (mountable != null) {
OnEntityDismounted(mountable, player);
}
}
}
private void Unload() {
for (int i = m_Controllers.Count - 1; i >= 0; i--) UnityEngine.Object.Destroy(m_Controllers[i]);
m_Controllers.Clear();
}
#endregion
#region Functions
private void CreateSleigh(BasePlayer player) {
BaseEntity sleigh = GameManager.server.CreateEntity(SLEIGH_ENTITY, player.transform.position);
sleigh.enableSaving = false;
sleigh.Spawn();
SleighController controller = sleigh.gameObject.AddComponent<SleighController>();
controller.MountSleigh(player);
m_Controllers.Add(controller);
}
private string Message(string key, ulong playerId = 0U) => lang.GetMessage(key, this, playerId == 0U ? null : playerId.ToString());
#endregion
#region Controller
private enum LootType {
SmallPresent, MediumPresent, LargePresent, MassivePresent, HackableCrate
}
private class SleighController : MonoBehaviour {
private SantaSleigh sleigh;
private Transform m_Transform;
private BasePlayer player;
private BaseMountable m_Mountable;
private LootType lootType = LootType.SmallPresent;
private float nextDropTime;
private float nextEffectTime;
private float nextLootCycleTime;
private float currentSpeed;
private float currentRotationSpeed;
private readonly float acceleration = 0.25f;
private readonly float maxSpeed = 5f;
private readonly float maxRotationSpeed = 1f;
private readonly float maxLeanAngle = 40f;
private float tiltForce;
private float adjRotationSpeed;
private void Awake() {
sleigh = GetComponent<SantaSleigh>();
sleigh.enabled = false;
m_Transform = sleigh.transform;
enabled = false;
CreateMountable();
}
private void Update() {
if (!player) return;
if (currentSpeed != 0) {
if (currentRotationSpeed != 0) {
adjRotationSpeed = currentRotationSpeed * (Mathf.Abs(currentSpeed) / maxSpeed);
tiltForce = Mathf.Lerp(tiltForce, adjRotationSpeed * maxLeanAngle, Time.deltaTime * 10f);
m_Transform.rotation *= Quaternion.Euler(0, adjRotationSpeed, 0);
m_Transform.localRotation = Quaternion.Euler(0, m_Transform.localEulerAngles.y, currentSpeed > 0f ? -tiltForce : tiltForce);
}
Vector3 position = m_Transform.position;
Vector3 target = position + (m_Transform.forward * currentSpeed);
float height = Mathf.Max(TerrainMeta.HeightMap.GetHeight(target), TerrainMeta.HeightMap.GetHeight(position));
target.y = Mathf.Max(SantaSleigh.desiredAltitude, height + SantaSleigh.altitudeAboveTerrain);
m_Transform.position = Vector3.Lerp(position, target, Time.deltaTime * 15f);
m_Transform.hasChanged = true;
}
}
private void LateUpdate() {
if (!player) return;
if (player.serverInput.WasJustPressed(BUTTON.JUMP)) {
enabled = false;
player.DismountObject();
player.MovePosition(sleigh.transform.position);
player.SendNetworkUpdateImmediate(false);
player.ClientRPCPlayer(null, player, "ForcePositionTo", m_Transform.position);
m_Mountable._mounted = null;
m_Mountable.SetFlag(BaseEntity.Flags.Busy, false, false);
player.EnsureDismounted();
Interface.Call("OnEntityDismounted", m_Mountable, player);
return;
}
float turn = player.serverInput.IsDown(BUTTON.LEFT) ? -1f : player.serverInput.IsDown(BUTTON.RIGHT) ? 1f : 0;
float forward = player.serverInput.IsDown(BUTTON.FORWARD) ? 1f : player.serverInput.IsDown(BUTTON.BACKWARD) ? -1f : 0;
if (forward > 0) currentSpeed = Mathf.Clamp(currentSpeed += (Time.fixedDeltaTime * acceleration), -maxSpeed * 0.5f, maxSpeed);
else if (forward < 0) currentSpeed = Mathf.Clamp(currentSpeed -= Time.fixedDeltaTime, -maxSpeed * 0.5f, maxSpeed);
else currentSpeed = Mathf.Lerp(currentSpeed, 0, Time.deltaTime * 3f);
if (turn > 0) currentRotationSpeed = Mathf.Clamp(currentRotationSpeed += (Time.fixedDeltaTime * maxRotationSpeed), -maxRotationSpeed, maxRotationSpeed);
else if (turn < 0) currentRotationSpeed = Mathf.Clamp(currentRotationSpeed -= (Time.fixedDeltaTime * maxRotationSpeed), -maxRotationSpeed, maxRotationSpeed);
else currentRotationSpeed = Mathf.Lerp(currentRotationSpeed, 0, Time.deltaTime * 3f);
if (player.serverInput.WasJustReleased(BUTTON.FIRE_PRIMARY)) DropPresent();
if (player.serverInput.WasJustPressed(BUTTON.FIRE_SECONDARY)) PlayEffects();
if (player.serverInput.WasJustPressed(BUTTON.RELOAD)) CycleLootType();
}
private void OnDestroy() {
if (player) player.DismountObject();
if (m_Mountable && !m_Mountable.IsDestroyed) m_Mountable.Kill();
if (sleigh && !sleigh.IsDestroyed) sleigh.Kill();
}
private void CreateMountable() {
m_Mountable = GameManager.server.CreateEntity(CHAIR_PREFAB, sleigh.transform.position) as BaseMountable;
m_Mountable.enableSaving = false;
m_Mountable.pickup.enabled = false;
m_Mountable.skinID = (ulong)1169930802;
m_Mountable.Spawn();
m_Mountable.maxMountDistance = 2f;
m_Mountable.isMobile = true;
m_Mountable.canWieldItems = false;
Destroy(m_Mountable.GetComponent<DestroyOnGroundMissing>());
Destroy(m_Mountable.GetComponent<GroundWatch>());
m_Mountable.GetComponent<MeshCollider>().convex = true;
m_Mountable.SetParent(sleigh);
m_Mountable.transform.localPosition = new Vector3(0f, 0.34f, -3.3f);
m_Mountable.transform.localRotation = Quaternion.Euler(0, 0, 0);
}
public void MountSleigh(BasePlayer player) {
this.player = player;
sleigh.CancelInvoke(sleigh.SendHoHoHo);
Vector3 spawnPosition = player.transform.position;
spawnPosition.y = TerrainMeta.HeightMap.GetHeight(spawnPosition) + SantaSleigh.altitudeAboveTerrain;
m_Transform.position = spawnPosition;
player.MountObject(m_Mountable);
enabled = true;
sleigh.enabled = false;
player.ChatMessage(m_GetMessage("Help.Controls", player.userID));
InvokeHandler.InvokeRepeating(this, UpdateNetworkGroup, 0, 1.5f);
}
private void UpdateNetworkGroup() {
Group group = Net.sv.visibility.GetGroup(sleigh.transform.position);
if (m_Mountable && m_Mountable.net?.group != group) m_Mountable.net?.SwitchGroup(group);
if (player && player.net?.group != group) player.net?.SwitchGroup(group);
}
private void CycleLootType() {
float time = Time.realtimeSinceStartup;
if (nextLootCycleTime > time) return;
int nextType = (int)lootType + 1;
if (nextType > 4) nextType = 0;
lootType = (LootType)nextType;
player.ChatMessage(string.Format(m_GetMessage("Msg.LootTypeChanged", player.userID), lootType));
nextLootCycleTime = time + 0.25f;
}
private void DropPresent() {
float time = Time.realtimeSinceStartup;
if (nextDropTime > time) return;
Item item = null;
switch (lootType) {
case LootType.SmallPresent : item = ItemManager.CreateByName(ITEM_SMALLPRESENT);
break;
case LootType.MediumPresent : item = ItemManager.CreateByName(ITEM_MEDIUMPRESENT);
break;
case LootType.LargePresent : item = ItemManager.CreateByName(ITEM_LARGEPRESENT);
break;
case LootType.MassivePresent : BaseEntity massivePresent = GameManager.server.CreateEntity(sleigh.prefabDrop.resourcePath, sleigh.dropOrigin.transform.position, sleigh.transform.rotation, true);
if (massivePresent) {
massivePresent.globalBroadcast = true;
massivePresent.Spawn();
}
break;
case LootType.HackableCrate : BaseEntity codelockCrate = GameManager.server.CreateEntity(CODELOCK_CRATE, sleigh.dropOrigin.transform.position, sleigh.transform.rotation, true);
if (codelockCrate) {
codelockCrate.globalBroadcast = true;
codelockCrate.Spawn();
}
break;
}
if (item != null) item.Drop(m_Mountable.transform.position + (Vector3.up * 1.25f), player.eyes.HeadForward() * 15f);
player.ChatMessage(string.Format(m_GetMessage("Msg.PresentDropped", player.userID), lootType));
nextDropTime = time + 0.25f;
}
private void PlayEffects() {
float time = Time.realtimeSinceStartup;
if (nextEffectTime > time) return;
sleigh.ClientRPC(null, "ClientPlayHoHoHo");
nextEffectTime = time + 5f;
}
}
#endregion
#region Commands
[ChatCommand("sleigh")]
private void cmdSleigh(BasePlayer player, string command, string[] args) {
if (!permission.UserHasPermission(player.UserIDString, USE_PERMISSION)) {
SendReply(player, Message("Error.NoPermission", player.userID));
return;
}
if (player.isMounted) {
SendReply(player, Message("Error.Mounted", player.userID));
return;
}
CreateSleigh(player);
}
#endregion
}
}