TheHolyWaffle / TeamSpeak-3-Java-API

A Java wrapper of TeamSpeak's 3 server query API.
MIT License
306 stars 107 forks source link

Server lag with Teamspeak API #306

Closed Axtkaempfer closed 5 years ago

Axtkaempfer commented 5 years ago

Hello, when I start the server, the API connects to the server as far as good, but if I interact with the API, for example, create a channel or a client move the server laggs for about 3-4 seconds and reacts after the action performed normally again. I have already tried to program the API Asyncron with the same success. An error itself does not occur directly but the above problem occurs.

package com.github.norbo11.util;

import java.util.HashMap; import java.util.Map;

import org.bukkit.Bukkit; import org.bukkit.entity.Player;

import com.github.norbo11.UltimateCards; import com.github.theholywaffle.teamspeak3.TS3Api; import com.github.theholywaffle.teamspeak3.TS3ApiAsync; import com.github.theholywaffle.teamspeak3.TS3Config; import com.github.theholywaffle.teamspeak3.TS3Query; import com.github.theholywaffle.teamspeak3.api.ChannelProperty; import com.github.theholywaffle.teamspeak3.api.CommandFuture; import com.github.theholywaffle.teamspeak3.api.wrapper.Channel; import com.github.theholywaffle.teamspeak3.api.wrapper.Client; import com.github.theholywaffle.teamspeak3.api.wrapper.ClientInfo;

import de.axt.MySQL.MySQLTS;

public class TeamspeakUtils {

public static TS3Config config= new TS3Config();
public static TS3Query query = new TS3Query(config);
public static TS3Api api = query.getApi();

public static void connectTeamspeak(){

    UltimateCards.print("§7Verbindung wird aufgebaut...");
    config.setHost("localhost");
    config.setQueryPort(10011);
    query.connect();
    UltimateCards.print("§aClient erfolgreich verbunden!");
    api.login("******", "*******");
    api.selectVirtualServerById(1);
    api.setNickname("PP-Bot");
    TS3Events.load();
}

public static boolean RegisterPlayerbyName(Player p) {

    if(!MySQLTS.isUserExist(p.getUniqueId())) {
        for(Client c : api.getClients()) {
            if(c.getIp().equalsIgnoreCase(p.getAddress().getHostName())) {
                if(c != null) {
                    MySQLTS.create(p.getUniqueId(), p.getName(), c.getUniqueIdentifier());
                    Messages.Tsregistered(p);
                }

            }else {
                Messages.nichtOnline(p);
                return false;
            }
        }
        return false;

    }
    return false;
}

public static void createChannel(Player dealer,int tischID,String gamemode) {

    final Map <ChannelProperty , String > properties =  new HashMap <> ();
    properties. put ( ChannelProperty . CHANNEL_FLAG_TEMPORARY , " 1 " );

    api.createChannel(gamemode+" Tisch ["+tischID+"]", properties);
    Channel ch = api.getChannelByNameExact(gamemode+" Tisch ["+tischID+"]", false);
    Client cli = api.getClientByUId(MySQLTS.getUID(dealer.getUniqueId()));
    api.moveClient(cli, ch);
    api.setClientChannelGroup(5, ch.getId(), cli.getDatabaseId());

}

public static void deleteChannel(Player p,String gamemode,int id){
    if(gamemode.contains("Poker")) {
        Channel ch = api.getChannelByNameExact("Poker Tisch ["+id+"]", true);
        api.deleteChannel(ch.getId());

    }else if(gamemode.contains("Blackjack")) {
        Channel ch = api.getChannelByNameExact("Blackjack Tisch ["+id+"]", true);
        api.deleteChannel(ch.getId());
    }
}

public static void movePlayer(Player p,String gamemode,int id) {
    Channel cl = api.getChannelByNameExact(gamemode+" Tisch ["+id+"]", true);
    Client cl2 = api.getClientByUId(MySQLTS.getUID(p.getUniqueId()));
    api.moveClient(cl2, cl);
}

public static void movePlayerStandart(Player p) {
    Client cl2 = api.getClientByUId(MySQLTS.getUID(p.getUniqueId()));
    api.moveClient(cl2.getId(), 24);
}

public static boolean isUserOnline(Player p){

    if(MySQLTS.isUserExist(p.getUniqueId())) {
        for(Client client : api.getClients()) {
            if(client.getIp().equalsIgnoreCase(p.getAddress().getHostName())) {
                Client cl = api.getClientByUId(MySQLTS.getUID(p.getUniqueId()));
                if(api.isClientOnline(cl.getId())) {
                    return true;
                }else {
                    return false;
                }

            }else {
                return false;
            }
        }

    }else {
        return false;
    }
    return false;

}

} `

rogermb commented 5 years ago

Hi Axtkaempfer 😄

First - timing. Your code currently does things in this order:

  1. Create TS3Config
  2. Create TS3Query using that TS3Config
  3. Change TS3Config

but it should be

  1. Create TS3Config
  2. Change TS3Config
  3. Create TS3Query using that TS3Config

But this isn't what's causing your bad performance issue.

This API offers two different flood rate settings, DEFAULT and UNLIMITED. By default, this API will only send one command every 350 milliseconds, because the TS3 server only allows queries to send 10 commands every 3 seconds. Queries that send commands too quickly will be banned.

Now, the way around this limit is to add IP of the server query client to the TS3 server's query_ip_whitelist.txt file, but as you're already connecting to localhost, you don't even need to do that, you're already whitelisted by default.

In other words, you just need to tell the TS3Query to use the UNLIMITED flood rate setting by calling config.setFloodRate(FloodRate.UNLIMITED);.

So to fix both of the issues I mentioned, you could start your code like this:

public static TS3Query query;
public static TS3Api api = query.getApi();

public static void connectTeamspeak() {
    UltimateCards.print("§7Verbindung wird aufgebaut...");

    TS3Config config = new TS3Config();
    config.setHost("localhost");
    config.setQueryPort(10011);
    config.setFloodRate(FloodRate.UNLIMITED);

    query = new TS3Query(config);
    query.connect();
    api = query.getApi();

    [...]

Also, you should try to reduce the number of calls to TS3Api methods if they aren't necessary. For example, api.getClients() only returns a list of clients that are online, so basically, all of those calls to api.getClientByUId and api.isClientOnline in your isUserOnline method are redundant.

Axtkaempfer commented 5 years ago

Thank you works fine now!

rogermb commented 5 years ago

Awesome, thanks for letting me know! Closed 😄