Fluxer Plugin

Started by Necroso, Today at 09:50 PM

Previous topic - Next topic

Necroso

What is Fluxer?

Fluxer is a communication platform where communities organize themselves through servers, channels and real-time messaging. It was created by Swedish developer Hampus Kraft and released in January 2026, gaining traction as an alternative to Discord after Discord's mandatory ID/age verification rollout. Fluxer's biggest differentiators are that it's open source (AGPLv3, code publicly available on GitHub), it's built to be self-hosted (still being actively developed, with federation planned down the line), it does not sell user data or use it to train AI per its terms, and it's free to use with no paywalls on core features - the optional Plutonium subscription only raises limits on the official hosted instance.


For VC:MP scripters, Fluxer can also be used as an external communication layer for a game server. A bot can receive events from your VC:MP server, send messages to channels and react to messages or other events coming from Fluxer.

This makes integrations such as these possible:

  • Send player chat to a Fluxer channel.
  • Send server startup/shutdown notifications.
  • Create administration or staff channels connected to the server.
  • Report joins, leaves, kicks, bans or other server events.
  • Receive commands from Fluxer.
  • Create server-status messages.
  • Send embeds and custom message payloads.
  • Edit or delete messages.
  • Upload files.
  • Listen for reactions, member events, channel events and other Gateway events.
  • Build custom REST API integrations directly from Squirrel.

The Fluxer Connector plugin provides the bridge between VC:MP's Squirrel environment and Fluxer's REST API and Gateway.

Instead of implementing HTTP requests, WebSockets, Gateway heartbeats, reconnection and rate-limit handling yourself, your Squirrel script can communicate with Fluxer through a simple API exposed by the plugin.



How the plugin works

The plugin provides a global Fluxer object to your Squirrel scripts.

There are essentially two sides to the integration:

VC:MP -> Fluxer

Your script calls functions such as:
Fluxer.SendMessage(...)
Fluxer.SendPayload(...)
Fluxer.EditMessage(...)
Fluxer.DeleteMessage(...)
Fluxer.Get(...)
Fluxer.Post(...)

Fluxer -> VC:MP

The plugin receives Gateway events and forwards them to Squirrel callbacks such as:
onFluxerReady(bot)
onFluxerMessage(message)
onFluxerEvent(eventName, jsonData)
onFluxerDispatch(event)
onFluxerResponse(response)
onFluxerError(message)

Gateway callbacks are executed on the VC:MP main thread, so they can be integrated naturally with your existing server script.




Creating your Fluxer application

Before connecting your VC:MP server, you will need a Fluxer application/bot and its token.

If you are not sure how to create or configure an application, follow this guide:

Bot / Application Setup Guide

Once you have the bot token, you can connect it from Squirrel.

Important: Treat your bot token like a password. Do not publish it or include it in scripts that you distribute publicly.



Basic connection

A simple connection can be created when your script loads:
const FLUXER_TOKEN = "YOUR_BOT_TOKEN";

function onScriptLoad() {
    Fluxer.ConfigureGateway(0, 1);

    if (!Fluxer.Connect(FLUXER_TOKEN))
        print("Could not start the Fluxer connector.");
}

Fluxer.Connect() starts the connector, but that does not necessarily mean Gateway authentication has already completed.

Use onFluxerReady when you need to know that the bot is actually ready:
function onFluxerReady(bot) {
    print(format("Fluxer authenticated as %s (%s)", bot.Username, bot.UserID));
}

You can also check the current state manually:
if (Fluxer.IsRunning()) print("Fluxer connector is running.");

if (Fluxer.IsReady()) print("Fluxer Gateway is ready.");

When unloading your script, disconnect the connector:
function onScriptUnload() {
    Fluxer.Disconnect();
}



Sending messages from VC:MP

The most common operation is sending a message to a Fluxer channel:
const FLUXER_CHANNEL_ID = "YOUR_CHANNEL_ID";

Fluxer.SendMessage(FLUXER_CHANNEL_ID, "Hello from VC:MP!");

A practical example is announcing when a player joins:
function onPlayerJoin(player) {
    Fluxer.SendMessage(FLUXER_CHANNEL_ID, format("%s joined the VC:MP server.", player.Name));
}

Or when a player leaves:
function onPlayerPart(player, reason) {
    Fluxer.SendMessage(FLUXER_CHANNEL_ID, format("%s left the server.", player.Name));
}



Creating a VC:MP <-> Fluxer chat bridge

One of the simplest uses of the plugin is connecting your in-game chat with a Fluxer channel.

VC:MP -> Fluxer
function onPlayerChat(player, message) {
    Fluxer.SendMessage(FLUXER_CHANNEL_ID, format("**%s:** %s", player.Name, message));

    return 1;
}

Fluxer -> VC:MP
function onFluxerMessage(message) {
    if (message.ChannelID != FLUXER_CHANNEL_ID) return;
    if (message.AuthorBot) return;

    Message(format("[#7C3AED][Fluxer][#FFFFFF] %s: %s", message.AuthorName, message.Content));
}

The AuthorBot check is particularly important for bridges. It prevents messages produced by bots from being processed again and potentially creating message loops.



Using custom message payloads

For more advanced messages, use Fluxer.SendPayload(channelId, payloadJson)

Unlike SendMessage, this accepts a complete JSON message payload.

For example:
local payload = "{\"content\":\"Server status\",\"embeds\":[{\"title\":\"VC:MP\",\"description\":\"The server is online\",\"color\":8134381}]}";

Fluxer.SendPayload(FLUXER_CHANNEL_ID, payload);

This can be useful for status systems, administration notifications, embeds, replies, components, allowed mentions and other message fields supported by Fluxer.

Note: The payload must be valid JSON. Squirrel tables are not automatically converted to JSON by the plugin.



Editing and deleting messages

Existing messages can be edited:
Fluxer.EditMessage("CHANNEL_ID", "MESSAGE_ID", "{\"content\":\"Updated VC:MP server status\"}");
They can also be deleted:
Fluxer.DeleteMessage("CHANNEL_ID", "MESSAGE_ID");
This makes it possible to create persistent server-status messages instead of posting a new message every time something changes.

For example, your script could maintain a single message containing:

  • Current player count.
  • Maximum slots.
  • Current game mode.
  • Server uptime.
  • Current map/location.
  • Staff online.

The same Fluxer message can then be updated whenever your server state changes.



Using the REST API

The plugin is not limited to its message helper functions.

You can send authenticated requests to bot-accessible Fluxer REST routes using:
Fluxer.Request(method, path[, jsonBody])
There are also convenient aliases:
Fluxer.Get(path[, jsonBody])
Fluxer.Post(path[, jsonBody])
Fluxer.Put(path[, jsonBody])
Fluxer.Patch(path[, jsonBody])
Fluxer.Delete(path[, jsonBody])

For example:
Fluxer.Get("/users/@me");
Or:
Fluxer.Get(
    "/channels/CHANNEL_ID/messages?limit=25"
);

A POST request can be made directly:
Fluxer.Post("/channels/CHANNEL_ID/messages", "{\"content\":\"Hello from the REST API\"}");
This generic API is useful when you want to access a Fluxer endpoint that does not have a dedicated Squirrel helper.



Understanding asynchronous requests

REST operations are asynchronous.

For example:
local requestId = Fluxer.SendMessage(
    FLUXER_CHANNEL_ID,
    "Hello!"
);

A positive request ID means that the request was accepted into the connector's local queue.

It does not mean Fluxer has already accepted the HTTP request.

The final result is delivered through:
function onFluxerResponse(response) {
    print(format("Request %d returned HTTP %d", response.RequestID, response.StatusCode));
}

The response contains useful fields including:

  • RequestID - ID originally returned to Squirrel.
  • StatusCode - HTTP status code.
  • Route - requested API route.
  • Body - raw response body.
  • Data - parsed JSON data when available.

For example:
local myRequest = Fluxer.Get("/users/@me");
function onFluxerResponse(response) {
    if (response.RequestID != myRequest) return;

    if (response.StatusCode >= 200 && response.StatusCode < 300) {
        print("Authenticated user: " + response.Data.username);
    }
    else {
        print(format("HTTP %d: %s", response.StatusCode, response.Body));
    }
}

Request IDs are especially useful when your script has multiple API requests running and needs to identify which operation produced each response.



Receiving Fluxer messages

For normal message handling, the easiest callback is onFluxerMessage(message)

The object provides:

  • ID
  • ChannelID
  • GuildID
  • AuthorID
  • AuthorName
  • AuthorBot
  • Content
  • Raw

Example:
function onFluxerMessage(message) {
    if (message.AuthorBot) return;

    print(format("[Fluxer] %s: %s", message.AuthorName, message.Content));
}

This callback is ideal for chat bridges and simple bot commands.



Creating Fluxer commands

Because incoming messages are available directly from Squirrel, you can implement commands using your normal scripting logic.

For example:
function onFluxerMessage(message) {
    if (message.AuthorBot) return;

    if (message.Content == "!players") {
        Fluxer.SendMessage(message.ChannelID, format("There are currently %d players online.", GetPlayers()));
    }
}

More advanced systems can check:

  • Channel IDs.
  • Guild IDs.
  • User IDs.
  • Roles obtained through API/Gateway data.
  • Custom command prefixes.
  • Arguments supplied after commands.

This allows Fluxer to become an external administration or monitoring interface for your VC:MP server.



Listening to Gateway events

The plugin is not restricted to messages.

Every Gateway dispatch can be observed using:
function onFluxerEvent(eventName, jsonData) {
    print("Gateway event: " + eventName);
}

For structured data, use:
function onFluxerDispatch(event) {
    print(format("Dispatch %s, sequence %d", event.Name, event.Sequence));
    // event.Data contains the parsed data.
}

The plugin also automatically converts Gateway event names into Squirrel callback names.

Examples:
MESSAGE_CREATE        -> onFluxerMessageCreate(data)
MESSAGE_UPDATE        -> onFluxerMessageUpdate(data)
MESSAGE_DELETE        -> onFluxerMessageDelete(data)
MESSAGE_REACTION_ADD  -> onFluxerMessageReactionAdd(data)

GUILD_MEMBER_ADD      -> onFluxerGuildMemberAdd(data)
GUILD_MEMBER_REMOVE   -> onFluxerGuildMemberRemove(data)

CHANNEL_CREATE        -> onFluxerChannelCreate(data)
CHANNEL_UPDATE        -> onFluxerChannelUpdate(data)

TYPING_START          -> onFluxerTypingStart(data)
VOICE_STATE_UPDATE    -> onFluxerVoiceStateUpdate(data)

For example:
function onFluxerGuildMemberAdd(data) {
    print("A member joined guild " + data.guild_id);
}

function onFluxerMessageReactionAdd(data) {
    print("Reaction added to message " + data.message_id);
}

This makes Gateway events feel similar to normal VC:MP callbacks: implement only the callbacks your script actually needs.



Raw vs parsed Gateway data

When using onFluxerDispatch, you have access to both raw and parsed information:
function onFluxerDispatch(event) {
    print(event.Name);

    // Original JSON:
    print(event.Raw);

    // Parsed Squirrel value:
    local data = event.Data;
}

event.Data recursively converts JSON into normal Squirrel values such as tables, arrays, strings, integers, floats, booleans and null values.

This is useful when implementing more complex integrations because you usually do not need to manually parse Gateway JSON.



Bot presence

Your bot's Gateway presence can be changed with:
Fluxer.SetPresence("{\"since\":null,\"activities\":[{\"name\":\"VC:MP\",\"type\":0}],\"status\":\"online\",\"afk\":false}");

For example, a server could periodically update its bot presence to reflect the state of the VC:MP server.

Possible ideas include:
VC:MP | 12 players
Vice City Multiplayer
Server Online
Waiting for players...



Sending files

The connector also supports multipart REST requests with a file.

Example:
local payload = "{\"content\":\"Latest server screenshot\",\"attachments\":[{\"id\":\"0\",\"filename\":\"server.png\"}]}";

Fluxer.Multipart("POST", "/channels/CHANNEL_ID/messages", payload, "screenshots/server.png", "server.png");

The file must be readable by the VC:MP server process.

This can be useful for sending generated reports, screenshots, logs or other files produced by your server scripts or related systems.



Error handling

Connector-level errors are delivered through:
function onFluxerError(message) {
    print("Fluxer error: " + message);
}

REST failures should normally be inspected through onFluxerResponse:
function onFluxerResponse(response) {
    if (response.StatusCode < 200 || response.StatusCode >= 300) {
        print(format("Fluxer request %d failed: HTTP %d: %s", response.RequestID, response.StatusCode, response.Body));
    }
}

Gateway disconnections can also be observed:
function onFluxerDisconnect(reason) {
    print("Fluxer Gateway disconnected.");
}

Temporary network failures may be followed by automatic reconnection and session resume.



Example: simple server integration

The following example combines the basic pieces into a small VC:MP/Fluxer integration:
const FLUXER_TOKEN      = "YOUR_BOT_TOKEN";
const FLUXER_CHANNEL_ID = "YOUR_CHANNEL_ID";

function onScriptLoad() {
    Fluxer.ConfigureGateway(0, 1);

    if (!Fluxer.Connect(FLUXER_TOKEN)) throw "Could not start Fluxer";
}

function onFluxerReady(bot) {
    print(format("Fluxer authenticated as %s (%s)", bot.Username, bot.UserID));

    Fluxer.SendMessage(FLUXER_CHANNEL_ID, "VC:MP server is online.");
}

function onPlayerJoin(player) {
    Fluxer.SendMessage(FLUXER_CHANNEL_ID, format("%s joined the server.", player.Name));
}

function onPlayerChat(player, message) {
    Fluxer.SendMessage(FLUXER_CHANNEL_ID, format("**%s:** %s", player.Name, message));

    return 1;
}

function onFluxerMessage(message) {
    if (message.ChannelID != FLUXER_CHANNEL_ID) return;

    if (message.AuthorBot) return;

    Message(format("[#7C3AED][Fluxer][#FFFFFF] %s: %s", message.AuthorName, message.Content));
}

function onFluxerResponse(response) {
    if (response.StatusCode < 200 || response.StatusCode >= 300) {
        print(format("Fluxer HTTP error %d: %s", response.StatusCode, response.Body));
    }
}

function onFluxerError(message) {
    print("Fluxer error: " + message);
}

function onScriptUnload() {
    Fluxer.Disconnect();
}

This is only a starting point. Since the connector exposes both the REST API and Gateway to Squirrel, the integration can be expanded according to the needs of your server.



Ideas for VC:MP scripters

The plugin can be used for much more than a simple chat bridge.

Some possible projects:

  • Administration bridge - Send reports, bans, kicks and administrative actions to staff channels.
  • Remote commands - Allow authorized Fluxer users to request server information or execute carefully controlled administrative commands.
  • Live player list - Maintain a Fluxer message containing the current players.
  • Server status - Keep a persistent status message updated with player count, uptime and other information.
  • Player reports - Forward in-game reports directly to a staff channel.
  • Join/leave logging - Maintain external logs of player activity.
  • Account integration - Connect Fluxer identities with your own VC:MP account system.
  • Event notifications - Announce races, minigames, rounds or other server events.
  • Reaction-based actions - React to Gateway events such as message reactions.
  • Custom bot systems - Use the generic REST and Gateway interfaces to build functionality beyond the provided helpers.


Important notes

  • REST calls are asynchronous. A request ID means the operation was queued, not that the HTTP request succeeded.
  • Use onFluxerResponse when the result of an API request matters.
  • Wait for onFluxerReady before treating the Gateway session as authenticated.
  • Do not expose your bot token.
  • Ignore bot-authored messages when building chat bridges unless you specifically need them.
  • JSON payload arguments must contain valid JSON strings.
  • Use the dedicated helpers when possible and Fluxer.Request / HTTP aliases for custom API routes.
  • Gateway event callbacks are optional. You only need to implement the events your script uses.



Getting Started

Create your account and explore Fluxer:

https://fluxer.app/

Need help creating the application/bot?

Read the Bot Setup Guide

Once you have your bot token and channel ID, connect the plugin from Squirrel and start building your VC:MP integration.