Projekt Shoebill 1.2 - Schreibe Gamemodes in Java

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • 123marvin123:


    Danke, sehr gut erklärt, ich habe es verstanden, dank der Beispiele und Erläuterungen :)
    In meinem Gamemode funktioniert das jetzt, nur ganz durchblicke ich es doch noch nicht ^^
    Das Problem nun besteht darin, dass ich mich in einem EventManager (playerEventManager) befinde, welcher zB das PlayerDeathEvent,... regelt.
    Wie kann ich dort eine Instanz kreieren? Ist ja sozusagen dann eine Instanz in etwas was eine Instanz erstellen soll :/


    Ziel: Ich will den Killer von PlayerDeathEvent nach PlayerSpawnEvent bringen/vererben:

    Java
    package com.samp.lvdm;import java.util.Random;import net.gtaun.shoebill.Shoebill;import net.gtaun.shoebill.common.command.CommandGroup;import net.gtaun.shoebill.common.command.PlayerCommandManager;import net.gtaun.shoebill.common.player.PlayerLifecycleHolder;import net.gtaun.shoebill.constant.WeaponModel;import net.gtaun.shoebill.data.Color;import net.gtaun.shoebill.data.Vector3D;import net.gtaun.shoebill.event.player.PlayerCommandEvent;import net.gtaun.shoebill.event.player.PlayerConnectEvent;import net.gtaun.shoebill.event.player.PlayerDeathEvent;import net.gtaun.shoebill.event.player.PlayerDisconnectEvent;import net.gtaun.shoebill.event.player.PlayerRequestClassEvent;import net.gtaun.shoebill.event.player.PlayerSpawnEvent;import net.gtaun.shoebill.event.player.PlayerUpdateEvent;import net.gtaun.shoebill.event.player.PlayerWeaponShotEvent;import net.gtaun.shoebill.object.Player;import net.gtaun.util.event.EventManager;import net.gtaun.util.event.EventManagerNode;import net.gtaun.util.event.HandlerPriority;public class PlayerManager{	public static final int MAX_PLAYERS = LvdmGamemode.MAX_PLAYERS;	private boolean suicid = false;	private boolean killed = false;	private Player[] lastKiller = new Player[MAX_PLAYERS];	private static final int INITIAL_MONEY = 50000;	private static final Vector3D[] RANDOM_SPAWNS =	{		new Vector3D(1958.3783f, 1343.1572f, 15.3746f),		new Vector3D(2199.6531f, 1393.3678f, 10.8203f),		new Vector3D(2483.5977f, 1222.0825f, 10.8203f),		new Vector3D(2637.2712f, 1129.2743f, 11.1797f),		new Vector3D(2000.0106f, 1521.1111f, 17.0625f),		new Vector3D(2024.8190f, 1917.9425f, 12.3386f),		new Vector3D(2261.9048f, 2035.9547f, 10.8203f),		new Vector3D(2262.0986f, 2398.6572f, 10.8203f),		new Vector3D(2244.2566f, 2523.7280f, 10.8203f),		new Vector3D(2335.3228f, 2786.4478f, 10.8203f),		new Vector3D(2150.0186f, 2734.2297f, 11.1763f),		new Vector3D(2158.0811f, 2797.5488f, 10.8203f),		new Vector3D(1969.8301f, 2722.8564f, 10.8203f),		new Vector3D(1652.0555f, 2709.4072f, 10.8265f),		new Vector3D(1564.0052f, 2756.9463f, 10.8203f),		new Vector3D(1271.5452f, 2554.0227f, 10.8203f),		new Vector3D(1441.5894f, 2567.9099f, 10.8203f),		new Vector3D(1480.6473f, 2213.5718f, 11.0234f),		new Vector3D(1400.5906f, 2225.6960f, 11.0234f),		new Vector3D(1598.8419f, 2221.5676f, 11.0625f),		new Vector3D(1318.7759f, 1251.3580f, 10.8203f),		new Vector3D(1558.0731f, 1007.8292f, 10.8125f),		new Vector3D(-857.0551f, 1536.6832f, 22.5870f),		new Vector3D(817.3494f, 856.5039f, 12.7891f),		new Vector3D(116.9315f, 1110.1823f, 13.6094f),		new Vector3D(-18.8529f, 1176.0159f, 19.5634f),		new Vector3D(-315.0575f, 1774.0636f, 43.6406f),		new Vector3D(1705.2347f, 1025.6808f, 10.8203f)	};	private EventManagerNode eventManagerNode;	private PlayerCommandManager commandManager;	private Random random;	public PlayerManager(EventManager rootEventManager)	{			random = new Random();		eventManagerNode = rootEventManager.createChildNode();		commandManager = new PlayerCommandManager(eventManagerNode);		commandManager.installCommandHandler(HandlerPriority.NORMAL);		commandManager.registerCommands(new LvdmCommands());		commandManager.registerCommands(new TestCommands());		commandManager.registerCommands(new AdminCommands()); 		// Example: register /test [command] ...		CommandGroup testGroup = new CommandGroup();		testGroup.registerCommands(new TestCommands());		commandManager.registerChildGroup(testGroup, "test");		// Example: register /admin [command] ...		CommandGroup adminCommands = new CommandGroup(); 		adminCommands.registerCommands(new AdminCommands()); 		commandManager.registerChildGroup(adminCommands, "admin");		commandManager.setUsageMessageSupplier((player, command, prefix, params, help) -> {             String message = prefix + command;             for (String param : params) {                 message += " [" + param + "]";             }             return message;         }); 	//--		eventManagerNode.registerHandler(PlayerUpdateEvent.class, (e) ->		{			Player player = e.getPlayer(); 			// getUpdateCount() Example			if (player.getUpdateCount() % 100 == 0)			{				player.setScore(player.getMoney());			}			if(suicid) {				Shoebill.get().runOnSampThread(() -> {					LvdmGamemode.queue.addPoints(player, "SELBSTMORD", -100, DynamicActionLabel.DynamicItem.TYPE_BIG);				});				suicid = false;			}			if(killed) {				Shoebill.get().runOnSampThread(() -> {					LvdmGamemode.functions.showKiller(player, lastKiller[player.getId()]);				});				killed = false;			}		});		eventManagerNode.registerHandler(PlayerWeaponShotEvent.class, (e) ->		{		//	e.getPlayer().sendMessage(Color.LIGHTBLUE, String.format("WeaponShot: hittype: %1$s, weapon: %2$s, pos: %3$s", e.getHitType(), e.getWeapon(), e.getPosition()));		});		eventManagerNode.registerHandler(PlayerConnectEvent.class, (e) ->		{			Player player = e.getPlayer();			player.sendGameText(5000, 5, "~w~SA-MP: ~r~Las Venturas ~g~MoneyGrub");			Player.sendMessageToAll(Color.GREEN,player.getName()+" Connected!");			player.sendMessage(Color.PURPLE, "Welcome to Las Venturas MoneyGrub, For help type /help.");			Player.sendDeathMessageToAll(player, null, WeaponModel.CONNECT);			Color color = new Color();			do color.setValue(random.nextInt()); while (color.getY() < 128);			player.setColor(color);		});		eventManagerNode.registerHandler(PlayerDisconnectEvent.class, (e) ->		{			Player player = e.getPlayer();			Player.sendMessageToAll(Color.RED,player.getName()+" Disconnected!");			Player.sendDeathMessageToAll(player, null, WeaponModel.DISCONNECT);		});		eventManagerNode.registerHandler(PlayerSpawnEvent.class, (e) ->		{				Player player = e.getPlayer();			player.giveMoney(INITIAL_MONEY);			player.toggleClock(true);			setRandomSpawnPos(player);			if(suicid) {				Shoebill.get().runOnSampThread(() -> {					LvdmGamemode.queue.addPoints(player, "SELBSTMORD", -100, DynamicActionLabel.DynamicItem.TYPE_BIG);				});				suicid = false;			}			if(killed) {				Shoebill.get().runOnSampThread(() -> {					LvdmGamemode.functions.showKiller(player, lastKiller[player.getId()]);				});				killed = false;			}		});		eventManagerNode.registerHandler(PlayerDeathEvent.class, (e) ->		{			Player player = e.getPlayer();			Player killer = e.getKiller();			player.setMoney(0);						Player.sendDeathMessageToAll(killer, player, e.getReason());			if (killer != null) {				killer.giveMoney(player.getMoney());			}			if(killer != null && killer.getName() != player.getName()) {				LvdmGamemode.queue.addPoints(killer, "GEGNER ELIMINIERT", 100, DynamicActionLabel.DynamicItem.TYPE_BIG);				if(LvdmGamemode.MessageOnRespawnAfterDead) {					killed = true;					lastKiller[player.getId()] = killer;				} else {					LvdmGamemode.functions.showKiller(player, killer);				}			} 			else if(killer == null && player != null || killer.getName() == player.getName()) {				if(LvdmGamemode.MessageOnRespawnAfterDead) {					suicid = true;				} else {					LvdmGamemode.queue.addPoints(player, "SELBSTMORD", -100, DynamicActionLabel.DynamicItem.TYPE_BIG);				}			}		});		eventManagerNode.registerHandler(PlayerRequestClassEvent.class, (e) ->		{			Player player = e.getPlayer();			setupForClassSelection(player);		});		eventManagerNode.registerHandler(PlayerCommandEvent.class, HandlerPriority.BOTTOM, (e) ->		{			Player player = e.getPlayer();			player.sendMessage(Color.RED, "Unknown command. Type /help to see help.");			e.setProcessed();		});	}	public void uninitialize()	{		commandManager.destroy();		eventManagerNode.destroy();	}	private void setRandomSpawnPos(Player player)	{		int rand = random.nextInt(RANDOM_SPAWNS.length);		player.setLocation(RANDOM_SPAWNS[rand]);		player.setInterior(0);	}	private void setupForClassSelection(Player player)	{		player.setInterior(14);		player.setLocation(258.4893f, -41.4008f, 1002.0234f);		player.setAngle(270.0f);		player.setCameraPosition(256.0815f, -43.0475f, 1004.0234f);		player.setCameraLookAt(258.4893f, -41.4008f, 1002.0234f);	}}


    Thx und danke für die Hilfe :thumbup:
    Musst dir das mit den Instanzen merken, für nen Tutorial oder so, war gut erklärt und würde bst noch anderen helfen, falls sie es nicht wussten wie ich ^^
    (Ich nutze normalerweise sehr viele Variablen :/)


    ------------------------
    >>edit:


    Habe es nun im EventHandler/Manager über folgendes gelöst:

    Code
    PlayerLifecycleHolder playerLifecycleHolder = new PlayerLifecycleHolder(rootEventManager.createChildNode()); 
    		playerLifecycleHolder.registerClass(Lifecycle.class, (lifecycle, p) -> new Lifecycle(lifecycle, p));


    Das doofe ist nur immer ein neuen Lifecycle.getObjects in jedem Event zu erstellen... Kann man nicht statt dessen ein globalen Array erstellen mit MAX_PLAYERS, welcher dann beim PlayerConnectEvent bzw PlayerRequestClassEvent auf die playerid abgestimmt wird und so dann immer wieder aufrufbar ist, ohne neu zu definieren? :D


    Bsp.:


    Kann man das auch anders aber einfacher als meine Methode machen oder ist deine wirklich die beste in dem Fall?
    Immer getObject in jeder Methode ist auch nicht soo toll, aber wäre auch nicht schlimm, hilft ja sehr :D
    Nur ich finde es bei meiner Methode nervig, dass man nach jeder Abfrage dann immer ''playerLifecycle[e.getPlayer().getId()]."... schreiben muss :D


    Und wäre meine nicht sicherer? Könnte ja sein, dass sich die playerLifecycle überschreiben, wenn zB 2 gleichzeitig sterben (Explosion) ?

  • Du könntest einen EventHandler für den Spieler erstellen:



    Ich bin mir nicht sicher ob es funktioniert, es ist aber einen Versuch wert. Mit den Attentions kannst du ein Event für einen bestimmten Spieler/Fahrzeug/etc. filtern.
    Es wird also nur für den einen Spieler aufgerufen ;)

  • Thx, läuft alles super! :)


    Also gibts - wie immer in Java - mehrere Möglichkeiten, es zu realisieren.
    Ich denke ich nehme das mit den Instanzen bei Werten, welche ich später noch brauche und das mit dem neuen EventHandler bei den Sachen, die einfach nur einmal ihren Zweck erfüllen sollen.

  • Solange unser Buildserver nicht erreichbar ist, könnt ihr auch die Sonatype Repo verwenden. (https://oss.sonatype.org/content/repositories/snapshots/)


    In der pom.xml tragt ihr bei repositories folgendes ein:


    Code
    <repository>
                <id>sonatype-nexus-snapshots</id>
                <name>Sonatype Nexus Snapshots</name>
                <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
                <snapshots>
                    <enabled>true</enabled>
                    <updatePolicy>daily</updatePolicy>
                </snapshots>
            </repository>


    //Update: Shoebill 1.1 wurde soeben released.
    Die neue Version ermöglicht es euch, Pawn Gamemodes und Filterscripts gleichzeitig mit Shoebill Gamemodes zu verwenden.
    Ein genaueres Tutorial folgt noch. Download im Startthread. Wenn ihr updaten möchtet, dann nehmt den updater aus dem neuen Downloadpaket und führt update-shoebill.bat aus.

  • >>edit:
    123marvin123:


    Die Links zu den Downloads sind wohl broken, es wird URL not request glaube angezeigt bei beiden...
    Ehm... Ich habe jetzt einfach von der GitHub gedownloaded, mal gucken ob es klappt


    Und wenn alles klappt und auch so, hammer Arbeit ! :thumbup:


    --------------------------


    Hab mir mal die Arbeit (^^) gemacht, um nen kleinen Fix in die DynamicActionLabel.java reinzuhauen.


    Frage: Habt ihr für dieses Problem eine bessere/saubere/stabilere Lösung? Diese braucht recht viel Performance :/


    >>update: Bugs gefixt


    --------------------------


    Fix der Bugs des ersten 'Beta' Posts ^^
    Man kann nun Farben und andere "~"/Tilde in den Inputs/Reasons nutzen (like ~r~, ~h~)
    Das einzige was noch erledigt werden muss: Max String Länge mit Autoremove, um Fehlermeldungen und hässlichem Aussehen voraus zu sein ;)


    DynamicActionLabel.java

    Java
    //Bug: Die max. Länge des input Strings sollte noch definiert werden, bzw ein Erkennungs- und Kürzungssystem eingebaut werden, um Fehlermeldungen zu vermeiden//Anfällig: Für Spams von Strings -> Fehler//Lsg.: Input einlesen, kürzen, ausgeben ^^ Am besten gleich bei addPoints()/add() + Timeout gegen Spam?package com.samp.lvdm;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.regex.*;import net.gtaun.shoebill.constant.TextDrawAlign;import net.gtaun.shoebill.exception.CreationFailedException;import net.gtaun.shoebill.object.Player;import net.gtaun.shoebill.object.PlayerTextdraw;public class DynamicActionLabel extends Thread {	private ArrayList<DynamicItem> items = new ArrayList<DynamicItem>();	private int mPoints = 0;	private boolean combo = false;	private PlayerTextdraw mComboTextbase = null;	private Player mPlayer;	public DynamicActionLabel() { }	public class DynamicItem {		public static final int TYPE_BIG = 1;		public static final int TYPE_SMALL = 2;		private int mYPosition = 0;		private String mText;		private Player mPlayer;		private PlayerTextdraw mVisibleTextdraw;		private boolean mRemovable = false;		private boolean mPending = true;		private long mTimestamp;		private int mType;		private PlayerTextdraw textdraw = null;		public void setPending(boolean pStatus) {			mPending = pStatus;		}		public boolean isActive() {			return ((mTimestamp + 6) < (System.currentTimeMillis() / 1000l)) ? false : true;		}		public boolean isPending() {			return mPending;		}		public boolean isRemovable() {			return mRemovable;		}		public int getYPosition() {			return mYPosition;		}		public String getText() {			return mText;		}		public void setText(String pText) {			mText = pText;		}		public DynamicItem(Player pPlayer, String pText, int pType) {			this.mText = pText;			this.mPlayer = pPlayer;			this.mVisibleTextdraw = createTextDraw(mText, 0, 0);			this.mTimestamp = (System.currentTimeMillis() / 1000l);			this.mType = pType;		}		public PlayerTextdraw createTextDraw(String pText, int x, int y) {			try {				textdraw = PlayerTextdraw.create(mPlayer, 400+x, 310+y);				textdraw.setText(pText);				textdraw.setAlignment(TextDrawAlign.RIGHT);				if(mType == TYPE_SMALL) {					textdraw.setLetterSize(0.135f*3, 0.135f*6);				}				else if(mType == TYPE_BIG) {					textdraw.setLetterSize(0.135f*4, 0.135f*8);				}			}			catch(CreationFailedException e) {		//	catch(Exception e) {				e.printStackTrace();			}			return textdraw;		}		public void setCurrentTextdraw(PlayerTextdraw pTextdraw) {			mVisibleTextdraw = pTextdraw;		}		public void moveDown() {			mYPosition++;			if(mYPosition > 100) {				mRemovable = true;			}			else {				PlayerTextdraw newTextdraw = createTextDraw(mText, 0, mYPosition);				hide();				setCurrentTextdraw(newTextdraw);				display();			}		}		public void display() {			if(mVisibleTextdraw != null)				mVisibleTextdraw.show();		}		public void hide() {			if(mVisibleTextdraw != null) {				mVisibleTextdraw.hide();					mVisibleTextdraw.destroy();			}		}	}	public void run() {		while(!interrupted()) {			//Server.get().sendMessageToAll(Color.BLUE, "Thread:"+Thread.currentThread().getName());			checkItemDuration();			if((mComboTextbase == null && mPlayer != null) || (mPlayer != null && !mComboTextbase.getText().equals(String.valueOf(mPoints))))				updateComboScore(mPlayer);			try {				List<DynamicItem> newList = new ArrayList<DynamicItem>(items);				Iterator<DynamicItem> it = newList.iterator();				while(it.hasNext()) {					DynamicItem item = it.next();					if(item.isPending()) {						moveItemsDown();						// show pending item						fadeItemIn(item);						// unset pending status						item.setPending(false);					}				}				Thread.sleep(200);			}			catch(Exception e) {				System.out.println(">>\t[Error]>> in run() :");				e.printStackTrace();			}		}	}	private void fadeItemIn(DynamicItem item) {		String text = item.getText();		String text2 = text;	//Addition to display Colors by Alf21	//############################################################### WICHTIG ###########################################################	//#								Anfällig, wenn bei der String/Input/Reason zu groß ist oder gespamt wird!  							#	//#												Lsg.: Reason erkennen und kürzen + Timeout?								  	#		boolean colors = false;		int colCount = 0;        Matcher matcher = Pattern.compile("\u007E+\\w+\u007E").matcher(text);        while(matcher.find()){        	colors = true;	    	colCount++;        }		int length = text.length();		if(colors){	        Matcher lastColor = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text); 		//~r~|			if(!lastColor.find()) {				length = text.length()-(colCount-1)*3;			}			else { //Falls hinten eine Farbe ist, um 3 wegen dem Ausschwenken verkürzen, die Farbe sieht man eh nicht, den Ausschwenker jedoch schon				length = text.length()-colCount*3;			}		}		for(int i=0;i<=length;i++) {			int i2 = i;			text2 = text.substring(0, i2);			if(colors) {		        Matcher matcher1 = Pattern.compile("\u007E\\z").matcher(text2); //~|		        Matcher matcher2 = Pattern.compile("\u007E+\\w\\z").matcher(text2); //~r|		        Matcher matcher3 = Pattern.compile("\u007E+\\w\u007E+\\w\\z").matcher(text2); //~r~A|		        Matcher matcher4 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text2); //~r~|		    /*		    * wenn: - der String ein "~"(Tilde) + [Buchstaben] enthält,		    * aber nicht, wenn: - der String selbst eine Farbangabe "~r~" ist 		    * 					- keine "Buchstabe eines Wortes auf den Str folgt		    * Ergebnis: -> um 1 erweitern		    */		        if(matcher2.find() && !matcher3.find() && !matcher4.find()){		        	i2 += 1;			        Matcher matcher5 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text.substring(0, i2));		        	if(!matcher5.find()) {		        		i2 -= 1;		        	}		        }		    /*		    * wenn: - der String ein "~"(Tilde) enthält,		    * aber nicht, wenn: - der String selbst eine Farbangabe "~r~" ist 		    * 					- keine "Buchstabe eines Wortes auf den Str folgt		    * Ergebnis: -> um 2 erweitern		    */		        else if(matcher1.find() && !matcher3.find() && !matcher4.find()){		        	i2 += 2;			        Matcher matcher5 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text.substring(0, i2));		        	if(!matcher5.find()) {		        		i2 -= 2;		        	}		        }			}			PlayerTextdraw newTextdraw = item.createTextDraw(text.substring(0, i2), -10, 0);			item.hide();			item.setCurrentTextdraw(newTextdraw);			item.display();			try {				Thread.sleep(10);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				System.out.println(">>\t[Error]>> in fadeItemIn() :");				e.printStackTrace();			}		}		if(mPlayer != null)			mPlayer.playSound(1131);		for(int i=0;i<=10;i++) {			PlayerTextdraw newTextdraw = item.createTextDraw(text, i-10, 0);			item.hide();			item.setCurrentTextdraw(newTextdraw);			item.display();			try {				Thread.sleep(20);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				System.out.println(">>\t[Error]>> in fadeItemIn() :");				e.printStackTrace();			}		}	}	private void checkItemDuration() {		try {			Iterator<DynamicItem> it = items.iterator();			while(it.hasNext()) {				DynamicItem item = it.next();				if(!item.isActive()) {					//Server.get().sendMessageToAll(Color.RED, "Removing item based on timestamp!");					// custom hide animation					String text = item.getText();					String text2 = text;				//Addition to display Colors by Alf21				//############################################################### WICHTIG ###########################################################				//#								Anfällig, wenn bei der String/Input/Reason zu groß ist oder gespamt wird!  							#				//#												Lsg.: Reason erkennen und kürzen + Timeout?								  	#					boolean colors = false;					int colCount = 0;			        Matcher matcher = Pattern.compile("\u007E+\\w+\u007E").matcher(text);			        while(matcher.find()){			        	colors = true;				    	colCount++;			        }					int length = text.length();					if(colors){				        Matcher lastColor = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text); 		//~r~|						if(!lastColor.find()) {							length = text.length()-(colCount-1)*3;						}						else { //Falls hinten eine Farbe ist, um 3 wegen dem Ausschwenken verkürzen, die Farbe sieht man eh nicht, den Ausschwenker jedoch schon							length = text.length()-colCount*3;						}					}					for(int i=0;i<=length;i++) {						int i2 = i;						text2 = text.substring(0, length-i2);						if(colors) {					        Matcher matcher1 = Pattern.compile("\u007E\\z").matcher(text2); 				//~|					        Matcher matcher2 = Pattern.compile("\u007E+\\w\\z").matcher(text2); 			//~r|					        Matcher matcher3 = Pattern.compile("\u007E+\\w\u007E+\\w\\z").matcher(text2); 	//~r~A|					        Matcher matcher4 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text2); 		//~r~|					    /*					    * wenn: - der String ein "~"(Tilde) + [Buchstaben] enthält,					    * aber nicht, wenn: - der String selbst eine Farbangabe "~r~" ist 					    * 					- keine "Buchstabe eines Wortes auf den Str folgt					    * Ergebnis: -> um 1 erweitern					    * 					    * Fix: Test, ob Erweiterung eine Farbe ergibt, falls nicht zurücksetzen					    */					        if(matcher2.find() && !matcher3.find() && !matcher4.find()){					        	i2 += 2;						        Matcher matcher5 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text.substring(0, (length+3)-i2));					        	if(!matcher5.find()) {					        		i2 -= 2;					        	}					        }					    /*					    * wenn: - der String ein "~"(Tilde) enthält,					    * aber nicht, wenn: - der String selbst eine Farbangabe "~r~" ist 					    * 					- keine "Buchstabe eines Wortes auf den Str folgt					    * Ergebnis: -> um 2 erweitern					    * 					    * Fix: Test, ob Erweiterung eine Farbe ergibt, falls nicht zurücksetzen					    */					        else if(matcher1.find() && !matcher3.find() && !matcher4.find()){					        	i2 += 1;						        Matcher matcher5 = Pattern.compile("\u007E+\\w\u007E\\z").matcher(text.substring(0, (length+3)-i2));					        	if(!matcher5.find()) {					        		i2 -= 1;					        	}					        }						}						PlayerTextdraw newTextdraw = item.createTextDraw(text.substring(0, length-i2), 0, item.getYPosition());						item.hide();						item.setCurrentTextdraw(newTextdraw);						item.display();						try {							Thread.sleep(10);						} catch (InterruptedException e) {							// TODO Auto-generated catch block							System.out.println(">>\t[Error]>> in checkItemDuration() :");							e.printStackTrace();						}					}					item.hide();						it.remove();				}			}		}		catch(Exception e) {			// TODO fix ConcurrentModificationException			System.out.println(">>\t[Error]>> in checkItemDuration() :");			e.printStackTrace();		}		//remove if necessary		if(items.size() == 0) {			combo = false;			//Server.get().sendMessageToAll(Color.BLUE, "COMBO:FALSE ("+items.size()+") ");			mPoints = 0;			if(mComboTextbase != null)				removeComboScore();		}	}	private void moveItemsDown() {		for(int i=0;i<18;i++) {			Iterator<DynamicItem> it = items.iterator();			while(it.hasNext()) {				DynamicItem item = it.next();				if(!item.isPending())					item.moveDown();				if(item.isRemovable()) {					if(items.contains(item)) {						item.hide();						it.remove();						//Server.get().sendMessageToAll(Color.RED, "REMOVE:"+items.size());					}				}			}			try {				Thread.sleep(30);			} catch (InterruptedException e) { 				System.out.println(">>\t[Error]>> in moveItemsDown() :");				e.printStackTrace();			}		} 	}	private void add(Player pPlayer, String text, int type) {		DynamicItem item = new DynamicItem(pPlayer, text, type);		items.add(item);	}	public void addPoints(Player pPlayer, String reason, int amount, int type) {		this.mPlayer = pPlayer;	// TODO INSECURE!!! Solve one queue per player in constructor!!!		//Addition by Alf21		if(!LvdmGamemode.allowNegativePoints)		{			if(this.mPoints + amount < 0) { //Test negative Value				this.mPoints = 0;			} else {				this.mPoints += amount; 			}		} else {			this.mPoints += amount;		}		if(amount != 0) {			add(pPlayer, reason+" "+amount, type);		}		else {			add(pPlayer, reason, type);		}		//check if combo mode		if(items.size() > 1) {			combo = true;			//Server.get().sendMessageToAll(Color.BLUE, "COMBO:TRUE ("+items.size()+")");			if(mComboTextbase != null)				removeComboScore();		}	}	private void updateComboScore(Player pPlayer) {		if(mPoints == 0 || items.size() <= 1)			return;		String score = String.valueOf(mPoints);		mComboTextbase = PlayerTextdraw.create(pPlayer, 425, 310);		for(int i=0;i<=score.length();i++) {			mComboTextbase.setText(score.substring(0, i));			mComboTextbase.show();			try {				Thread.sleep(50);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				System.out.println(">>\t[Error]>> in updateComboScore() :");				e.printStackTrace();			}		}	}	private void removeComboScore() {		mComboTextbase.setText(" ");		mComboTextbase.hide();		mComboTextbase.destroy();	}}


    Zum Testen ein paar Commands, aber da es eine Beta ist, gibts auch hier noch ein paar Bugs: beim Spam-Nutzen des Commands 'testBeta6' wird eine kleine Fehlermeldung auftauchen bzw. beim nutzen von zB 2x 'testBeta6' + 'teamKill 0'

    Code
    @Command	@CommandHelp("/teamKill [playerID]")	public boolean teamKill(Player p, int targetID) {		Player.get(targetID).setHealth(0.0f);		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(p, "~r~TEAMKILL (~w~" + Player.get(targetID).getName() + "~r~)", -100, DynamicActionLabel.DynamicItem.TYPE_BIG);			p.sendMessage(Color.RED, "* Du hast " + Player.get(targetID).getName() + " aus deinem Team getötet!");		});		return true;	}	@Command	@CommandHelp("/testBeta1")	public boolean testBeta1(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test1 (~w~start~g~)end", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/testBeta2")	public boolean testBeta2(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test2 (~w~start~g~)end~r~", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/testBeta3")	public boolean testBeta3(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test3 ~y~(~w~start~g~)end~r~", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/testBeta4")	public boolean testBeta4(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test4 ~p~(~w~start~g~)hfu~b~dus~x~dhffhu~r~", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/testBeta5")	public boolean testBeta5(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test5 ~p~(~w~start~g~)hfu~b~dus~x~dhffhu", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/testBeta6")	public boolean testBeta6(Player player) {		Shoebill.get().runOnSampThread(() -> {			LvdmGamemode.queue.addPoints(player, "~g~Test6 ~p~(~w~start~g~)fu~b~dsh~fs~x~dhffhu~", 20, DynamicActionLabel.DynamicItem.TYPE_BIG);		});		return true;	}	@Command	@CommandHelp("/heal [HP]")	public boolean heal(Player p, String params) //String, um es später auf Float und Double zu parsen...	{		try {	       Float.parseFloat(params);	       Double.parseDouble(params);	    } catch (NumberFormatException e) {	    /*	e.printStackTrace();	    	System.out.println(">>\t[ERROR] in heal ::::: in AdminCommands");*/	    	p.sendMessage(Color.RED, ">>[ERROR]: Dein Parameter muss eine Zahl sein!");	        return false;	    }		LvdmGamemode.queue.addPoints(p, "Geheilt auf " + Double.parseDouble(params) + " Leben", -100, DynamicActionLabel.DynamicItem.TYPE_BIG);		p.setHealth(Float.parseFloat(params));		return true;	}	@Command	@CommandHelp("/explode [playerID]") 	public boolean explode(Player p, int pID) {		float x, y, z;		// Get the player's position		AngledLocation locationTarget = Player.get(pID).getLocation();		x = locationTarget.getX();		y = locationTarget.getY();		z = locationTarget.getZ();	    // Create an explosion at the player's position		Player.get(pID).createExplosion(x, y, z, 12, 10);		return true;	}


    MfG Alf21

  • mir fehlt seit dem neuen Update die net/gtaun/shoebill/event/server/GameModeInitEvent, weshalb der Server denke nicht starten will:


    Fehlermeldung:


    Steht die iwo zum download zur Verfügung oder woran liegt es? :(

  • Dann hast du irgendwelche alten Artefakte. Wahrscheinlich eine alte shoebill-api.


    //Edit:
    Falls euer Server crasht wenn ihr ein Dialog anzeigt, bitte ich euch den mitgelieferten shoebill-updater zu verwenden. (update-shoebill.bat/sh)
    Dieser Bug sollte nun gefixxt sein, und euer Server sollte nicht aufgrund dieses Fehlers crashen.





    - Alle Callbacks die den Rückgabewert behandeln können nun korrekt in Shoebill verwendet werden. (PlayerUpdateEvent unterbrechen, PlayerTextEvent, etc.)
    - Es können nun native Funktionen von anderen Plugins aufgerufen werden. (Stelle dafür sicher das Shoebill in der server.cfg an erster Stelle steht)
    - Der player.spawn() Bug wurde behoben, die Spieler spawnen wie gewohnt


    (Benutzung)



    Callbacks unterbinden:


    PHP
    eventManager.registerHandler(PlayerTextEvent.class, event -> {
                if(event.getPlayer().isSpectating())
                    event.disallow(); //There will be no message in the chat if the player is currently spectating somebody
    });


    Native Funktionen aufrufen (Streamer Beispiel):


    PHP
    AmxCallable createDynamicObject = null;
    for(AmxInstance instance : Shoebill.get().getAmxInstanceManager().getAmxInstances()) {
            createDynamicObject = instance.getNative("CreateDynamicObject");
            if(createDynamicObject != null) {
                    //found CreateDynamicObject native, call it like this:
                    createDynamicObject.call(18421, ....); //normal pawn arguments. Make sure you put a f after a Float value, like this: 13.0f or 0f
                    break;
           }
    }


    Bitte benutzt den beigelegten shoebill-updater, weil sich der Launcher, das Plugin und die Runtime geändert haben. Einfach die update-shoebill.bat/sh Datei im Serverordner starten und die neusten Dateien werden runtergeladen.



    Ich hab mal ein kleines Video gemacht, wie mein ein einfaches Projekt in IntelliJ IDEA 14 aufsetzt:

    Externer Inhalt www.youtube.com
    Inhalte von externen Seiten werden ohne Ihre Zustimmung nicht automatisch geladen und angezeigt.
    Durch die Aktivierung der externen Inhalte erklären Sie sich damit einverstanden, dass personenbezogene Daten an Drittplattformen übermittelt werden. Mehr Informationen dazu haben wir in unserer Datenschutzerklärung zur Verfügung gestellt.

    https://www.youtube.com/watch?v=g2SOqax3Euw



    Es wurde soeben ein wichtiger Fehler behoben. Ihr könnt mit dem mitgelieferten Updater (update-shoebill.bat/sh) die benötigten Dateien automatisch runterladen lassen.
    Ihr könnt jedoch auch die Dateien aus dem Startpost neu runterladen, und die Dateien ersetzen. Das Update sollte auf jeden Fall durchgeführt werden, wenn ihr die Sicherheit und Stabilität eures Servers nicht vernachlässigen wollt.


    //Edit: Update 4. März




    - Callbacks hooken & native Funktionen aufrufen
    - Eine Amx mit allen Callbacks ist nun nicht mehr nötig, Shoebill findet die Callbacks automatisch


    Wir sind froh, euch das neuste Update präsentieren zu dürfen. Das Update bringt die Möglichkeit Callbacks zu hooken.
    Bitte stellt sicher, dass ihr den shoebill-updater verwenden (update-shoebill.bat/sh im server Ordner), weile viele Dateien geändert wurden (shoebill-runtime, launcher, plugin, api)


    In diesem Beispiel werde ich euch zeigen, wie ihr Callbacks des Plugin FCNPC hooken könnt, und native Funktionen aufzurufen:
    (plugin url: http://forum.sa-mp.com/showthread.php?t=428066)


    Hook hinzufügen (Stellt sicher, dass ihr die Hook wieder löscht wenn der GM / das Plugin wieder entladen wird):


    Der FCNPC_OnCreate Callback sieht wie folgt aus:
    public FCNPC_OnCreate(npcid);


    Wie man sieht, beinhaltet er einen Parameter (Integer). Also müssen wir diesen Parameter am Ende der .hookCallback() Methode registrieren. Es existieren folgende Datentypen:


    i -> Integer
    f -> Float
    s -> String


    Wenn man also einen Callback hat, der so aussieht:
    public OnPlayerChangeName(id, old_name, new_name[]);


    müsste man ihn wie folgt registrieren:


    PHP
    Shoebill.get().getAmxInstanceManager().hookCallback("OnPlayerChangeName", amxCallEvent -> {
    
    
    }, "iss");


    Wenn man nun einen NPC mithilfe von FCNPC erstellen möchte, muss die native Funktion aufgerufen werden (in einem Befehl z.B):
    Die Funktion dafür sieht wie folgt aus:
    native FCNPC_Create(name[]);


    Außerdem wird die ID des erstellten NPCs zurück gegeben:



    - Dieses Update erlaubt es, Werte per Referenz zu übergeben (benötigt z.B. für GetPlayerName & GetPlayerPos)


    Um das neue Feature nutzen zu können, müsst ihr das Plugin und shoebill-api updaten. (update-shoebill.bat/sh in dem Server Ordner)


    So wird es benutzt:



    Der Code ist natürlich nicht besonders nützlich, da man auch einfach player.getName(); verwenden kann, man kann jedoch auch native Funktionen von anderen Plugins aufrufen (z.B. FCNPC_GetPosition).
    Aktuell sind 3 Datentypen verfügbar:


    + ReferenceString
    + ReferenceFloat
    + ReferenceInt


    welche alle im Package net.gtaun.shoebill.amx.types zu finden sind.

    7 Mal editiert, zuletzt von 123marvin123 () aus folgendem Grund: Update 4. März

  • Hey ich bins wieder ^^
    Was wäre die einfachste Methode zu checken, ob ein Spieler connected ist ?
    (PAWN: if(IsPlayerConnected(playerid)){...})
    wie mache ich das hier ? Über das neue Update mit den Referenzen oder das update am 25 Jan mit den Callbacks?
    leider gibt es im Internet keine Dokumentation :/
    Man sollte für Shoebill auch eine Übersicht machen, damit man schnell etwas findet und nicht nach Befehlen oder Abfragen / Klassennamen suchen muss :o


    Bin dabei einfach den Chat zu säubern (Chat-Saubermachen-Funktion^^), aber ist wohl schwerer als ich es dachte für mich 8|

  • Alf21: Es gibt doch die Javadocs (Shoebill API & shoebill-common), da steht eigentlich alles an Funktionen drin was man wissen muss.


    Chat clearen würde ich so machen:

    Java
    for(Player p: Player.get()) { //Player.get() gibt ne Liste mit allen Spielern zurück
        for (int i = 0; i < 10; i++) { //10 anpassen, ka wie viele das sein müssen.
            p.sendMessage(Color.WHITE, "");
        }
    }


    bzw. wenn du den Chat von ALLEN Spielern löschen willst kannste auch einfach

    Java
    for (int i = 0; i < 10; i++) {
        Player.sendMessageToAll(Color.WHITE, "");
    }

    The fact is, I am right. And if you think I'm wrong, you are wrong.

  • Wie Installiert man das denn, damit ich es nutzen kann? Das ist mein einzigstes Problem :D

    @MiX(eP) :
    Dazu hat 123marvin123 extra ein Tutorial gemacht :D
    Ich nutze zB Eclipse. Ich habe alles der Anleitung nach gemacht, Downloads sind ja auch angegeben.
    Dann bin ich einfach in Eclipse unter Hilfe gegangen und unter Marktplatz. Dort kannst du dir kostenlos Maven downloaden, dazu musst du nur "m2e" als Plugin suchen und installieren, glaube das heißt iwie "m2e Support for Keppler S2" oder so ^^ Auf jeden Fall, falls das nicht geht muss du dir erst Keppler S2 oder wie das heißt downloaden, kannst du dort auch einfach suchen. Und fertig, dann musst du nur noch einrichten (Maven, einfach nach Installationsanleitung).


    Hier meine Maven Bsp. Datei:

    Code
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">	<modelVersion>4.0.0</modelVersion>	<groupId>[Dein Pfad, wie dein Package-Name, in dem der Gamemode ist, z.B. com.samp.gamemode]</groupId>	<artifactId>Dein_Projektname</artifactId>	<version>0.0.1-SNAPSHOT</version>		<name>Dein_Projektname</name>	<description>Deine Projekt Beschreibung</description>	<url>Deine_URL_zur_Website</url>		<properties>		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>	</properties>		<repositories>		<repository>			<id>central</id>			<name>Central</name>			<url>http://repo1.maven.org/maven2/</url>		</repository>		<repository>			<id>gtaun-public-repo</id>			<name>GTAUN Public Repository</name>			<url>http://repo.gtaun.net/content/groups/public</url>		</repository>		<repository>			<id>sonatype-oss-snapshots</id>			<name>Sonatype Oss Snapshots</name>			<url>https://oss.sonatype.org/content/repositories/snapshots/</url>			<snapshots>			<enabled>true</enabled>			<updatePolicy>daily</updatePolicy>			</snapshots>		</repository>	</repositories>		<dependencies>		<dependency>			<groupId>junit</groupId>			<artifactId>junit</artifactId>			<version>3.8.1</version>			<scope>test</scope>		</dependency>			<dependency>			<groupId>net.gtaun</groupId>			<artifactId>shoebill-api</artifactId>			<version>1.1-SNAPSHOT</version>			<type>jar</type>			<scope>compile</scope>		</dependency>				<dependency>			<groupId>net.gtaun</groupId>			<artifactId>shoebill-common</artifactId>			<version>1.0-SNAPSHOT</version>			<type>jar</type>			<scope>compile</scope>		</dependency>
    		<dependency>			<groupId>net.gtaun</groupId>			<artifactId>shoebill-utilities</artifactId>			<version>1.0-SNAPSHOT</version>			<type>jar</type>			<scope>compile</scope>		</dependency>
    		<dependency>			<groupId>net.gtaun</groupId>			<artifactId>util-event</artifactId>			<version>1.0-SNAPSHOT</version>			<type>jar</type>			<scope>compile</scope>		</dependency>	</dependencies>		<build>		<defaultGoal>clean install</defaultGoal>
    		<plugins>			<plugin>				<groupId>org.apache.maven.plugins</groupId>				<artifactId>maven-compiler-plugin</artifactId>				<version>3.1</version>				<configuration>					<source>1.8</source>					<target>1.8</target>				</configuration>			</plugin>			<plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-jar-plugin</artifactId>                <version>2.3.1</version>                <configuration>                    <outputDirectory>[Dein Ausgabepfad, z.B. C:\Users\...]</outputDirectory>                </configuration>            </plugin>		</plugins>	</build></project>


    Dann ein Gamemode bauen, unter Debug -> Maven Install oder Maven Build ausführen, dann die jar in den ServerOrdner, unter shoebill->gamemodes, alles anpassen, also maven Pfad usw. in shoebill.yml und resources.yml und dann die Startup.bat ausführen ^^


    //edit


    Ich denke ich verstehe jetzt das Problem... Du meintest bestimmt wie man es auf nem Server wie einen externen Linux Server installiert. Falls ja, das Problem habe ich auch. Ich kann keinen Maven Path angeben und keine Ahnung, wie man das Shoebill Plugin da starten lässt...

  • Wie sieht das eigentlich aus mit Sicherung von Daten ?
    Bspw. ein Datein oder alternativ Datenbanken ?


    Kann man für Datein einfach die "Java Standards"(So nenn ich das jetzt einfach mal) nutzen ?
    Aber wie sieht es bspw. bei Datenbanken aus ?


    Bräuchte man dafür "Plugins" ?
    Wenn ja, muss man die für Shoebill anpassen ?

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Du kannst ganz normal auf Datenbanktreiber für Java zugreifen und hast auch Zugriff aufs Dateisystem (wobei ich noch nie ausshalb des Scriptfiles Ordners war, von daher kann ich mir da irren).


    Besondere Plugins brauchst du nicht, es geht alles was du auch normal in Java nutzten kannst.

    The fact is, I am right. And if you think I'm wrong, you are wrong.

    Einmal editiert, zuletzt von seegras ()

  • @MiX(eP): Du kannst die erstelle .jar Datei aus deiner Maven-Repo nehmen und auf den Server in den shoebill/gamemodes Ordner kopieren. Dann musst du nurnoch die benötigten Libs manuell in die resources.yml eintragen.


    @BlackAce: Das Shoebill Plugin (also die Binaries für den SAMP Server) erstellt eine Java Virtual Machine (JVM). Genau das selbe passiert, wenn du jedes andere Java Programm startest, wie z.B. Minecraft. Das heißt, du kannst jede Funktion von Java benutzen (Dateisystem verwalten, Emails senden, Daten von einem FTP-Server holen, Shell-Befehle ausführen oder direkt einen Webserver basierend auf Java). Außerdem kannst du jede Java Library verwenden, die existiert, wie z.B. Apache Commons. Dir steht alles offen, du kannst Mysql / MongoDB / Sqlite verwenden oder dein ganz eigenes Dateiformat entwerfen.

  • Das klingt mMn sehr gut :)


    Aber eine Frage hab ich noch, wie sieht es eigentlich mit der Unterstützung zukünfitger SA:MP Versionen aus ?


    Ich weiß Kalcor hat bisher immer einen recht entspannten Updatezyklus an den Tag gelegt, aber man weiß ja nie bei ihm :D

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Wenn sich die Funktionen der Parametern nicht groß verändern funktioniert alles weiter. Bei neuen Callback und Funktionen die noch nicht von Shoebill implementiert wurden, kannst du auch die Nativen Interfaces von Shoebill benutzen, und jegliche Funktion aufrufen oder ein beliebiges Callback hooken. Das funktioniert übrigens auch mit jedem anderem Plugin auch, du kannst z.B. das Audio Plugin über Shoebill steuern und dessen Funktionen und Callback verwenden. Wenn du ein Beispiel sehen möchtest kannst du folgendes durchlesen -> Project Shoebill 1.1 - Schreibe Gamemodes in Java

  • An alle die Probleme mit den Anfängen haben, so wie ich :D
    Es gibt nen schönes Dealership Plugin für Shoebill / auf Java, daran kann man sich gut orientieren, zB wie man objektorientiert programmiert oder Sachen mit Dialogen und Lifecycles / Referenzen.


    Ich werde ein paar experimentelle Sachen ausprobieren, dennoch erstmal ein RPG Grundsystem aufbauen, mal sehen wie es wird ^^

  • Ich bekomme einen Syntax Fehler bei den Events.
    Nutze JRE 7

    Java
    eventManagerNode.registerHandler(PlayerSpawnEvent.class, (e) -> {
        Player player = e.getPlayer();
        player.giveMoney(INITIAL_MONEY);
        player.toggleClock(true);
        setRandomSpawnPos(player);
    });


    Edit

    Code
    e cannot be resolved