Tablist is based on sending 80 fake players, which every player defines one entry on the list. This library is a tool, what can help you to send tablist.
Plugin uses this library:
https://www.spigotmc.org/resources/...ated-tablist-header-footer-and-entries.78122/
INSTALLATION
Put it into your plugins folder.
FOR DEVELOPERS - How to use this library
1. You must create TablistManager object by this constructor:
So you must create class which extends TablistGenerator and class which extends TablistUpdater.
TabEntry represents one "bar" of the tablist.
In this class you can just listen an events what can change something on your tablist and update specified bars. Do it by get PlayerTablist object from TablistManager and execute method:
It can be useful for you:
2. After enable all plugins, Tablist calls event TablistLoadEvent
You should set TablistManger to yours. Everything else will do tablist plugin for you.
Example of results (from RefreshTablist - https://www.spigotmc.org/resources/78122/):
WARNING
This plugin will not support 1.17 due to NMS changes. Read more
Plugin uses this library:
https://www.spigotmc.org/resources/...ated-tablist-header-footer-and-entries.78122/
INSTALLATION
Put it into your plugins folder.
FOR DEVELOPERS - How to use this library
1. You must create TablistManager object by this constructor:
Spoiler: TablistManager
package pl.mnekos.tablist ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.Set ;
import java.util.UUID ;
import org.bukkit.entity.Player ;
import pl.mnekos.tablist.packets.BarPacketFactory ;
public class TablistManager {
public static final UUID [ ] BARS = new UUID [ 80 ] ;
private final Set <PlayerTablist > tablists = new HashSet ( ) ;
private TablistGenerator generator ;
private TablistUpdater updater ;
public TablistManager (TablistGenerator generator, TablistUpdater updater ) throws Exception {
this. generator = generator ;
this. updater = updater ;
BarPacketFactory. loadInfoField ( ) ;
updater. start ( this ) ;
}
public PlayerTablist createTablist (Player player ) {
PlayerTablist tablist = new PlayerTablist (player ) ;
this. tablists. add (tablist ) ;
String [ ] headerfooter = this. generator. generateHeaderFooter (player ) ;
tablist. sendTablist (headerfooter [ 0 ], headerfooter [ 1 ], this. generator. generateBars (player ) ) ;
return tablist ;
}
public void removeTablist (Player player ) {
PlayerTablist tablist = this. getTablist (player ) ;
if (tablist != null ) {
tablist. removeTablist ( ) ;
}
}
public PlayerTablist getTablist (Player player ) {
Iterator var2 = this. tablists. iterator ( ) ;
PlayerTablist tablist ;
do {
if ( !var2. hasNext ( ) ) {
return null ;
}
tablist = (PlayerTablist )var2. next ( ) ;
} while ( !tablist. getPlayer ( ). equals (player ) ) ;
return tablist ;
}
public void stopUpdating ( ) {
this. updater. stop ( ) ;
}
static {
for ( int i = 0 ; i < 80 ; ++i ) {
BARS [i ] = UUID. fromString ( String. format ( "00000000-0000-00%s-0000-000000000000", i < 10 ? "0" + i : Integer. toString (i ) ) ) ;
}
}
}
Code (Java):
package pl.mnekos.tablist ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.Set ;
import java.util.UUID ;
import org.bukkit.entity.Player ;
import pl.mnekos.tablist.packets.BarPacketFactory ;
public class TablistManager {
public static final UUID [ ] BARS = new UUID [ 80 ] ;
private final Set <PlayerTablist > tablists = new HashSet ( ) ;
private TablistGenerator generator ;
private TablistUpdater updater ;
public TablistManager (TablistGenerator generator, TablistUpdater updater ) throws Exception {
this. generator = generator ;
this. updater = updater ;
BarPacketFactory. loadInfoField ( ) ;
updater. start ( this ) ;
}
public PlayerTablist createTablist (Player player ) {
PlayerTablist tablist = new PlayerTablist (player ) ;
this. tablists. add (tablist ) ;
String [ ] headerfooter = this. generator. generateHeaderFooter (player ) ;
tablist. sendTablist (headerfooter [ 0 ], headerfooter [ 1 ], this. generator. generateBars (player ) ) ;
return tablist ;
}
public void removeTablist (Player player ) {
PlayerTablist tablist = this. getTablist (player ) ;
if (tablist != null ) {
tablist. removeTablist ( ) ;
}
}
public PlayerTablist getTablist (Player player ) {
Iterator var2 = this. tablists. iterator ( ) ;
PlayerTablist tablist ;
do {
if ( !var2. hasNext ( ) ) {
return null ;
}
tablist = (PlayerTablist )var2. next ( ) ;
} while ( !tablist. getPlayer ( ). equals (player ) ) ;
return tablist ;
}
public void stopUpdating ( ) {
this. updater. stop ( ) ;
}
static {
for ( int i = 0 ; i < 80 ; ++i ) {
BARS [i ] = UUID. fromString ( String. format ( "00000000-0000-00%s-0000-000000000000", i < 10 ? "0" + i : Integer. toString (i ) ) ) ;
}
}
}
So you must create class which extends TablistGenerator and class which extends TablistUpdater.
Spoiler: TablistGenerator
Code (Java):
package
pl.mnekos.tablist
;
import org.bukkit.entity.Player ;
import org.bukkit.plugin.Plugin ;
public abstract class TablistGenerator {
protected Plugin plugin ;
public TablistGenerator (Plugin plugin ) {
this. plugin = plugin ;
}
/**
* Method creates player header and footer for specified Player.
* @param player - specified player
* @return Table with header and footer
*/
public abstract String [ ] generateHeaderFooter (Player player ) ;
/**
* Method creates tablist for specified player.
* @param player - specified player
* @return 80-size table which every element represents one entry in tablist
*/
public abstract TabEntry [ ] generateBars (Player player ) ;
}
import org.bukkit.entity.Player ;
import org.bukkit.plugin.Plugin ;
public abstract class TablistGenerator {
protected Plugin plugin ;
public TablistGenerator (Plugin plugin ) {
this. plugin = plugin ;
}
/**
* Method creates player header and footer for specified Player.
* @param player - specified player
* @return Table with header and footer
*/
public abstract String [ ] generateHeaderFooter (Player player ) ;
/**
* Method creates tablist for specified player.
* @param player - specified player
* @return 80-size table which every element represents one entry in tablist
*/
public abstract TabEntry [ ] generateBars (Player player ) ;
}
TabEntry represents one "bar" of the tablist.
Spoiler: TabEntry
package pl.mnekos.tablist ;
import com.mojang.authlib.properties.Property ;
public class TabEntry implements Cloneable {
// borrowed from Project Ares
public static final Property DEFAULT_SKIN = new Property (
"textures",
"eyJ0aW1lc3RhbXAiOjE0MTEyNjg3OTI3NjUsInByb2ZpbGVJZCI6IjNmYmVjN2RkMGE1ZjQwYmY5ZDExODg1YTU0NTA3MTEyIiwicHJvZmlsZU5hbWUiOiJsYXN0X3VzZXJuYW1lIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg0N2I1Mjc5OTg0NjUxNTRhZDZjMjM4YTFlM2MyZGQzZTMyOTY1MzUyZTNhNjRmMzZlMTZhOTQwNWFiOCJ9fX0=",
"u8sG8tlbmiekrfAdQjy4nXIcCfNdnUZzXSx9BE1X5K27NiUvE1dDNIeBBSPdZzQG1kHGijuokuHPdNi/KXHZkQM7OJ4aCu5JiUoOY28uz3wZhW4D+KG3dH4ei5ww2KwvjcqVL7LFKfr/ONU5Hvi7MIIty1eKpoGDYpWj3WjnbN4ye5Zo88I2ZEkP1wBw2eDDN4P3YEDYTumQndcbXFPuRRTntoGdZq3N5EBKfDZxlw4L3pgkcSLU5rWkd5UH4ZUOHAP/VaJ04mpFLsFXzzdU4xNZ5fthCwxwVBNLtHRWO26k/qcVBzvEXtKGFJmxfLGCzXScET/OjUBak/JEkkRG2m+kpmBMgFRNtjyZgQ1w08U6HHnLTiAiio3JswPlW5v56pGWRHQT5XWSkfnrXDalxtSmPnB5LmacpIImKgL8V9wLnWvBzI7SHjlyQbbgd+kUOkLlu7+717ySDEJwsFJekfuR6N/rpcYgNZYrxDwe4w57uDPlwNL6cJPfNUHV7WEbIU1pMgxsxaXe8WSvV87qLsR7H06xocl2C0JFfe2jZR4Zh3k9xzEnfCeFKBgGb4lrOWBu1eDWYgtKV67M2Y+B3W5pjuAjwAxn0waODtEn/3jKPbc/sxbPvljUCw65X+ok0UUN1eOwXV5l2EGzn05t3Yhwq19/GxARg63ISGE8CKw=" ) ;
public String text = "" ;
public int ping = 10000 ;
public Property head ;
public TabEntry ( ) {
this. head = DEFAULT_SKIN ;
}
public TabEntry ( String text ) {
this. head = DEFAULT_SKIN ;
this. text = text ;
}
public TabEntry getText ( String text ) {
this. text = text ;
return this ;
}
public TabEntry setPing ( int ping ) {
this. ping = ping ;
return this ;
}
public TabEntry setHead (Property head ) {
this. head = head ;
return this ;
}
public TabEntry removeHead ( ) {
return setHead (DEFAULT_SKIN ) ;
}
@Override
public TabEntry clone ( ) {
return new TabEntry (text ). setPing (ping ). setHead (head ) ;
}
}
Code (Java):
package pl.mnekos.tablist ;
import com.mojang.authlib.properties.Property ;
public class TabEntry implements Cloneable {
// borrowed from Project Ares
public static final Property DEFAULT_SKIN = new Property (
"textures",
"eyJ0aW1lc3RhbXAiOjE0MTEyNjg3OTI3NjUsInByb2ZpbGVJZCI6IjNmYmVjN2RkMGE1ZjQwYmY5ZDExODg1YTU0NTA3MTEyIiwicHJvZmlsZU5hbWUiOiJsYXN0X3VzZXJuYW1lIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg0N2I1Mjc5OTg0NjUxNTRhZDZjMjM4YTFlM2MyZGQzZTMyOTY1MzUyZTNhNjRmMzZlMTZhOTQwNWFiOCJ9fX0=",
"u8sG8tlbmiekrfAdQjy4nXIcCfNdnUZzXSx9BE1X5K27NiUvE1dDNIeBBSPdZzQG1kHGijuokuHPdNi/KXHZkQM7OJ4aCu5JiUoOY28uz3wZhW4D+KG3dH4ei5ww2KwvjcqVL7LFKfr/ONU5Hvi7MIIty1eKpoGDYpWj3WjnbN4ye5Zo88I2ZEkP1wBw2eDDN4P3YEDYTumQndcbXFPuRRTntoGdZq3N5EBKfDZxlw4L3pgkcSLU5rWkd5UH4ZUOHAP/VaJ04mpFLsFXzzdU4xNZ5fthCwxwVBNLtHRWO26k/qcVBzvEXtKGFJmxfLGCzXScET/OjUBak/JEkkRG2m+kpmBMgFRNtjyZgQ1w08U6HHnLTiAiio3JswPlW5v56pGWRHQT5XWSkfnrXDalxtSmPnB5LmacpIImKgL8V9wLnWvBzI7SHjlyQbbgd+kUOkLlu7+717ySDEJwsFJekfuR6N/rpcYgNZYrxDwe4w57uDPlwNL6cJPfNUHV7WEbIU1pMgxsxaXe8WSvV87qLsR7H06xocl2C0JFfe2jZR4Zh3k9xzEnfCeFKBgGb4lrOWBu1eDWYgtKV67M2Y+B3W5pjuAjwAxn0waODtEn/3jKPbc/sxbPvljUCw65X+ok0UUN1eOwXV5l2EGzn05t3Yhwq19/GxARg63ISGE8CKw=" ) ;
public String text = "" ;
public int ping = 10000 ;
public Property head ;
public TabEntry ( ) {
this. head = DEFAULT_SKIN ;
}
public TabEntry ( String text ) {
this. head = DEFAULT_SKIN ;
this. text = text ;
}
public TabEntry getText ( String text ) {
this. text = text ;
return this ;
}
public TabEntry setPing ( int ping ) {
this. ping = ping ;
return this ;
}
public TabEntry setHead (Property head ) {
this. head = head ;
return this ;
}
public TabEntry removeHead ( ) {
return setHead (DEFAULT_SKIN ) ;
}
@Override
public TabEntry clone ( ) {
return new TabEntry (text ). setPing (ping ). setHead (head ) ;
}
}
Spoiler: TablistUpdater
Code (Java):
package
pl.mnekos.tablist
;
public abstract class TablistUpdater {
/**
* Method starts to listen for events and creates tasks to update tablist entries.
* @param manager - manager which is used to manage players tablist.
*/
public abstract void start (TablistManager manager ) ;
/**
* Method stops to listen for events and cancel tasks, which are needed to update tablist entries.
*/
public abstract void stop ( ) ;
}
public abstract class TablistUpdater {
/**
* Method starts to listen for events and creates tasks to update tablist entries.
* @param manager - manager which is used to manage players tablist.
*/
public abstract void start (TablistManager manager ) ;
/**
* Method stops to listen for events and cancel tasks, which are needed to update tablist entries.
*/
public abstract void stop ( ) ;
}
In this class you can just listen an events what can change something on your tablist and update specified bars. Do it by get PlayerTablist object from TablistManager and execute method:
Spoiler: update bar
public void updateBar ( int index, @Nonnull TabEntry entry ) {
Validate. isTrue (index <= 79, "Bar index cannot be higher than 79!" ) ;
Validate. isTrue (index >= 0, "Bar index cannot be smaller than 0!" ) ;
Tablist. executorService. submit ( ( ) -> {
try {
Bar bar = this. bars [index ] ;
PlayerConnection connection = ( (CraftPlayer ) this. player ). getHandle ( ). playerConnection ;
PacketPlayOutPlayerInfo packet ;
if (bar. setHead (entry. head ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. ADD_PLAYER, bar ) ;
connection. sendPacket (packet ) ;
} else {
if (bar. setText (entry. text ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. UPDATE_DISPLAY_NAME, bar ) ;
connection. sendPacket (packet ) ;
}
if (bar. setPing (entry. ping ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. UPDATE_LATENCY, bar ) ;
connection. sendPacket (packet ) ;
}
}
} catch ( Exception e ) {
Bukkit. getLogger ( ). log (Level. SEVERE, "An error occurred while updating bar " + index + " for player " + player. getName ( ) + "." ) ;
}
} ) ;
}
Code (Java):
public void updateBar ( int index, @Nonnull TabEntry entry ) {
Validate. isTrue (index <= 79, "Bar index cannot be higher than 79!" ) ;
Validate. isTrue (index >= 0, "Bar index cannot be smaller than 0!" ) ;
Tablist. executorService. submit ( ( ) -> {
try {
Bar bar = this. bars [index ] ;
PlayerConnection connection = ( (CraftPlayer ) this. player ). getHandle ( ). playerConnection ;
PacketPlayOutPlayerInfo packet ;
if (bar. setHead (entry. head ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. ADD_PLAYER, bar ) ;
connection. sendPacket (packet ) ;
} else {
if (bar. setText (entry. text ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. UPDATE_DISPLAY_NAME, bar ) ;
connection. sendPacket (packet ) ;
}
if (bar. setPing (entry. ping ) ) {
packet = BarPacketFactory. getPacket (EnumPlayerInfoAction. UPDATE_LATENCY, bar ) ;
connection. sendPacket (packet ) ;
}
}
} catch ( Exception e ) {
Bukkit. getLogger ( ). log (Level. SEVERE, "An error occurred while updating bar " + index + " for player " + player. getName ( ) + "." ) ;
}
} ) ;
}
It can be useful for you:
2. After enable all plugins, Tablist calls event TablistLoadEvent
Spoiler: TablistLoadEvent
Code (Java):
package
pl.mnekos.tablist
;
import org.bukkit.event.Event ;
import org.bukkit.event.HandlerList ;
public class TablistLoadEvent extends Event {
private static final HandlerList HANDLERS_LIST = new HandlerList ( ) ;
@Override
public HandlerList getHandlers ( ) {
return HANDLERS_LIST ;
}
public static HandlerList getHandlerList ( ) {
return HANDLERS_LIST ;
}
private TablistManager manager = null ;
public TablistLoadEvent ( ) {
super ( false ) ;
}
public void setTablistManager (TablistManager manager ) {
this. manager = manager ;
}
public TablistManager getTablistManager ( ) {
return manager ;
}
}
import org.bukkit.event.Event ;
import org.bukkit.event.HandlerList ;
public class TablistLoadEvent extends Event {
private static final HandlerList HANDLERS_LIST = new HandlerList ( ) ;
@Override
public HandlerList getHandlers ( ) {
return HANDLERS_LIST ;
}
public static HandlerList getHandlerList ( ) {
return HANDLERS_LIST ;
}
private TablistManager manager = null ;
public TablistLoadEvent ( ) {
super ( false ) ;
}
public void setTablistManager (TablistManager manager ) {
this. manager = manager ;
}
public TablistManager getTablistManager ( ) {
return manager ;
}
}
You should set TablistManger to yours. Everything else will do tablist plugin for you.
Example of results (from RefreshTablist - https://www.spigotmc.org/resources/78122/):
WARNING
This plugin will not support 1.17 due to NMS changes. Read more
Quick facts
- Edition: Minecraft Java
- File type: .jar
- Minecraft versions listed: 1.12, 1.13, 1.14
- How to install: Install the matching mod loader (Forge, Fabric or NeoForge) for your Minecraft version. → Download the .jar. → Put it in the .minecraft/mods folder and launch that loader profile.
- Where to get it: Opens on Spigot — not every file is mirrored on our own servers.
Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.
Tablist [1.12 - 1.16] is a free Minecraft Java mod. Compatible with Minecraft 1.12, 1.13, 1.14, 1.15 and newer. Downloaded 51,441 times (via Spigot). Download it and open it directly in the game.