[Plugin] Shoebill 1.1 - SA-MP Java Development Kit

@lucesita: I changed the order in this commit: https://github.com/Shoebill/shoebill...592f349e1616fa.

@dusk: It is hard for me to reproduce this error. Can you give me some advice on how and when this happens?
Reply

Hello
I would like to know if you have already checked what I posted before, thank you!
Reply

@Su37Erich: Oh, I'm sorry, I think I overlooked your post. I will edit this post when I got an answer for you.

//Edit:

Your CommandEntry Problem:

I will have to see your full code for the CommandEntry problem, because when I test it, it works perfectly fine. Is your Command in a CommandGroup, or is it directly registered in the PlayerCommandManager?

Your Timer Problem:

Your Timer will be destroyed if you don't save the instance. You said your variable is an instance variable, but where do you declare it? Do you declare it in the method or did you define it in the class? If you defined it in the method, the variable will be destroyed. You can create a "trash list" with timers in it, which will be cleared after X seconds depending if the timer is still running or not (use the timer.isRunning() method).

Here is an example (I think I will add this to shoebill-common):
PHP код:
package org.marvin;
import net.gtaun.shoebill.object.Timer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
 * Created by marvin on 24.04.16.
 * Copyright © Marvin Haschker 2016.
 */
public class TemporaryTimer implements Timer {
    private static 
Timer recycleTimer;
    private static List<
TemporaryTimertimers;
    static {
        
timers = new ArrayList<>();
        
recycleTimer Timer.create(5000-> {
            
Iterator<TemporaryTimeriterator timers.iterator();
            while(
iterator.hasNext()) {
                
TemporaryTimer timer iterator.next();
                if(!
timer.isRunning() && timer.hasBeenStarted()) {
                    
timer.destroy();
                    
iterator.remove();
                    
System.out.println("Timer destroyed.");
                }
            }
        });
        
recycleTimer.start();
    }
    public static 
TemporaryTimer create(int intervalTimerCallback callback) {
        return 
create(intervalTimer.COUNT_INFINITEcallback);
    }
    public static 
TemporaryTimer create(int intervalint countTimerCallback callback) {
        return new 
TemporaryTimer(intervalcountcallback);
    }
    private 
Timer timer;
    private 
boolean hasBeenStarted false;
    private 
TemporaryTimer(int intervalint countTimerCallback callback) {
        
timer Timer.create(intervalcountcallback);
        
timers.add(this);
    }
    @
Override
    
public int getInterval() {
        return 
timer.getInterval();
    }
    @
Override
    
public int getCount() {
        return 
timer.getCount();
    }
    @
Override
    
public boolean isRunning() {
        return 
timer.isRunning();
    }
    @
Override
    
public void setInterval(int ms) {
        
timer.setInterval(ms);
    }
    @
Override
    
public void setCount(int count) {
        
timer.setCount(count);
    }
    @
Override
    
public void start() {
        
timer.start();
        
hasBeenStarted true;
        
System.out.println("Timer started.");
    }
    @
Override
    
public void stop() {
        
timer.stop();
    }
    @
Override
    
public void setCallback(TimerCallback callback) {
        
timer.setCallback(callback);
    }
    @
Override
    
public void destroy() {
        
timer.destroy();
    }
    @
Override
    
public boolean isDestroyed() {
        return 
timer.isDestroyed();
    }
    private 
boolean hasBeenStarted() {
        return 
hasBeenStarted;
    }

Usage:
PHP код:
TemporaryTimer.create(10005-> {
            
System.out.println("Iteration #" String.valueOf(i));
        }).
start(); 
This timer will be destroyed after it finished.
Reply

Here is the code for the commands:
Код:
public abstract class Commands{
    private String help = "";
    private static CommandGroup group;
    static EventManager event;
    public static void prepare(EventManager eventM, CommandGroup groupM){
        event = eventM;
        group = groupM;
    }
    public void enableHelp(){
        if(help.isEmpty()){
            group.getCommands()
            .stream()
            .sorted((o1, o2) -> o1.getCommand().compareToIgnoreCase(o2.getCommand()))
            .forEach(commandEntry -> {
                if(commandEntry.getOrigin() == this.getClass()){
                    help = help+"{FF0000}/"+commandEntry.getCommand()+"{FFFFFF} - "+commandEntry.getHelpMessage()+"\n";
                }
            });
        }
    }
    void showHelpDialog(Player player){
        MsgboxDialog.create(player, event)
        .caption("{91FF00}Dev commands")
        .message(help).buttonOk("Ok")
        .buttonCancel("")
        .build()
        .show();
    }
}
Код:
public class DevCmds extends Commands{
    @BeforeCheck
    public boolean checkPremission(Player p, String cmd, String params){
        SPlayer sPlayer = SPlayer.playerInfo[p.getId()];
        if(!sPlayer.isAdmin(SPlayer.AdminType.DEVELOPER)){
            p.sendMessage(Color.RED, "» You don't have permissions to use this command");
            return false;
        }
        return true;
    }
    @Command
    @CommandHelp("Change the server time")
    public boolean changetime(Player player, int hour){
        //Some stuff here
        return true;
    }
//More commands
@Command
    @CommandHelp("Help")
    public boolean devcmds(Player player){
        showHelpDialog(player);
        return true;
    }
}
Код:
PlayerCommandManager commandEvents = new PlayerCommandManager(event);

        CommandGroup group = new CommandGroup();
        Commands.prepare(event, group);

        DevCmds devCmds= new DevCmds();
        grupo.registerCommands(devCmds);
        devCmds.enableHelp();
Problem 2 solved, thank you!
Reply

@Su37Erich: The getCommand() problem should be fixed with this commit:https://github.com/Shoebill/shoebill...d0bb20af04eeea

And the Timer problem can be fixed with this: https://github.com/Shoebill/shoebill...6a05c17af93600

You can create TemporaryTimers with TemporaryTimer.create(). You don't need to assign a variable to it, just call start() and it will be automatically deleted when it has stopped running.

The new artifact should be in the repository now.
Reply

@mk124 I've been trying to diagnose that null pointer exception on my own by adding some custom debug prints to shoebill-api... Here's what I added:
Resource.java:

Код:
protected void enable() throws Throwable
	{
		System.out.println("Resource:enable rootEventManager:" + rootEventManager);
		this.eventManager = rootEventManager.createChildNode();
		System.out.println("Resource:enable eventManager: "+  eventManager);
		System.out.println("Resource:enable getEventManager:" + getEventManager());
		onEnable();
		isEnabled = true;
		
		ResourceEnableEvent event = new ResourceEnableEvent(this);
		eventManager.dispatchEvent(event, getEventManager(), this);
	}
My plugin onEnable:
Код:
@Override
    public void onEnable() throws Throwable {
        Instance.instance = this;
        this.vehicles = new ArrayList<>();
        this.maxSpeeds = new HashMap<>();
        this.random = new Random();
        this.vehicleEngineTimers = new HashMap<>();
        if(getEventManager() == null)
            logger.error("How can it be null?");
      //  this.eventManager = getEventManager().createChildNode();
        if(Shoebill.get().getResourceManager().getPlugin(DatabasePlugin.class) != null) {
            System.out.println("Database plugin is loaded...");
            load();
        } else {
            eventManager.registerHandler(ResourceEnableEvent.class, e -> {
                if(e.getResource().getClass().equals(DatabasePlugin.class)) {
                    load();
                }
            });
        }
    }

 private void load() {
        System.out.println("Is it still null? " + getEventManager());
        this.eventManager = getEventManager().createChildNode(); // This is line 82 of file VehiclePlugin.java: the null pointer exception originates here.
        // Stuff that I commented out
        logger.info("Vehicle manager initialized");

    }
Output
Код:
2016-04-25 16:15:24,170 INFO  [out] - Resource:enable rootEventManager:net.gtaun.util.event.EventManagerRoot@94f96a
2016-04-25 16:15:24,171 INFO  [out] - Resource:enable eventManager: net.gtaun.util.event.EventManagerChild@7e20cf
2016-04-25 16:15:24,171 INFO  [out] - Resource:enable getEventManager:null
2016-04-25 16:15:24,171 ERROR [VehiclePlugin] - How can it be null?
2016-04-25 16:15:24,171 INFO  [out] - Database plugin is loaded...
2016-04-25 16:15:24,172 INFO  [out] - Is it still null? null
2016-04-25 16:15:24,172 ERROR [err] - java.lang.NullPointerException
2016-04-25 16:15:24,172 ERROR [err] -   at lt.ltrp.VehiclePlugin.load(VehiclePlugin.java:82)
And I must say, this makes no sense...
Reply

@dusk: This really makes no sense. Is this occurring only when using a specific plugin? Can you add some debug messages in the disable() method, because it is the only place where the eventManager will be set to null.
Reply

Ahhh I figured it out, as always my stupidity is the answer. A while ago I changed that class to extend Resource but I forgot that it had a method getEventManager which overrode getEventManager in Resource.
Reply

@dusk: Ok, I honestly didn't think it was a bug in Shoebill's code
Reply

Neither did I, but I was all out of ideas..

Anyway new issue. How come shoebill-updater.jar doesn't download shoebill-launcher 1.3?
Reply

@dusk: I'm sorry, I forgot to upload it.
Reply

Seems you forgot the plugin too!
Reply

@dusk: Oh, then the 1.3-SNAPSHOT isn't ready for deployment yet, but I will upload it, because I think it should be stable.

//Edit: Uploaded.
Reply

Thanks for it, I am going to test it.
By the way, have you checked the issue with the MapAndreas class?
Reply

Now dialogs works fine, thanks!

I have another suggestion: In the default shoebill linux package, the startup.sh looks like:
Код:
export LD_LIBRARY_PATH=.:$JRE_HOME/lib/i386:$JRE_HOME/lib/i386/client:$JRE_HOME/lib/i386/server:/usr/local/lib
As you see, the "path" is set to $CLIENT_JRE_PATH, $SERVER_JRE_PATH. However, using this way, the server will use the client VM instead of the server VM. So the suggestion would be to change the order (put the server VM path first). That should perform better.

Other issue (on linux, haven't tested on windows): onDisable (from my gamemode) is not called when I kill the process using CTRL+C or using "pkill samp03svr". The only way to call onDisable is to use rcon "exit" command. This is very important, since most cleanup is done here.

I dont know why it happens, I even dont know if it happens on shoebill or is a sampgdk problem. Anyway, using a blank gamemode, OnGameModeExit is working fine when killing the process.
Reply

@lucesita: Thanks for your suggestion, I will change the bundled startup.sh in the upcoming Shoebill 2.0 package.

I will also take a look at the onDisable() problem.
Reply

This seems really nice for people who prefer Java over Pawn. I'm currently in my second semester learning Java and I'd really like to give this plugin a shot since I'm sure I can really learn a lot from using it. However, I have some motivation problems. First, it looks god damn difficult to set up a server compared to what I am used to with Pawn. Secondly, I have strong concerns that it has bugs that prevent me from continuing development and thus breaking my work flow. And last but not least, the only support for coding problems comes from you, mk124, and 123marvin123. Just by looking at your lvdm mode, there's thousands of questions coming to my mind. Are there any plans on giving the people using your plugin a forum?
Reply

Hi Manyula,

thanks for your post. I am happy that you found this project. There are various videos on how to setup a Shoebill server and how to setup your working environment (take a look at post #1 at the bottom). After you got everything setup, you can even use our custom-made project generator, that will generate a full blown maven project with everything setup for you (https://github.com/Shoebill/project-generator/releases). We are planing to release more tutorials and documentations with the release of Shoebill 2.0, but that will still take some time because I am really busy with my private life right now. You will find support here, and I don't think your workflow will be held back by me or any other supporter of this project. We usually answer really quickly (most of the time under 12 hours). You can also join our Slack group, maybe you will get a even faster support there (http://shoebill.slack.com).

We do not plan on giving our users a forum, due to the fact that there is not a high enough demand so it would be worth spending time setting up a forum.
Reply

About slack, I can not join. I'm pretty sure that to join slacks team one needs an invitation from an administrator. AFAIK slack doesn't support open, invitationless chats.
Reply

Ok, I see. I am new to Slack, so I didn't knew that you can only invite people. I made a website where you can enter your email address and you will be automatically added to the invite list:

http://37.114.61.175:3000/

Just enter your email address and click on "Join" and you should get a invitation immediately.
Reply


Forum Jump:


Users browsing this thread: 7 Guest(s)