Back to Editor

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:

  1. Graph Normalization: The canvas is serialized to a JSON Intermediate Representation. Connections are resolved and validated for cycles and missing links.
  2. Type Checking: Every port connection is checked against the Type Registry to ensure type compatibility.
  3. 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.
  4. Compilation: The .java files are compiled with javac against 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 Player wire to a slot that expects CommandSender is valid because Player implements CommandSender. 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

  • Valint

Float

Outputs a decimal number (float).

Output

  • Valfloat

String

Outputs a text value (string). The node width auto-adjusts to the text length (capped at twice the default width).

Output

  • Outstring

Boolean

Outputs true or false. Choose via the dropdown property.

Output

  • Valbool

Random Number

Generates a random number between Min and Max.

Inputs

  • Minfloat (default 0)
  • Maxfloat (default 100)

Output

  • Val — the random value

Properties

  • Typeint, float, or byte

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

  • Stringstring

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

  • Resultstring

Replace Text

Performs a find-and-replace on a string.

Inputs

  • Text — the source string
  • Search — substring to find
  • Replace — what to substitute

Output

  • Resultstring

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 — flow
  • Value — 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 — flow
  • Player — the target player
  • Key — 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 player
  • Key — 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 — flow
  • Player
  • Key — string key
  • Value — the operand

Properties

  • Operation: Set, Add, Subtract, Multiply, Divide

Outputs

  • Next — flow
  • Result — 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) or MULTIPLE (a collection).

Registry Set

Inputs

  • Exec — flow
  • Key — string
  • Value

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 by Delta
  • Delta — the amount to add per tick
  • Exec Reset — flow: reset the counter to Initial
  • Player — 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, or char.

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 typed List<T>
  • Countint (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 — flow
  • List — any List or array type; Item output adapts to the element type when connected

Outputs

  • Body — flow (runs once per element)
  • Item — the current element, typed
  • Indexint (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 type
  • Indexint (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 — flow
  • Event — 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, or onDisable

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 — flow
  • SenderCommandSender (the player or console that ran the command)
  • Argumentsstring[] (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 — flow
  • Object — the target object (any type)
  • Additional parameter ports generated per the selected method

Outputs

  • Next — flow
  • Result — 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.

  1. Connect any typed object to the node.
  2. Open the Properties panel to browse all available getters.
  3. 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 — flow
  • Playerorg.bukkit.entity.Player
  • Messagestring

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 — flow
  • Object — any type

Outputs

  • Next — flow
  • Is Typebool

Is Valid

Is Valid

Guards downstream logic against null or empty objects.

Inputs

  • Exec — flow
  • Object — 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 — flow
  • Conditionbool (inline checkbox for a constant default)

Outputs

  • True — flow (runs when Condition is true)
  • False — flow (runs when Condition is false)

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 type
  • B — any type

Properties

  • Operator: ==, !=, >, <, >=, <=

Output

  • Resultbool

AND

Returns true only when both inputs are true.

Inputs

  • Abool
  • Bbool

Output

  • Resultbool

OR

Returns true when either input is true.

Inputs

  • Abool
  • Bbool

Output

  • Resultbool

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 — flow
  • Startint (default 0)
  • Endint (default 10)

Outputs

  • Done — flow (runs after the loop finishes)
  • Indexint (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 — flow
  • Conditionbool

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 — flow
  • Flow 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

  1. Enter your plugin name in the top header field.
  2. Click Build Plugin.
  3. Monitor the Build Console for errors or warnings.
  4. Download the compiled .jar file 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 → outputs Player
  • Format Text: Template "Welcome, {0}!"Arg 0 receives the player's name (via Invoke MethodgetName())
  • Send Message: Player from the event, Message from Format Text

Pattern: Cancel Fall Damage

  • Event Node: EntityDamageEventsetCancelled input
  • Connect a Boolean constant (true) to the setCancelled setter 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: EntityDeathEventgetKiller outputs a Player
  • Is Valid: Check the killer is not null (Valid branch continues)
  • Get Player Data: Key "balance", Default 0
  • 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