<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://developer.vellocetsoftware.com/index.php?action=history&amp;feed=atom&amp;title=Grimwar%2FVMod</id>
	<title>Grimwar/VMod - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://developer.vellocetsoftware.com/index.php?action=history&amp;feed=atom&amp;title=Grimwar%2FVMod"/>
	<link rel="alternate" type="text/html" href="https://developer.vellocetsoftware.com/w/index.php?title=Grimwar/VMod&amp;action=history"/>
	<updated>2026-08-25T07:05:12Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://developer.vellocetsoftware.com/w/index.php?title=Grimwar/VMod&amp;diff=27&amp;oldid=prev</id>
		<title>DocumentationBot: Publish SDK documentation</title>
		<link rel="alternate" type="text/html" href="https://developer.vellocetsoftware.com/w/index.php?title=Grimwar/VMod&amp;diff=27&amp;oldid=prev"/>
		<updated>2026-08-25T05:13:03Z</updated>

		<summary type="html">&lt;p&gt;Publish SDK documentation&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{GameNav}}&lt;br /&gt;
{{Notice|title=Version target|This guide covers VMod API 5 and addon schema 9. A server rejects packages built for another API or schema.}}&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;VMod&amp;#039;&amp;#039;&amp;#039; is Grimwar&amp;#039;s server-authoritative C# mod runtime. The server compiles source with Roslyn C# 2.0 and runs the result through dotnow. Grimwar itself remains an IL2CPP build.&lt;br /&gt;
&lt;br /&gt;
A VMod can use the public &amp;lt;code&amp;gt;Grimwar.ModApi&amp;lt;/code&amp;gt; services. It cannot reference Unity, FishNet, Grimwar internals, arbitrary files, sockets, reflection, processes, or native code.&lt;br /&gt;
&lt;br /&gt;
== What a VMod package contains ==&lt;br /&gt;
&lt;br /&gt;
The addon folder is the install unit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
community.hello/&lt;br /&gt;
  addon.json&lt;br /&gt;
  mod.json&lt;br /&gt;
  HelloMod.csx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;.csx&amp;lt;/code&amp;gt; below a Unity project&amp;#039;s &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder so the editor recognizes C# without asking Unity to compile the file. A VMod kept outside Unity can use &amp;lt;code&amp;gt;.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;addon.json&amp;lt;/code&amp;gt; registers the folder with Grimwar&amp;#039;s addon catalog:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;schemaVersion&amp;quot;: 9,&lt;br /&gt;
  &amp;quot;id&amp;quot;: &amp;quot;community.hello&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Hello Server&amp;quot;,&lt;br /&gt;
  &amp;quot;author&amp;quot;: &amp;quot;Ada&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,&lt;br /&gt;
  &amp;quot;distributionProfile&amp;quot;: &amp;quot;development&amp;quot;,&lt;br /&gt;
  &amp;quot;buildId&amp;quot;: &amp;quot;0123456789abcdef0123456789abcdef&amp;quot;,&lt;br /&gt;
  &amp;quot;createdUtc&amp;quot;: &amp;quot;2026-08-25T00:00:00Z&amp;quot;,&lt;br /&gt;
  &amp;quot;sdkVersion&amp;quot;: &amp;quot;1.0.3&amp;quot;,&lt;br /&gt;
  &amp;quot;unityVersion&amp;quot;: &amp;quot;6000.3.17f1&amp;quot;,&lt;br /&gt;
  &amp;quot;requires&amp;quot;: [],&lt;br /&gt;
  &amp;quot;contents&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;kind&amp;quot;: &amp;quot;mods&amp;quot;,&lt;br /&gt;
      &amp;quot;id&amp;quot;: &amp;quot;community.hello&amp;quot;,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;Hello Server&amp;quot;,&lt;br /&gt;
      &amp;quot;mod&amp;quot;: { &amp;quot;manifest&amp;quot;: &amp;quot;mod.json&amp;quot; }&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The addon ID, content ID, and VMod ID must resolve to the same normalized ID. &amp;lt;code&amp;gt;requires&amp;lt;/code&amp;gt; contains addon IDs. Grimwar enables and loads required addons before the package that names them.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt; defines the code entry point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;id&amp;quot;: &amp;quot;community.hello&amp;quot;,&lt;br /&gt;
  &amp;quot;name&amp;quot;: &amp;quot;Hello Server&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,&lt;br /&gt;
  &amp;quot;apiVersion&amp;quot;: 5,&lt;br /&gt;
  &amp;quot;kind&amp;quot;: &amp;quot;addon&amp;quot;,&lt;br /&gt;
  &amp;quot;entryPoint&amp;quot;: &amp;quot;CommunityMods.HelloMod&amp;quot;,&lt;br /&gt;
  &amp;quot;sourceFiles&amp;quot;: [&amp;quot;HelloMod.csx&amp;quot;],&lt;br /&gt;
  &amp;quot;dependencies&amp;quot;: [],&lt;br /&gt;
  &amp;quot;permissions&amp;quot;: [],&lt;br /&gt;
  &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
  &amp;quot;serverOnly&amp;quot;: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Field !! Rule&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || Stable ID up to 96 characters. Use lowercase letters, digits, dots, underscores, and hyphens.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;apiVersion&amp;lt;/code&amp;gt; || Must equal the server&amp;#039;s current VMod API, currently &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;addon&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;gameMode&amp;lt;/code&amp;gt;. Administrative host operations require &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;entryPoint&amp;lt;/code&amp;gt; || Fully qualified, non-abstract class implementing &amp;lt;code&amp;gt;IMod&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sourceFiles&amp;lt;/code&amp;gt; || Relative &amp;lt;code&amp;gt;.cs&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.csx&amp;lt;/code&amp;gt; paths contained by this addon.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dependencies&amp;lt;/code&amp;gt; || VMod IDs that must load first.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;permissions&amp;lt;/code&amp;gt; || Permission names the VMod may attach to its commands and menu items. This does not grant those permissions to players.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;serverOnly&amp;lt;/code&amp;gt; || Must be &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; in API 5.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Write the entry class ==&lt;br /&gt;
&lt;br /&gt;
This mod registers &amp;lt;code&amp;gt;hello&amp;lt;/code&amp;gt; for chat and authenticated consoles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using Grimwar.ModApi;&lt;br /&gt;
&lt;br /&gt;
namespace CommunityMods&lt;br /&gt;
{&lt;br /&gt;
    public sealed class HelloMod : IMod&lt;br /&gt;
    {&lt;br /&gt;
        private IModContext _context;&lt;br /&gt;
&lt;br /&gt;
        public void OnLoad(IModContext context)&lt;br /&gt;
        {&lt;br /&gt;
            _context = context;&lt;br /&gt;
            var result = context.Commands.Register(new ModCommandSpec&lt;br /&gt;
            {&lt;br /&gt;
                Name = &amp;quot;hello&amp;quot;,&lt;br /&gt;
                Description = &amp;quot;Say hello to the server.&amp;quot;,&lt;br /&gt;
                MinimumArguments = 0,&lt;br /&gt;
                MaximumArguments = 0,&lt;br /&gt;
                AllowChat = true,&lt;br /&gt;
                AllowConsole = true,&lt;br /&gt;
                ChatAliases = new[] { &amp;quot;hi&amp;quot; }&lt;br /&gt;
            }, &amp;quot;OnHello&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (!result.Success)&lt;br /&gt;
                throw new InvalidOperationException(result.Message);&lt;br /&gt;
&lt;br /&gt;
            context.Log.Write(&amp;quot;Hello Server loaded.&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public void OnUnload()&lt;br /&gt;
        {&lt;br /&gt;
            _context = null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public void OnHello(IModCommandInvocation command)&lt;br /&gt;
        {&lt;br /&gt;
            var name = command.Caller == null&lt;br /&gt;
                ? &amp;quot;server console&amp;quot;&lt;br /&gt;
                : command.Caller.DisplayName;&lt;br /&gt;
            _context.Messages.Broadcast(&amp;quot;Hello from &amp;quot; + name + &amp;quot;!&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Registrations take a method name because delegates do not cross the interpreter boundary. Grimwar verifies the method before accepting the registration.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Registration !! Handler signature&lt;br /&gt;
|-&lt;br /&gt;
| Command || One &amp;lt;code&amp;gt;IModCommandInvocation&amp;lt;/code&amp;gt; parameter&lt;br /&gt;
|-&lt;br /&gt;
| Event || One &amp;lt;code&amp;gt;ModEvent&amp;lt;/code&amp;gt; parameter&lt;br /&gt;
|-&lt;br /&gt;
| Timer || One &amp;lt;code&amp;gt;ModTimerInvocation&amp;lt;/code&amp;gt; parameter&lt;br /&gt;
|-&lt;br /&gt;
| VSig subscription || One &amp;lt;code&amp;gt;ModVSigEvent&amp;lt;/code&amp;gt; parameter&lt;br /&gt;
|-&lt;br /&gt;
| Menu || One &amp;lt;code&amp;gt;ModMenuInvocation&amp;lt;/code&amp;gt; parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OnUnload&amp;lt;/code&amp;gt; must clear references and release any VMod-owned state that is not already scoped through the host. Commands, event subscriptions, timers, effects, and dynamic modes are removed when the package unloads.&lt;br /&gt;
&lt;br /&gt;
== Public API services ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;IModContext&amp;lt;/code&amp;gt; supplies the following services:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Service !! Use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Log&amp;lt;/code&amp;gt; || Namespaced server log messages.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Commands&amp;lt;/code&amp;gt; || Chat, local console, server console, and RCON commands with aliases, argument limits, and permissions.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Players&amp;lt;/code&amp;gt; || Immutable player snapshots and selectors such as exact name, unique partial name, Steam ID, client ID, &amp;lt;code&amp;gt;@me&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;@random&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Messages&amp;lt;/code&amp;gt; || Broadcast or private chat, escaped colored segments, and major or minor HUD messages.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Menus&amp;lt;/code&amp;gt; || Server-owned numeric menus and shared VMod Admin entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Effects&amp;lt;/code&amp;gt; || Health, damage, slap, slay, timed damage or movement multipliers, weapon restrictions, and screen shake.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Audio&amp;lt;/code&amp;gt; || Play addon-owned audio globally, for one player, or at a world position.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Admin&amp;lt;/code&amp;gt; || Permission checks, immunity-aware targeting, kick, ban, and unban for &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt; packages.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GameMode&amp;lt;/code&amp;gt; || Read mode state. The active &amp;lt;code&amp;gt;gameMode&amp;lt;/code&amp;gt; package can change teams, respawn players, and end rounds or matches.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Events&amp;lt;/code&amp;gt; || Player, combat, round, match, and mode-change subscriptions.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Scheduler&amp;lt;/code&amp;gt; || One-shot and repeating callbacks.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Clock&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Random&amp;lt;/code&amp;gt; || Monotonic or Unix time and a per-VMod random source.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Storage&amp;lt;/code&amp;gt; || Sandboxed typed key/value data under the VMod&amp;#039;s state directory.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VSig&amp;lt;/code&amp;gt; || Emit or subscribe to bounded VSig signals.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Mods&amp;lt;/code&amp;gt; || Inspect loaded packages. Administrative VMods can request reloads.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ModPlayer&amp;lt;/code&amp;gt; and other API objects are snapshots. Keep the stable player ID and call &amp;lt;code&amp;gt;Players.Find&amp;lt;/code&amp;gt; again when current state matters.&lt;br /&gt;
&lt;br /&gt;
== Events and timers ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
public void OnLoad(IModContext context)&lt;br /&gt;
{&lt;br /&gt;
    _context = context;&lt;br /&gt;
&lt;br /&gt;
    var subscription = context.Events.Subscribe(&lt;br /&gt;
        ModEventKind.PlayerSpawned,&lt;br /&gt;
        &amp;quot;OnPlayerSpawned&amp;quot;);&lt;br /&gt;
    if (!subscription.Success)&lt;br /&gt;
        throw new InvalidOperationException(subscription.Message);&lt;br /&gt;
&lt;br /&gt;
    context.Scheduler.Once(5f, &amp;quot;OnTimer&amp;quot;, &amp;quot;startup&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnPlayerSpawned(ModEvent value)&lt;br /&gt;
{&lt;br /&gt;
    if (value.Player != null)&lt;br /&gt;
        _context.Messages.Tell(value.Player.Id, &amp;quot;Welcome back.&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnTimer(ModTimerInvocation value)&lt;br /&gt;
{&lt;br /&gt;
    _context.Log.Write(value.TimerId + &amp;quot; fired with state &amp;quot; + value.State);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Combat events put the victim in &amp;lt;code&amp;gt;Player&amp;lt;/code&amp;gt; and a connected attacker or killer in &amp;lt;code&amp;gt;OtherPlayer&amp;lt;/code&amp;gt;. Read &amp;lt;code&amp;gt;Amount&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HealthAfter&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WeaponId&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AbilityId&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WasHeadshot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WasCritical&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;WasSuicide&amp;lt;/code&amp;gt; for scalar event data.&lt;br /&gt;
&lt;br /&gt;
Timers have a 50 ms minimum interval, a 24-hour maximum delay, and a limit of 256 timers per VMod. Cancel repeating timers when their owning activity ends.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
&lt;br /&gt;
A permission on &amp;lt;code&amp;gt;ModCommandSpec.Permission&amp;lt;/code&amp;gt; must also appear in &amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt;. The manifest declaration allows the VMod to ask for the permission; server admin configuration decides who has it.&lt;br /&gt;
&lt;br /&gt;
VMod Admin reads groups and users from &amp;lt;code&amp;gt;&amp;amp;lt;data&amp;amp;gt;/config/mods&amp;lt;/code&amp;gt;. A wildcard such as &amp;lt;code&amp;gt;admin.*&amp;lt;/code&amp;gt; grants one namespace. A leading minus sign is an explicit deny and wins over grants. Immunity prevents one administrator from targeting another administrator with the same or higher value.&lt;br /&gt;
&lt;br /&gt;
Do not put an RCON password or another secret in VMod source, manifests, or addon configuration.&lt;br /&gt;
&lt;br /&gt;
== Send signals to VSig ==&lt;br /&gt;
&lt;br /&gt;
Every VMod owns a source alias named &amp;lt;code&amp;gt;mod:&amp;amp;lt;mod-id&amp;amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
_context.VSig.Emit(&amp;quot;round_started&amp;quot;, _context.GameMode.ActiveId);&lt;br /&gt;
_context.VSig.EmitFrom(&lt;br /&gt;
    &amp;quot;mod:community.hello.stage&amp;quot;,&lt;br /&gt;
    &amp;quot;opened&amp;quot;,&lt;br /&gt;
    3,&lt;br /&gt;
    &amp;quot;sewer_gate&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A custom source must be the owned alias or a child below it. Payloads can contain at most eight null, string, Boolean, or numeric values. Send a 64-bit identifier such as a Steam ID as a string.&lt;br /&gt;
&lt;br /&gt;
A VMod can subscribe to a map signal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
context.VSig.Subscribe(&amp;quot;escape_trigger&amp;quot;, &amp;quot;on_executed&amp;quot;, &amp;quot;OnEscape&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
public void OnEscape(ModVSigEvent value)&lt;br /&gt;
{&lt;br /&gt;
    _context.Log.Write(value.SourceAlias + &amp;quot;.&amp;quot; + value.OutputName);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[Grimwar/VSig#Signals shared with VMod|Signals shared with VMod]] for the map side.&lt;br /&gt;
&lt;br /&gt;
== Supported C# subset ==&lt;br /&gt;
&lt;br /&gt;
VMods can use ordinary control flow, classes, structs, enums, arrays, strings, &amp;lt;code&amp;gt;StringBuilder&amp;lt;/code&amp;gt;, and approved &amp;lt;code&amp;gt;System.Collections&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;System.Collections.Generic&amp;lt;/code&amp;gt; shapes.&lt;br /&gt;
&lt;br /&gt;
The validator rejects file and network I/O, reflection, processes, console or environment access, threads, tasks, Unity or Grimwar internals, native interop, unsafe code, &amp;lt;code&amp;gt;typeof&amp;lt;/code&amp;gt;, async methods, iterators, lambdas, LINQ queries, &amp;lt;code&amp;gt;try&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;catch&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;finally&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;using&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lock&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;foreach&amp;lt;/code&amp;gt;, precompiled DLLs, and extra assembly references. Use indexed &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; loops and explicit cleanup.&lt;br /&gt;
&lt;br /&gt;
Compilation alone does not guarantee that an arbitrary generic combination exists in the IL2CPP host. Start with arrays, &amp;lt;code&amp;gt;List&amp;amp;lt;T&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Dictionary&amp;amp;lt;string, T&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;HashSet&amp;amp;lt;string&amp;amp;gt;&amp;lt;/code&amp;gt; using types present in the public API and bundled examples.&lt;br /&gt;
&lt;br /&gt;
== Install and test a VMod ==&lt;br /&gt;
&lt;br /&gt;
# Run &amp;lt;code&amp;gt;vmod_runtime_paths&amp;lt;/code&amp;gt; through an authenticated server console or RCON session. Use the printed addon path instead of guessing a platform-specific data directory.&lt;br /&gt;
# Copy the complete addon folder into &amp;lt;code&amp;gt;&amp;amp;lt;data&amp;amp;gt;/addons&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Restart the server, or run &amp;lt;code&amp;gt;vmod_runtime_reload&amp;lt;/code&amp;gt; while no scripted game mode is active.&lt;br /&gt;
# Run &amp;lt;code&amp;gt;vmod_runtime_list&amp;lt;/code&amp;gt; and confirm the package is loaded and not faulted.&lt;br /&gt;
# Exercise every chat and console alias with empty, quoted, invalid, and maximum-length arguments.&lt;br /&gt;
# Run the test again with a non-admin player when the VMod declares permissions.&lt;br /&gt;
# Reload it more than once and check that handlers, timers, commands, and effects do not duplicate.&lt;br /&gt;
&lt;br /&gt;
Useful server commands:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Command !! Result&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vmod_runtime_list&amp;lt;/code&amp;gt; || Lists loaded and faulted VMods.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vmod_runtime_reload&amp;lt;/code&amp;gt; || Refreshes addons and permissions, recompiles changed source, and reloads in dependency order.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vmod_runtime_reload_admins&amp;lt;/code&amp;gt; || Reloads admin groups and users without unloading VMods.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vmod_runtime_paths&amp;lt;/code&amp;gt; || Prints addon, config, state, and compiler-cache roots.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sv_vmod_enabled 0&amp;lt;/code&amp;gt; || Disables the VMod runtime at startup.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The server refuses &amp;lt;code&amp;gt;vmod_runtime_reload&amp;lt;/code&amp;gt; while a scripted game mode is active. Change to a native mode first.&lt;br /&gt;
&lt;br /&gt;
== Distribution rules ==&lt;br /&gt;
&lt;br /&gt;
VMod-only packages are currently installed manually or through the development overlay. Steam Workshop publishing accepts map-only Release packages and rejects packages that contain VMods. Server-only VMod source is not installed on remote players.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;--addon-root &amp;amp;lt;absolute-folder&amp;amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;GRIMWAR_ADDON_ROOT&amp;lt;/code&amp;gt; during development to load a package directly. For ordinary installation, copy the complete folder containing &amp;lt;code&amp;gt;addon.json&amp;lt;/code&amp;gt;; a loose &amp;lt;code&amp;gt;.csx&amp;lt;/code&amp;gt; file is never an installable VMod.&lt;br /&gt;
&lt;br /&gt;
Bundled examples are available in Grimwar&amp;#039;s &amp;lt;code&amp;gt;StreamingAssets/Grimwar/Addons&amp;lt;/code&amp;gt; source tree. &amp;lt;code&amp;gt;grimwar.rtd&amp;lt;/code&amp;gt; is the smallest command and effect example. &amp;lt;code&amp;gt;grimwar.admin&amp;lt;/code&amp;gt; covers permissions and menus. &amp;lt;code&amp;gt;grimwar.zombie_mod&amp;lt;/code&amp;gt; is a scripted mode. &amp;lt;code&amp;gt;grimwar.quake_sounds&amp;lt;/code&amp;gt; combines server logic with addon-owned audio.&lt;br /&gt;
&lt;br /&gt;
[[Category:Grimwar]] [[Category:VMod]] [[Category:Server modding]]&lt;/div&gt;</summary>
		<author><name>DocumentationBot</name></author>
	</entry>
</feed>