Jump to content

Phaser System


Tom1

Recommended Posts

Really couldn't think of anything else to call it, but it's pretty much what it does, it will handle the appropriate phase, but on the last phase it's handled in a separate method (easy way to describe). Anyways, documentation explains it all.
 
package phaser; /** * A simple abstract class that is used for representing an action that <ii>must</ii> * be performed in <b>phases.</b> I will allow myself to elabored: * <p> * A phaser (example) can be someone so simple as used in the runescape protocol * for things like <ii>agility,</ii> say we have phase 1, the player will walk * back from an object, then at phase 2 the wil force run and perform the * animation for the object, then at the final phase the player will receive XP * and many other things that may aquire. * </p> *  * @author Thomas Le Godais */public abstract class Phaser {		/**	 * An integer that is used to represent how many <b>phases</b> <ii>this</ii>	 * phaser should have.	 */	private int phaseCount;		/**	 * An integer that is used to represent the delay that we're going to be	 * starting the tick.	 */	private int delayTime;		/**	 * An integer that is used to represent the delay between the <b>periodic	 * ticks</b> of the phaser.	 */	private int periodicTime;		/**	 * An integer that is used to represent the current phase we're handling.	 */	private int currentPhase = 0;		/**	 * Constructs a new {@code Phaser} instance.	 *	  * @param phaseCount	 *            The amount of phases that this current phaser has.	 * @param delayTime	 *            The amount of time to delay the phaser before starting.	 * @param periodicTime	 *            The amount of time in which we <ii>tick</ii> the phaser.	 */	public Phaser(int phaseCount, int delayTime, int periodicTime) {		this.phaseCount = phaseCount;		this.delayTime = delayTime;		this.periodicTime = periodicTime;	}	 /**	 * Handles the set amount of phases.	 * <p>	 * The user will set the amount of "phases" that we will go through, then	 * from there we will cycle through them (they can or can not have a delay).	 * This will handle every phase - 1, the final phase is handled in it's own	 * method).	 * </p>	 *	  * @param currentPhase	 *            The current phase that we're currently processing for, please	 *            note <b>this will only cycle the amount of phases, but minus	 *            the last one because we're not processing for it</b>.	 */	public abstract void handlePhase(int currentPhase);	 /**	 * This is used to process the final phase, not this can just be something	 * simple as (in the runescape protocol) a player receiving expereince for	 * the task they performed (skill-wise). Or it can be used to process	 * certain tasks that a player needs (no examples come to mind, sorry).	 */	public abstract void finalPhase();	 /**	 * Gets the amount of max phases <b>this</b> phaser should cycle!	 *	  * @return the phaseCount	 */	public int getPhaseCount() {		return phaseCount;	}	 /**	 * Gets the amount of time in which to delay the initial start of the	 * phaser.	 *	  * @return the delayTime	 */	public int getDelayTime() {		return delayTime;	}	 /**	 * Gets the periodic <ii>tick</ii> time of the phaser.	 *	  * @return the periodicTime	 */	public int getPeriodicTime() {		return periodicTime;	}	 /**	 * Gets the current phase of this tick.	 *	  * @return the currentPhase	 */	public int getCurrentPhase() {		return currentPhase;	}	 /**	 * Sets the current phase (currentPhase + 1).	 *	  * @param currentPhase the currentPhase to set	 */	public void setCurrentPhase(int currentPhase) {		this.currentPhase = currentPhase;	}	 /**	 * Sets the phase count.	 *	  * @param phaseCount the phaseCount to set	 */	public void setPhaseCount(int phaseCount) {		this.phaseCount = phaseCount;	}	 /**	 * Sets the delay time.	 *	  * @param delayTime the delayTime to set	 */	public void setDelayTime(int delayTime) {		this.delayTime = delayTime;	}	 /**	 * Sets the period time.	 *	  * @param periodicTime the periodicTime to set	 */	public void setPeriodicTime(int periodicTime) {		this.periodicTime = periodicTime;	}}
package phaser; import java.util.Collections;import java.util.Iterator;import java.util.LinkedList;import java.util.List; /** * An {@link Thread} that will be used to listen to <b>incoming</b> * {@link Phaser} requests to a list. * <p> * This list will be cycle every certain amount of ms (milliseconds). And once * the thread has finished all of its phases {@see Phaser#finalPhase()} the * {@link Phaser} will then be removed from the list, and not be handled anymore * by this thread. * </p> *  * @author Thomas Le Godais *  */public class PhaseProcessor extends Thread {	 /**	 * An constant that is used to represent the tick at which this cycles	 * (being default 600ms!).	 */	private static final long CYCLE_COUNT = 600;	 /**	 * A simple flag that is used to indicate if the thread processor should be	 * running.	 */	private boolean threadStarted = false;	 /**	 * An {@link List} that is used for adding/removing phasers from/to.	 * <p>	 * The reason that we're using a synchronized list, is for example say we're	 * on the main thread (in RSPS sense the game thread, and we add/remove a	 * phaser, we <b>do not</b> want to cause <ii>synchronization</ii>	 * exceptions between the 2 threads because they will not be <ii>synced</ii>	 * with each other.	 * </p>	 */	private List<Phaser> phasers = Collections.synchronizedList(new LinkedList<Phaser>());	 /**	 * Constructs a new {@code PhaseProcessor} instance.	 * <p>	 * Here we're are going to set the name of the thread (this is useful if an	 * error occurs in this thread, instead of it labelling it by the thread-ID	 * we can know the thread right away[incase we have many threads in a	 * application]). And since this is a really important part of an	 * application (may be used to perform high priority updates) this is a MAX	 * priority thread.	 * </p>	 */	public PhaseProcessor() {		this.setName("Phase-Processor-Thread");		this.setPriority(Thread.MAX_PRIORITY);	}	 /*	 * (non-Javadoc)	 *	  * @see java.lang.Thread#run()	 */	@Override	public void run() {		while (isThreadStarted()) {						/* Get the current time we starting handling the phaser. */			long currentTime = System.currentTimeMillis();						/*			 * Prevent the thread from processing because there is no phasers to			 * currently handle.			 */			if (phasers.isEmpty())				return;						/*			 * Iterate through the list to get all of the current phasers, only			 * if the list is not empty.			 */			for (Iterator<Phaser> it$ = phasers.iterator(); it$.hasNext();) {								/*				 * Check to make sure a phaser is not {@code Null} in the list.				 *				  * If the phaser is {@code Null} we're going to "continue"				 * because we do not want to halt all of the other phasers that				 * could possibly cycling!				 */				Phaser phaser = (Phaser)it$.next();				if (phaser == null)					continue;								/*				 * This block of code is used to check if we still have time				 * left before we're going to process a task.				 *				  * If we do have time left we're going to subtract one ms				 * (millisecond) from it, and then we're going to "continue"				 * because we do not want to stop processing other tasks that				 * may exist!				 */				if (phaser.getDelayTime() > 0) {					phaser.setDelayTime(phaser.getDelayTime() - 1);					continue;				}								/*				 * Next, we're going to cycle the phaser! But, we have to make				 * sure we increment the current phase (only if it's not the				 * final phase)! But, if it's the final phase we're going to				 * handle the other method {@see Phaser#finalPhase()} instead of				 * {@see Phaser#handlePhase()}.				 */				int maxPhase = phaser.getPhaseCount();								/*				 * A simple flag used to indicate if we should remove this				 * phaser from processing (only called on the final state)!				 */				boolean shouldRemove = false;				if (phaser.getCurrentPhase() != maxPhase) {					phaser.setCurrentPhase(phaser.getCurrentPhase() + 1);					phaser.handlePhase(phaser.getCurrentPhase());				} else {					phaser.finalPhase();					shouldRemove = true;				}											/*				 * Finally we're going to have to decide if we should either				 * remove the current phaser (to stop processing) or, are we				 * going to reset the delay between each phase (if exists!).				 */				if (shouldRemove)					phasers.remove(phaser);				else {					phaser.setDelayTime(phaser.getPeriodicTime());				}								/*				 * Here we're going to get the total time it took to process the				 * phaser!				 */				long totalTime = CYCLE_COUNT + (System.currentTimeMillis() - currentTime);								/*				 * If the total time is less then zero we're going to prevent it				 * from sleeping because we can not sleep at a negative count!				 */				if (totalTime < 0)					continue;								/*				 * And finally, to end this all off, we're going to sleep the				 * current thread after processing!				 */				try {					Thread.sleep(totalTime);				} catch (InterruptedException e) {					e.printStackTrace();				}			}		}	}		/**	 * Submits a new {@link Phaser} into the {@link List} for processing!	 *	  * @param phaser The phaser we're adding into the list.	 */	public void submit(Phaser phaser) {		if (phaser == null)			return;				phasers.add(phaser);	}		/**	 * Shutdown the phaser from processing!	 */	public void shutdown() {		phasers.clear();		setThreadStarted(false);	}		/**	 * Gets the current list of phasers.	 *	  * @return The list.	 */	public synchronized List<Phaser> getPhasers() {		return phasers;	}	 /**	 * Gets the flag that is used to indicate if this thread should be	 * processing.	 *	  * @return the threadStarted	 */	public boolean isThreadStarted() {		return threadStarted;	}	 /**	 * Sets the value of the "threadStarted" flag.	 *	  * @param threadStarted the threadStarted to set	 */	public void setThreadStarted(boolean threadStarted) {		this.threadStarted = threadStarted;	}}
 
A small example :)
package phaser.test; import phaser.PhaseProcessor;import phaser.Phaser; public class Test {		private static final PhaseProcessor phaseProcessor = new PhaseProcessor();	 public static void main(String[] args) {				/* First begin by starting the phaser cycle! */		phaseProcessor.setThreadStarted(true);		phaseProcessor.start();				/* Now, we're going to submit a phase to the thread! */		phaseProcessor.submit(new Phaser(22, 0, 600) {			 /**			 * An integer used for testing the count.			 */			int testCount = 0;						/*			 * (non-Javadoc)			 * @see phaser.Phaser#handlePhase(int)			 */			@Override			public void handlePhase(int currentPhase) {				if (currentPhase <= 5)					System.out.println("Current phase is less than, or equal to 5!");				else if (currentPhase >= 10)					System.out.println("Current phase is greater then or eqal to 10!");				else					System.out.println("Phase was neither!");								testCount += 1;			}			 /*			 * (non-Javadoc)			 * @see phaser.Phaser#finalPhase()			 */			@Override			public void finalPhase() {				System.out.println("Phaser finished at test count: " + testCount);			}		});	}}
Link to comment
Share on other sites

Alright, the majority of people who use Hyperion, Apollo, RuneSource, RS2Server, etc, they use Graham's event system, I however use the Tickable system that was released with RS2Server. 

 

Obviously it's setup as:

 

World.getWorld().newTickable(new Tickable(2) { @Overridepublic void execute() { } });

 

It'd be helpful to add the phase system to it, so for the people already using the tickable system could easily implement it if needed.

 

Like for myself, before I got a new skill system, I was using multiple tick events for woodcutting, first tick cut, second respawn tree. 

Link to comment
Share on other sites

Yea, it could work the same as that, are you would do is make the instance of PhaseProcessor in the World so when the server starts, it will start the phase processing. Then we can apply the same thing here.

 

 

 punlic void submitPhaser(Phaser phaser) {	phaseProcessor.submit(phaser);}

 

and then to use it, you would just

 World.getWorld().submitPhaser(new Phaser(4, 0, 600) {	 @Override	public void handlePhase(int currentPhase) {		System.out.println("Handling phase " + currentPhase);	}	 @Override	public void finalPhase() {		System.out.println("Performing final phase!");			}});
Edited by Tomm
  • Like 1
Link to comment
Share on other sites

Why do you call the actual remove method inside that loop for? That will just throw a modification error on the next loop. Disregarding that, you won't be able to add another inner class inside the phaser if you were to attempt on adding another timed event like that lol

 

private List<Phaser> phasers = Collections.synchronizedList(new LinkedList<Phaser>());
  public synchronized List<Phaser> getPhasers() {        return phasers;    }

 

What's the point of synchronizing a list that has methods that are all synchronized lol

 

Also, you should know that the main thread and this thread would go off sync if an event is added after which would delay some actions (would be better if you ran this off the main thread to prevent this), did you even think this code through? 0/10 would not use

Link to comment
Share on other sites

Why do you call the actual remove method inside that loop for? That will just throw a modification error on the next loop. Disregarding that, you won't be able to add another inner class inside the phaser if you were to attempt on adding another timed event like that lol

 

private List<Phaser> phasers = Collections.synchronizedList(new LinkedList<Phaser>());
  public synchronized List<Phaser> getPhasers() {        return phasers;    }

 

What's the point of synchronizing a list that has methods that are all synchronized lol

 

Also, you should know that the main thread and this thread would go off sync if an event is added after which would delay some actions (would be better if you ran this off the main thread to prevent this), did you even think this code through? 0/10 would not use

 

Lol at you, you're completely wrong. The whole point of the synchronization is to prevent cross-thread synchronization errors. 0/10 eh? Better then I guarantee  anything you could do. I had a task system similar to this, and it worked perfectly, although my task system to handle on different phases (it was more like a tick, that you could delay).

So learn to read code before you judge.

Link to comment
Share on other sites

Lol at you, you're completely wrong. The whole point of the synchronization is to prevent cross-thread synchronization errors. 0/10 eh? Better then I guarantee  anything you could do. I had a task system similar to this, and it worked perfectly, although my task system to handle on different phases (it was more like a tick, that you could delay).

So learn to read code before you judge.

 

My comment was pointing out how you synchronize an object that has methods that synchronizes for you

 

I just tried using this on my 718 for a timed phase combat script for the nomad boss fight, works fine.. 

 

yes because this piece of code

 

  if (phasers.isEmpty())                return;

 

 

will permit you to run a task again after the first time lol, does anyone even really test this type of stuff ?

  • Like 1
Link to comment
Share on other sites

My comment was pointing out how you synchronize an object that has methods that synchronizes for you

 

 

yes because this piece of code

 

  if (phasers.isEmpty())                return;

 

 

will permit you to run a task again after the first time lol, does anyone even really test this type of stuff ?

 

As what Sensationial posted, he already stated it works, I even tested it myself.

 

Regard the, "phasers.isEmpty()," do you understand what that code does? I am simply preventing the rest of that method from processing because there are no tasks, so there is no need to sleep.

 

I'm being nice here, so do not take me off as a dick.

Link to comment
Share on other sites

As what Sensationial posted, he already stated it works, I even tested it myself.

 

Regard the, "phasers.isEmpty()," do you understand what that code does? I am simply preventing the rest of that method from processing because there are no tasks, so there is no need to sleep.

 

I'm being nice here, so do not take me off as a dick.

 

return stops the whole method from continuing lol, I think you meant to use continue ... even in a loop it will stop

Edited by Bythex
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...