


A comprehensive framework for V Rising mod developers to easily build commands with advanced features like command overloading, history, smart matching, and plugin-specific execution.
For Server Operators
This plugin should be installed into the BepInEx/plugins folder and be kept up to date. It is required by other plugins for commands.
dotnet add package VRising.VampireCommandFramework
[BepInDependency("gg.deca.VampireCommandFramework")]
CommandRegistry.RegisterAll()
[Command("foo")]
public void Foo(ICommandContext ctx, int count, string orValues = "with defaults", float someFloat = 3f)
=> ctx.Reply($"You'd do stuff here with your parsed {count} and stuff");
This command would execute for:
.foo 5.foo 5 works.foo 5 "or really fancy" 3.145But if you typed .foo 5.123 you'd see a generated usage message like:
*.foo (count) [orValues="with defaults"] [someFloat=3]*
.helpcount, orValues, and someFloat are automatically converted(count) [orValues="with defaults"] [someFloat=3]The framework handles these additional command patterns:
Command with parameters:
[Command("give")]
public void GiveItem(ICommandContext ctx, string item, int count = 1)
=> ctx.Reply($"Gave {count} {item}");
.give sword, .give sword 5Command groups:
[CommandGroup("admin")]
public class AdminCommands
{
[Command("ban")]
public void Ban(ICommandContext ctx, string player)
=> ctx.Reply($"Banned {player}");
}
.admin ban PlayerNameFor commands that take free-form text (a message, a reason, a timezone ID), mark the final string parameter with [Remainder] to capture everything the user typed after the preceding arguments, with spacing and quotes preserved.
[Command("say")]
public void Say(ICommandContext ctx, string channel, [Remainder] string message)
=> ctx.Reply($"[{channel}] {message}");
.say global hello everyone → channel = "global", message = "hello everyone".say global "hello, friends!" → message = "\"hello, friends!\"" (quotes kept as typed)Rules:
string.[Remainder] string reason = null.Auto-generated .help output renders a remainder parameter as <name...>, distinct from (name) for required and [name=default] for optional, so users get a visual cue for free, unless you supply a manual usage: string on [Command].
You can now create multiple commands with the same name but different parameter types:
[Command("teleport")]
public void TeleportToPlayer(ICommandContext ctx, string playerName)
=> ctx.Reply($"Teleporting to {playerName}");
[Command("teleport")]
public void TeleportToCoords(ICommandContext ctx, float x, float y)
=> ctx.Reply($"Teleporting to {x}, {y}");
When there's ambiguity, players will be presented with options and can select using .1, .2, etc.
All commands execute through a middleware pipeline. You can add your own middleware by implementing ICommandMiddleware and adding it to the CommandRegistry.Middlewares list.
Middleware is perfect for implementing permissions and roles, cooldowns, logging, command costs, rate limiting, and other cross-cutting concerns that should apply across commands even from other VCF plugins.
V Roles is an example of a Middleware plugin for VCF that adds in roles that commands and users can get assigned.
Example middleware:
public class CooldownMiddleware : CommandMiddleware
{
public override bool CanExecute(ICommandContext ctx, CommandAttribute cmd, MethodInfo method)
{
// Your cooldown logic here
return !IsOnCooldown(ctx.Name, cmd.Name);
}
}
The framework includes rich formatting utilities for enhanced chat responses:
// Text formatting
ctx.Reply($"{"Important".Bold()} message with {"emphasis".Italic()}");
ctx.Reply($"{"Warning".Underline()} - please read carefully");
// Colors (using predefined color constants)
ctx.Reply($"{"Error".Color(Color.Red)} - something went wrong");
ctx.Reply($"{"Success".Color(Color.Green)} - command completed");
ctx.Reply($"{"Info".Color(Color.LightBlue)} message");
// Text sizing
ctx.Reply($"{"Large Header".Large()} with {"small details".Small()}");
// Combining formatting
ctx.Reply($"{"Critical".Bold().Color(Color.Red).Large()} system alert!");
// Paginated replies for long content
var longText = "Very long text that might exceed chat limits...";
ctx.SysPaginatedReply(longText); // Automatically splits into multiple messages
Create converters for your custom types:
public class PlayerConverter : CommandArgumentConverter<Player>
{
public override Player Parse(ICommandContext ctx, string input)
{
var player = FindPlayer(input);
if (player == null)
throw ctx.Error($"Player '{input}' not found");
return player;
}
}
The VampireCommandFramework also provides these powerful features across all commands:
The help system has been significantly improved:
.help - Lists all available plugins.help <plugin> - Shows commands for a specific plugin.help <command> - Shows detailed help for a specific command.help-all - Shows all commands from all plugins.help-all <filter> - Shows all commands matching the filterAll help commands support case-insensitive searching and include:
Players can easily repeat previous commands:
.! - Repeat the last command.! 3 - Repeat the 3rd most recent command.! list or .! l - Show command history (last 10 commands)When a command isn't found, the system suggests up to 3 closest matches:
Command not found: .tleport
Did you mean: .teleport, .teleport-home, .tp
Some commands accept free-form text as their final argument, so you can type multi-word values (a message, a reason, a path) without wrapping them in quotes. For example:
.announce Server restart in 5 minutes
Server restart in 5 minutes is captured as a single argument. If you do type quotes, they're preserved as part of the text.
You can spot these commands in .help <command>: each parameter is shown in a distinct shape so you can tell at a glance which one eats the rest of the line.
(name): a required argument (single word or quoted).[name=default]: an optional argument with a default value.<name...>: a remainder argument that captures everything you type after the preceding arguments as this one value, spaces and all.So a help line like:
.announce (channel) <message...>
means channel is a single required word and message... eats everything else you type.
Note: if a command's author supplied a custom usage string, .help shows that text verbatim instead of the shapes above, so the <name...> marker is only guaranteed for commands using the default help rendering.
Players can execute commands from specific plugins to avoid conflicts:
.HealthMod heal
.MagicMod heal
Some commands can work with different types of input. For example, a teleport command might accept either a player name or coordinates:
.teleport PlayerName
.teleport 100 200
When your input could match multiple command variations, you'll see a list of options and can select the one you want using .1, .2, etc.
Built-in commands for managing BepInEx configurations across all plugins:
.config dump <plugin> - View plugin configuration (admin only).config set <plugin> <section> <key> <value> - Modify settings (admin only)VCF includes tools to help you track and manage plugin versions on your server.
.version - Lists all installed plugins and their current versions (admin only)Please feel free to direct questions to @decaprime or @odjit on discord at the V Rising Modding Discord