OnItemResearch
OnItemResearch is called on a ResearchTable right after a research attempt passes the game's checks and before the timer starts, the table locks, and scrap is charged.
void OnItemResearch(ResearchTable researchTable, Item targetItem, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
researchTable | ResearchTable | The ResearchTable entity the player is using. Useful for position, owner checks (researchTable.OwnerID) and for finding the table's storage container if you need to inspect or modify scrap or placed items. |
targetItem | Item | The item in the table's target slot that is about to be researched. Its info.shortname and skin identify the blueprint; the game requires amount <= 1 before this hook runs. |
player | BasePlayer | The BasePlayer who initiated the research. Already validated by the game, but you should still null-check it before using inventory or chat APIs. |
Return value
The return value is ignored. The game calls the hook and immediately continues with CollectedForCrafting, the research timer, the lock and the scrap charge, so returning null, false or any other value changes nothing. To stop a research attempt, use CanResearchItem, which is called earlier and aborts the whole block on a non-null return.
How it works
The hook fires inside ResearchTable.DoResearch, after the method has confirmed a target item exists, CanResearchItem returned no objection, the item stack is exactly one, the item is researchable, and the loot rules allow the action. It runs before targetItem.CollectedForCrafting, before researchFinishedTime is set, before the table inventory is locked and before the scrap cost is deducted, so at this point nothing has changed yet.
Because the call happens before the table locks and the scrap is taken, this is a good place to record the attempt, charge an extra currency, or announce the research to a team. It is not a cancellation point: the game does not read a return value here, so blocking the action must be done in CanResearchItem, which runs earlier in the same method and stops the chain when it returns a non-null value.
ResearchTable is the concrete type, so declaring the first parameter as BaseEntity still works but narrows nothing; keep the exact ResearchTable type if you need members like the table's inventory. Null-check targetItem, player and researchTable before using them.
Example plugin: Announce and log successful blueprint research
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Research Announcer", "RustPluginGenerator", "1.0.0")]
[Description("Announces blueprint research to the player and their team")]
public class ResearchAnnouncer : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Announce to the researching player")]
public bool AnnounceToPlayer = true;
[JsonProperty("Announce to team members")]
public bool AnnounceToTeam = true;
[JsonProperty("Only announce these item shortnames (empty = all)")]
public List<string> WatchList = new List<string>();
}
private PluginConfig config;
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>
{
["Research.Self"] = "You started researching: {0}",
["Research.Team"] = "{0} started researching: {1}"
}, this);
}
private string Msg(string key, string userId = null, params object[] args)
{
return string.Format(lang.GetMessage(key, this, userId), args);
}
private void OnItemResearch(ResearchTable researchTable, Item targetItem, BasePlayer player)
{
if (targetItem?.info == null || player == null) return;
if (config.WatchList != null && config.WatchList.Count > 0 && !config.WatchList.Contains(targetItem.info.shortname)) return;
string itemName = targetItem.info.displayName != null ? targetItem.info.displayName.english : targetItem.info.shortname;
if (config.AnnounceToPlayer)
player.ChatMessage(Msg("Research.Self", player.UserIDString, itemName));
if (!config.AnnounceToTeam || player.currentTeam == 0) return;
var team = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
if (team == null) return;
foreach (ulong memberId in team.members)
{
if (memberId == player.userID.Get()) continue;
BasePlayer member = BasePlayer.FindByID(memberId);
if (member == null || !member.IsConnected) continue;
member.ChatMessage(Msg("Research.Team", member.UserIDString, player.displayName, itemName));
}
}
}
}The plugin listens for OnItemResearch and treats it as a confirmed research attempt, since the game already filtered out invalid cases. On each attempt it looks up the item's display name and sends a formatted message to the researching player and, if they are on a team, to every teammate using RelationshipManager.ServerInstance.FindTeam. A short config list of item shortnames can limit announcements to weapons and other high-value items, and the whole feature can be switched off from the config. Messages go through the language file so admins can translate them. Counters are kept in memory only and reset on reload, avoiding any file writes inside a hook that fires on player interaction.
Common use cases
Notify teammates of blueprint unlocks
Call
OnItemResearchto tell a player's team which blueprint they just started researching, so group members know the crafting option is about to become available.Grant extra progression rewards
Because the attempt is already validated, you can safely call a referenced plugin such as Economics or a custom points system to reward the player for researching a specific item.
Track what players research
Accumulate per-player research counts in memory or a data file (written outside the hook, e.g. on a timer or unload) to build player statistics for the server panel.
Pitfalls
It cannot cancel the research
The hook fires after all checks passed and its return value is discarded. Use
CanResearchItemif you need to block a specific item from being researched.Nothing is charged yet
Scrap has not been taken and the blueprint is not yet granted when this hook runs. Do not assume the player already paid or that the item will definitely finish, since the research can still be interrupted.
Table ownership is not implied
OwnerIDon the table identifies who placed it, which may differ fromplayeron shared bases or public tables. Do not gate rewards on the table owner unless that is your intent.
Build a plugin with OnItemResearch
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 OnItemResearch
Generate