EzAdmin

Docs/Developer reference

Developer reference

Code your game can use, with examples you can copy.

C#CloudScript
Unity
if EzAdmin.HasItem(player, "vip_hat") then ... end

if (EzAdminClient.IsFrozen) controller.enabled = false;

EzAdminPlugin.api().recordPurchase(uuid, "Kit", 500, "coins", id);

The one rule: the server decides

Everything EzAdmin gives your game says what a player is allowed. The thing itself, paying out a reward or letting a message through, must happen on your server.

A game client can be modified. A client that is told "double rewards are on" and then asks for its own reward is a client a mod menu can make ask for a million. So:

  • Unity on PlayFab: anything that pays out, unlocks or lets a player talk goes through CloudScript. The client may read the same state to show it (a "Double XP" banner, a greyed out chat box), and that is all.
PlayFab games: wire it through CloudScript. Your client calls your CloudScript handler (SendChat, ClaimReward). The handler checks the player with the EzAdmin helpers, using currentPlayerId, and does the work with the Server API. The client never sends an amount, a player id or anything else it expects to be trusted. See CloudScript.

Mutes

A member timed out in Discord is muted in your game for the same length, and unmuted when the timeout ends or is removed. Turn it on in /settings: Discord timeouts mute them in game.

  • PlayFab games: the mute is written to the player as EzAdmin_Mute. Chat that goes through CloudScript checks ezadminIsMuted(currentPlayerId). Chat that does not (Photon, Vivox, your own server) checks it on that server, or at the very least greys out the chat box with the client helpers.

Live events

/event start name:Double XP multiplier:2 length:2h in Discord turns an event on in your game. Your reward code multiplies by EzAdmin's multiplier, which is 1 whenever nothing is on, so the same line of code works every day of the year. Events end by themselves.

/freeze holds a player in place while staff look into them. A Unity game reads IsFrozen and stops its own player controller.

PlayFab CloudScript

For Unity games on PlayFab, this is where anything that matters is decided. Paste EzAdmin.CloudScript.js at the bottom of your revision (Game Manager, Automation, CloudScript) and call these helpers from your own handlers.

handlers.SendChat = function (args, context) {
    if (ezadminIsMuted(currentPlayerId)) {
        return { ok: false, message: "Muted for " + ezadminMuteSecondsLeft(currentPlayerId) + "s." };
    }
    return postChat(currentPlayerId, args.text);
};

Always currentPlayerId, never a player id from args. currentPlayerId comes from the signed in session and cannot be faked; anything in args came from the client.

HelperDoes
ezadminIsMuted(playFabId)true while timed out in Discord
ezadminMuteSecondsLeft(playFabId)seconds of the timeout left
ezadminNotifyBan(playFabId, name)after your code bans someone: Discord gets a Lift ban button
EzAdminGetMyStatus (handler)for clients: { muted, mutedFor }, for showing only
EzAdminRedeemLinkCode, EzAdminGetLinkStatus (handlers)linking; the client packages call these for you

Unity (C#)

From EzAdminClient, after your own PlayFab login. For showing things; decide payouts in CloudScript.

using EzAdmin.Client;

EzAdminClient.EventChanged += () =>
{
    eventBanner.SetActive(EzAdminClient.EventName != "");
    eventLabel.text = EzAdminClient.EventName + " x" + EzAdminClient.Multiplier;
};

EzAdminClient.FreezeChanged += frozen => playerController.enabled = !frozen;

EzAdminClient.Instance.GetMuteStatus((muted, secondsLeft) =>
{
    chatInput.interactable = !muted;
});
CallGives
EventName, Multiplier, EventEndsAt, EventChangedthe live event; Multiplier is 1 when none is on
IsFrozen, FreezeChanged/freeze and /unfreeze
Announcement, LastAnnouncement/announce; the Link Screen shows a banner by itself
IsStaff, StaffChangedthe player may open the Staff Panel
GetMuteStatus(Action<bool, int>)muted, seconds left
RedeemLinkCode(code, Action<bool, string>)links the player; show the message
ReportPlayer(playFabId, name, reason, ...)a report into Discord
ViewProfile(playFabId, Action<EzAdminProfile>)their Discord profile, if they allow it

Unity: your own screen, your own keyboard

The built in Link Screen is optional. EzAdminLink is one static class your code calls from anywhere, whatever keyboard or UI you have:

using EzAdmin.Client;

EzAdminLink.Redeem(myKeyboard.Text, (ok, message) => myStatusLabel.text = message);

EzAdminLink.WhenLinked(discordName =>
{
    welcomeSign.text = "Welcome back, " + discordName;
    discordBadge.SetActive(true);
});

if (EzAdminLink.IsLinked) { ... }

EzAdminLink.StatusChanged += message => myStatusLabel.text = message;
EzAdminLinkDoes
Redeem(code, onDone)sends a code from any keyboard; onDone(ok, message)
Check(onDone)asks whether this account is linked; onDone(linked, discordName)
IsLinked, DiscordName, IsBusy, Statusthe current state
WhenLinked(action)runs now if linked, or the moment they link
Linked, StatusChangedevents, from whichever screen did it
Clean(raw), IsComplete(raw), CodeLengthfor your own input box
Reset()after your game signs in a different player

Keeping the built in screen but using your own keyboard: set its Keyboard to Custom, open your keyboard from On Keyboard Requested, and call SetCode on the EzAdminLinkScreen (it submits by itself when the code is complete). The screen also has AppendCharacter, Backspace, Clear, Submit, Open, Close and OpenSystemKeyboard.

Unity: Discord on your leaderboard

Show each player's Discord name, id and picture next to their score. One request covers up to 50 players, and results are cached, so a board that refreshes every few seconds does not ask again each time.

row.GetComponent<EzAdminProfileView>().Show(entry.PlayFabId, entry.DisplayName);

var ids = leaderboard.Select(e => e.PlayFabId).ToList();
EzAdminProfiles.Get(ids, found =>
{
    foreach (var entry in leaderboard)
    {
        EzAdminProfile p = found[entry.PlayFabId];
        string name = p.Visible ? p.Name : entry.DisplayName;
        if (p.Visible) EzAdminProfiles.LoadAvatar(p.AvatarUrl, tex => rowFor(entry).Picture.texture = tex, 64);
    }
});

Privacy is the player's. Another player sees someone's Discord only when the server shows profiles by default (/settings: Show linked players' Discord in game) or that player chose to show it with /profile; their own choice always wins. Staff EzAdmin trusts always see it. When it is hidden, Linked is true and Visible false: show your game's own name.

The website in your game

Linking and the Staff Panel are EzAdmin web pages. EzAdminClient.OpenLinkPage() and OpenStaffPanel() open them through EzAdminWeb: the browser by default (over the game on a Quest), or a panel inside your game if you add a web view plugin and set EzAdminWeb.Opener = url => myWebView.LoadUrl(url);

Rooms and staff tools

Rooms and staff lookup

Each Unity player reports themselves, so EzAdmin only knows which server or room they are in when your game says so. Call SetRoom when a player joins one (a Photon room, a Mirror or Netcode server, a dedicated server) and the Staff Panel groups players by server. LookupPlayer is for your own staff UI; EzAdmin checks the person asking holds Player Lookup in Discord.

EzAdminClient.Instance.SetRoom(PhotonNetwork.CurrentRoom.Name);

EzAdminClient.Instance.LookupPlayer("Kestrel", (ok, result) =>
{
    if (!ok) { staffText.text = result.message; return; }
    staffText.text = result.name + ": " + string.Join(", ", result.lines);
});

Staff tools

Switch on In game staff tools in /features and give the In game Staff Tools permission to your staff roles. Linked staff then get /ez vanish, /ez fly, /ez noclip, /ez tp <name>, /ez bring <name>, /ez heal and /ez god where your game supports them. Who may use them is decided in Discord, never by the game, and every use is written to the audit log.

Unity games make their own buttons, because only your game knows how its players move:

EzAdminClient.StaffToolsChanged += allowed => staffToolbar.SetActive(allowed);

void ToggleVanish()
{
    if (!EzAdminClient.CanUseStaffTools) return;
    vanished = !vanished;
    myRenderer.enabled = !vanished;
    EzAdminClient.Instance.LogStaffTool("vanish", vanished);
}

Data shapes

WhereNameShape
PlayFab Read Only DataEzAdmin_Mute{"until": 1790000000} (unix seconds), removed when unmuted
PlayFab Read Only DataEzAdmin_Link{"discordId": "...", "discordName": "...", "guildId": "...", "at": ...}
Bridge jobmute / unmute{"seconds": 600} / {}
Bridge jobannounce{"message": "..."}, for every player
Poll policyevent{"name": "...", "multiplier": 2, "endsAt": ...}, or none

Only EzAdmin writes these. PlayFab's Read Only Data can be read by the player's own client but only changed with your title's secret key, which never leaves EzAdmin and your CloudScript.

Missing something?

If your game needs a call this page does not have, open a ticket and say what you are building.