C#:
using Network;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Double Jump", "Raul-Sorin Sorban", "1.2.2")]
[Description("A plugin which allows you to double-jump in Rust. Anti-hack's automatically handled.")]
public class DoubleJump : RustPlugin
{
public static DoubleJump Instance { get; set; }
public FlyhackSettings Settings { get; set; } = new FlyhackSettings();
#region Permissions
public const string UsePerm = "doublejump.use";
public const string TemporaryUsePerm = "doublejump.temporaryuse";
private void InstallPermissions()
{
permission.RegisterPermission(UsePerm, this);
permission.RegisterPermission(TemporaryUsePerm, this);
}
private bool HasPermission(BasePlayer player, string perm, bool quiet = true)
{
if (!permission.UserHasPermission(player.UserIDString, perm))
{
if (!quiet) player.ChatMessage($"You need to have the \"{perm}\" permission.");
return false;
}
return true;
}
#endregion
#region Overrides
public bool IsInitialized { get; set; }
public Dictionary<BasePlayer, bool> Jumpers { get; } = new Dictionary<BasePlayer, bool>();
public Dictionary<BasePlayer, Timer> JumperTimers { get; } = new Dictionary<BasePlayer, Timer>();
private void Loaded()
{
if (!IsInitialized) return;
if (ConfigFile == null) ConfigFile = new Core.Configuration.DynamicConfigFile($"{Manager.ConfigPath}{Path.DirectorySeparatorChar}{Name}.json");
try
{
Config = ConfigFile.ReadObject<RootConfig>();
}
catch (Exception exception)
{
Config = new RootConfig();
PrintError($"The JSON content in the config is not valid. Error: {exception}");
}
Settings.Save();
Settings.Apply();
timer.Every(0.1f, () =>
{
foreach (var player in BasePlayer.activePlayerList)
{
if (!HasPermission(player, UsePerm)) continue;
if (!Jumpers.ContainsKey(player)) Jumpers.Add(player, false);
if (player.IsOnGround())
{
UndoDoubleJump(player);
Jumpers[player] = false;
}
}
});
}
private void Unload()
{
Settings.Load();
foreach (var player in permission.GetPermissionUsers(TemporaryUsePerm))
{
permission.RevokeUserPermission(player, UsePerm);
permission.RevokeUserPermission(player, TemporaryUsePerm);
}
}
private void OnServerInitialized()
{
IsInitialized = true;
Instance = this;
InstallPermissions();
Loaded();
}
private void OnServerSave()
{
if (!IsInitialized) return;
ConfigFile.WriteObject(Config);
}
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
var player = entity.ToPlayer();
if (player == null || Config.EnableDoubleJumpFallDamage || info.damageTypes.GetMajorityDamageType() != Rust.DamageType.Fall) return null;
if (!Jumpers.ContainsKey(player)) Jumpers.Add(player, false);
if (Jumpers[player]) return true;
return null;
}
private void OnPlayerInput(BasePlayer player, InputState input)
{
if (player.IsFlying || player.RecentlyInAir(1f) ||
player.IsSwimming() ||
(Config.OnlyOutside && !player.IsOutside())) return;
if (input.WasJustPressed(BUTTON.JUMP) && !player.IsOnGround() && HasPermission(player, UsePerm) && Oxide.Core.Interface.CallHook("CanDoubleJump", player) == null)
{
DoDoubleJump(player);
JumperTimers[player] = timer.Once(Config.FallTime, () =>
{
JumperTimers[player]?.Destroy();
UndoDoubleJump(player);
});
}
}
private void OnUserPermissionGranted(string id, string permName)
{
if (permName == TemporaryUsePerm)
{
permission.GrantUserPermission(id, UsePerm, this);
timer.In(Config.TemporaryUseTime, () =>
{
permission.RevokeUserPermission(id, UsePerm);
permission.RevokeUserPermission(id, TemporaryUsePerm);
});
}
}
#endregion
public void DoDoubleJump(BasePlayer player)
{
if (!Jumpers.ContainsKey(player)) Jumpers.Add(player, false);
if (Jumpers[player]) return;
SendEffectTo("assets/bundled/prefabs/fx/screen_jump.prefab", player);
if (player.estimatedVelocity.x != 0 || player.estimatedVelocity.z != 0)
player.ApplyInheritedVelocity((player.estimatedVelocity) + new UnityEngine.Vector3(0f, Config.HorizontalJumpYVelocity, 0f));
else player.ApplyInheritedVelocity(new UnityEngine.Vector3(0f, Config.VerticalJumpYVelocity, 0f));
player.SendNetworkUpdateImmediate();
Jumpers[player] = true;
if (JumperTimers.ContainsKey(player)) JumperTimers[player]?.Destroy();
}
public void UndoDoubleJump(BasePlayer player)
{
if (!Jumpers.ContainsKey(player)) Jumpers.Add(player, false);
if (!Jumpers[player] || JumperTimers[player] == null) return;
player.ApplyInheritedVelocity(new UnityEngine.Vector3(0, 0f, 0f));
player.SendNetworkUpdateImmediate();
}
#region Helpers
public static void SendEffectTo(string effect, BasePlayer player)
{
if (player == null) return;
var effectInstance = Effect.reusableInstance;
effectInstance.Init(Effect.Type.Generic, player, 0, Vector3.up, Vector3.zero);
effectInstance.pooledstringid = StringPool.Get(effect);
NetWrite netWrite = Net.sv.StartWrite();
netWrite.PacketID(Message.Type.Effect);
effectInstance.WriteToStream(netWrite);
netWrite.Send(new SendInfo(player.net.connection));
effectInstance.Clear();
}
#endregion
#region Config
public Core.Configuration.DynamicConfigFile ConfigFile { get; set; }
public Core.Configuration.DynamicConfigFile DataFile { get; set; }
public RootConfig Config { get; set; } = new RootConfig();
public class FlyhackSettings
{
public float HorizontalForgiveness { get; set; }
public float HorizontalInertiaForgiveness { get; set; }
public float VerticalForgiveness { get; set; }
public float VerticalInertiaForgiveness { get; set; }
public void Load()
{
ConVar.AntiHack.flyhack_forgiveness_horizontal = HorizontalForgiveness;
ConVar.AntiHack.flyhack_forgiveness_horizontal_inertia = HorizontalInertiaForgiveness;
ConVar.AntiHack.flyhack_forgiveness_vertical = VerticalForgiveness;
ConVar.AntiHack.flyhack_forgiveness_vertical_inertia = VerticalInertiaForgiveness;
Instance.Puts($"Loaded old FlyHack settings.");
}
public void Save()
{
HorizontalForgiveness = ConVar.AntiHack.flyhack_forgiveness_horizontal;
HorizontalInertiaForgiveness = ConVar.AntiHack.flyhack_forgiveness_horizontal_inertia;
VerticalForgiveness = ConVar.AntiHack.flyhack_forgiveness_vertical;
VerticalInertiaForgiveness = ConVar.AntiHack.flyhack_forgiveness_vertical_inertia;
Instance.Puts($"Stored original FlyHack settings.");
}
public void Apply()
{
ConVar.AntiHack.flyhack_forgiveness_horizontal = 100;
ConVar.AntiHack.flyhack_forgiveness_horizontal_inertia = 500;
ConVar.AntiHack.flyhack_forgiveness_vertical = 100;
ConVar.AntiHack.flyhack_forgiveness_vertical_inertia = 500;
Instance.Puts($"Reconfigured AntiHack so double-jump's now possible. Changes will undo on plugin unload.");
}
}
public class RootConfig
{
public bool OnlyOutside { get; set; } = true;
public float HorizontalJumpYVelocity { get; set; } = 7.5f;
public float VerticalJumpYVelocity { get; set; } = 10f;
public bool EnableDoubleJumpFallDamage { get; set; } = false;
public float FallTime { get; set; } = 0.75f;
public float TemporaryUseTime { get; set; } = 20f;
}
#endregion
}
}