03.02.2016, 18:34
(
Последний раз редактировалось Alf21; 03.02.2016 в 18:38.
Причина: Added link for the original article
)
This is an info chat (written in Java for the Shoebill Plugin), which created PlayerTextdraws and displays them animated in a adjustable duration.
ChatMessage.java
Chat.java
Installation:
Initialize the chat in a Plugin in onEnable() or in Gamemode in onInit()! You need to save the reference (Chat chat = new Chat()). So on, uninitialize the chat in onDisable() with chat.destroy();
Example use:
A Command:
Coming updates: Performance improvement (better visibility) with pre-calculation!
Please leave a command, thanks
ChatMessage.java
Код:
/**
*
*/
package me.alf21.util.chat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.gtaun.shoebill.constant.TextDrawAlign;
import net.gtaun.shoebill.constant.TextDrawFont;
import net.gtaun.shoebill.data.Color;
import net.gtaun.shoebill.object.Destroyable;
import net.gtaun.shoebill.object.Player;
import net.gtaun.shoebill.object.PlayerTextdraw;
import net.gtaun.shoebill.object.Timer;
/**
* @author Alf21
*
*/
public class ChatMessage implements Destroyable{
private PlayerTextdraw textdraw;
private int slot;
private Timer timer;
private boolean sliding;
private String text;
private int count;
private Player player;
private Long time;
private int currentEndIndex;
public ChatMessage(Player player, String text, int slot) {
this.player = player;
this.text = removeNonColorCodes(text).trim();
this.slot = slot;
count = 1;
createTextdraw(0,0);
time = System.currentTimeMillis();
}
public void slideIn() {
sliding = true;
reset();
final int length = getTextLength();
final int interval = (int) Chat.slideTime/length;
currentEndIndex = 0;
timer = Timer.create(interval, length, (factualInterval) -> {
currentEndIndex++;
currentEndIndex = cutTextIn(currentEndIndex);
textdraw.hide();
textdraw.setText(text.substring(0, currentEndIndex));
textdraw.show();
if(count == length) {
sliding = false;
timer.stop();
}
count++;
});
timer.start();
}
public void slideOut() {
sliding = true;
reset();
final int length = getTextLength();
final int interval = (int) Chat.slideTime/length;
currentEndIndex = text.length();
timer = Timer.create(interval, length-1, (factualInterval) -> {
currentEndIndex--;
currentEndIndex = cutTextOut(currentEndIndex);
textdraw.hide();
textdraw.setText(text.substring(0, currentEndIndex));
textdraw.show();
if(count == length-1) {
sliding = false;
timer.stop();
}
count++;
});
timer.start();
}
public void moveUp() {
reset();
final int maxCount = 15;
final int interval = (int) Chat.slideTime/maxCount;
timer = Timer.create(interval, maxCount, (factualInterval) -> {
textdraw.hide();
textdraw.destroy();
createTextdraw(0, (float) -count*(15f/(float) maxCount));
textdraw.show();
if(count == maxCount) {
slot++;
timer.stop();
}
count++;
});
timer.start();
}
public void hide() {
textdraw.hide();
}
public void show() {
textdraw.show();
}
private void reset() {
if(timer != null)
timer.destroy();
count = 1;
}
private void createTextdraw(float x, float y) {
textdraw = PlayerTextdraw.create(player, 630+x, 385-15*slot+y);
textdraw.setText(text);
textdraw.setAlignment(TextDrawAlign.RIGHT);
textdraw.setBackgroundColor(Color.BLACK);
textdraw.setFont(TextDrawFont.get(1));
textdraw.setLetterSize(0.5f, 1);
textdraw.setColor(Color.WHITE);
textdraw.setOutlineSize(1);
textdraw.setProportional(true);
textdraw.setSelectable(false);
}
/**
* @return the sliding
*/
public boolean isSliding() {
return sliding;
}
/**
* @param sliding the sliding to set
*/
public void setSliding(boolean sliding) {
this.sliding = sliding;
}
/**
* @return the time when textdraw was created
*/
public Long getTime() {
return time;
}
/**
* @return the textdraw
*/
public PlayerTextdraw getTextdraw() {
return textdraw;
}
/**
* @return the player
*/
public Player getPlayer() {
return player;
}
/* (non-Javadoc)
* @see net.gtaun.shoebill.object.Destroyable#destroy()
*/
@Override
public void destroy() {
if(timer != null) {
if(timer.isRunning())
timer.stop();
timer.destroy();
timer = null;
}
if(textdraw != null) {
textdraw.hide();
textdraw.destroy();
textdraw = null;
}
}
/* (non-Javadoc)
* @see net.gtaun.shoebill.object.Destroyable#isDestroyed()
*/
@Override
public boolean isDestroyed() {
if(timer != null || textdraw != null)
return false;
return true;
}
private String removeNonColorCodes(String text) {
final String prefixOfColorCodes = "COLOR"; //The prefix of any color code like "COLOR_RED" <- HERE>> if String == "": "_RED"
final String connectionOfColorCodes = "\u005F"; //The connection label or Unicode, here: "\u005F" == "_" <- HERE>> if String == "": "COLORRED"
String replaceStr = prefixOfColorCodes + connectionOfColorCodes;
text = text.replaceAll("\u007E" + "w" + "\u007E", replaceStr + "WHITE");
text = text.replaceAll("\u007E" + "r" + "\u007E", replaceStr + "RED");
text = text.replaceAll("\u007E" + "g" + "\u007E", replaceStr + "GREEN");
text = text.replaceAll("\u007E" + "b" + "\u007E", replaceStr + "DARK" + connectionOfColorCodes + "BLUE");
text = text.replaceAll("\u007E" + "y" + "\u007E", replaceStr + "YELLOW");
text = text.replaceAll("\u007E" + "p" + "\u007E", replaceStr + "PURPLE");
text = text.replaceAll("\u007E" + "l" + "\u007E", replaceStr + "BLACK");
text = text.replaceAll("\u007E" + "h" + "\u007E", replaceStr + "LIGHTER");
text = text.replaceAll("\u007E+([\\w[\u003C\u003E&&[\\S]]]?)\u007E", ""); //replace unknown colors and Commands
text = text.replaceAll("\u007E", ""); //replace other "~"
text = text.replaceAll(replaceStr + "WHITE", "\u007E" + "w" + "\u007E");
text = text.replaceAll(replaceStr + "RED", "\u007E" + "r" + "\u007E");
text = text.replaceAll(replaceStr + "GREEN", "\u007E" + "g" + "\u007E");
text = text.replaceAll(replaceStr + "DARK" + connectionOfColorCodes + "BLUE", "\u007E" + "b" + "\u007E");
text = text.replaceAll(replaceStr + "YELLOW", "\u007E" + "y" + "\u007E");
text = text.replaceAll(replaceStr + "PURPLE", "\u007E" + "p" + "\u007E");
text = text.replaceAll(replaceStr + "BLACK", "\u007E" + "l" + "\u007E");
text = text.replaceAll(replaceStr + "LIGHTER", "\u007E" + "h" + "\u007E");
return text;
}
private int cutTextIn(int endIndex) {
int currentEndIndex = endIndex;
String string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex++;
string = text.substring(0, currentEndIndex);
}
//check whether string contains color codes
Matcher matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E").matcher(text); //~r~|
if(matcher.find()) {
//match ~
int matcherState = 0;
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~|...
Matcher matcher2 = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~s~r~|...
if(matcher.find() && !matcher2.find()) {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~|...
matcherState = 3;
}
else {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\\z").matcher(string); //~r|...
if(matcher.find()) {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\\z").matcher(string); //~r|...
matcherState = 4;
}
else {
matcher = Pattern.compile("\u007E\\z").matcher(string); //~|...
matcherState = 5;
}
}
while(matcher.find()) {
//check whether color code is after this color code
if(currentEndIndex+matcherState <= text.length()) {
currentEndIndex += matcherState;
string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex++;
string = text.substring(0, currentEndIndex);
}
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~| <- update the matcher
if(!matcher.find()) {
currentEndIndex -= 2;
string = text.substring(0, currentEndIndex);
}
else
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~| <- update the matcher
matcherState = 3;
}
}
string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex++;
string = text.substring(0, currentEndIndex);
}
matcher2 = Pattern.compile("\u007E\\z").matcher(string); //~|...
if(matcher2.find()) {
if(currentEndIndex+3 <= text.length())
currentEndIndex += 3;
}
}
return currentEndIndex;
}
private int cutTextOut(int endIndex) {
int currentEndIndex = endIndex;
String string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex--;
string = text.substring(0, currentEndIndex);
}
//check whether string contains color codes
Matcher matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E").matcher(text); //~r~|
if(matcher.find()) {
//match ~
int matcherState = 0;
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~|...
if(matcher.find()) {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~|...
matcherState = 3;
}
else {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\\z").matcher(string); //~r|...
String string2 = text.substring(0, currentEndIndex+1);
Matcher matcher2 = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string2); //~r~|...
if(matcher.find() && matcher2.find()) {
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\\z").matcher(string); //~r|...
matcherState = 2;
}
else {
matcher = Pattern.compile("\u007E\\z").matcher(string); //~|...
matcherState = 1;
}
}
while(matcher.find()) {
//check whether color code is before this color code
if(currentEndIndex-matcherState > 0) {
currentEndIndex -= matcherState;
string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex--;
string = text.substring(0, currentEndIndex);
}
matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z").matcher(string); //~r~| <- update the matcher
matcherState = 3;
}
}
string = text.substring(0, currentEndIndex);
while(string.trim().length() < string.length()){
currentEndIndex--;
string = text.substring(0, currentEndIndex);
}
}
return currentEndIndex;
}
private int getTextLength() {
int length = text.replace(" ", "").length();
Matcher matcher = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E").matcher(text); //~r~
while(matcher.find()) {
length -= 3;
}
return length;
}
}
Код:
/**
*
*/
package me.alf21.util.chat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import net.gtaun.shoebill.object.Destroyable;
import net.gtaun.shoebill.object.Player;
import net.gtaun.shoebill.object.Timer;
/**
* @author Alf21
*/
public class Chat implements Destroyable {
private Timer timer;
public static final int updateDelay = 50;
public static final int displayTime = 5000;
public static final int slideTime = 500;
private ArrayList<ChatMessage> chatMessages;
private ChatMessage currentChatMessage;
private Map<Player, String> queue;
public Chat() {
reset();
initializeTimer();
}
//TODO Chat right bottom Corner, with new Infos sliding down if new message received
// 5 Slots, 6 available Textdraws
public void sendMessage(Player player, String text) {
if(chatMessages != null && chatMessages.size() > 5) {
//slide getSlot > 5 out
}
queue.put(player, text);
if(!timer.isRunning())
timer.start();
}
private void reset() {
if(chatMessages != null && !chatMessages.isEmpty()) {
chatMessages.stream().forEach((chatMessage) -> {
chatMessage.hide();
chatMessage.destroy();
});
}
chatMessages = new ArrayList<ChatMessage>();
queue = new HashMap<Player, String>();
currentChatMessage = null;
}
private void initializeTimer() {
timer = Timer.create(updateDelay, (factualInterval) -> {
Long systemTime = System.currentTimeMillis();
ArrayList<ChatMessage> removeMessages = new ArrayList<ChatMessage>(); //TODO Solution with Iterator
if(chatMessages != null && !chatMessages.isEmpty()) {
chatMessages.stream().forEach((chatMessage) -> {
if(systemTime-chatMessage.getTime() >= slideTime) {
if(currentChatMessage != null) {
currentChatMessage = null;
}
}
if(systemTime-chatMessage.getTime() >= displayTime+2*slideTime) {
removeMessages.add(chatMessage);
}
else if(systemTime-chatMessage.getTime() >= displayTime+slideTime) {
if(!chatMessage.isSliding()) {
chatMessage.slideOut();
}
}
});
removeMessages.stream().forEach((removeMessage) -> {
removeChatMessage(removeMessage);
});
removeMessages.clear();
}
if(currentChatMessage == null && !queue.isEmpty()) {
Map.Entry<Player,String> entry = queue.entrySet().iterator().next();
Player player = entry.getKey();
currentChatMessage = new ChatMessage(player, entry.getValue(), 0);
queue.remove(player);
chatMessages.add(currentChatMessage);
}
if(currentChatMessage != null) {
if(chatMessages.size() > 1) {
chatMessages.stream().forEach((chatMessage) -> {
if(chatMessage != currentChatMessage)
chatMessage.moveUp();
});
}
if(!currentChatMessage.isSliding()) {
currentChatMessage.slideIn();
}
}
if(chatMessages != null && chatMessages.isEmpty()) {
timer.stop();
reset();
}
});
}
private void removeChatMessage(ChatMessage chatMessage) {
if(chatMessages.contains(chatMessage)) {
chatMessages.remove(chatMessage);
}
chatMessage.destroy();
}
/* (non-Javadoc)
* @see net.gtaun.shoebill.object.Destroyable#destroy()
*/
@Override
public void destroy() {
if(timer != null) {
if(timer.isRunning())
timer.stop();
timer.destroy();
timer = null;
}
if(currentChatMessage != null) {
currentChatMessage.destroy();
currentChatMessage = null;
}
if(chatMessages != null) {
chatMessages.stream().forEach((chatMessage) -> chatMessage.destroy());
chatMessages = null;
}
if(queue != null) {
queue = null;
}
}
/* (non-Javadoc)
* @see net.gtaun.shoebill.object.Destroyable#isDestroyed()
*/
@Override
public boolean isDestroyed() {
if(timer != null || currentChatMessage != null || chatMessages != null || queue != null)
return false;
return true;
}
//TODO: add background box and increase if new message and resize on message destroy
}
Initialize the chat in a Plugin in onEnable() or in Gamemode in onInit()! You need to save the reference (Chat chat = new Chat()). So on, uninitialize the chat in onDisable() with chat.destroy();
Example use:
A Command:
Код:
@Command
@CommandHelp("/chatme")
public boolean chatme(Player player, String msg) {
EventSystem.getInstance().getChat().sendMessage(player, msg);
return true;
}
Please leave a command, thanks

