Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Facepunch; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Oxide.Core; using Oxide.Core.Libraries; using Oxide.Core.Libraries.Covalence; using Oxide.Core.Plugins; namespace Oxide.Plugins { [Info("Discord Report", "misticos", "1.2.1")] [Description("Send reports from players ingame to a Discord channel")] class DiscordReport : CovalencePlugin { #region Variables [PluginReference("PlaceholderAPI")] private Plugin _placeholders = null; private Action<IPlayer, StringBuilder, bool> _placeholderProcessor = null; private static DiscordReport _ins; private const string SteamProfileXML = "https://steamcommunity.com/profiles/{0}?xml=1"; private const string SteamProfile = "https://steamcommunity.com/profiles/"; private readonly Regex _steamProfileIconRegex = new Regex(@"(?<=<avatarIcon>[\w\W]+)https://.+\.jpg(?=[\w\W]+<\/avatarIcon>)", RegexOptions.Compiled); private Dictionary<string, uint> _cooldownData = new Dictionary<string, uint>(); private Time _time = GetLibrary<Time>(); private const string PermissionIgnoreCooldown = "discordreport.ignorecooldown"; private const string PermissionUse = "discordreport.use"; private const string PermissionAdmin = "discordreport.admin"; #endregion #region Configuration private Configuration _config; private class Configuration { [JsonProperty("Webhook URL")] public string Webhook = "YOUR WEBHOOK LINK HERE"; [JsonProperty("Message Content")] public string MessageContent = ""; [JsonProperty("Embed Title")] public string EmbedTitle = "My Server Report"; [JsonProperty("Embed Description")] public string EmbedDescription = "Report sent by a player from your server"; [JsonProperty("Embed Color")] public int EmbedColor = 1484265; [JsonProperty("Set Author Icon From Player Profile")] public bool AuthorIcon = true; [JsonProperty("Use Reporter (True) Or Suspect (False) As Author")] public bool IsReporterIcon = true; [JsonProperty("Allow Reporting Admins")] public bool ReportAdmins = false; [JsonProperty("Report Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)] public List<string> ReportCommands = new List<string> { "report" }; [JsonProperty("Allow Only Online Suspects Reports")] public bool OnlyOnlineSuspects = true; [JsonProperty("Threshold Before Sending Reports")] public int Threshold = 0; #if RUST [JsonProperty("Show Recent Suspect Combatlog")] public bool ShowCombatlog = false; [JsonProperty("Show In-Game Subject")] public bool ShowInGameSubject = true; [JsonProperty("Minimum In-Game Report Subject Length")] public int SubjectMinimumGame = 0; [JsonProperty("Minimum In-Game Report Message Length")] public int MessageMinimumGame = 0; [JsonProperty("Allowed In-Game Report Types", ObjectCreationHandling = ObjectCreationHandling.Replace)] public string[] AllowedTypes = { "cheat", "abusive", "name", "spam" }; [JsonProperty("Recent Combatlog Entries")] public int CombatlogEntries = 2; #endif [JsonProperty("Cooldown In Seconds")] public uint Cooldown = 300; [JsonProperty("User Cache Validity In Seconds")] public uint UserCacheValidity = 86400; [JsonProperty("Minimum Message Length")] public int MessageMinimum = 0; } protected override void LoadConfig() { base.LoadConfig(); try { _config = Config.ReadObject<Configuration>(); if (_config == null) throw new Exception(); SaveConfig(); } catch { PrintError("Your configuration file contains an error. Using default configuration values."); LoadDefaultConfig(); } } protected override void SaveConfig() => Config.WriteObject(_config); protected override void LoadDefaultConfig() => _config = new Configuration(); #endregion #region Work with Data private Dictionary<string, PlayerData> _loadedData = new Dictionary<string, PlayerData>(); private void SaveData(string id) { PlayerData data; if (!_loadedData.TryGetValue(id, out data)) return; Interface.Oxide.DataFileSystem.WriteObject(nameof(DiscordReport) + '/' + id, data); } private PlayerData GetOrLoadData(string id) { PlayerData data; if (_loadedData.TryGetValue(id, out data)) return data; try { data = Interface.Oxide.DataFileSystem.ReadObject<PlayerData>(nameof(DiscordReport) + '/' + id); } catch (Exception e) { PrintError(e.ToString()); } return _loadedData[id] = data ?? new PlayerData(); } private class PlayerData { public string ImageURL = string.Empty; public string LastKnownAddress = string.Empty; public HashSet<string> Reporters = new HashSet<string>(); public uint LastImageUpdate = 0; } #endregion #region Discord Classes // ReSharper disable NotAccessedField.Local private class WebhookBody { [JsonProperty("embeds")] public List<EmbedBody> Embeds; [JsonProperty("content")] public string Content = null; } private class EmbedBody { [JsonProperty("title")] public string Title; [JsonProperty("type")] public string Type; [JsonProperty("description")] public string Description; [JsonProperty("color")] public int Color; [JsonProperty("author")] public AuthorBody Author; [JsonProperty("fields")] public List<FieldBody> Fields; public class AuthorBody { [JsonProperty("name")] public string Name; [JsonProperty("url")] public string AuthorURL; [JsonProperty("icon_url")] public string AuthorIconURL; } public class FieldBody { [JsonProperty("name")] public string Name; [JsonProperty("value")] public string Value; [JsonProperty("inline")] public bool Inline; } } // ReSharper restore NotAccessedField.Local #endregion #region Hooks protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary<string, string> { { "Webhook: Reporter Data Title", "Reporter" }, { "Webhook: Suspect Data Title", "Suspect" }, #if RUST { "Webhook: Combatlog Title", "Suspect's Combatlog #{n}" }, { "Webhook: Combatlog Attacker Title", "Attacker" }, { "Webhook: Combatlog Target Title", "Target" }, { "Webhook: Combatlog Time Title", "Time" }, { "Webhook: Combatlog Weapon Title", "Weapon" }, { "Webhook: Combatlog Ammo Title", "Ammo" }, { "Webhook: Combatlog Distance Title", "Distance" }, { "Webhook: Combatlog Old HP Title", "Old HP" }, { "Webhook: Combatlog New HP Title", "New HP" }, { "Webhook: Combatlog Info Title", "Info" }, #endif { "Webhook: Reporter Data", "#{discordreport.total} {name} ({id}). IP: {ip}.\n" + "Ping: {ping}ms. Connected: {connected}" }, { "Webhook: Suspect Data", "#{discordreport.total} {name} ({id}). IP: {ip}.\n" + "Ping: {ping}ms. Connected: {connected}" }, { "Webhook: Report Subject", "Report Subject" }, { "Webhook: Report Message", "Report Message" }, { "Command: Syntax", "Syntax:\n" + "report (ID / \"Name\") (Message)\n" + "WARNING! Use quotes for names." }, { "Command: User Not Found", "We were unable to find this user or multiple were found." }, { "Command: Report Sent", "Thank you for your report, it was sent to our administration." }, { "Command: Exceeded Cooldown", "You have exceeded your cooldown on reports." }, { "Command: Cannot Report Admins", "You cannot report admins." }, { "Command: Cannot Use", "You cannot use this command since you do not have enough permissions." }, { "Command: Message Length", "Please add more information to the message." } }, this); } private void Init() { _ins = this; permission.RegisterPermission(PermissionIgnoreCooldown, this); permission.RegisterPermission(PermissionUse, this); permission.RegisterPermission(PermissionAdmin, this); foreach (var command in _config.ReportCommands) AddCovalenceCommand(command, nameof(CommandReport)); } private void Loaded() { foreach (var player in players.Connected) OnUserConnected(player); } private void Unload() { _ins = null; } private void OnUserConnected(IPlayer player) { var user = GetOrLoadData(player.Id); if (_config.AuthorIcon) UpdateCachedImage(player, user); user.LastKnownAddress = player.Address; SaveData(player.Id); } private void OnPlaceholderAPIReady() { _placeholderProcessor = _placeholders.Call<Action<IPlayer, StringBuilder, bool>>("GetProcessPlaceholders", 1); _placeholders.Call("AddPlaceholder", this, "discordreport.total", new Func<IPlayer, string, object>( (player, s) => GetOrLoadData(player.Id).Reporters.Count)); } private void OnPluginUnloaded(Plugin plugin) { if (plugin?.Name != "PlaceholderAPI") return; _placeholderProcessor = null; } #if RUST private void OnPlayerReported(BasePlayer player, string targetName, string targetId, string subject, string message, string type) { if (player == null) return; // Empty message will not be shown if (_config.MessageMinimumGame != 0 && !string.IsNullOrEmpty(message) && message.Length < _config.MessageMinimumGame) return; subject = subject.Substring(3 + type.Length); if (_config.SubjectMinimumGame != 0 && _config.ShowInGameSubject && subject.Length < _config.SubjectMinimumGame) return; if (_config.AllowedTypes.Length != 0 && !_config.AllowedTypes.Contains(type)) return; var suspect = players.FindPlayer(targetId); if (suspect == null || player.IPlayer == null) return; if (!CanUse(player.IPlayer)) return; if (!_config.ReportAdmins && suspect.HasPermission(PermissionAdmin)) return; if (_config.OnlyOnlineSuspects && !suspect.IsConnected) return; if (ExceedsCooldown(player.IPlayer)) return; SendReport(player.IPlayer, suspect, _config.ShowInGameSubject ? subject : string.Empty, message); } #endif #endregion #region Commands private void CommandReport(IPlayer player, string command, string[] args) { if (!CanUse(player)) { player.Reply(GetMsg("Command: Cannot Use", player.Id)); return; } if (args.Length < 2) goto syntax; var message = string.Join(" ", args.Skip(1)); if (_config.MessageMinimum != 0 && message.Length < _config.MessageMinimum) { player.Reply(GetMsg("Command: Message Length", player.Id)); return; } var suspect = players.FindPlayer(args[0]); if (suspect == null || !suspect.IsConnected && _config.OnlyOnlineSuspects) { player.Reply(GetMsg("Command: User Not Found", player.Id)); return; } if (!_config.ReportAdmins && suspect.HasPermission(PermissionAdmin)) { player.Reply(GetMsg("Command: Cannot Report Admins", player.Id)); return; } if (ExceedsCooldown(player)) { player.Reply(GetMsg("Command: Exceeded Cooldown", player.Id)); return; } SendReport(player, suspect, string.Empty, message); player.Reply(GetMsg("Command: Report Sent", player.Id)); return; syntax: player.Reply(GetMsg("Command: Syntax", player.Id)); } #endregion #region Helpers private void UpdateCachedImage(IPlayer player, PlayerData data) { var now = _time.GetUnixTimestamp(); // If cached and still valid, return if (!string.IsNullOrEmpty(data.ImageURL) && data.LastImageUpdate + _config.UserCacheValidity > now) return; webrequest.Enqueue(string.Format(SteamProfileXML, player.Id), string.Empty, (code, result) => { data.ImageURL = _steamProfileIconRegex.Match(result).Value; data.LastImageUpdate = now; SaveData(player.Id); }, this); } #region Webhook private void SendReport(IPlayer reporter, IPlayer suspect, string subject, string message) { // Threshold var cached = GetOrLoadData(suspect.Id); cached.Reporters.Add(reporter.Id); if (cached.Reporters.Count < _config.Threshold) return; // Author Icon var authorIconURL = string.Empty; var author = _config.IsReporterIcon ? reporter : suspect; if (_config.AuthorIcon) { var user = GetOrLoadData(author.Id); if (!string.IsNullOrEmpty(user.ImageURL)) authorIconURL = user.ImageURL; UpdateCachedImage(author, user); // Won't get update now but will be for any other reports for this user } // Embed data const string type = "rich"; var body = new WebhookBody { Embeds = new List<EmbedBody>(), Content = string.IsNullOrEmpty(_config.MessageContent) ? null : _config.MessageContent }; var fields = new List<EmbedBody.FieldBody>(); if (!string.IsNullOrEmpty(subject)) { fields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Report Subject"), Value = subject, Inline = false }); } if (!string.IsNullOrEmpty(message)) { fields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Report Message"), Value = message, Inline = false }); } fields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Reporter Data Title"), Value = FormatUserDetails(new StringBuilder(GetMsg("Webhook: Reporter Data")), reporter), Inline = false }); fields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Suspect Data Title"), Value = FormatUserDetails(new StringBuilder(GetMsg("Webhook: Suspect Data")), suspect), Inline = false }); body.Embeds.Add(new EmbedBody { Title = _config.EmbedTitle, Description = _config.EmbedDescription, Type = type, Color = _config.EmbedColor, Author = new EmbedBody.AuthorBody { AuthorIconURL = authorIconURL, AuthorURL = SteamProfile + author.Id, Name = author.Name }, Fields = fields }); // Rust-specific embed data #if RUST if (_config.ShowCombatlog && suspect.Object is BasePlayer) { var events = CombatLog.Get(((BasePlayer)suspect.Object).userID).ToArray(); for (var i = 1; i <= _config.CombatlogEntries && i <= events.Length; i++) { var combat = events[events.Length - i]; var combatFields = new List<EmbedBody.FieldBody>(); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Attacker Title"), Value = combat.attacker, Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Target Title"), Value = combat.target, Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Time Title"), Value = (UnityEngine.Time.realtimeSinceStartup - combat.time).ToString("0.0s"), Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Weapon Title"), Value = combat.weapon, Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Ammo Title"), Value = combat.ammo, Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Distance Title"), Value = combat.distance.ToString("0.0m"), Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Old HP Title"), Value = combat.health_old.ToString("0.0"), Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog New HP Title"), Value = combat.health_new.ToString("0.0"), Inline = true }); combatFields.Add(new EmbedBody.FieldBody { Name = GetMsg("Webhook: Combatlog Info Title"), Value = string.IsNullOrEmpty(combat.info) ? "none" : combat.info, Inline = true }); body.Embeds.Add(new EmbedBody { Title = GetMsg("Webhook: Combatlog Title").Replace("{n}", $"{i}"), Type = type, Color = _config.EmbedColor, Fields = combatFields }); } } #endif // Send a web request webrequest.Enqueue(_config.Webhook, JObject.FromObject(body).ToString(), (code, result) => { if (code == 204) { SetCooldown(reporter); } else { PrintWarning($"Discord Webhook returned {code}:\n{result}"); } }, this, RequestMethod.POST, new Dictionary<string, string> { { "Content-Type", "application/json" } }); } private string FormatUserDetails(StringBuilder builder, IPlayer player) { // Apply placeholders if possible _placeholderProcessor?.Invoke(player, builder, false); return builder .Replace("{name}", player.Name).Replace("{id}", player.Id) .Replace("{ip}", GetOrLoadData(player.Id)?.LastKnownAddress ?? "Unknown") .Replace("{ping}", player.IsConnected ? player.Ping.ToString() : "0") .Replace("{connected}", player.IsConnected.ToString()).ToString(); } #endregion #region Cooldown private bool ExceedsCooldown(IPlayer player) { if (player.HasPermission(PermissionIgnoreCooldown)) return false; var currentTime = _time.GetUnixTimestamp(); if (_cooldownData.ContainsKey(player.Id)) return _cooldownData[player.Id] - currentTime < _config.Cooldown; return false; } private void SetCooldown(IPlayer player) => _cooldownData[player.Id] = _time.GetUnixTimestamp(); #endregion private bool CanUse(IPlayer player) => player.HasPermission(PermissionUse); private string GetMsg(string key, string userId = null) => lang.GetMessage(key, this, userId); #endregion } }
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
API Exploit
24 min ago | 0.44 KB
Admin password
25 min ago | 0.44 KB
Changelly Profit Guide
25 min ago | 0.44 KB
Enmanuel - 28.09.2026
6 hours ago | 0.08 KB
InImageCronista-json_config
9 hours ago | 0.47 KB
InImageCronistaV-B
10 hours ago | 188.68 KB
Membuat Urutan Bash KORAN
17 hours ago | 0.26 KB
Untitled
1 day ago | 0.71 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!