[Include] [Shoebill] ColorCode supported Info Chat
#1

ColorCode supported Info Chat

******* Video
(original article [GERMAN])
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
Код:
/**
 * 
 */
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;
	}

}
Chat.java
Код:
/**
 * 
 */
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
}
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:
Код:
	@Command
	@CommandHelp("/chatme")
	public boolean chatme(Player player, String msg) {
		EventSystem.getInstance().getChat().sendMessage(player, msg);
		return true;
	}
Coming updates: Performance improvement (better visibility) with pre-calculation!

Please leave a command, thanks
Reply
#2

I think it's good, but I really find Shoebill a lot confusing.
Reply
#3

Looks pretty interesting, the code does too. Going to try this out, thanks for the share.
Reply
#4

Well done!
Btw, nice idea with textdraw sliding. At first I thought that you were re-creating textdraw on a new position, but you just set it's string
Also, I think you should make size of a textdraw's text a bit smaller and narrower
Reply
#5

Thanks for the feedback!

@SystemX:
If you need some explanations, examples or statements why using Shoebill, you can write me, i really can recommend Shoebill, easily, fast and lots of external function support.
@FreAkeD:
Thanks, the only animation bug occurs when you are try to display a message like this:
Код:
"WHITE                      SPACES"
, because i trimmed the text for this reason, that i did not know that textdraws will display whitespaces at the end, but i can fix this soon.
@valych:
Yeah, i try to reach the limits of SAMP and its performance so i play with textdraws and calculation, but this chat works great and have a advanced animation
You easily can change the appearance of the textdraw in createTextdraw(), it depends on the taste of every person^^

I improved the code to pre-calculate the string snippets and handle the chat with a better displayed performance!

ChatMessage.java
Код:
/**
 * 
 */
package me.alf21.util.chat;

import java.util.regex.Matcher;

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 String[] slideInStrings;
	private String[] slideOutStrings;
	
	public ChatMessage(Player player, String text, int slot) {
		this.player = player;
		this.text = removeNonColorCodes(text).trim();
		this.slot = slot;
		this.count = 1;
		createTextdraw(0,0);
		
		//initialize the string snippets to slide the text in
		slideInStrings = new String[getTextLength()];
		slideOutStrings = new String[getTextLength()-1];
		
		//calculate the string snippets
		int currentEndIndex = 0;
		for(int i=0; i<slideInStrings.length; i++) {
			currentEndIndex++;
			currentEndIndex = cutTextIn(currentEndIndex);
			slideInStrings[i] = text.substring(0, currentEndIndex);
		}
		currentEndIndex = text.length();
		for(int i=0; i<slideOutStrings.length; i++) {
			currentEndIndex--;
			currentEndIndex = cutTextOut(currentEndIndex);
			slideOutStrings[i] = text.substring(0, currentEndIndex);
		}
		
		time = System.currentTimeMillis();
	}
	
	public void slideIn() {
		sliding = true;
		reset();
		final int length = slideInStrings.length;
		final int interval = (int) Chat.slideTime/length;
		timer = Timer.create(interval, length, (factualInterval) -> {
			textdraw.hide();
			textdraw.setText(slideInStrings[count-1]);
			textdraw.show();
			if(count == length) {
				sliding = false;
				timer.stop();
			}
			count++;
		});
		timer.start();
	}
	
	public void slideOut() {
		sliding = true;
		reset();
		final int length = slideOutStrings.length;
		final int interval = (int) Chat.slideTime/length;
		timer = Timer.create(interval, length, (factualInterval) -> {
			textdraw.hide();
			textdraw.setText(slideOutStrings[count-1]);
			textdraw.show();
			if(count == length) {
				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 = Chat.colorStringPattern.matcher(text);
        if(matcher.find()) {
        	int matcherState = 0;
	        matcher = Chat.colorStringEndPattern.matcher(string);
	        Matcher matcher2 = Chat.wrongColorStringPattern.matcher(string);
	        if(matcher.find() && !matcher2.find()) {
	        	matcher = Chat.colorStringEndPattern.matcher(string); //update the matcher
	        	matcherState = 3;
	        }
	        else {
		        matcher = Chat.tildeLetterPattern.matcher(string);
		        if(matcher.find()) {
		        	matcher = Chat.tildeLetterPattern.matcher(string); //update the matcher
		        	matcherState = 4;
		        }
		        else {
			        matcher = Chat.tildePattern.matcher(string); //update the matcher
			        matcherState = 5;
		        }
	        }
	        while(matcher.find()) {
	        	//also 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 = Chat.colorStringEndPattern.matcher(string); //update the matcher
		        	if(!matcher.find()) {
			    		currentEndIndex -= 2;
			    		string = text.substring(0, currentEndIndex);
		        	}
		        	else 
		        		matcher = Chat.colorStringEndPattern.matcher(string); //update the matcher
		        	matcherState = 3;
		        }
	        }

        	string = text.substring(0, currentEndIndex);
	    	while(string.trim().length() < string.length()){
	    		currentEndIndex++;
	    		string = text.substring(0, currentEndIndex);
	    	}
	    	
	    	matcher2 = Chat.tildePattern.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 = Chat.colorStringPattern.matcher(text);
        if(matcher.find()) {
        	int matcherState = 0;
	        matcher = Chat.colorStringEndPattern.matcher(string);
	        if(matcher.find()) {
	        	matcher = Chat.colorStringEndPattern.matcher(string); //update the matcher
	        	matcherState = 3;
	        }
	        else {
		        matcher = Chat.tildeLetterPattern.matcher(string);
		        String string2 = text.substring(0, currentEndIndex+1);
		        Matcher matcher2 = Chat.colorStringEndPattern.matcher(string2);
		        if(matcher.find() && matcher2.find()) {
		        	matcher = Chat.tildeLetterPattern.matcher(string); //update the matcher
		        	matcherState = 2;
		        }
		        else {
			        matcher = Chat.tildePattern.matcher(string); //update the matcher
			        matcherState = 1;
		        }
	        }
	        while(matcher.find()) {
	        	//also 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 = Chat.colorStringEndPattern.matcher(string); //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 = Chat.colorStringPattern.matcher(text);
        while(matcher.find()) {
        	length -= 3;
        }
		return length;
	}

}
Chat.java
Код:
/**
 * 
 */
package me.alf21.util.chat;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

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;
	public static final Pattern 	colorStringPattern = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E"), //...~r~...
									colorStringEndPattern = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z"), //...~r~|
									tildeLetterPattern = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\\z"), //...~r|
									tildePattern = Pattern.compile("\u007E\\z"), //...~|
									wrongColorStringPattern = Pattern.compile("\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E+([\\w[\u003C\u003E&&[\\S]]]{1})\u007E\\z"); //...~s~r|
	private ArrayList<ChatMessage> chatMessages;
	private ChatMessage currentChatMessage;
	private Map<Player, String> queue;

	public Chat() {
		reset();
		initializeTimer();
	}
	
	public void sendMessage(Player player, String text) {
		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 / destroy if there is no message
}
Reply
#6

That will be extremely taxing resource wise (bandwidth mainly).
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)