Bukkit Join Event [closed] - events

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to do some stuff onPlayerJoin but nothing is working. I think it is the bukkit problem. How should I do it? My code:
#EventHandler
private void onJoin(PlayerJoinEvent e) {
// Join MSGs
e.setJoinMessage(ChatColor.GOLD + "Hrac " + ChatColor.RED + e.getPlayer().getName() + ChatColor.GOLD + " se pripojil.");
e.setJoinMessage(ChatColor.GOLD + "Hrac " + ChatColor.RED + e.getPlayer().getName() + ChatColor.GOLD + " se odpojil.");
BukkitScheduler scheduler = getServer().getScheduler();
scheduler.scheduleSyncDelayedTask(this, new Runnable() {
#Override
public void run() {
// Teleport every join
Location spawn = (Location) getConfig().get("Spawn");
e.getPlayer().teleport(spawn);
e.getPlayer().sendMessage("teleported to spawn");
// Setting ops
if(getConfig().get("ops") != null ) {
ops = (ArrayList<String>) getConfig().getStringList("ops");
}
for (String o : ops) {
if(e.getPlayer().getName() == o) {
e.getPlayer().setOp(true);
e.getPlayer().sendMessage("op");
}
}
}
}, 20L);
}

There's multiple issues with your code:
You are using the BukkitScheduler.scheduleSyncDelayedTask method instead of the runTaskLater so your task is executed every second instead of one second after the player joined
getServer().getScheduler().runTaskLater(this, new Runnable(){}, 20L);
You are checking if the player is an op by comparing his name with ==, Strings should be compared with the equals method so do this instead
for(String o : ops)
{
if(e.getPlayer().getName().equals(o))
{
//...
}
}
You can't set the join message twice, if you want a multiline join message, send it yourself to all players of the server.
getServer().broadcastMessage("hello");
Hope this helps, good luck with your plugin development

I disagree with what xtrontros said above, you can still use the bukkit scheduler and it seems you have used it well, a delayed task will not repeat.
However when creating locations from config try parsing it instead of casting it. For example:
String[] data = config.getString("spawn").split(",");
Location spawn = new Location(Double.parseDouble(data[0]), Double.parseDouble(data[1]), Double.parseDouble(data[2]), Float.parseFloat(data[3]), Float.parseFloat(data[4]));
Then teleport your players there.
You should also make sure you've registered events in that class, in your onEnable() in your Main class add this
getServer.getPluginManager().registerEvents(new MyClassConstructor(), this)
Or if the event is in your Main class, use this method instead
getServer.getPluginManager().registerEvents(this, this)

Added #Override upto onEnable() method and working now

Related

DART PROBLEM ...Why is it showing an error can't uderstand? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 days ago.
Improve this question
Image showing error in vs code
I am following a tutorial video ,in which when he is using "string" as data type it is not showing any error
but when i am using it it shows an error . but when iam using "Var" instead of string the error would go away.
Its because of null safety as var is nullable so you need not to initialize but inacase of string it is not nullable so you need to make it like this
class Deck {
List<Card> cards = [];
}
class Card {
String? suit;
String? rank;
}
//to access use this
void test()
{
Card c = Card();
print(c.suit ?? "unknown suit");
print(c.rank ?? "unknown rank");
}
or alternatively better make a constructor
class Card2{
String suit;
String rank;
Card2(this.suit, this.rank);
}
//use like this
void test2()
{
Card2 c2 = Card2("suit", "9.8");
print(c2.suit);
print(c2.rank);
}

Is CoroutineScope(SupervisorJob()) runs in Main scope?

I was doing this code lab
https://developer.android.com/codelabs/android-room-with-a-view-kotlin#13
and having a question
class WordsApplication : Application() {
// No need to cancel this scope as it'll be torn down with the process
val applicationScope = CoroutineScope(SupervisorJob())
// Using by lazy so the database and the repository are only created when they're needed
// rather than when the application starts
val database by lazy { WordRoomDatabase.getDatabase(this, applicationScope) }
val repository by lazy { WordRepository(database.wordDao()) }
}
private class WordDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch {
var wordDao = database.wordDao()
// Delete all content here.
wordDao.deleteAll()
// Add sample words.
var word = Word("Hello")
wordDao.insert(word)
word = Word("World!")
wordDao.insert(word)
// TODO: Add your own words!
word = Word("TODO!")
wordDao.insert(word)
}
}
}
}
this is the code I found, as you can see, it is directly calling scope.launch(...)
my question is that:
isn't all the Room operations supposed to run in non-UI scope? Could someone help me to understand this? thanks so much!
Is CoroutineScope(SupervisorJob()) runs in Main scope?
No. By default CoroutineScope() uses Dispatchers.Default, as can be found in the documentation:
CoroutineScope() uses Dispatchers.Default for its coroutines.
isn't all the Room operations supposed to run in non-UI scope?
I'm not very familiar specifically with Room, but generally speaking it depends if the operation is suspending or blocking. You can run suspend functions from any dispatcher/thread. deleteAll() and insert() functions in the example are marked as suspend, therefore you can run them from both UI and non-UI threads.

How do i exit from a method and run another when a condition is triggered, JDA discord wrappper

public void onMessageReceived(MessageReceivedEvent event) {
String[] messagelements = event.getMessage().getContentRaw().split("\\s+");
if (event.getMessage().getContentRaw().equalsIgnoreCase("what is the number beside " + wordanswer) && event.getAuthor().isBot()){
time = System.currentTimeMillis();
while (System.currentTimeMillis() - time <= 8000){
if (answered.equalsIgnoreCase("answered")) {
return;
}else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
if (answered.equalsIgnoreCase("notanswered")){
event.getChannel().sendMessage("times up").queue();
}
}
}
public void onMessageReactionAdd (MessageReactionAddEvent event) {
Thread.currentThread().setPriority(10);
if (event.getUser().equals(worker)) {
if (answered.equalsIgnoreCase("notanswered")){
if (event.getReactionEmote().getName().equalsIgnoreCase(emoteanswer)){
event.getChannel().sendMessage("Correct!").queue();
}
else{
event.getChannel().sendMessage("Wrong").queue();
}
answered = "answered";
}
}
}
the variable answered is to check if the user has already answered the question. However, when my timer starts, it does not detect any activity from the the onMessageReactionAdd and only reacts to it after the timer ends in which "times up" will always be sent then the Wrong/Correct option will then be sent. How do i run both methods simultanously or stop a method and run another when a condition happens. (note that the reaction is the user answer). The timer gives a time limit on the answering the qn and the player will be wrong if they fail to answer within the time limit. Some people suggested using a new thread but i haven’t mastered java and need some help doing that
You could use either an eventwaiter, or create a response based on a state-machine (Credits to Minn for posthing this)
Depending on your use case, this will differ on how you're going to use it.

redissonClient.poll() only returning the first 8 characters of String type value

Currently using reddison, creating a redissonClient and trying to poll data from redis server. I can see the data in the redis db if I check via redis-cli but when I look at the string value in my java application it is always the first 8 characters of the string and no more. Not sure why it won't give me the whole value.
I've tried using the .peek() method as well and I see the same symptom in that I only get 8 characters of the string returned.
Here is the main part of the code I can provide more details as needed:
#Service
#Slf4j
public class RedisConsumer {
RedisConfig redisConfig;
//RQueue<String> redisQueue;
RBlockingQueue<String> redisQueue;
#Autowired
RedisConsumer(RedisConfig redisConfig) {
this.redisConfig = redisConfig;
}
public void pollAuditQueue() {
//Redisson
redisQueue.add("{JSON string here snipped out for brevity}");
String item = redisQueue.poll();
if (!Objects.isNull(item)) {
log.info("I found this item: " + item);
} else {
log.info("Nothing in queue...");
}
}
#PostConstruct
private void init() throws Exception {
RedissonClient redissonClient = redisConfig.redisson();
redisQueue = redissonClient.getBlockingQueue("test");
while(true) {
pollAuditQueue();
Thread.sleep(5000);
}
}
When I look at the print statement in my console I see:
I found this item: {"AuditEv
When I check the redis-cli I can see the whole value:
1) "\xfc\t{\"AuditEvent\":{\"timestamp\":\"2018-11-27 04:31:47.818000+0000\" snipped the rest out for brevity}"
Lastly if I check that the item was removed from Redis after being polled in the Java app I can confirm that it is.
Any help would be great since it's not throwing any specific error I'm not finding any resources online to help address it.
I've found one thing I didn't notice in my earlier testing. When I manually insert using the redis cli I was replicating what my first tests through Java did which put the \xfc\t at the front which can be seen in my sample above.
Just now when I used redisQueue.add from within my application I noticed in redis it has \xfc\x80\x90\x01 instead and those do return the entire string to me in my application. I assume then this has to do with memory allocation somehow? I'm marking the question as resolved as I am no longer experiencing the issue. If anyone can drop on comment on what those letter/numbers mean though it may be meaningful for anyone that reads this post later. Once I have researched it I will add that comment myself if no one has beat me to it!
Add encoding:
RMap map = redisson.getMap("SessionMap"); -->
RMap map = redisson.getMap("SessionMap", new StringCodec("UTF-8"));

Trying to change value cells in a background worker thread

I'm trying to update a Ultragridrow cell in a background worker, but this is throwing a InvalidOperation Exception when this is called more than 1 time.
Here you have the method that starts the RunWorkerAsync.
private void RefreshGridCacheStart()
{
try
{
if (this.uGridCache.Rows.Count == 0)
{
return;
}
if(!workerThread.IsBusy)
{
workerThread.DoWork += LookUpHostnames;
workerThread.ProgressChanged += UpdateCacheHostCell;
workerThread.RunWorkerCompleted += WorkerCompleted;
workerThread.WorkerReportsProgress = true;
workerThread.RunWorkerAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
This is the DoWork method:
private void LookUpHostnames(object sender, DoWorkEventArgs e)
{
var rowValues = new object[2];
try
{
foreach (UltraGridRow row in uGridCache.Rows)//here is were I get an invalid operation exception
{
string cellValue = row.Cells["Host"].Text;
if (Globals.cNet.isValidIP(cellValue))
{
rowValues[0] = row;
rowValues[1] = cellValue;
workerThread.ReportProgress(0, rowValues);
string resolvedHostname = Globals.cIPLookup.LookupHostFromIP(cellValue);
rowValues[1] = resolvedHostname;
workerThread.ReportProgress(0, rowValues);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
And this is the Report Progress method:
private void UpdateCacheHostCell(object sender, ProgressChangedEventArgs e)
{
var rowValues = e.UserState as object[];
var row = (UltraGridRow) rowValues[0];
var sMesage = (string) rowValues[1];
row.Cells["Host"].Value = sMesage;
}
You can find your answer here Different question but ultimately the same problem. Your are changing data inside a foreach loop which invalidates the enumerator.
There are 2 possible solutions I see from reading your code
Save all changes that need to be made to an List of changes and only report progress once after the foreach loop. This might not be a very good solution though since you are processing in the background. If there is other code running that could also change the data in the grid you would get the same error again.
Since you are not adding rows you could easily change the foreach to a for loop. This might also lead to an issue if code on the main thread could add, or worse, remove rows
Sounds like something must be changing the underlying row collection hence invalidating your enumerable.
If you convert your enumerable to a list using .ToList() (this will cause the enumerable to iterate and give you a new list containing the items in the original) you will be able to iterate over this new enumerable and changes in the source won't affect you.
foreach (UltraGridRow row in uGridCache.Rows.ToList())
{
....
workerThread.ReportProgress(0, rowValues);
}
You will have to be aware that if something else is changing the rows on the grid, your ReportProgress might be reporting progress of something that no longer exists in the grid, you might want to check in your ReportProgress handler whether reporting on progress for that item is still valid before doing whatever you do.
The MSDN documentation on DoWork states the following:
"You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the BackgroundWorker events.".
You can view the full details of the DoWork method here:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
Accessing the UltraGridRows from this event is causing you to access the UltraGrid from another thread and windows forms controls aren't thread safe.
Note that this isn't limited to accessing properties of the control. If you were to set values in the data source that the UltraGrid is bound to you would have the same issue as the change notifications would then happen on the background thread and the UI would still be manipulated from the background thread.
Note that there are only a few members that are actually thread safe on windows forms controls and these are documented in the section on Thread Safety for Control on MSDN: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx
Safe, Simple Multithreading in Windows Forms is a good resource for threading in windows forms even though it is older:
Part 1: http://msdn.microsoft.com/en-us/library/ms951089.aspx
Part 2: http://msdn.microsoft.com/en-us/library/ms951109.aspx
Part 3: http://msdn.microsoft.com/en-us/library/ms993020.aspx
How to: Make Thread-Safe Calls to Windows Forms Controls is also a good resource
http://msdn.microsoft.com/en-us/library/ms171728.aspx

Resources