GUIDE — How to Read & Evaluate a Rust Plugin Before Uploading
Pro vs Amateur Code | Red Flags & Green Flags | Updated March 2026 | Oxide & Carbon
Pro vs Amateur Code | Red Flags & Green Flags | Updated March 2026 | Oxide & Carbon
Before uploading any plugin to your server you should spend 5 minutes reading the code. You do not need to be a programmer — this guide shows you exactly what to look for to tell if a plugin was written by a professional or an amateur, and whether it is safe to run on your server.
Why This Matters
A badly written plugin can:
- Crash your server under load
- Cause massive memory leaks over time
- Delete player data on server restart
- Open security holes that allow console injection
- Conflict silently with other plugins causing impossible-to-debug errors
A well-written plugin runs for weeks without issues, uses minimal resources, and fails gracefully when something goes wrong.
Step 1 — Check the Plugin Header
The very first lines tell you a lot. Open the .cs file in Notepad++ or VS Code and look at the top.
✔ Professional header:
Code:
[Info("BetterChat", "OxideMod", "5.2.3")]
[Description("Enhances the in-game chat with groups, colors, and titles")]
✘ Amateur header:
Code:
[Info("myplugin", "unknown", "1.0.0")]
[Description("plugin")]
| What to check | Green flag | Red flag |
|---|---|---|
| Plugin name | Clear descriptive name | "myplugin", "test", "untitled" |
| Author | Known name matching seller | "unknown", "anon", blank |
| Version | 3 digits e.g. 2.1.4 | "1.0" only — never updated |
| Description | Clear sentence what it does | Empty or just "plugin" |
Step 2 — Look at How Data Is Saved
Bad data handling = player data loss on restart. This is the most important thing to check.
✔ Professional — uses Oxide Interface with error handling:
Code:
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, _storedData);
}
private void LoadData()
{
try
{
_storedData = Interface.Oxide.DataFileSystem
.ReadObject<StoredData>(Name) ?? new StoredData();
}
catch
{
_storedData = new StoredData();
PrintWarning("Data file corrupted — creating new file.");
}
}
✘ Amateur — writes raw files with no error handling:
Code:
private void SaveData()
{
File.WriteAllText("data.json", JsonConvert.SerializeObject(data));
}
Why it matters: Raw file writes with no try/catch will permanently corrupt your player data if the server crashes mid-write. Professional code uses Oxide's built-in data system which handles this safely.
Step 3 — Check for Memory Leaks
Memory leaks are the most common performance killer on modded servers. Every time you reload a plugin without an Unload method, old timers, UI elements and cached data stay in RAM forever.
✔ Professional — cleans up everything on Unload:
Code:
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList)
DestroyUI(player);
_cachedData.Clear();
_timers.ForEach(t => t?.Destroy());
_timers.Clear();
}
✘ Amateur — no Unload method anywhere in the file:
Code:
// ... plugin just ends here with no cleanup at all
}
Also check how timers are stored:
Code:
// ✔ Good — stored so it can be destroyed on unload
private Timer _repeatingTimer;
_repeatingTimer = timer.Every(60f, DoSomething);
// ✘ Bad — fire and forget, never cleaned up
timer.Every(60f, DoSomething);
Step 4 — Check Permission Registration
✔ Professional — registers all permissions in Init:
Code:
private void Init()
{
permission.RegisterPermission("myplugin.use", this);
permission.RegisterPermission("myplugin.admin", this);
permission.RegisterPermission("myplugin.vip", this);
}
✘ Amateur — checks permissions without registering them first:
Code:
private void OnPlayerConnected(BasePlayer player)
{
if (permission.UserHasPermission(player.UserIDString, "myplugin.use"))
{
// this will ALWAYS return false
// permission was never registered
}
}
Why it matters: Unregistered permissions never appear in oxide.show perms and always return false. The plugin appears broken and you spend hours debugging something that was never going to work.
Step 5 — Check Config Handling
✔ Professional — merges config with defaults, handles errors:
Code:
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) LoadDefaultConfig();
SaveConfig();
}
catch
{
PrintWarning("Config error — loading defaults.");
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig()
{
_config = new Configuration
{
MaxPlayers = 100,
EnableMessages = true,
Prefix = "[Server]"
};
}
✘ Amateur — crashes if any config key is missing:
Code:
void Loaded()
{
maxPlayers = (int)Config["MaxPlayers"];
// throws NullReferenceException if key doesn't exist
// server crashes on plugin load
}
Step 6 — Quick Red Flag Checklist (Ctrl+F in Notepad++)
Scan the plugin for these in under 2 minutes:
| Search for | Red flag if found |
|---|---|
| System.IO.File | Raw file access — data loss risk |
| Thread.Sleep | Blocks server main thread — causes freezes |
| catch { } | Empty catch — swallows all errors silently |
| while(true) | Infinite loop — server freeze risk |
| Process.Start | Executes system commands — major security hole |
| WebClient | Synchronous HTTP — blocks main thread |
| Search for | Green flag if found |
|---|---|
| void Unload() | Plugin cleans up properly |
| try { } catch | Error handling exists |
| Interface.Oxide | Uses official Oxide API correctly |
| permission.Register | Permissions registered properly |
| webrequest.Enqueue | Async HTTP — correct approach |
Step 7 — Judge Code Size vs Claimed Features
| Plugin size | What it usually means |
|---|---|
| Under 100 lines | Simple utility — fine for small tasks |
| 100–500 lines | Standard plugin — check all basics above |
| 500–2000 lines | Complex — check Unload and data handling carefully |
| Over 2000 lines | Large paid plugin — expect high quality at this size |
Warning: A plugin claiming to do something complex in only 50 lines is almost certainly broken or incomplete.
Summary — 5-Minute Plugin Check
- Check the header — real author, proper version, clear description
- Find SaveData/LoadData — must use Oxide data system with try/catch
- Find void Unload() — must exist and clean up timers, UI, cache
- Search permission.Register — must be present in Init or Loaded
- Search LoadConfig — must have default fallback
- Ctrl+F the red flag list — any hit means investigate further
If this guide helped you — drop a like
More Rust server guides coming soon.