Skip to main content

Overview

The Remain class is Foundation’s main compatibility layer, providing:
  • Cross-version player methods
  • JSON and component messaging
  • Title and action bar support
  • Boss bar rendering
  • Particle effects
  • Command registration
  • NMS packet handling
  • Block and entity manipulation
Many methods handle version differences automatically, allowing your plugin to work across multiple Minecraft versions

Player methods

getOnlinePlayers

Gets all online players (handles Collection vs Array return types).
returns
Collection<Player>
Collection of online players
for (Player player : Remain.getOnlinePlayers()) {
    player.sendMessage("Hello!");
}

getHealth

Gets entity health as integer (handles double vs int).
entity
LivingEntity
required
The entity
returns
int
The health value
int health = Remain.getHealth(player);
player.sendMessage("Health: " + health);

getMaxHealth

Gets max health of entity.
entity
LivingEntity
required
The entity
returns
int
Maximum health value
int maxHealth = Remain.getMaxHealth(player);

getViewDistance

Gets player’s client view distance.
player
Player
required
The player
returns
int
View distance in chunks
int viewDistance = Remain.getViewDistance(player);

respawn

Respawns a player (handles different API versions).
player
Player
required
The player to respawn
delayTicks
int
Delay before respawn (default: 2)
Remain.respawn(player);
Remain.respawn(player, 5); // Wait 5 ticks

JSON and components

sendJson

Sends a JSON message to a player.
sender
CommandSender
required
The recipient
json
String
required
The JSON string
String json = "{\"text\":\"Click me\",\"color\":\"green\"," +
              "\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/help\"}}";
Remain.sendJson(player, json);

toJson

Converts text to JSON format.
message
String|ItemStack|BaseComponent[]
required
The content to convert
returns
String
JSON representation
String json = Remain.toJson("&aHello &bWorld");

ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
String itemJson = Remain.toJson(item);

toLegacyText

Converts JSON to legacy colored text.
json
String
required
The JSON string
denyEvents
boolean
Throw exception if click/hover events found (default: true)
returns
String
Legacy text with color codes
String json = "{\"text\":\"Hello\",\"color\":\"red\"}";
String legacy = Remain.toLegacyText(json);
// Returns: "&cHello"

Title and action bar

sendTitle

Sends a title to the player.
player
Player
required
The player
title
String
required
Main title text
subtitle
String
Subtitle text
fadeIn
int
Fade in time in ticks (default: 20)
stay
int
Stay time in ticks (default: 60)
fadeOut
int
Fade out time in ticks (default: 20)
// Simple title (3 second display)
Remain.sendTitle(player, "&6Welcome", "&7to our server");

// Custom timing
Remain.sendTitle(player, 10, 100, 10, "&cWarning", "&7Read the rules");

resetTitle

Clears the title from player’s screen.
player
Player
required
The player
Remain.resetTitle(player);

sendActionBar

Displays text above hotbar.
player
Player
required
The player
text
String
required
The message to display
Remain.sendActionBar(player, "&eCoins: &6" + coins);

sendTablist

Sets tab list header and footer.
player
Player
required
The player
header
String
Header text (can be null)
Footer text (can be null)
Remain.sendTablist(player, 
    "&6&lMy Server\n&7Welcome!",
    "&7Players: &e" + Remain.getOnlinePlayers().size()
);

Boss bar

sendBossbarPercent

Shows a boss bar with percentage.
player
Player
required
The player
message
String
required
The boss bar text
percent
float
required
Fill percentage (0.0 to 1.0)
color
CompBarColor
Bar color
style
CompBarStyle
Bar style
Remain.sendBossbarPercent(player, "&eLoading...", 0.5f);
Remain.sendBossbarPercent(player, "&cBoss Health", 0.75f, 
    CompBarColor.RED, CompBarStyle.SEGMENTED_10);

sendBossbarTimed

Shows boss bar for limited time.
player
Player
required
The player
message
String
required
The message
seconds
int
required
Duration in seconds
Remain.sendBossbarTimed(player, "&aWelcome to the server!", 10);

removeBossbar

Removes boss bar from player.
player
Player
required
The player
Remain.removeBossbar(player);

Block manipulation

setTypeAndData

Sets block type and data (handles legacy data values).
block
Block
required
The block to modify
material
Material|CompMaterial
required
The material to set
data
byte
Legacy data value (pre-1.13)
Remain.setTypeAndData(block, Material.WOOL, (byte) 14);
Remain.setTypeAndData(block, CompMaterial.RED_WOOL);

setData

Sets block data value (legacy support).
block
Block
required
The block
data
int
required
The data value
Remain.setData(block, 5);

setBed

Places a bed block correctly (handles legacy two-block beds).
block
Block|Location
required
The initial block/location
facing
BlockFace
required
Direction the bed should face
BlockFace facing = PlayerUtil.getFacing(player);
Remain.setBed(block, facing);

Entity spawning

spawnFallingBlock

Spawns a falling block entity.
location
Location
required
Where to spawn
material
Material|Block
required
The block type
data
byte
Legacy data value
returns
FallingBlock
The spawned falling block
FallingBlock falling = Remain.spawnFallingBlock(
    location,
    Material.SAND
);

FallingBlock colored = Remain.spawnFallingBlock(
    location,
    Material.WOOL,
    (byte) 14
);

Command registration

newCommand

Creates a new plugin command instance.
label
String
required
The command name
returns
PluginCommand
The command instance
PluginCommand cmd = Remain.newCommand("mycommand");
cmd.setExecutor(new MyCommandExecutor());

registerCommand

Registers a command to the server.
command
Command
required
The command to register
PluginCommand cmd = Remain.newCommand("test");
cmd.setExecutor(this);
Remain.registerCommand(cmd);

unregisterCommand

Unregisters a command from the server.
label
String
required
The command label
removeAliases
boolean
Also remove aliases (default: true)
Remain.unregisterCommand("oldcommand");
Remain.unregisterCommand("test", false); // Keep aliases

Utility methods

newNamespaced

Creates a NamespacedKey (MC 1.13+).
name
String
The key name (optional, generates random if null)
returns
NamespacedKey
The namespaced key
NamespacedKey key = Remain.newNamespaced("custom_recipe");
NamespacedKey random = Remain.newNamespaced(); // Random name

getLocation

Gets the location of an inventory.
inventory
Inventory
required
The inventory
returns
Location
The location (null if not available)
Location loc = Remain.getLocation(inventory);
if (loc != null) {
    loc.getWorld().createExplosion(loc, 2.0f);
}

getBiome

Gets biome at location (handles coordinate changes).
location
Location
required
The location
returns
Biome
The biome
Biome biome = Remain.getBiome(player.getLocation());
if (biome == Biome.DESERT) {
    player.sendMessage("Hot!");
}

getLocale

Gets player’s client language.
player
Player
required
The player
returns
String
Language code (e.g., “en_US”) or null
String locale = Remain.getLocale(player);
if ("es_ES".equals(locale)) {
    player.sendMessage("¡Hola!");
} else {
    player.sendMessage("Hello!");
}

Advanced features

sendPacket

Sends an NMS packet to a player.
player
Player
required
The player
packet
Object
required
The NMS packet object
// Advanced use only
Object packet = createCustomPacket();
Remain.sendPacket(player, packet);
This is an advanced feature requiring knowledge of NMS (Net Minecraft Server) classes

getHandleEntity

Gets the NMS entity handle.
entity
Object
required
The Bukkit entity or block state
returns
Object
The NMS entity
Object nmsEntity = Remain.getHandleEntity(player);

Version checks

The Remain class provides several boolean flags:
if (Remain.hasParticleAPI()) {
    // Use particle API
}

if (Remain.hasScoreboardTags()) {
    entity.getScoreboardTags().add("custom_tag");
}

if (Remain.hasAdvancements()) {
    // Use advancement API
}

Examples

Cross-version titles

public void showWelcome(Player player) {
    Remain.sendTitle(
        player,
        "&6&lWelcome!",
        "&7Enjoy your stay"
    );
    
    Remain.sendActionBar(player, "&aTip: Type /help for commands");
}

Boss bar countdown

public void startCountdown(Player player, int seconds) {
    new BukkitRunnable() {
        int remaining = seconds;
        
        @Override
        public void run() {
            if (remaining <= 0) {
                Remain.removeBossbar(player);
                cancel();
                return;
            }
            
            float percent = (float) remaining / seconds;
            Remain.sendBossbarPercent(
                player,
                "&eTime remaining: &6" + remaining + "s",
                percent,
                CompBarColor.YELLOW,
                CompBarStyle.PROGRESS
            );
            
            remaining--;
        }
    }.runTaskTimer(plugin, 0, 20);
}

Build docs developers (and LLMs) love