Skip to content
RustPluginGenerator

OnNpcConversationEnded

OnNpcConversationEnded is called on the server when a player finishes talking to an NPCTalking NPC, just before the game removes that player from the NPC's conversingPlayers list.

Signature
void OnNpcConversationEnded(NPCTalking nPCTalking, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
nPCTalkingNPCTalkingThe NPC whose conversation is ending. It is the NPCTalking component that ran Server_OnConversationEnded, so you can read its entity position, net ID or flags.
playerBasePlayerThe player leaving the conversation, or null when the method is called without a valid player. Always null-check before using it.

Return value

The hook is called with the result ignored, so returning null, true or any value has no effect on the game. The original method continues and the player is removed from the NPC's conversingPlayers list as usual.

How it works

The hook fires inside NPCTalking.Server_OnConversationEnded, which the game runs when a conversation session with an NPC of type NPCTalking (for example mission or vendor-style dialogue NPCs) is closing. The call happens before the original method bodies out its cleanup, so at the moment your hook runs the player is still listed in conversingPlayers. Both parameters are passed straight from the method: the NPC component itself and the BasePlayer that ended the conversation.

Use the hook to react to conversation ends: close custom UI you opened for that player, hand out a reward once per NPC, log dialogue completion, or start a follow-up action. The player argument can be null in theory, so guard it. Declaring a more specific type for the second parameter will not narrow anything useful here since only BasePlayer is ever passed; making the first parameter a different type than NPCTalking would make Oxide skip calls entirely.

Because the return value is ignored, this hook cannot block or alter the conversation. It only observes. Keep the handler cheap: it can fire for every player interacting with many NPCs on a busy server.

Example plugin: Reward players the first time they finish an NPC conversation

NpcConversationReward.cs
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Npc Conversation Reward", "RustPluginGenerator", "1.0.0")]
    [Description("Gives a configurable reward the first time a player finishes a conversation with a given NPC")]
    public class NpcConversationReward : RustPlugin
    {
        private const string PermUse = "npcconversationreward.reward";

        private class PluginConfig
        {
            [JsonProperty("Reward item shortname")]
            public string ItemShortname = "scrap";

            [JsonProperty("Reward amount")]
            public int Amount = 25;

            [JsonProperty("Reward only for permission holders")]
            public bool PermissionOnly = false;
        }

        private class StoredData
        {
            public Dictionary<string, List<ulong>> Completed = new Dictionary<string, List<ulong>>();
        }

        private PluginConfig config;
        private StoredData data;

        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"] = "You received {0} x {1} for finishing the conversation.",
                ["NoItem"] = "Reward item '{0}' is invalid, contact an admin."
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
        }

        private void Unload()
        {
            Interface.Oxide.DataFileSystem.WriteObject(Name, data);
        }

        private void OnNpcConversationEnded(NPCTalking nPCTalking, BasePlayer player)
        {
            if (nPCTalking == null || player == null || nPCTalking.IsDestroyed) return;
            if (config.PermissionOnly && !permission.UserHasPermission(player.UserIDString, PermUse)) return;

            var npcId = nPCTalking.net != null ? nPCTalking.net.ID.Value : 0UL;
            var key = npcId.ToString();

            List<ulong> players;
            if (!data.Completed.TryGetValue(key, out players))
            {
                players = new List<ulong>();
                data.Completed[key] = players;
            }

            if (players.Contains(player.userID.Get())) return;

            var item = ItemManager.CreateByName(config.ItemShortname, Mathf.Max(1, config.Amount));
            if (item == null)
            {
                PrintWarning(string.Format("Invalid reward item shortname: {0}", config.ItemShortname));
                return;
            }

            player.GiveItem(item);
            players.Add(player.userID.Get());
            player.ChatMessage(Msg("Reward", player.UserIDString, item.amount, item.info.displayName.english));
        }
    }
}

The plugin listens on OnNpcConversationEnded and, for each completed conversation, records a pair of identifiers (player user ID and NPC net ID) in a saved data file so the same player cannot farm the same NPC repeatedly. On a first completion it grants a configurable item and condition through ItemManager.CreateByName, warns in chat through the message table, and marks the data dirty. Init registers the npcconversationreward.reward permission, which limits rewards to selected players. All state lives in oxide/data/NpcConversationReward.json via Interface.Oxide.DataFileSystem, and Unload saves it. Null checks cover a missing player, a destroyed NPC and an invalid shortname in config.

Common use cases

  • One-time dialogue rewards

    Give an item, a currency through a referenced plugin or a permission when a player finishes talking to a specific NPC for the first time.

  • Close custom dialogue UI

    If you draw your own CUI panels around NPC interaction, destroy the panel for that player here so it does not stay on screen after the conversation closes.

  • Track NPC dialogue progress

    Append conversation completions to a data file to build quest-style progression, then unlock later NPCs or commands based on the count.

Pitfalls

  • The return value does nothing

    Returning false or any other value will not cancel the conversation end or keep the player in the NPC's list. Use OnNpcConversationStart or the respond hooks if you need to influence dialogue.

  • The player can be null

    The original method checks player != null after the hook call, so your code must do the same before touching UserIDString, inventory or network state.

  • Fires per player and per NPC

    On a populated server with many NPC interactions this hook can run often. Do the minimum work in the handler, save data on a timer or in Unload instead of writing to disk every call.

Build a plugin with OnNpcConversationEnded

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: One-time dialogue rewards using the OnNpcConversationEnded hook, with a config file and a permission
Generate this plugin

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 OnNpcConversationEnded

Generate