using Network; using System; using System.Collections.Generic; using System.IO; using UnityEngine; namespace Oxide.Plugins { [Info("Double Jump", "Raul-Sorin Sorban", "1.1.8")] [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 Jumpers { get; } = new Dictionary(); public Dictionary JumperTimers { get; } = new Dictionary(); private void Loaded() { if (!IsInitialized) return; if (ConfigFile == null) ConfigFile = new Core.Configuration.DynamicConfigFile($"{Manager.ConfigPath}{Path.DirectorySeparatorChar}{Name}.json"); try { Config = ConfigFile.ReadObject(); } 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.isInAir || 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 = new Effect(); 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 } }