<?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-10-21T20:42:55Z</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=137&amp;oldid=prev</id>
		<title>DocumentationBot: Version 1</title>
		<link rel="alternate" type="text/html" href="https://developer.vellocetsoftware.com/w/index.php?title=Grimwar/VMod&amp;diff=137&amp;oldid=prev"/>
		<updated>2026-10-01T04:13:05Z</updated>

		<summary type="html">&lt;p&gt;Version 1&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{GameNav}}&lt;br /&gt;
A VMod adds server behavior to Grimwar using C#. Use it for commands, player services, persistent settings, or a custom game mode. For doors, triggers, and map event routing, [[Grimwar/VSig|VSig]] is usually enough.&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;
== Create a standalone VMod ==&lt;br /&gt;
&lt;br /&gt;
# Launch the Grimwar SDK&amp;#039;s VSDK app. Script-only VMods build without Unity; native media uses the SDK compiler.&lt;br /&gt;
# Under &amp;#039;&amp;#039;&amp;#039;Standalone resources&amp;#039;&amp;#039;&amp;#039;, choose &amp;#039;&amp;#039;&amp;#039;VMod&amp;#039;&amp;#039;&amp;#039; and select &amp;#039;&amp;#039;&amp;#039;Create…&amp;#039;&amp;#039;&amp;#039;. Choose a parent folder outside the SDK installation.&lt;br /&gt;
# Select &amp;#039;&amp;#039;&amp;#039;Open folder&amp;#039;&amp;#039;&amp;#039; and edit &amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt;: set a stable ID, name, author, version, and entry point.&lt;br /&gt;
# Select &amp;#039;&amp;#039;&amp;#039;Edit source&amp;#039;&amp;#039;&amp;#039; and implement &amp;lt;code&amp;gt;Grimwar.ModApi.IMod&amp;lt;/code&amp;gt;. Save your files in the external editor.&lt;br /&gt;
# Select &amp;#039;&amp;#039;&amp;#039;Validate&amp;#039;&amp;#039;&amp;#039; to check the source against Grimwar&amp;#039;s public API.&lt;br /&gt;
# Choose a build output folder outside the source folder and select &amp;#039;&amp;#039;&amp;#039;Build&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# Choose the installed Grimwar executable and select &amp;#039;&amp;#039;&amp;#039;Play in game&amp;#039;&amp;#039;&amp;#039;. This rebuilds the package and launches Grimwar with that output folder as its add-on overlay. Start a local host to execute the VMod.&lt;br /&gt;
&lt;br /&gt;
You maintain &amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt; and its declared &amp;lt;code&amp;gt;.cs&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;.csx&amp;lt;/code&amp;gt; sources. The SDK generates the installable package and its &amp;lt;code&amp;gt;addon.json&amp;lt;/code&amp;gt;. Rebuilding replaces only an earlier standalone package with the same ID; it never overwrites your source folder or a mixed-content package.&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;author&amp;quot;: &amp;quot;Your name&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;: 15,&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.cs&amp;quot;],&lt;br /&gt;
  &amp;quot;dependencies&amp;quot;: [],&lt;br /&gt;
  &amp;quot;requires&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;
Use lowercase letters, digits, dots, underscores, and hyphens for stable IDs (up to 96 characters). New code targets API 15; APIs 11 through 15 are supported. The entry point must be a public, concrete &amp;lt;code&amp;gt;IMod&amp;lt;/code&amp;gt; class with a public parameterless constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt; is &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;. &amp;lt;code&amp;gt;dependencies&amp;lt;/code&amp;gt; lists VMod IDs that must load first; &amp;lt;code&amp;gt;requires&amp;lt;/code&amp;gt; lists add-on IDs that provide content. &amp;lt;code&amp;gt;permissions&amp;lt;/code&amp;gt; declares command/menu permission names; it does not grant them to players. &amp;lt;code&amp;gt;serverOnly&amp;lt;/code&amp;gt; must remain &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Attach a VMod to a map ==&lt;br /&gt;
&lt;br /&gt;
# Open and save the map in Vertex using the Grimwar game profile.&lt;br /&gt;
# In &amp;#039;&amp;#039;&amp;#039;Map settings → SDK resources&amp;#039;&amp;#039;&amp;#039;, choose &amp;#039;&amp;#039;&amp;#039;VMod&amp;#039;&amp;#039;&amp;#039; and select &amp;#039;&amp;#039;&amp;#039;Create…&amp;#039;&amp;#039;&amp;#039;. To reuse source, choose &amp;#039;&amp;#039;&amp;#039;Attach…&amp;#039;&amp;#039;&amp;#039; and select its folder inside the map source folder.&lt;br /&gt;
# Select &amp;#039;&amp;#039;&amp;#039;Edit source&amp;#039;&amp;#039;&amp;#039;. Edit the generated &amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt; in the same folder to set its identity and source list.&lt;br /&gt;
# Implement map behavior through the same &amp;lt;code&amp;gt;Grimwar.ModApi&amp;lt;/code&amp;gt; used by standalone VMods. The starter subscribes to &amp;lt;code&amp;gt;map.ready&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Save the external files and map, then build the map. Invalid code or unsupported API calls stop compilation.&lt;br /&gt;
# Select &amp;#039;&amp;#039;&amp;#039;Play in game&amp;#039;&amp;#039;&amp;#039; to compile and test in the installed game.&lt;br /&gt;
&lt;br /&gt;
Map scripts are included inside the compiled scene. There is one map package to install or publish; do not build a companion standalone package for the attached scripts. &amp;#039;&amp;#039;&amp;#039;Detach&amp;#039;&amp;#039;&amp;#039; removes the map reference and keeps your source files.&lt;br /&gt;
&lt;br /&gt;
The server initializes attached modules before &amp;lt;code&amp;gt;map.ready&amp;lt;/code&amp;gt;, filters their VSig subscriptions to that map, and disposes them before removing map entities. Each load creates fresh module instances; explicitly persisted storage remains per module ID. Standalone VMods retain server-session lifetime. Clients receive the scene data but never execute VMods.&lt;br /&gt;
&lt;br /&gt;
Attached scripts cannot request admin permissions, external-service capabilities or declarations. Install privileged VMods separately on the server. Dependencies resolve across the map and installed server modules. Missing dependencies, duplicate active module IDs, compilation errors, and failed initialization prevent the map from starting. Unload maps with attached scripts before reloading server VMods.&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;
&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. The host removes commands, event subscriptions, timers, effects, scripted bots, and dynamic modes when the package unloads.&lt;br /&gt;
&lt;br /&gt;
== Add sounds or data ==&lt;br /&gt;
&lt;br /&gt;
Open the module&amp;#039;s Content controls to import files or reference an installed media pack. Use &amp;lt;code&amp;gt;context.Audio&amp;lt;/code&amp;gt; for sounds and API 15&amp;#039;s &amp;lt;code&amp;gt;context.Content&amp;lt;/code&amp;gt; for declared text/data. See [[Grimwar/Custom content#Use media in a VMod|Custom content in VMods]] for examples.&lt;br /&gt;
&lt;br /&gt;
An attached module&amp;#039;s Content button is beside its Edit source control in Vertex. Its assets travel with the map. A standalone module builds its assets into its own package.&lt;br /&gt;
&lt;br /&gt;
== Test and distribute ==&lt;br /&gt;
&lt;br /&gt;
Build and validate before testing. Start a local host to run the script; simply opening a client menu does not exercise server behavior. Check the command with ordinary players as well as administrators when it uses permissions.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;vmod_runtime_list&amp;lt;/code&amp;gt; to see loaded or faulted modules and &amp;lt;code&amp;gt;vmod_runtime_paths&amp;lt;/code&amp;gt; to find the server&amp;#039;s add-on directory. Copy complete built add-on folders for manual installs. Unload maps with attached modules and leave scripted game modes before using &amp;lt;code&amp;gt;vmod_runtime_reload&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For a standalone release, set &amp;lt;code&amp;gt;thumbnail&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;mod.json&amp;lt;/code&amp;gt; to a relative 1920 × 1080 PNG and enable Release package in VSDK. Publish it as VMod through Grimwar&amp;#039;s Addons screen. Map-bound modules publish inside the map&amp;#039;s Release package. Workshop subscribers receive the declared source, but only servers execute it.&lt;br /&gt;
&lt;br /&gt;
See [[Grimwar/Steam Workshop addons|Workshop publishing]] for dependencies and updates, or [[Grimwar/Dedicated servers|Dedicated servers]] for installation.&lt;br /&gt;
&lt;br /&gt;
== Larger scripts ==&lt;br /&gt;
&lt;br /&gt;
[[Grimwar/VMod reference]] covers API services, events and timers, operator configuration, game modes, permissions, bots, and VSig integration.&lt;br /&gt;
&lt;br /&gt;
VMods use a restricted C# subset. Use named public handler methods and indexed &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; loops. Direct file/network access, reflection, threads, tasks, lambdas, LINQ, and precompiled DLLs are not supported. VSDK validation reports unsupported code; a successful desktop C# build alone does not establish VMod compatibility.&lt;br /&gt;
&lt;br /&gt;
[[Category:Grimwar]] [[Category:VMod]] [[Category:Server modding]]&lt;/div&gt;</summary>
		<author><name>DocumentationBot</name></author>
	</entry>
</feed>