C# setup
The C# plugin API is two NuGet packages. The rest of the API is on Making a plugin. The C# example is a complete project to copy.
| Package | Used by |
|---|---|
vMenu.Enhanced.ClientAPI |
your client script |
vMenu.Enhanced.ServerAPI |
your server script |
Pin both to the vMenu Enhanced version your server runs. They bring the CitizenFX assemblies with them, so you do not reference those yourself.
Project layout
Section titled “Project layout”Keep the two halves in separate output folders. Each package ships its own copy of CitizenFX.Base.dll and CitizenFX.FiveM.Shared.dll, and two files with the same name cannot share a folder.
MyPlugin/ fxmanifest.lua client/ the client assembly and everything it depends on server/ the server assembly and everything it depends onEvery client side DLL has to be listed in files, because players download those rather than reading them off the server’s disk:
fx_version 'cerulean'games { 'gta5' }
files { 'client/CitizenFX.Base.dll', 'client/CitizenFX.FiveM.Shared.dll', 'client/CitizenFX.FiveM.Client.dll', 'client/MessagePack.dll', 'client/MessagePack.Annotations.dll', 'client/Microsoft.NET.StringTools.dll', 'client/vMenu.Enhanced.PluginContracts.dll', 'client/vMenu.Enhanced.ClientAPI.dll',}
client_script 'client/MyPlugin.Client.dll'server_script 'server/MyPlugin.Server.dll'Add a package reference, check for a new DLL in your client output, add a line for it. Miss one and players get an assembly load error the moment they open the menu. The server half needs no files entries.
Things specific to C#
Section titled “Things specific to C#”| Topic | Detail |
|---|---|
| Entry points | VMenuPlugin.Create on the client, VMenuServer.RegisterAsync on the server, both from an IScript’s Initialize. |
| Text | Text.Literal and Text.Key. A plain string converts to a literal by itself. |
| Gates | PluginGate.Permission and PluginGate.Setting, combined with & and |. A plain string converts to a permission gate. |
| Batches | using (plugin.BeginBatch()) { ... } |
| Inserting rows | using (menu.InsertAt(2)) { ... } |
| Positions | Counted from 0. |
| Opening menus | await menu.RequestOpenAsync(), or RequestOpenAsync(MenuPriority.Medium). See standalone menus. |
Compiler warnings
Section titled “Compiler warnings”The vMenu.Enhanced.ClientAPI package brings an analyzer that warns about the two ways a plugin can take the screen away from the player.
| Id | When |
|---|---|
VMENU001 |
RequestOpenAsync with MenuPriority.High, or a priority only known at runtime. |
VMENU002 |
RequestOpenAsync with doNotClose set, or a value only known at runtime. |
Silence one per call with #pragma warning disable VMENU001 once you have made sure the call is warranted.
On a regular (legacy) FiveM server
Section titled “On a regular (legacy) FiveM server”The same two packages also have a .NET Framework 4.6.2 build for the regular FiveM runtime. NuGet picks it when your project targets .NET Framework 4.6.2 or newer.
| Topic | Detail |
|---|---|
| Entry points | Call VMenuPlugin.Create and VMenuServer.RegisterAsync from your BaseScript’s constructor, or from an onResourceStart event handler for your own resource. Never call them from a tick. You do not have to wait for vMenu to start first: the plugin API registers as soon as vMenu is there, and again whenever it restarts. See start order and reconnecting. |
| Script files | Your client and server scripts must be named *.net.dll. |
files |
List Newtonsoft.Json.dll, System.ValueTuple.dll, vMenu.Enhanced.Polyfills.dll, vMenu.Enhanced.PluginContracts.dll and vMenu.Enhanced.ClientAPI.dll. The CitizenFX assemblies come with FiveM. |
| Newtonsoft.Json | The package ships the build legacy vMenu always used, which works in the client sandbox. Do not add the Newtonsoft.Json NuGet package next to it. |
