OnFeedbackReported
OnFeedbackReported is called when a player submits an in-game feedback or player report, after the report object is built and just before the server forwards it to the Facepunch reports endpoint.
void OnFeedbackReported(BasePlayer player, string subject, string message, Facepunch.Models.ReportType reportType)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who submitted the feedback report through the in-game report dialog. |
subject | string | The selected report reason or subject text chosen by the reporter in the report UI. |
message | string | The free-text description the reporter typed; may be an empty string if the field was left blank. |
reportType | Facepunch.Models.ReportType | A Facepunch.Models.ReportType value describing the kind of report (player, entity, general feedback) as sent by the client. |
Return value
The original method returns void and the hook call sits directly on the code path with no branch on its result, so whatever you return is discarded. Return nothing (or null) - it has no effect on whether the report is transmitted.
How it works
The hook fires inside BasePlayer's feedback handling routine once the client has sent a complete report payload: the subject, the message body and the report type are already assembled into a feedback object. It is a read-only observation point, not a gate - the game continues to push the report to the configured reports endpoint (Server.reportsServerEndpoint) right after the hook call, so nothing you do here cancels the submission.
player is the reporter. subject is the chosen reason string, message is the typed description, and reportType (from Facepunch.Models.ReportType) tells you whether it was a player report, an entity report or a general feedback type. Use them together to filter: for example, only act on player reports, or only on reports whose message mentions a specific term.
You cannot narrow this hook with a more specific parameter type: player is always a BasePlayer, so declaring a subclass just causes Oxide to skip the call. Since the method returns void, any return value is ignored.
Example plugin: Log and acknowledge submitted reports
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Report Logger", "RustPluginGenerator", "1.0.0")]
[Description("Stores recent in-game feedback reports and notifies staff")]
public class ReportLogger : RustPlugin
{
private const string PermView = "reportlogger.view";
private PluginConfig config;
private ReportData data;
private class PluginConfig
{
[JsonProperty("Max stored reports")] public int MaxStored { get; set; } = 100;
[JsonProperty("Acknowledge reporter")] public bool Acknowledge { get; set; } = true;
[JsonProperty("Notify staff in chat")] public bool NotifyStaff { get; set; } = true;
}
private class ReportEntry
{
public string ReporterName;
public string ReporterId;
public string Subject;
public string Message;
public string Type;
public int Time;
}
private class ReportData
{
public List<ReportEntry> Reports = new List<ReportEntry>();
}
protected override void LoadDefaultConfig() => config = new PluginConfig();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<PluginConfig>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Configuration file is invalid, using defaults");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Thanks"] = "Thanks for your report, {0}. Staff have been notified.",
["StaffNote"] = "{0} ({1}) submitted a report: {2}",
["ListHeader"] = "Last {0} reports:",
["ListLine"] = "[{0}] {1} ({2}): {3} - {4}",
["NoReports"] = "No reports have been stored yet."
}, this);
}
private void Init()
{
permission.RegisterPermission(PermView, this);
data = Interface.Oxide.DataFileSystem.ReadObject<ReportData>(Name);
if (data == null) data = new ReportData();
if (data.Reports == null) data.Reports = new List<ReportEntry>();
}
private void Unload()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, data);
}
private string Msg(string key, string userId = null, params object[] args)
=> string.Format(lang.GetMessage(key, this, userId), args);
private void OnFeedbackReported(BasePlayer player, string subject, string message, Facepunch.Models.ReportType reportType)
{
if (player == null) return;
data.Reports.Add(new ReportEntry
{
ReporterName = player.displayName,
ReporterId = player.UserIDString,
Subject = subject,
Message = message,
Type = reportType.ToString(),
Time = Facepunch.Math.Epoch.Current
});
while (data.Reports.Count > config.MaxStored)
data.Reports.RemoveAt(0);
Interface.Oxide.DataFileSystem.WriteObject(Name, data);
if (config.Acknowledge)
player.ChatMessage(Msg("Thanks", player.UserIDString, player.displayName));
if (!config.NotifyStaff) return;
var note = Msg("StaffNote", null, player.displayName, player.UserIDString, subject);
foreach (var target in BasePlayer.activePlayerList)
{
if (target == null || !target.IsConnected) continue;
if (target.IsAdmin || permission.UserHasPermission(target.UserIDString, PermView))
target.ChatMessage(note);
}
}
[ChatCommand("reportlog")]
private void CmdReportLog(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermView))
return;
if (data.Reports.Count == 0)
{
player.ChatMessage(Msg("NoReports", player.UserIDString));
return;
}
int count = 5;
if (args != null && args.Length > 0) int.TryParse(args[0], out count);
if (count < 1) count = 1;
if (count > 20) count = 20;
player.ChatMessage(Msg("ListHeader", player.UserIDString, count));
int start = Math.Max(0, data.Reports.Count - count);
for (int i = data.Reports.Count - 1; i >= start; i--)
{
var entry = data.Reports[i];
player.ChatMessage(Msg("ListLine", player.UserIDString, entry.Time, entry.ReporterName, entry.ReporterId, entry.Subject, entry.Type));
}
}
}
}The plugin keeps a bounded history of submitted reports in oxide/data. When OnFeedbackReported fires, it records the reporter's name and ID, the subject, message and report type, then trims the list to the configured maximum and saves. It can send the reporter a confirmation message from the language file and push a short chat note to admins who hold the reportlogger.view permission or have admin status. A chat command reportlog lists the most recent entries to staff. Nothing in the plugin touches the report itself, so Facepunch still receives the submission through the reports endpoint.
Common use cases
Staff review queue
Persist every submitted report to
oxide/dataso moderators can review reports later, even when no admin was online when the report was sent.Admin alerts
Send a short chat note to online admins and permitted users whenever a new report arrives, so they can react quickly without opening external tooling.
Reporter acknowledgement
Reply to the reporting player with a language-file message confirming their feedback was received, which reduces repeat reports for the same issue.
Pitfalls
You cannot cancel the submission
The hook fires just before the report is forwarded to
Server.reportsServerEndpoint. Returning a value does not stop the transmission; blocking reports would require changes beyond this hook.Client-supplied text is untrusted
subjectandmessagecome from the client and can be empty, very long or misleading. Treat them as display data only and never parse them into commands or file paths.Do not assume the endpoint is configured
If
Server.reportsServerEndpointis empty the report never leaves the server, butOnFeedbackReportedstill fires. Do not treat the hook as proof that Facepunch received the report.
Build a plugin with OnFeedbackReported
Describe what should happen and get a compiled plugin that uses this hook.
Edit the prompt on the next screen. 2 free plugins a month, no card.
Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.
Build a plugin with OnFeedbackReported
Generate