VisualMC Reference Manual
VisualMC is a visual node editor that compiles your graph into native Java source code and
produces a deployable Spigot plugin .jar. It is not an interpreter
— the output runs at full JVM speed.
You build plugins by placing Nodes on the canvas and connecting them with Wires. Each node represents a discrete operation. Wires carry typed data or execution order between nodes.
Note: VisualMC produces native Java bytecode. Plugins compile against the Spigot API library and are indistinguishable from handwritten plugins at runtime.
Nodes, Wires & Flow
Every node has Input ports (left side) and Output ports (right side). Ports are categorised as either data or flow:
- Data wires carry a typed value (e.g.
int,Player,string). - Flow wires (white) control when a node executes — equivalent to statement ordering in code.
Nodes that have a flow input only run when that flow is activated. Pure data nodes
(e.g. Integer, Boolean) compute their value on demand whenever another node
reads them.
Build Pipeline
Clicking Build Plugin runs the following stages:
- Graph Normalization: The canvas is serialized to a JSON Intermediate Representation. Connections are resolved and validated for cycles and missing links.
- Type Checking: Every port connection is checked against the Type Registry to ensure type compatibility.
- Java Source Emitting: The IR is traversed and each node emits its equivalent Java statement(s). Event listeners, command registrations, and class boilerplate are generated automatically.
- Compilation: The
.javafiles are compiled withjavacagainst the bundled Spigot API, producing the final.jar.
Errors during any stage are reported in the Build Console at the bottom of the editor.
The Type Registry
The Type Registry is a parsed snapshot of the Spigot API (spigot-api.json) that the
editor loads at startup. It powers several features:
- Inheritance Resolution: Connecting a
Playerwire to a slot that expectsCommandSenderis valid becausePlayerimplementsCommandSender. The registry resolves this automatically. - Method Discovery: Nodes like Invoke Method and Extract Object Fields query the registry to list every method available on the connected object's type, including inherited methods.
- Enum Population: Any input expecting an enum (e.g.
Material,GameMode,Sound) is auto-populated with a searchable dropdown of valid constants. - Subclass Suggestions: The Cast and Check Type nodes suggest valid subtypes for the connected source type.
Type System
Wires are strictly typed. Incompatible types cannot be connected without a conversion node.
| Type | Description |
|---|---|
int |
32-bit whole number. Used for counts, indices, health. |
float / double |
Decimal number. Used for coordinates, damage multipliers, speeds. |
bool |
Boolean true / false. Used in conditions and flags. |
string |
Text value. Used for messages, keys, names. |
char |
Single character. |
long |
64-bit whole number. Used for timestamps, large counters. |
any |
Unresolved / generic type. Accepted by universal input slots. Resolves at connect time where possible. |
flow |
Execution-order wire (white). Not a data value — controls when a node runs. |
| Object types | Any Spigot/Bukkit class, e.g. org.bukkit.entity.Player,
org.bukkit.Location.
|
| List types | A typed java.util.List, e.g. List<Player>. |
Constant / Primitive Nodes
These nodes hold a fixed value and expose it as an output wire. They have no flow input — their value is read on demand.
Integer
Outputs a whole number (int). Edit inline in the node or via the Properties
panel.
Output
Val—int
Float
Outputs a decimal number (float).
Output
Val—float
String
Outputs a text value (string). The node width auto-adjusts to the text length
(capped at twice the default width).
Output
Out—string
Boolean
Outputs true or false. Choose via the dropdown property.
Output
Val—bool
Random Number
Generates a random number between Min and Max.
Inputs
Min—float(default 0)Max—float(default 100)
Output
Val— the random value
Properties
- Type —
int,float, orbyte
Math Nodes
Standard arithmetic operations. All accept two inputs of any numeric type and emit a
Result.
| Node | Operation | Notes |
|---|---|---|
| Add | A + B | Also concatenates two strings if either input is a string. |
| Subtract | A − B | |
| Multiply | A × B | |
| Divide | A ÷ B | Division by zero returns 0. |
| Absolute Difference | |A − B| | Also works component-wise on Location objects. |
To String
Converts any value or object to its text representation. Equivalent to calling
.toString().
Input
Object— any type
Output
String—string
Text Nodes
Format Text
Builds a string from a template containing {0}, {1}, …
placeholders. Input ports are generated automatically from the placeholders in the template.
Connecting to the last port auto-adds a new argument slot.
Properties
- Template — e.g.
Hello {0}, you have {1} coins!
Inputs
Arg 0,Arg 1, … — auto-generated, any type
Output
Result—string
Replace Text
Performs a find-and-replace on a string.
Inputs
Text— the source stringSearch— substring to findReplace— what to substitute
Output
Result—string
Static Variables
Static variables are global values that persist for the full lifetime of the running plugin instance (they reset on plugin reload). Declare them in the Variables panel on the left side of the editor.
Get Variable
Reads the current value of a static variable. The node title shows the variable name.
Output
Value— typed to the variable's declared type
Set Variable
Updates a static variable to a new value.
Inputs
Exec— flowValue— typed to the variable's declared type
Output
Next— flow
Player Data
Stores arbitrary key-value metadata per player in memory. Data is not persistent across server restarts unless you add your own saving logic.
Set Player Data
Inputs
Exec— flowPlayer— the target playerKey— string identifying the data slot (autocomplete from existing keys)Initial— default value if the slot is empty (used on first access)Value— the new value to write
Output
Next— flow
The Data Type is inferred automatically from what you connect to
Initial or Value.
Get Player Data
Inputs
Player— the target playerKey— string key (autocomplete)Default— returned if the key does not exist
Output
Value— typed to the stored data type
Process Player Data
Modifies a player data slot in one step — combining Get + Math + Set.
Inputs
Exec— flowPlayerKey— string keyValue— the operand
Properties
- Operation:
Set,Add,Subtract,Multiply,Divide
Outputs
Next— flowResult— the modified value
Global Registry Data
Same concept as Player Data but stored at the plugin level — not tied to any player. Accessible from any event or function in the graph.
Registry Get
Inputs
Key— string (autocomplete from Registry Set nodes)
Output
Value— typed to the configured Data Type
Properties
- Data Type: Search for any primitive or class type.
- Storage Type:
SINGLE(one value per key) orMULTIPLE(a collection).
Registry Set
Inputs
Exec— flowKey— stringValue
Output
Next— flow
In-Memory Counter
A high-efficiency numeric counter for rapid tracking (hit counts, timers, combo systems).
In-Memory Counter
Inputs
Exec Add— flow: increment the counter byDeltaDelta— the amount to add per tickExec Reset— flow: reset the counter toInitialPlayer— associates the counter with a specific player (contextual)Initial— starting value used on reset
Outputs
Next Add— flow (after increment)Next Reset— flow (after reset)Value— the current counter value
Properties
- Counter ID: A string key identifying this counter.
- Type:
byte,short,int,long,float,double,boolean, orchar.
List Nodes
List (Make List)
Assembles individual items into a typed java.util.List. Connecting to the last
slot auto-adds a new slot. The list type locks to the type of the first connected item.
Inputs
0,1,2, … — auto-managed item slots
Outputs
List— a typedList<T>Count—int(number of items)
Use Add Element / Remove Element buttons (Properties panel) to manage slot count. The Sort button re-packs the list, moving filled slots to the front.
For Each Loop
Iterates over every element in a List or array.
Inputs
Exec— flowList— any List or array type;Itemoutput adapts to the element type when connected
Outputs
Body— flow (runs once per element)Item— the current element, typedIndex—int(0-based position)Done— flow (runs after all elements are processed)
Get Element
Reads one item from a list by index.
Inputs
List— any List/array typeIndex—int(0-based, default 0)
Output
Value— typed to the list's element type
Event Nodes
Spigot Event
Listens for a specific Minecraft server event. The starting node for almost all plugin logic.
Properties
- Event Type: Search and select any Spigot event class (e.g.
PlayerJoinEvent,BlockBreakEvent). - Priority:
LOWEST,LOW,NORMAL,HIGH,HIGHEST,MONITOR
Outputs (auto-generated)
Next— flowEvent— the raw event object, typed to the selected event class- One port per getter method of the event (e.g.
getPlayer,getBlock,getDamage)
Inputs (auto-generated, optional)
- One port per setter method (e.g.
setDamage,setCancelled). All are optional — connect only what you need to modify.
Plugin Lifecycle
Triggered during the plugin's startup or shutdown, rather than in response to a game event.
Properties
- Lifecycle Event:
onLoad,onEnable, oronDisable
Output
Next— flow
Command
Triggers when a player or the console runs a specific slash command.
Properties
- Command Name: The command name without a slash (spaces are stripped
automatically). Node title updates to
Command: /<name>.
Outputs
Next— flowSender—CommandSender(the player or console that ran the command)Arguments—string[](all words after the command name)
Invoke Method
Invoke Method
Calls a specific Java method on any Spigot or Bukkit object. Connecting a typed object to
Object auto-updates the Type property. Use the Properties
panel to search and select the desired method — the node then generates input ports for each
parameter and an output port for the return value.
Inputs
Exec— flowObject— the target object (any type)- Additional parameter ports generated per the selected method
Outputs
Next— flowResult— return value (only shown if the method is non-void)
Extract Object Fields
Deconstructs a complex object by exposing its getter methods as individual typed output ports.
- Connect any typed object to the node.
- Open the Properties panel to browse all available getters.
- Check the fields you need — each selected getter adds a typed output port.
Example: Connect a Location object and extract X,
Y, Z, World, Pitch, and Yaw as
separate double / World wires.
Send Message
Send Message
Sends a text message directly to a player.
Inputs
Exec— flowPlayer—org.bukkit.entity.PlayerMessage—string
Output
Next— flow
Properties
- Use Prefix (checkbox): When enabled, the plugin's configured prefix is prepended to the message.
Cast
Generic Cast
Converts a base-type object wire to a specific subclass type, unlocking that class's specialized API methods. The Type Registry suggests valid subclasses for the connected source type.
Input
Object— any type (label updates to match the connected type name)
Output
Casted— re-typed to the selected target class
Open Properties to search for the target class. The node title updates to
Cast to <ClassName>. The source type display shows suggestions limited to
valid subclasses.
Check Type
Check Type (Is <Type>?)
Tests whether an object is an instance of a specific class without changing the wire type.
Node title updates to Is <ClassName>?.
Inputs
Exec— flowObject— any type
Outputs
Next— flowIs Type—bool
Is Valid
Is Valid
Guards downstream logic against null or empty objects.
Inputs
Exec— flowObject— any type (label adapts to the connected type)
Outputs
Valid— flow (object is non-null and non-empty)Invalid— flow (object is null or empty)
If Statement
If Statement
Splits execution into two branches based on a boolean condition.
Inputs
Exec— flowCondition—bool(inline checkbox for a constant default)
Outputs
True— flow (runs when Condition istrue)False— flow (runs when Condition isfalse)
Compare & Logic
Compare
Evaluates two values with a comparison operator. The input types lock to the first concrete type connected — mismatched types are rejected.
Inputs
A— any typeB— any type
Properties
- Operator:
==,!=,>,<,>=,<=
Output
Result—bool
AND
Returns true only when both inputs are true.
Inputs
A—boolB—bool
Output
Result—bool
OR
Returns true when either input is true.
Inputs
A—boolB—bool
Output
Result—bool
Loops
For Loop (Scope Box)
Executes its body a fixed number of times. Renders as a resizable box — nodes placed inside it run each iteration.
Inputs
Exec— flowStart—int(default 0)End—int(default 10)
Outputs
Done— flow (runs after the loop finishes)Index—int(current counter, from Start to End−1)Next Loop— flow (body execution; nodes inside the box run here)
While Loop (Scope Box)
Continues executing its body as long as a condition is true. Resizable scope
box.
Inputs
Exec— flowCondition—bool
Outputs
Body— flow (runs each iteration)Done— flow (runs once the condition is false)
Merge Flow & End Flow
Merge Flow
Combines two execution paths back into one. Useful for rejoining the branches of an If Statement.
Inputs
Flow 1— flowFlow 2— flow
Output
Exit— flow
End Flow
Terminates the current execution path. Equivalent to a bare return; statement.
Input
In— flow
Functions & Subgraphs
Encapsulate reusable logic into Functions (Subgraphs) to keep large graphs manageable.
Function (Call Function)
Represents a call to a custom function in the main graph. Ports appear based on the Function Input and Function Output nodes inside the subgraph. Double-click to enter and edit the subgraph.
Inputs
Exec— flow- + one port per Function Input defined inside
Outputs
Next— flow- + one port per Function Output defined inside
Entry Point
Placed inside a subgraph — marks where execution begins when the function is called.
Output
Exec— flow
Return
Stops the function and returns control to the caller.
Input
Exec— flow
Function Input
Defines one input parameter for the enclosing function. The output wire is available inside
the subgraph body. Connecting a typed wire to this node's output auto-locks the port type if
it is still any.
Properties
- Port Name: Label shown on the outer Function node's input port.
- Port Type: Data type of the parameter. Can be set manually or inferred from a connection.
Output
- A wire of the configured type
Function Output
Defines one return value for the enclosing function. Connecting a typed wire to this node's
input auto-locks the port type if it is still any.
Properties
- Port Name: Label shown on the outer Function node's output port.
- Port Type: Data type of the return value.
Input
- A wire of the configured type
Tip: Select a group of nodes and use the Convert to Function context menu action to automatically package them into a new subgraph.
Building and Deployment
- Enter your plugin name in the top header field.
- Click Build Plugin.
- Monitor the Build Console for errors or warnings.
- Download the compiled
.jarfile from the editor.
To install the plugin, copy the .jar into your server's /plugins folder
and restart (or use /reload confirm for compatible builds).
Common Patterns
Pattern: Send a Welcome Message on Join
- Event Node:
PlayerJoinEvent→ outputsPlayer - Format Text: Template
"Welcome, {0}!"→Arg 0receives the player's name (via Invoke Method →getName()) - Send Message:
Playerfrom the event,Messagefrom Format Text
Pattern: Cancel Fall Damage
- Event Node:
EntityDamageEvent→setCancelledinput - Connect a Boolean constant (
true) to thesetCancelledsetter input on the event node to cancel all damage unconditionally, or gate it through an If Statement that checks the damage cause.
Pattern: Economy Reward on Kill
- Event Node:
EntityDeathEvent→getKilleroutputs aPlayer - Is Valid: Check the killer is not null (
Validbranch continues) - Get Player Data: Key
"balance", Default0 - Add: Balance + reward amount
- Set Player Data: Key
"balance", write the new total - Send Message: Notify the killer of their reward
Pattern: Custom Command with Type Cast
- Command Node: Name
heal - Cast: Cast
Sender(CommandSender) →Player - Invoke Method:
setHealth(double)on the casted Player, value 20.0 - Send Message: Confirm the heal to the player