How to give a message in bukkit after 60 seconds? - java

thanks for all that helped me! I will be more detailed now. What I want to do is a Bukkit plugin which after one minute, and if the player dropped something, the console displays an information message, like "Players are moving", but I just can make the first message appear: "Player dropped something" and I think that the error is on the boolean that I used. Please, can anyone help me with bukkit? This is my code:
public class HgCake extends JavaPlugin implements Listener{
boolean reference = false;
#Override
public void onEnable() {
Bukkit.getServer().getPluginManager().registerEvents(this, this);
}
#EventHandler
public void onDropItem (PlayerDropItemEvent e) {
getLogger().info("Player dropped something");
reference = true;
}
public void onPlayerMove (PlayerMoveEvent e){
if (reference = true){
getLogger().info("Players are moving");
}
}
}

Bukkit has a built in scheduling system that you can read up on
Scheduler Programming
Use this instead of normal Java timers, trust me. It'll make your life easier in the long run.
To do what you're wanting to do, you'd need a BukkitRunnable class to give to the scheduler.
This is a generic one I over-simplified for example purposes:
public class Callback extends BukkitRunnable{
private Object targetObject;
public Method targetMethod;
private Object[] perameters;
public Callback(Object targetObject, String methodName, Object[] argsOrNull){
try {
this.targetMethod = targetObject.getClass().getMethod(methodName, (Class<?>[]) argsOrNull);
} catch (Exception e){
e.printStackTrace();
}
this.targetObject = targetObject;
this.perameters = argsOrNull;
}
public void run(){
try {
this.targetMethod.invoke(this.targetObject,perameters);
} catch (Exception e){
e.printStackTrace();
}
}
}
Then you create an object of that runnable, providing the callback method/props as args, and give it to the scheduler to run in 60 seconds:
For the movement part, you just watch that while the item is dropped and nobody's moved yet.
public class DropWatcher implements Listener {
private Boolean hasAnythingMoved;
private Boolean dropped;
private Pwncraft plugin;
private Player player;
public DropWatcher(Pwncraft plugin, Player player){
this.player = player;
this.hasAnythingMoved = false;
this.dropped = false;
this.plugin = plugin;
this.plugin.pluginManager.registerEvents(this, plugin);
}
//Drop event listener: When the player drops an item, it sets dropped to true, and initiates the countdown.
#EventHandler
public void onDropItem (PlayerDropItemEvent e) {
if(e.getPlayer().equals(this.player) && !this.dropped){
this.dropped = true;
BukkitCallbackTask doInSixtySeconds = new BukkitCallbackTask(this, "timesUp" , null);
doInSixtySeconds.runTaskLater(plugin, 1200); // time is in ticks (20 ticks +/- = 1 sec), so 1200 ticks = 1 min.
}
}
//Watches for other-players' movement, and sets hasAnythingMoved to true if so.
#EventHandler
public void onMove (PlayerMoveEvent e){
if(!e.getPlayer().equals(this.player) && this.dropped && !this.hasAnythingMoved){
this.hasAnythingMoved = true;
}
}
/*
This is the method the runnable calls when the timer is up.
It checks for movement, and if so, sends a message and explodes the player
(Just because it can. You're welcome to veto the explosion.)
*/
public void timesUp(){
if(this.hasAnythingMoved){
this.player.sendMessage("Someone moved! Time to party!");
this.player.getWorld().createExplosion(this.player.getLocation(), 5F);
this.dropped = false;
this.hasAnythingMoved = false;
}
}
}

You forgot the #EventHandler for the PlayerMoveEvent I think.
It should be:
public class HgCake extends JavaPlugin implements Listener{
boolean reference = false;
#Override
public void onEnable() {
Bukkit.getServer().getPluginManager().registerEvents(this, this);
}
#EventHandler
public void onDropItem (PlayerDropItemEvent e) {
getLogger().info("Player dropped something");
reference = true;
}
#EventHandler
public void onPlayerMove (PlayerMoveEvent e){
if (reference = true){
getLogger().info("Players are moving");
}
}
}

int plannedActivity = getServer().getScheduler().runTaskLaterAsynchronously(this, new Runnable() {
public void run() {
//whatever you want to do
}
}, 120L);

Related

Referencing boolean in interface

I ran into a bit of an issue and was hoping someone could tell me what I'm missing here.
for some context I have the following methods:
private boolean windowork;
public class WinidowMalfunction extends Event {
ControllerException newException = new ControllerException("Error:");
public WinidowMalfunction(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
windowork = false;
someThingWentWrongHere(1, "Error at WinidowMalfunction");
}
}
private boolean poweron;
public class PowerOut extends Event {
public PowerOut(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
poweron = false;
someThingWentWrongHere(2, "Error at powerOut event");
}
}
and I'm creating interface Fixable where I need to change the value of poweron and windowork to change their values to true. but I can't get the FIxable to accept the references. they are all in the same class so is there a way to reference these boolean function in an interface
EDIT:
Assignment question:
In this part, we add functionality for restoring the saved GreenhouseControls object and having it resume execution where it left off. It demonstrates the use of interfaces and the capability of Java methods to return objects.
Create the following interface
interface Fixable {
// turns Power on, fix window and zeros out error codes
void fix ();
// logs to a text file in the current directory called fix.log
// prints to the console, and identify time and nature of
// the fix
void log();
}
You can do something like this:
interface Fixable {
public boolean setTrue();
}
class Foo implements Fixable {
private boolean windowork = false;
public void setTrue() {
windowork = true;
}
}
class Bar implements Fixable {
private boolean poweron = false;
public void setTrue() {
poweron = true;
}
}
The only advantage of the above is if you had an array of Fixable objects you could iterate thru them and do this.
for (Fixable f : fixableArray) {
f.setTrue();
}
An interface can be designed in a way to read-write a boolean property that resides in the class/instance.
public interface Somename {
public boolean isPowerOn();
public void setPowerTo(boolean arg);
}

Threading in java with BasicPlayer

My current issue is that I need to be able to know the status of the basic player instance at all times. This would require a thread to get the status while the scanner waits for input from the user. The status would be used to automatically play the next audio file. Things I have done. First I made sure that this code that works inline. Next I tried to it in the thread, to no avail. I think it has to do with syncing the object between both threads
I tried making a synchronized getter of the basic player instance but it did not work
public class Player implements Runnable {
private String song;
private boolean comp = false;
private String path;
private final BasicPlayer player;
public Player () {
player = new BasicPlayer();
path = System.getProperty("user.dir") +"/src/Music/";
}
public void setSongName (String songName) {
song = songName;
}
public String getSongName() {
return song;
}
public void play () {
try {
player.open(new URL("file:///" + path + song));
player.play();
new Thread(new Player()).start();
} catch (BasicPlayerException | MalformedURLException e) {
e.printStackTrace();
}
}
private synchronized boolean isComplete () {
return getStatus() == 2;
}
public synchronized int getStatus(){
synchronized (player) {
return getPlayer().getStatus();
}
}
public synchronized boolean getComplete() {
return comp;
}
public synchronized void setComp(boolean comp) {
this.comp = comp;
}
private synchronized BasicPlayer getPlayer() {
synchronized (player) {
return player;
}
}
#Override
public void run() {
while (!isComplete()) {
BackendUtils.sleep(1000);
System.out.println(getStatus());
setComp(false);
}
setComp(true);
}
}
In this piece of code I am attempting to update a synchronized boolean to know then the audio is finished labeled comp. I try by using a synchronized player instance. The following code demonstrates how I tested if the threading was work or not.
import java.util.Scanner;
public class BackendTesting {
private static Scanner scanner = new Scanner(System.in);
private static Player player = new Player();
public static void main(String[] args) {
while (true) {
String input = input("$ ");
if (input.contains("ply play")) {
player.setSongName(input.substring(input.lastIndexOf(" ") + 1) + ".mp3");
player.play();
}
}
}
private static String input (String prompt) {
System.out.print(prompt);
return scanner.nextLine();
}
}
Try something like this:
In the thread class
public void run() {
MainClass.getInstance().playNextSong();
}
In the main class
public void playNextSong(){
synchronized(lock)
{
while (!isComplete()) {
lock.wait();
}
setComp(true);
lock.notifyAll();
}
}
Definitely you have to update it according to your needs.
Hope that helps.

What should we do to overcome livelock? (in general and specific to the code example provided below)

I'm new to Java and is trying to learn the concept of livelock.
I found a great example of livelock online, where a husband and wife are trying to eat soup, but only have one spoon between them. Each spouse is too polite, and will pass the spoon if the other has not yet eaten.
My question is, what should we do to overcome the problem of livelock in general, and in this particular example? I am looking to modify my code to demonstrate the solution to the problem.
public class Livelock {
static class Spoon {
private Diner owner;
public Spoon(Diner d) { owner = d; }
public Diner getOwner() { return owner; }
public synchronized void setOwner(Diner d) { owner = d; }
public synchronized void use() {
System.out.printf("%s has eaten!", owner.name);
}
}
static class Diner {
private String name;
private boolean isHungry;
public Diner(String n) { name = n; isHungry = true; }
public String getName() { return name; }
public boolean isHungry() { return isHungry; }
public void eatWith(Spoon spoon, Diner spouse) {
while (isHungry) {
// Don't have the spoon, so wait patiently for spouse.
if (spoon.owner != this) {
try { Thread.sleep(1); }
catch(InterruptedException e) { continue; }
continue;
}
// If spouse is hungry, insist upon passing the spoon.
if (spouse.isHungry()) {
System.out.printf(
"%s: You eat first my darling %s!%n",
name, spouse.getName());
spoon.setOwner(spouse);
continue;
}
// Spouse wasn't hungry, so finally eat
spoon.use();
isHungry = false;
System.out.printf(
"%s: I am stuffed, my darling %s!%n",
name, spouse.getName());
spoon.setOwner(spouse);
}
}
}
public static void main(String[] args) {
final Diner husband = new Diner("Bob");
final Diner wife = new Diner("Alice");
final Spoon s = new Spoon(husband);
new Thread(new Runnable() {
public void run() { husband.eatWith(s, wife); }
}).start();
new Thread(new Runnable() {
public void run() { wife.eatWith(s, husband); }
}).start();
}
}
In general there isn't a universal solution to livelock.
A thread has to stop repeating the same actions if no progress has been detected.
In your example allowing spouse to eat more than once (thereby detecting that the loved one has not eaten and no progress has been made, since eating takes just 1 step) should force the owner of the spoon to just eat.
Obviously real life scenarios will be more elaborate, but detecting zero progress and acting differently than normally is crucial.

Stopping and resuming infinite loop on key input

Let's say we have an infinite loop, and we want to put it to sleep for a while, and then resume it. Instead of having a set time, we resume it when we press a key.
For example, in Java we could have:
while(true){
doSomething();
}
Now, we could make this interruptable in many ways. We want to interrupt it on a key press, so we will have:
boolean running = true;
...
this.addKeyListener(this);
...
#override
public void keyPressed(KeyEvent e){
running = false;
}
And then run a method (let's say run), which contains:
while(running){
doSomething();
}
But then we'd meet one problem: resuming.
So we take the keyPressed method, and change it's body to:
running = !running;
if(running){
run();
}
There is just one problem here: the KeyListener won't do anything until the run method is finished. I've tried using threads, where we would have:
private class Runner implements Runnable {
#Override
public void run() {
while (running) {
doSomething();
}
}
}
and in keyPressed:
if(running){
runner.wait();
}else{
runner.notify();
runner.run();
}
running = !running;
but in my actual code the doSomething method is code that can't be interrupted (because it handles output to the screen), so thread.wait() can never be called (it will throw exceptions all the time and not actually wait).
So then, to summarize: How does one stop and resume looping something at will using key input in Java?
wait and notify are intended to be called from different threads. As the name implies, wait should be called in the thread which is paused and waiting to be notified that a condition has changed:
private final Object keyPressMonitor = new Object();
private boolean running = true;
private Runnable gameLoop = new Runnable() {
#Override
public void run() {
try {
synchronized (keyPressMonitor) {
while (true) {
while (!running) {
keyPressMonitor.wait();
}
doSomething();
}
}
} catch (InterruptedException e) {
logger.log(Level.INFO,
"Interrupted; cleaning up and exiting.", e);
}
}
};
The other thread, presumably the AWT Event Dispatch Thread which is where your KeyListener (or Action invoked by an ActionMap/InputMap binding) is called, would notify the looping thread that the proper key has been pressed or released:
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == theKeyICareAbout) {
synchronized (keyPressMonitor) {
running = true;
keyPressMonitor.notifyAll();
}
}
}
public void keyReleased(KeyEvent event) {
if (event.getKeyCode() == theKeyICareAbout) {
synchronized (keyPressMonitor) {
running = false;
keyPressMonitor.notifyAll();
}
}
}
You can use Semaphore for these purposes:
private static class Runner implements Runnable {
private final AtomicInteger permits = new AtomicInteger(0);
private final Semaphore semaphore = new Semaphore(1, true);
private volatile boolean running;
public void putToSleep() {
semaphore.acquireUninterruptibly();
}
public void resume() {
semaphore.release(permits.getAndSet(0));
}
#Override
public void run() {
while (running) {
semaphore.acquireUninterruptibly(Integer.MAX_VALUE);
semaphore.release(Integer.MAX_VALUE);
doSomething();
}
}
private void doSomething() {
//...
}
}

enum singleton implementing keyListener

I have this simple singleton that is used for keyboard polling, it implements the keyListener only to change the state of a Boolean. I get the keyListener object via get getKeyListener(). I'm not sure if this is the way to go, but the code works. Might there be a better way of accomplishing this?
UPDATE: Simpler way to poll key inputs using bitset
package Singleton;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.BitSet;
public enum bitKeyProcessor implements KeyListener{
INSTANCE;
private final BitSet bitset = new BitSet();
#Override
public void keyPressed(KeyEvent e) {
bitset.set(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
try{bitset.clear(e.getKeyCode());}
catch(Exception ex) {ex.printStackTrace();}
}
public void keyTyped(KeyEvent e) {};
public boolean isUp(){
if(bitset.get(KeyEvent.VK_UP))
return true;
return false;
}
....
public boolean isUpRight(){
if( isUp() && isRight())
return true;
return false;
}
The first thing that I would ask is why doesn't your enum implement KeyListener interface itself ? This would make your code more readable and would get rid of any need for statics (other than the INSTANCE, of course).
enum eSingleton implements KeyListener {
INSTANCE;
private boolean[] keyUp = new boolean[256];
private boolean[] keyDown = new boolean[256];
private boolean listen;
public void update(){
keyUp = new boolean[256];
}
public void listen(final boolean startStop){
listen = startStop;
}
public boolean isKeyUp(int key){
return keyUp[key];
}
public boolean isKeyDown(int key){
return keyDown[key];
}
#Override
public void keyPressed(KeyEvent e) {
keyUp[e.getKeyCode()] = false;
keyDown[e.getKeyCode()] = true;
}
#Override
public void keyReleased(KeyEvent e) {
keyUp[e.getKeyCode()] = true;
keyDown[e.getKeyCode()] = false;
}
#Override
public void keyTyped(KeyEvent e) {}
}
I don't think there is problem with your singleton I am just not sure about the code inside it.
Rather than creating two separate boolean arrays for Key Up/Down why not implement a KeyProcessor.
Whenever key event is received send keycode to Keyporcessor with action associate with it
e.g.
KeyProcessor.sendKeyEvent(keycode, PRESSED);
KeyProcessor.sendKeyEvent(keycode, RELEASED);
KeyProcessor.sendKeyEvent(keycode, TYPED);
Now create a command map in which you will have Hashmap with keys constructed using keycode & command.
Hashmap.put(keycode, PROCCESS_KEY_A)
enum command
{
PROCCESS_KEY_A;
pressed(){};
released(){};
typed(){};
}
sendKeyEvent will invoke method based on key event of the enum retrieved from command map.

Categories

Resources