OnMissionStart
OnMissionStart is called by BaseMission.MissionStart before the mission's objectives are initialised for a player. Returning a non-null value cancels the start so the objective loop never runs.
object OnMissionStart(BaseMission mission, BaseMission.MissionInstance missionInstance, BasePlayer assignee)Parameters
| Parameter | Type | Description |
|---|---|---|
mission | BaseMission | The BaseMission entity that is being started, e.g. the mission game object holding the objectives array. Use mission.ShortPrefabName or net.ID to identify which mission type is running. |
missionInstance | BaseMission.MissionInstance | The per-assignee MissionInstance holding the objective progression, timer and completion state. Null-check it before touching its fields; it is the object the game mutates while objectives advance. |
assignee | BasePlayer | The BasePlayer the mission is started for. May be null when the game starts a mission without a direct assignee, so guard before reading UserIDString or transform. |
Return value
Return null (or nothing) to let the mission start normally and initialise its objectives. Return any non-null object to abort MissionStart before the objective loop, so the instance is not set up for the assignee.
How it works
The hook fires once per BaseMission.MissionStart(instance, assignee) call, right at the top of the method and before the objectives array is looped over. The game calls MissionStart when a player is assigned a spawned mission and objectives need to be activated for that instance. mission is the mission entity (its type and prefab tell you which mission it is), missionInstance is the mutable state that tracks objective progress for that player, and assignee is the player receiving it.
Because the call sits in front of the objective loop, it is the last safe point to refuse a mission: nothing has been assigned yet, so cancelling leaves the player without objectives and without a half-initialised instance. You cannot narrow dispatch by declaring a more specific parameter type here unless the game passes that exact subclass for every call, which it does not; check the mission type inside the hook instead.
Use it for gating mission access (permissions, groups, playtime, team state) and for announcing starts to other players. It fires per start, not per objective, so keep it cheap and avoid per-tick work.
Example plugin: Restrict missions to permission holders with a chat notice
using System.Collections.Generic;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Mission Permission Gate", "RustPluginGenerator", "1.0.0")]
[Description("Restricts mission starts to players with a permission and announces valid starts.")]
public class MissionPermissionGate : RustPlugin
{
private const string PermUse = "missionpermissiongate.use";
private void Init()
{
permission.RegisterPermission(PermUse, this);
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Blocked"] = "You do not have access to missions yet.",
["Announce"] = "{0} has started a mission: {1}"
}, this);
}
private string Msg(string key, string userId = null, params object[] args)
{
return string.Format(lang.GetMessage(key, this, userId), args);
}
private object OnMissionStart(BaseMission mission, BaseMission.MissionInstance missionInstance, BasePlayer assignee)
{
if (mission == null || missionInstance == null || assignee == null)
return null;
if (assignee.IsAdmin || permission.UserHasPermission(assignee.UserIDString, PermUse))
{
string missionName = mission.GetType().Name ?? "unknown";
Server.Broadcast(Msg("Announce", null, assignee.displayName, missionName));
return null;
}
assignee.ChatMessage(Msg("Blocked", assignee.UserIDString));
return false;
}
}
}The plugin registers a missionpermissiongate.use permission and, in OnMissionStart, checks the assignee against it (or IsAdmin). When the player lacks access, the hook returns false, which stops the mission start. Players who are allowed get a server-wide broadcast naming the player and the mission's runtime type name, using the Announce language string. Null checks on mission, missionInstance and assignee keep NPC or unsolicited starts from throwing. No config is needed, so the plugin stays a single focused file; messages live in the language file so admins can translate them.
Common use cases
Rank-gated mission access
Check a permission or a group before allowing the mission; return a non-null object to block it for players who have not earned access, and notify them through lang messages.
Team state checks
Read
assignee.currentTeamand refuse the start when the player is not in a team or their team leader has missions disabled, so group servers can keep mission progress per squad.Mission announcements
Post a server-wide message when a mission starts for a player, using
missionidentity to name the objective set, without modifying the game path.
Pitfalls
Assignee can be null
The game may start a mission without a direct player reference. Dereferencing
assignee.UserIDStringor readingtransformwithout a null check throws inside the hook and can break the start path for every mission.Cancelling leaves no objectives
A non-null return skips the objective loop entirely, so the player receives a mission instance that will never progress. Only cancel when you intend to (and have a way to) prevent the assignment from happening elsewhere.
Runs per start, not per player
Do not assume one call per player session; the mission system may start instances for other assignees. Keep the hook cheap and never use PrintWarning or heavy loops inside it.
Build a plugin with OnMissionStart
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 OnMissionStart
Generate