OnMissionSucceeded
OnMissionSucceeded is called after a mission's objectives are finished, from inside BaseMission.MissionSuccess, once the instance has been marked Accomplished and the mission-ended and complete routines have run.
void OnMissionSucceeded(BaseMission mission, BaseMission.MissionInstance missionInstance, BasePlayer assignee)Parameters
| Parameter | Type | Description |
|---|---|---|
mission | BaseMission | The mission definition that was completed. Use it to read the mission name or compare against a specific mission type before granting rewards. |
missionInstance | BaseMission.MissionInstance | The concrete instance the assignee finished. It holds status, progress and objective data; treat it as read-only context here. |
assignee | BasePlayer | The player who completed the mission. This is the player to reward, message or record. It can be null in edge cases, so check it before use. |
Return value
The hook's return value is ignored; the game method returns void and calls the hook as its last statement. Returning anything has no effect on mission state.
How it works
The hook fires at the end of BaseMission.MissionSuccess, which sets instance.status to Accomplished, runs MissionEnded and MissionComplete, and only then calls OnMissionSucceeded. Because it fires after the status change and completion routines, the mission is already finished from the game's point of view: you cannot cancel or fail it from here.
Every argument is useful. mission is the mission type/definition, good for filtering by name or class. missionInstance is the specific run that just completed. assignee is the player who gets credit. Declaring a more specific type for mission (for example a concrete mission subclass) makes Oxide skip calls for other mission types; declaring the assignee as BasePlayer is the default, so narrowing it further is rarely useful.
The hook is invoked through a virtual method, so servers using custom missions built on BaseMission also call it. Use it for rewards, logging, statistics or chat notifications. It does not fire on failure; use OnMissionFailed for that.
Example plugin: Reward and log completed missions
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Mission Reward Log", "RustPluginGenerator", "1.0.0")]
[Description("Rewards players with scrap when they complete a mission and records completion counts.")]
public class MissionRewardLog : RustPlugin
{
private const string DataFile = "MissionRewardLog";
private PluginConfig config;
private Dictionary<ulong, int> completions = new Dictionary<ulong, int>();
private class PluginConfig
{
[JsonProperty("Reward enabled")]
public bool Enabled = true;
[JsonProperty("Scrap reward")]
public int ScrapAmount = 50;
[JsonProperty("Notify admins in console")]
public bool NotifyAdmins = true;
}
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>
{
["Reward"] = "Mission complete! You received {0} scrap. Total missions: {1}",
["NoReward"] = "Mission complete! Total missions: {0}"
}, this);
}
private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);
private void OnServerInitialized()
{
completions = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>(DataFile) ?? new Dictionary<ulong, int>();
}
private void OnMissionSucceeded(BaseMission mission, BaseMission.MissionInstance missionInstance, BasePlayer assignee)
{
if (assignee == null || assignee.IsNpc) return;
if (!completions.ContainsKey(assignee.userID))
completions[assignee.userID] = 0;
completions[assignee.userID]++;
if (config.Enabled && config.ScrapAmount > 0)
{
var item = ItemManager.CreateByName("scrap", config.ScrapAmount);
if (item != null)
assignee.GiveItem(item);
}
if (config.Enabled && config.ScrapAmount > 0)
assignee.ChatMessage(Msg("Reward", assignee.UserIDString, config.ScrapAmount, completions[assignee.userID]));
else
assignee.ChatMessage(Msg("NoReward", assignee.UserIDString, completions[assignee.userID]));
if (config.NotifyAdmins)
{
var missionName = mission?.missionName?.english;
if (string.IsNullOrEmpty(missionName)) missionName = "a mission";
Puts($"{assignee.displayName} completed {missionName} (total {completions[assignee.userID]})");
}
}
private void Unload()
{
Interface.Oxide.DataFileSystem.WriteObject(DataFile, completions);
}
}
}OnMissionSucceeded ignores null and NPC assignees, then awards a configurable scrap reward via ItemManager.CreateByName and GiveItem. The player receives a localized chat message; when the reward is disabled or the amount is zero, the message reports only the running total. Each completion is tallied in a per-player dictionary persisted to oxide/data with Interface.Oxide.DataFileSystem, and the total is shown back to the player. With NotifyAdmins enabled, a console line records the player's display name, mission name and total. Unload writes the dictionary to disk.
Common use cases
Grant mission rewards
Give scrap, items or plugin currency when a player completes a mission, using the assignee argument to target the right player.
Track completion statistics
Count how many missions each player finishes and persist the totals for leaderboards or progression plugins.
Notify admins and players
Send a chat message to the assignee and a console note to admins describing which mission was completed.
Pitfalls
The mission is already complete
By the time this hook fires the instance is marked Accomplished and the end routines have run, so you cannot cancel or refund the mission here; use CanAssignMission or OnMissionStart for gating.
Assignee can be null
Always null-check
assigneebefore touching inventory or sending chat; treating it as guaranteed will throw on unusual server setups or custom missions.Avoid double rewards on custom missions
Custom
BaseMissionsubclasses call the same hook. If you reward by mission name, verify the instance is the one you expect or you may grant rewards twice.
Build a plugin with OnMissionSucceeded
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 OnMissionSucceeded
Generate