Finish support for greeting/farewall text on area markers

This commit is contained in:
Mike Primm 2020-05-25 13:55:36 -05:00
parent 14f55bd6a8
commit 5e15187e46
17 changed files with 298 additions and 9 deletions

View File

@ -77,6 +77,20 @@ public class MapManager {
private boolean tpspausefullrenders = false;
private boolean tpspausezoomout = false;
// User enter/exit processing
private static final int DEFAULT_ENTEREXIT_PERIOD = 1000; // 1 second
private static final int DEFAULT_TITLE_FADEIN = 10; // 10 ticks = 1/2 second
private static final int DEFAULT_TITLE_STAY = 70; // 70 ticks = 3 1/2 second
private static final int DEFAULT_TITLE_FADEOUT = 20; // 20 ticks = 1 second
private static final boolean DEFAULT_ENTEREXIT_USETITLE = true;
private int enterexitperiod = DEFAULT_ENTEREXIT_PERIOD; // Enter/exit processing period
private int titleFadeIn = DEFAULT_TITLE_FADEIN;
private int titleStay = DEFAULT_TITLE_STAY;
private int titleFadeOut = DEFAULT_TITLE_FADEOUT;
private boolean enterexitUseTitle = DEFAULT_ENTEREXIT_USETITLE;
private HashMap<UUID, HashSet<EnterExitMarker>> entersetstate = new HashMap<UUID, HashSet<EnterExitMarker>>();
private boolean did_start = false;
private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */
@ -934,8 +948,20 @@ public class MapManager {
scheduleDelayedJob(this, 1000); /* Once per second */
}
}
private HashMap<UUID, HashSet<EnterExitMarker>> entersetstate = new HashMap<UUID, HashSet<EnterExitMarker>>();
private void sendPlayerEnterExit(DynmapPlayer player, EnterExitText txt) {
core.getServer().scheduleServerTask(new Runnable() {
public void run() {
if (enterexitUseTitle) {
player.sendTitleText(txt.title, txt.subtitle, titleFadeIn, titleStay, titleFadeOut);
}
else {
if (txt.title != null) player.sendMessage(txt.title);
if (txt.subtitle != null) player.sendMessage(txt.subtitle);
}
}
}, 0);
}
private class DoUserMoveProcessing implements Runnable {
public void run() {
@ -954,7 +980,7 @@ public class MapManager {
for (EnterExitMarker m : newset) {
EnterExitText txt = m.getGreetingText();
if ((txt != null) && ((oldset == null) || (oldset.contains(m) == false))) {
Log.info(String.format("User %s enter: %s - %s", player.getName(), txt.title, txt.subtitle));
sendPlayerEnterExit(player, txt);
}
}
// See which we just left
@ -962,15 +988,16 @@ public class MapManager {
for (EnterExitMarker m : oldset) {
EnterExitText txt = m.getFarewellText();
if ((txt != null) && (newset.contains(m) == false)) {
Log.info(String.format("User %s exit: %s - %s", player.getName(), txt.title, txt.subtitle));
sendPlayerEnterExit(player, txt);
}
}
}
newstate.put(puuid, newset);
}
entersetstate = newstate; // Replace old with new
scheduleDelayedJob(this, 1000); /* Once per second */
if (enterexitperiod > 0) {
scheduleDelayedJob(this, enterexitperiod);
}
}
}
@ -1055,6 +1082,12 @@ public class MapManager {
if (tpslimit_fullrenders > 19.5) tpslimit_fullrenders = 19.5;
tpslimit_zoomout = configuration.getDouble("zoomout-min-tps", 18.0);
if (tpslimit_zoomout > 19.5) tpslimit_zoomout = 19.5;
// Load enter/exit processing settings
enterexitperiod = configuration.getInteger("enterexitperiod", DEFAULT_ENTEREXIT_PERIOD);
titleFadeIn = configuration.getInteger("titleFadeIn", DEFAULT_TITLE_FADEIN);
titleStay = configuration.getInteger("titleStay", DEFAULT_TITLE_STAY);
titleFadeOut = configuration.getInteger("titleFadeOut", DEFAULT_TITLE_FADEOUT);
enterexitUseTitle = configuration.getBoolean("enterexitUseTitle", DEFAULT_ENTEREXIT_USETITLE);
// Load the save pending job period
savependingperiod = configuration.getInteger("save-pending-period", 900);
if ((savependingperiod > 0) && (savependingperiod < 60)) savependingperiod = 60;
@ -1501,7 +1534,11 @@ public class MapManager {
scheduleDelayedJob(new DoZoomOutProcessing(), 60000);
scheduleDelayedJob(new CheckWorldTimes(), 5000);
scheduleDelayedJob(new DoTouchProcessing(), 1000);
scheduleDelayedJob(new DoUserMoveProcessing(), 1000);
// If enabled, start enter/exit processing
if (enterexitperiod > 0) {
Log.info("Starting enter/exit processing");
scheduleDelayedJob(new DoUserMoveProcessing(), enterexitperiod);
}
/* Resume pending jobs */
for(FullWorldRenderState job : active_renders.values()) {
scheduleDelayedJob(job, 5000);

View File

@ -94,4 +94,12 @@ public interface DynmapPlayer extends DynmapCommandSender {
* Return UUID, or null if not available
*/
public default UUID getUUID() { return null; }
/**
* Send title and subtitle text (called from server thread)
*/
public default void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
// Fallback if not implemented
if (title != null) this.sendMessage(title);;
if (subtitle != null) this.sendMessage(subtitle);
}
}

View File

@ -37,6 +37,7 @@ import org.dynmap.hdmap.HDPerspective;
import org.dynmap.markers.AreaMarker;
import org.dynmap.markers.CircleMarker;
import org.dynmap.markers.EnterExitMarker;
import org.dynmap.markers.EnterExitMarker.EnterExitText;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerAPI;
import org.dynmap.markers.MarkerDescription;
@ -828,6 +829,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
private static boolean processAreaArgs(DynmapCommandSender sender, AreaMarker marker, Map<String,String> parms) {
String val = null;
String val2 = null;
try {
double ytop = marker.getTopY();
double ybottom = marker.getBottomY();
@ -839,6 +841,8 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
boolean boost = marker.getBoostFlag();
int minzoom = marker.getMinZoom();
int maxzoom = marker.getMaxZoom();
EnterExitText greet = marker.getGreetingText();
EnterExitText farew = marker.getFarewellText();
val = parms.get(ARG_STROKECOLOR);
if(val != null)
@ -886,6 +890,22 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
marker.setBoostFlag(boost);
marker.setMinZoom(minzoom);
marker.setMaxZoom(maxzoom);
// Handle greeting
val = parms.get(ARG_GREETING);
val2 = parms.get(ARG_GREETINGSUB);
if ((val != null) || (val2 != null)) {
String title = (val != null) ? ((val.length() > 0) ? val : null) : ((greet != null) ? greet.title : null);
String subtitle = (val2 != null) ? ((val2.length() > 0) ? val2 : null) : ((greet != null) ? greet.subtitle : null);
marker.setGreetingText(title, subtitle);
}
// Handle farewell
val = parms.get(ARG_FAREWELL);
val2 = parms.get(ARG_FAREWELLSUB);
if ((val != null) || (val2 != null)) {
String title = (val != null) ? ((val.length() > 0) ? val : null) : ((farew != null) ? farew.title : null);
String subtitle = (val2 != null) ? ((val2.length() > 0) ? val2 : null) : ((farew != null) ? farew.subtitle : null);
marker.setFarewellText(title, subtitle);
}
} catch (NumberFormatException nfx) {
sender.sendMessage("Invalid parameter format: " + val);
return false;
@ -1050,6 +1070,11 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
private static final String ARG_WORLD = "world";
private static final String ARG_BOOST = "boost";
private static final String ARG_DESC = "desc";
private static final String ARG_GREETING = "greeting";
private static final String ARG_GREETINGSUB = "greetingsub";
private static final String ARG_FAREWELL = "farewell";
private static final String ARG_FAREWELLSUB = "farewellsub";
/* Parse argument strings : handle 'attrib:value' and quoted strings */
private static Map<String,String> parseArgs(String[] args, DynmapCommandSender snd) {
@ -2196,6 +2221,16 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
}
if (m.getMaxZoom() >= 0) {
msg += ", maxzoom:" + m.getMaxZoom();
}
EnterExitText t = m.getGreetingText();
if (t != null) {
if (t.title != null) msg += ", greeting='" + t.title + "'";
if (t.subtitle != null) msg += ", greetingsub='" + t.subtitle + "'";
}
t = m.getFarewellText();
if (t != null) {
if (t.title != null) msg += ", farewell='" + t.title + "'";
if (t.subtitle != null) msg += ", farewellsub='" + t.subtitle + "'";
}
sender.sendMessage(msg);
}

View File

@ -3,7 +3,7 @@ package org.dynmap.markers;
/**
* This defines the public interface to an area marker object, for use with the MarkerAPI
*/
public interface AreaMarker extends MarkerDescription {
public interface AreaMarker extends MarkerDescription, EnterExitMarker {
/**
* Get top Y coordinate
* @return coordinate

View File

@ -19,6 +19,7 @@ import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import org.bukkit.entity.Player;
import org.dynmap.DynmapChunk;
import org.dynmap.Log;
import org.dynmap.bukkit.helper.BukkitVersionHelper;
@ -189,5 +190,11 @@ public class BukkitVersionHelperSpigot113_2 extends BukkitVersionHelperCB {
}
return p;
}
// Send title/subtitle to user
public void sendTitleText(Player p, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
if (p != null) {
p.sendTitle(title, subtitle, fadeInTicks, stayTicks, fadeOutTIcks);
}
}
}

View File

@ -10,6 +10,7 @@ import org.bukkit.ChunkSnapshot;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import org.bukkit.entity.Player;
import org.dynmap.DynmapChunk;
import org.dynmap.Log;
import org.dynmap.bukkit.helper.BukkitVersionHelperCB;
@ -201,5 +202,11 @@ public class BukkitVersionHelperSpigot114_1 extends BukkitVersionHelperCB {
}
return p;
}
// Send title/subtitle to user
public void sendTitleText(Player p, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
if (p != null) {
p.sendTitle(title, subtitle, fadeInTicks, stayTicks, fadeOutTIcks);
}
}
}

View File

@ -10,6 +10,7 @@ import org.bukkit.ChunkSnapshot;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import org.bukkit.entity.Player;
import org.dynmap.DynmapChunk;
import org.dynmap.Log;
import org.dynmap.bukkit.helper.BukkitVersionHelperCB;
@ -201,5 +202,11 @@ public class BukkitVersionHelperSpigot115 extends BukkitVersionHelperCB {
}
return p;
}
// Send title/subtitle to user
public void sendTitleText(Player p, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
if (p != null) {
p.sendTitle(title, subtitle, fadeInTicks, stayTicks, fadeOutTIcks);
}
}
}

View File

@ -201,4 +201,13 @@ public abstract class BukkitVersionHelper {
}
public abstract String getStateStringByCombinedId(int blkid, int meta);
}
// Send title/subtitle to user
public void sendTitleText(Player p, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
// Do send message for old implementations
if (p != null) {
if (title != null) p.sendMessage(title);
if (subtitle != null) p.sendMessage(subtitle);
}
}
}

View File

@ -40,6 +40,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketTitle;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.UserListBans;
import net.minecraft.server.management.UserListIPBans;
@ -1341,6 +1342,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -40,6 +40,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketTitle;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.UserListBans;
import net.minecraft.server.management.UserListIPBans;
@ -1351,6 +1352,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -41,6 +41,8 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketTimeUpdate;
import net.minecraft.network.play.server.SPacketTitle;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.UserListBans;
import net.minecraft.server.management.UserListIPBans;
@ -1356,6 +1358,27 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -39,6 +39,7 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketTitle;
import net.minecraft.particles.IParticleData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.UserListBans;
@ -1296,6 +1297,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -38,6 +38,7 @@ import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.ServerPlayNetHandler;
import net.minecraft.network.play.server.STitlePacket;
import net.minecraft.particles.IParticleData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.BanList;
@ -1325,6 +1326,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof ServerPlayerEntity) {
ServerPlayerEntity mp = (ServerPlayerEntity) player;
STitlePacket times = new STitlePacket(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
STitlePacket titlepkt = new STitlePacket(STitlePacket.Type.TITLE, new StringTextComponent(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
STitlePacket subtitlepkt = new STitlePacket(STitlePacket.Type.SUBTITLE, new StringTextComponent(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -38,6 +38,7 @@ import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.ServerPlayNetHandler;
import net.minecraft.network.play.server.STitlePacket;
import net.minecraft.particles.IParticleData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.BanList;
@ -1325,6 +1326,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof ServerPlayerEntity) {
ServerPlayerEntity mp = (ServerPlayerEntity) player;
STitlePacket times = new STitlePacket(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
STitlePacket titlepkt = new STitlePacket(STitlePacket.Type.TITLE, new StringTextComponent(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
STitlePacket subtitlepkt = new STitlePacket(STitlePacket.Type.SUBTITLE, new StringTextComponent(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -39,6 +39,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.S45PacketTitle;
import net.minecraft.potion.Potion;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.BanList;
@ -1333,6 +1334,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
S45PacketTitle times = new S45PacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.playerNetServerHandler.sendPacket(times);
if (title != null) {
S45PacketTitle titlepkt = new S45PacketTitle(S45PacketTitle.Type.TITLE, new ChatComponentText(title));
mp.playerNetServerHandler.sendPacket(titlepkt);
}
if (subtitle != null) {
S45PacketTitle subtitlepkt = new S45PacketTitle(S45PacketTitle.Type.SUBTITLE, new ChatComponentText(subtitle));
mp.playerNetServerHandler.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -40,6 +40,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketTitle;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.UserListBans;
import net.minecraft.server.management.UserListIPBans;
@ -1330,6 +1331,26 @@ public class DynmapPlugin
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
if (player instanceof EntityPlayerMP) {
EntityPlayerMP mp = (EntityPlayerMP) player;
SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
mp.connection.sendPacket(times);
if (title != null) {
SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
mp.connection.sendPacket(titlepkt);
}
if (subtitle != null) {
SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
mp.connection.sendPacket(subtitlepkt);
}
}
}
}
/* Handler for generic console command sender */
public class ForgeCommandSender implements DynmapCommandSender

View File

@ -720,6 +720,15 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public UUID getUUID() {
return uuid;
}
/**
* Send title and subtitle text (called from server thread)
*/
@Override
public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTIcks) {
if (player != null) {
helper.sendTitleText(player, title, subtitle, fadeInTicks, stayTicks, fadeOutTIcks);
}
}
}
/* Handler for generic console command sender */
public class BukkitCommandSender implements DynmapCommandSender {