C#:
using System;
using System.Collections.Generic;
using System.Reflection;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using ProtoBuf;
using UnityEngine;
namespace Oxide.Plugins;
[Info("Ping Location", "Ilovepatatos", "1.0.4")]
[Description("Pings location for teammates using the middle mouse button call of duty style.")]
public class PingLocation : RustPlugin
{
private static readonly MethodInfo s_applyPingStyle = typeof(BasePlayer).GetMethod("ApplyPingStyle", BindingFlags.Instance | BindingFlags.NonPublic);
private Configuration _internalConfigs;
#region Configs
[Serializable]
private class Configuration
{
[JsonProperty("Use perms")]
public string UsePerms = "pinglocation.use";
[JsonProperty("Ping duration")]
public float Duration = 2f;
[JsonProperty("Max ping distance")]
public float MaxDistance = 300;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_internalConfigs = Config.ReadObject<Configuration>();
SaveConfig();
}
catch (Exception ex)
{
LoadDefaultConfig();
Puts($"The configuration file seems to be corrupted! Loading default configuration...");
Puts(ex.Message);
}
}
protected override void LoadDefaultConfig()
{
_internalConfigs = new Configuration();
}
protected override void SaveConfig()
{
Config.WriteObject(_internalConfigs);
}
#endregion
#region Hooks
[UsedImplicitly]
[HookMethod(nameof(Init))]
private void Init()
{
permission.RegisterPermission(_internalConfigs.UsePerms, this);
}
[UsedImplicitly]
[HookMethod(nameof(OnPlayerInput))]
private void OnPlayerInput(BasePlayer player, InputState input)
{
if (input.WasJustPressed(BUTTON.FIRE_THIRD))
TryPing(player);
}
#endregion
#region Methods
private void TryPing(BasePlayer player)
{
Configuration configs = _internalConfigs;
if (!permission.UserHasPermission(player.UserIDString, configs.UsePerms))
return;
const int layer = (1 << (int)Rust.Layer.Player_Server) | (1 << (int)Rust.Layer.World) | (1 << (int)Rust.Layer.Construction) |
(1 << (int)Rust.Layer.Terrain) | (1 << (int)Rust.Layer.Tree);
if (!Cast(player, out Vector3 pos, configs.MaxDistance, layer))
return;
player.State.pings ??= new List<MapNote>();
List<MapNote> pings = player.State.pings;
if (pings.Count >= ConVar.Server.maximumPings)
pings.RemoveAt(0);
var note = Facepunch.Pool.Get<MapNote>();
note.isPing = true;
note.worldPosition = pos;
note.timeRemaining = configs.Duration;
note.totalDuration = configs.Duration;
s_applyPingStyle?.Invoke(player, new object[] { note, BasePlayer.PingType.Hostile });
pings.Add(note);
player.DirtyPlayerState();
player.SendPingsToClient();
player.TeamUpdate(true);
}
#endregion
#region Utility
private static bool Cast(BasePlayer player, out Vector3 pos, float distance, int layerMask)
{
bool result = Physics.Raycast(player.eyes.HeadRay(), out RaycastHit hit, distance, layerMask);
pos = hit.point;
return result;
}
#endregion
}