I am using Bukkit API 1.8 with Java 7.
I have a repeating task that loops through all the players on the server and sets their armor randomly to either leather, chainmail, etc...
When I use the method setHelmet,setChestplate, etc... I update their inventory like usual, but since this task is running every 6 ticks, it runs fast. Therefore, when a player tries to fire a bow, the bow resets its power every time this task runs.
Since I knew it was a problem with updating the inventory, I tried removing the updateInventory method.
After doing this the armor still got put on and changed, but the bow was still being reset every time the task was ran.
How would I keep the bow from resetting while still keeping the task running?
My code:
#SuppressWarnings("deprecation")
public static void repeatEffect()
{
main.getServer().getScheduler().scheduleAsyncRepeatingTask(main, new Runnable()
{
#Override
public void run()
{
for(Player o : Bukkit.getOnlinePlayers())
{
Material M1 = Material.WOOL;
int num = rainbow.get(o.getName());
if(num==1)
{
M1 = Material.LEATHER_HELMET;
}
else if(num==2)
{
M1 = Material.CHAINMAIL_HELMET;
}
else if(num==3)
{
M1 = Material.GOLD_HELMET;
}
else if(num==4)
{
M1 = Material.IRON_HELMET;
}
else if(num==5)
{
M1 = Material.DIAMOND_HELMET;
}
rainbow.put(o.getName(), num+1);
if(rainbow.get(o.getName())>5)
{
rainbow.put(o.getName(), 1);
}
ItemStack rrhelm = createItemStack(M1, 1, "§a§lR§b§la§c§li§d§ln§e§lb§f§lo§a§lw §c§lH§d§le§e§ll§f§lm§a§le§b§lt", "§7Very special piece of armor");
o.getInventory().setHelmet(rrhelm);
}
}
}
, 6, 6);
}
If changing armour resets the players bow, you could work around it by only changing the armour of players who are joining, not wielding a bow or just after an EntityShootBowEvent.
To see if the player is wielding a bow, use:
org.bukkit.Bukkit.entity.Player player = ...;
boolean hasBowEquiped = player.getEquipment().getItemInHand().getData().getItemType().equals(Material.BOW);
After testing this some more, the only way I was able to reproduce the bow complication was by calling the deprecated updateInventory() method which you said you removed. I'm fairly certain that you still have this method somewhere in your code because I can't find anything else that would cause the bow to act this way (I was still able to fire the bow but the animation looks glitchy and the power of the arrow is sometimes incorrect).
The only difference between my code is that I used new ItemStack(M1) instead of your createItemStack() method to instantiate the helmet (also tried changing name, lore and amount). I was still able to shoot a bow just fine. Could the resetting of the bow/inventory have something to do with your createItemStack method?
There's no reason why you should be running this task asynchronously. You're accessing the Bukkit API from an asynchronous task or different thread which is a big no-no and can cause all kinds of tricky problems. Use the scheduleSyncRepeatingTask method to run the task in the same thread.
For simplicity's sake I randomly set a single armor slot (also tried all four) to either leather or iron every 6 ticks. Didn't seem to interfere with the bow. Could we see your code? Here is mine:
public void onEnable() {
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
for (World world : Bukkit.getWorlds()) {
for (Player player : world.getPlayers()) {
if (Math.random() < 0.5) {
player.getInventory().setBoots(new ItemStack(Material.IRON_BOOTS));
} else {
player.getInventory().setBoots(new ItemStack(Material.LEATHER_BOOTS));
}
}
}
}
}, 0, 6);
}
Related
I am using a Thread to do some calculations related to the app that need to be done simultaneously but this Thread causes the FPS to drop (logically) and I wanted to know how to resolve the issue as the Thread is not doing any heavy calculations at all. Here is the code where I implement the Thread and the Thread itself.
incrementMass = new IncrementMass();
incrementMass.start();
// I added some extra functionality to the InputProcessor but I assume that is irrelevant
if(InputProcessor.isButtonUp() && InputProcessor.getButtonLetGo() == RIGHT && !isJustPressed) {
isJustPressed = true;
try {
incrementMass.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
} else if(Gdx.input.isButtonJustPressed(RIGHT)) {
isJustPressed = false;
incrementMass.restart();
}
The Thread:
/**
* Thread to increment the mass in a while loop.
*/
public class IncrementMass extends Thread {
/**
* Increments the mass when started.
*/
#Override
public void run() {
super.run();
while(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
MainScreen.m += 100;
System.out.println(MainScreen.m);
}
}
/**
* Resets the mass so the whole thing starts over (for the creation of a new planet)
*/
public void restart() {
MainScreen.m = 100000;
}
}
All this is called in the render() function of my Screen by the way.
I have one idea as to what is causing this: Every frame I create a new Thread which is not optimal but everything else I tried failed to actually perform my calculations correctly. It definitely solves the FPS problem to have the initiation of the Thread and the ´start()´ function in the constructor of my Screen but that for some reason messes with the incrementing of the mass and makes it a fixed value: the value I reset it to in ´restart()´
I've been trying to solve this but I'm baffled so here I am.
As said in the comment, there was no function for isButtonJustUp() which made it not be able to run sequentially. Therefore I made a Thread so that it was sequential which is not a good implementation of Threads. I've come up with a solution:
if(Gdx.input.isButtonPressed(RIGHT)) {
m += 100;
} else if(InputProcessor.isButtonJustUp() && InputProcessor.getButtonLetGo() == RIGHT) {
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
m=0;
}
I haven't made isButtonJustUp() yet but it is the best way rather than implementing an unnecessary Thread.
I am making a minecraft mini game plugin, i need to make a loop that do the minigame, if the game is ended, stop it, but else continue, for making that i just created a boolean that is false and i put a :
while(isEnded) {
//my code
}
But in my code, there is async fuction, so it's repeat, but the async function don't have the time to finish before an other loop start, so all my game is glitched.
Any solution to await the async function ? ( i am using Bukkit.getServer().getScheduler().runTaskTimer(Main.plugin, new Runnable() { )
thanks for the help ;)
I don't really understand where you are stuck, but I will give you some way to do what you are looking for.
Run method from the end of mini-games.
For example, when the game when, you are running a method:
public void endGame() {
// do something
callMethod();
}
Use for another variable.
You can just set a variable, then run a task like that :
public static boolean isEnd = false;
public void runTask() {
Bukkit.getScheduler().runTaskTimer(myPlugin, () -> {
if(isEnd) {
// do something
}
}, 20, 20);
}
Finally, set the variable when it's fine with just MyClass.isEnd = true;
It will run each 20 ticks (so each second, because 20 ticks = 1 second).
If you know the time to wait, you can use the same scheduler as you are using and as I explain in #2 option.
Context
I have an activity where a user clicks hit or miss for three turns and then it is the computers turn, to click hit or miss.
The problem
The problem is when it is the computers turn the program hangs the recycler view and makes multiple clicking sounds before eventually displaying the a result. You can see this here:
What I've tried
Through some troubleshooting I seen that I should preform the computers task in a background thread and any UI changes should be preformed in the runOnUiThread. So I have this (this is the onClickEvent):
AsyncTask.execute(new Runnable() {
#Override
public void run() {
playerHit(whosThrowing);
runOnUiThread(new Runnable() {
#Override
public void run() {
setAdapterToDisplayStats(whosThrowing);
tv_numberToHit.setText(numToHit.get(whosThrowing));
if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
nextPlayerTurn(whosThrowing);
}
}
});
}
});
break;
case R.id.btn_miss:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
playerMissed(whosThrowing);
runOnUiThread(new Runnable() {
#Override
public void run() {
setAdapterToDisplayStats(whosThrowing);
//Player threw their three darts. Change player.
if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
nextPlayerTurn(whosThrowing);
}
}
});
}
});
break;
However this didn't solve the problem and the GIF above actually shows the result of this code. I designed this first for a Human v Human scenario and then started implementing a Human V Computer scenario. I thought this would have been straight forward get a result for the computer either hit or miss and perfomClick() on the relevant button.
As you can see in the above code block, the majority of the methods are in the runOnUiThread this is because these methods contain at least one bit of code that changes the UI but parts that doesn't mess with the UI. I can't imagine I have to go through and wrap each line of code in a run in background or run in UI thread, surely? Just when it is the computers turn.
The setAdapterToDisplayStats(whosThrowing); calls onBindViewHolder in a separate class which updates the recylerview. Does having just setAdapterToDisplayStats(whosThrowing) ensure that anything after it even if it is in a separate class runsOnTheUi thread?
Code that may be having an effect
Computers throw
if(opponent.equals("COMPUTER") && confirmedPlayers.get(0).equals("A.I") && Integer.parseInt(amountThrown.get(0)) % 3 == 0){
btn_hit.setEnabled(false);
btn_miss.setEnabled(false);
for (int i = 0; i < 3; i++) {
takeCompThrow();
}
btn_hit.setEnabled(true);
btn_miss.setEnabled(true);
}
return whosThrowing;
Computers performClick
The preformClick was what I had originally wrapped in a runnable block, thinking anything I called after it would be done in the background thread. Although this is where I first ran into the problem and moved it to the onClick() as I read the UI should be done separately but still no joy.
private void takeCompThrow() {
boolean hitOrMiss = computerThrow.computerHitOrMiss(compLevel);
if(hitOrMiss) {
btn_hit.performClick();
} else {
btn_miss.performClick();
Here's how it preforms Human V Human in case that's important:
The main question
Where am I going wrong?
In my opinion the problem is related with this code block, because you are trying to update recyclerview for multiple times in a really short period.
for (int i = 0; i < 3; i++) {
takeCompThrow();
}
Since you are the owner of the calculation logic, you can directly play turns and update the result directly without performing clicks. In this regard, there is no need to use any async task, unless there is a huge calculation cost.
My first suggestion, you can do sth like this:
if this is computer turn
for 1..3
calculate result for the computer turn
update recyclerview
There is a second option, but I'd go definitely with the above . Even though it will be a quick solution but won't be the best. You just need to put delay between computer clicks in order to let Recyclerview to calculate and redraw elements. So it will be like with the existing code :
for (int i = 0; i < 3; i++) {
takeCompThrow();
someDelay();
}
I made an 'Oregon Trail' like game, it uses a 'game over' method to ask if the user wants to play again.
The main issue:
My teacher mentioned something vague about if the game looped enough times, we'd end up with a stackOverflow. That makes sense to me because the game continues to nest methods inside of each other the way I have it, adding to the stack each time a 'new game' method is called because the outer methods are still there waiting to complete.
I've boiled down an example of what I mean. Assuming there were pauses for user input and such, how am I supposed to make sure my memory utilization doesn't keep growing as I call methods inside other methods? I think the word for this is 'recursive', thus my title.
If anyone could recommend correct form for dealing with this, I'd be really grateful.
public class Testing
{
public static void main(String[] args) {
System.out.println("main method");
gameStart();
}
private static void gameStart()
{
System.out.println("some other method called");
gameOver();
}
private static void gameOver()
{
System.out.println("game over called"); //I would ask the user if they want to play again.
//keeping it concise to illustrate my point, instead of using an if statement
gameStart();//starting the cycle I'm concerned about. Assume the user indicated they would like to play again.
}
}
Recursion needs a condition where it will not continue calling.
Recursion is most commonly seen where a method calls itself, such as computing the fibonacci sequence, where
fib(n) == fib(n-1) + fib(n-2)
fib(0) is defined as 0, so you don't have to compute.
fib(1) is defined as 1, so you don't have to compute.
Every other number is computed by the fib() method calling itself twice, but it escapes making the recursive call for the two defined cases, where there is nothing to compute. In pseudo code
int fib(int n)
{
if (n == 0) return 0; // doesnt have to recursively call
if (n == 1) return 1; // same
return fib(n-1) + fib(n-2);
}
In your case, you have two methods that call each other, but you have no condition where the calls can escape from that.
A possibility would be that gameOver() only calls gameStart() when the game ends in a tie, something like
public class Testing
{
public static void main(String[] args) {
System.out.println("main method");
gameStart();
}
private static void gameStart()
{
System.out.println("some other method called");
gameOver();
}
private static void gameOver()
{
System.out.println("game over called");
if (gameTied()) {
gameStart();
}
}
}
If you're just asking "do you want to play again?" -- that would be better done in main, along the lines of
public static void main(String[] args) {
System.out.println("main method");
String playGame = "Yes";
while (playGame.equalsIgnoreCase("Yes") {
gameStart();
playGame = ask("Play again?");
}
}
To avoid unlimited recursion you may switch over to iteration and introduce return values for those methods which currently decide how to proceed (currently by directly calling the corresponding actions).
Let those methods return some sign what to do next, for example by using an enum.
Then write a loop which calls the right methods depending on the return values.
Example (abbreviated, I assume you know Java syntax):
enum Action { Start, ShowEnd, Quit }
main:
Action nextAction = Action.Start;
while (action != Action.Quit)
{
switch (action)
{
case Start:
nextAction = gameStart();
break;
case ShowEnd:
nextAction = gameEnd();
break;
// ToDo: write more actions!
default:
break;
}
}
This assumes that each such method executes until a decision was made about which action to take next.
This way your call stack will always be quite flat, as the execution always returns to the main method and then branches off into other methods.
When you write recursive code you should make sure that you have some sort of end condition BESIDES calling the function again. For example I added an end condition for the gameOver method with if(gamePlayedThisManyTimes <= 1) return;. When running the following code, the value you give the method gameStart will determine how many games you play and gameOver will decrement the value when it calls 'gameStart' to eventually reach that end condition of the recursion.
public static void main(String[] args)
{
System.out.println("main method");
gameStart(10);
}
private static void gameStart(int playGameThisManyTimes)
{
System.out.println("Game " + playGameThisManyTimes + " started...");
System.out.println("some other method called");
gameOver(playGameThisManyTimes);
}
private static void gameOver(int gamePlayedThisManyTimes)
{
System.out.println("game over called for " + gamePlayedThisManyTimes); //I would ask the user if they want to play again.
if(gamePlayedThisManyTimes <= 1)
return;
else
gameStart(gamePlayedThisManyTimes - 1);
}
Output
main method
Game 10 started...
some other method called
game over called for 10
Game 9 started...
some other method called
game over called for 9
Game 8 started...
some other method called
game over called for 8
Game 7 started...
some other method called
game over called for 7
Game 6 started...
some other method called
game over called for 6
Game 5 started...
some other method called
game over called for 5
Game 4 started...
some other method called
game over called for 4
Game 3 started...
some other method called
game over called for 3
Game 2 started...
some other method called
game over called for 2
Game 1 started...
some other method called
game over called for 1
I am working on a game using the thread-per-client model. The game operates so that every half a second all of the players need to be updated. The updates all have to happen within the half a second interval, so they need to all be executed at the same time. My idea is to have a class that keeps track of when the "global update" needs to happen and then when the time comes, go through all of the players and tell it to update:
for(Player p : currentPlayers) {
p.update();
}
The problem is that since every player has their own thread, I want the player to take advantage of that fact since it is already there. If I go through the updates from a different class, then there is one thread executing what a couple hundred threads could be doing individually. How can I design it so that if a thread calls method 'update()' in class Player, a different thread than the one that called it executes it, or perhaps a different approach that can achieve the same goal?
If you need any clarification, please ask! Thanks a lot!
UPDATE: What do you guys think of this (I can't figure out how to format long amounts of code in posts!):
UPDATE 2: Just realized I would need to know when all of the players finish updating to reset the last time...
public class PseudoExample implements Runnable
{
// Assume 'players' is full of active players.
private Player[] players = new Player[100];
private long lastUpdate = System.currentTimeMillis();
public void run()
{
while (true)
{
if (System.currentTimeMillis() - lastUpdate >= 500)
{
for (Player p : players)
{
p.update = true;
}
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
private class Player implements Runnable
{
private boolean update = false;
public void run()
{
while (true)
{
if (update)
{
// Do updating here ...
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
}
}
I think the best way to handle this would be instead of calling p.update(), you could send an asynchronous message to p. This would use the Handler functionality. This is probably the cleanest way, although I believe some (likely trivial) overhead will occur from the message passing.
So, in your ticking thread (i.e. the one that calls the global update), you would have a reference to a Handler object for each client thread. Then, you look would look like
for (Player p : currentPlayers) {
p.handler().sendMessage(); // this isn't exactly the syntax
}
and in your Player, you would have a PlayerHandler object that extends Handler and overrides handleMessage(Message).
EDIT: the comments on the question are good ones - don't use more threads than you need to. They might seem to be the "right" abstraction, but they introduce a ton of potentially tricky issues. If all of your computation needs to be done in between ticks, it might not matter whether it's done sequentially or not.