Jump to content
TheD

[Tutorial/Snippet] DTimer

Recommended Posts

Hi Guys,

Lately I am using a separate class for some of my timing actions, and a feature I use a lot, which I call EndTimer. Not everybody has tons of time to maintain a bot farm, Or people want to bot over night, but only for a few hours. With EndTimer we cover some of these features, and it is all possible, and your script could be a whole lot more useful to some people. 

You can find the source code at the bottom of this tutorial.

 

About EndTimer

EndTimer is a really simple concept that logs you out after a certain time. You decide the global duration, and the res will be randomized. By default EndTimer is not on.

 

About DTimer in general

Next to EndTimer I also decided to add a couple of my other timing actions to the class. Like getting the current hour, minute and second.

 

Setting up DTimer

At the top of the script you'll see "package scripts.DTools;" 
Create a directory named DTools inside your scripts folder. Create a new Class named DTimer.java Copy the entire content from the pastebin link below, and paste it in DTimer.java

 

Using DTimer in your Script

Inside your run() function paste this:

DTimer.startScriptTimer(); //We want to start our timer
DTimer.callGUI(); //Call the GUI to let the user set-up EndTimer

We want the user to declare when we should end the script. We can either use the default GUI in EndTimer, which we call by using DTimer.callGUI(); or we can use DTimer.setEnd(HourToEndAt); if you would like to use your own GUI.

 

Placing EndTimer in your Script

Inside your loop we need to check a little something. To give you an example how it could look:

@Override
public void run() 
{
  while(true)
  {
  	if(DTimer.checkEndTimer()) //returns true if we succesfully logged out & are not in combat
  	{
		this.stopScript();
  	}
    
    //all the other code you have
    //even more code you have
    //moremoremore
    //somuchmore
    //feelsbadman still more
  }
}

The code you need to look at:

	if(DTimer.checkEndTimer()) //returns true if we succesfully logged out & are not in combat
  	{
		this.stopScript();
  	}

 

To display the time ran we could add a line like this in our paint:

g.drawString("time ran: "+ DTimer.getHour() + ":" + DTimer.getMinute() + ":" + DTimer.getSecond(), 5,305);

To also show the end time in our script you could use:

	if(DTimer.getEndAfterTime()) g.drawString("Ending script when we ran "+(DTimer.getEndHour())+":"+(DTimer.getEndMinute())+":"+(DTimer.getEndSeconds())+" (HH:MM:SS)", 10,315);
	if(!DTimer.getEndAfterTime()) g.drawString("Not using End-timer", 10,315);

 

Read the pastebin code and annotations for further information about the code!

 

http://pastebin.com/9dBcc7Aa

 

Side note: This could also be done using a Timer class. 

My colleague script writers gave some great examples: 

 

 

Share this post


Link to post
Share on other sites

Half of this code is re-inventing a date/time class:

getSecond/hour/minute/etc/etc/etc. You can remove half of this code immediately using a few off the shelf built right into the core api classes, such as the new Java 8 LocalDateTime class. Prior to 8 we had classes that handled this as well, why reinvent the wheel?

 

Let me preface the rest of my feedback on the fact that I did not read through all of this code.

It would appear I can only set a time in hours which is a bit crazy considering we are looking at a 450 line timer class.


This checkEndTimer method makes a few improper assumptions, has the ability to get stuck in an infinite loop, and has the ability to slow a script by potentially 3 seconds every loop cycle. There is no reason to check if the player is in combat if the next end time is in 13 hours. Furthermore, a 3 second wait is no guarantee on a player leaving combat. There is also no reason to do any of this if we are not even using the timer (end_after_time). The if statement to determine if the script has passed it’s end time is long winded, and can be simplified. The logout while loop has no exit point in the case something goes wrong, not even a timeout. So you potentially could be trying to logout for multiple minutes spam clicking the logout button every 1-5 seconds until your player dies, you get banned, or lose connection etc..

 

Warfront1

Edited by warfront1
  • Like 3

Share this post


Link to post
Share on other sites
25 minutes ago, warfront1 said:

Half of this code is re-inventing a date/time class:

getSecond/hour/minute/etc/etc/etc. You can remove half of this code immediately using a few off the shelf built right into the core api classes, such as the new Java 8 LocalDateTime class. Prior to 8 we had classes that handled this as well, why reinvent the wheel?

 

Let me preface the rest of my feedback on the fact that I did not read through all of this code.

It would appear I can only set a time in hours which is a bit crazy considering we are looking at a 450 line timer class.


This checkEndTimer method makes a few improper assumptions, has the ability to get stuck in an infinite loop, and has the ability to slow a script by potentially 3 seconds every loop cycle. There is no reason to check if the player is in combat if the next end time is in 13 hours. Furthermore, a 3 second wait is no guarantee on a player leaving combat. There is also no reason to do any of this if we are not even using the timer (end_after_time). The if statement to determine if the script has passed it’s end time is long winded, and can be simplified. The logout while loop has no exit point in the case something goes wrong, not even a timeout. So you potentially could be trying to logout for multiple minutes spam clicking the logout button every 1-5 seconds until your player dies, you get banned, or lose connection etc..

 

Warfront1

Hi Warfront1,

Thanks for your feedback!

I overlooked the combat checker, I added it last minute, and indeed it was placed wrong. Since we would always wait, no matter if we should actually end the script already.
Changed it & updated code. Thanks. I also added a timeout to the while loop, just in case. You were right there too :).

I looked up the LocalDataTime class you were talking about : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html
Isn't this just for the time based on the real time, not based on time ran?

Would like to see a reply on it.

Thanks again!

DScripting

Share this post


Link to post
Share on other sites
                if(Player.getRSPlayer().isInCombat()) General.sleep(500,3000); //We could be in combat, so we wait a sec.
                if(Player.getRSPlayer().isInCombat()) return false; //still in combat, not going to spam log-out.

- Player#getRSPlayer can and will return null using your current logic. This will crash the script after an exception is thrown
- Using static sleeps won't guarantee that you've exited combat, use dynamic 
- I doubt 0.5 to 3 seconds is even close to the average amount of time  a player is in combat for
 

A lot of your code can be simplified. Having a timer object would make your life a lot easier:

import org.tribot.api.Timing;

public class Timer {

    private long startTime;
    private long timeout;

    public Timer() {
        restart();
    }

    public Timer(long timeout) {
        this.timeout = timeout + startTime;
        restart();
    }

    public void restart() {
        this.startTime = System.currentTimeMillis();
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
    
    public long getElapsedTime() {
        return System.currentTimeMillis() - startTime;
    }

    public long getPerHour(long value) {
        return value * 3600000 / getElapsedTime();
    }

    public String toElapsedString() {
        return Timing.msToString(getElapsedTime());
    }

    public boolean isActive() {
        return timeout > System.currentTimeMillis();
    }

}


 

Edited by Flamo353

Share this post


Link to post
Share on other sites

Let me just preface this by saying that this isn't a personal attack or anything since there is quite a few of us criticizing, but I feel like you over complicated a relatively simple thing.
Here's a simple Timer class I made http://pastebin.com/xCemqeEq. It's basically a countdown timer. Java has a Timer class in the standard library, but even that felt too complicated for this.

So now your script will be something like this

boolean runScript;
Timer timer;

@Override
public void run() {
    runScript = true;
    long duration = value from GUI (converted to milliseconds)
    timer = new Timer(duration);
    while (runScript && timer.isRunning()) {
        // execute script tasks
    }
    // perform end script tasks such as getting out of combat and logging out
}

@Override
public void onPaint(Graphics g) {
    // Use TRiBot's built in msToString method to convert the remaining time to HH:MM:SS format
    g.drawString("Running Time: " + Timing.msToString(this.getRunningTime()), 10, 80);
    g.drawString("Remaining Time: " + Timing.msToString(timer.remainingTime()), 10, 100);
}

 

Edited by Encoded

Share this post


Link to post
Share on other sites
10 hours ago, Encoded said:

Let me just preface this by saying that this isn't a personal attack or anything since there is quite a few of us criticizing, but I feel like you over complicated a relatively simple thing.
Here's a simple Timer class I made http://pastebin.com/xCemqeEq. It's basically a countdown timer. Java has a Timer class in the standard library, but even that felt too complicated for this.

So now your script will be something like this

boolean runScript;
Timer timer;

@Override
public void run() {
    runScript = true;
    long duration = value from GUI (converted to milliseconds)
    timer = new Timer(duration);
    while (runScript && timer.isRunning()) {
        // execute script tasks
    }
    // perform end script tasks such as getting out of combat and logging out
}

@Override
public void onPaint(Graphics g) {
    // Use TRiBot's built in msToString method to convert the remaining time to HH:MM:SS format
    g.drawString("Running Time: " + Timing.msToString(this.getRunningTime()), 10, 80);
    g.drawString("Remaining Time: " + Timing.msToString(timer.remainingTime()), 10, 100);
}

 

Hi Encoded,

Thanks for taking a moment to review my code and giving me feedback, I really appreciate it. 

The option you gave me would be a really efficient way to get the running time etc. Thanks for that. I also like how you made your timer class short and simple. :)

My goal with writing this was mainly to practice and to help new scripters with a stand-alone class including a simple set-up GUI for using EndTimer, as I saw a lot of scripts do not yet have this feature. 

Second to that, I wanted it to be as dynamic as possible for everyone so you can use it for everything. I must admit I did not know about "Timing.msToString" really efficient method! 
 

As you can read here I have been away for quite some time, so once again. Thanks for reviewing my code. I won't let your time go to waste, and will use it see how I can improve my code while still reaching my goals with the class.

Thanks

DScripting

 

10 hours ago, Flamo353 said:
                if(Player.getRSPlayer().isInCombat()) General.sleep(500,3000); //We could be in combat, so we wait a sec.
                if(Player.getRSPlayer().isInCombat()) return false; //still in combat, not going to spam log-out.

- Player#getRSPlayer can and will return null using your current logic. This will crash the script after an exception is thrown
- Using static sleeps won't guarantee that you've exited combat, use dynamic 
- I doubt 0.5 to 3 seconds is even close to the average longest amount of time  a player is in combat for
 

A lot of your code can be simplified. Having a timer object would make your life a lot easier:

import org.tribot.api.Timing;

public class Timer {

    private long startTime;
    private long timeout;

    public Timer() {
        restart();
    }

    public Timer(long timeout) {
        this.timeout = timeout + startTime;
        restart();
    }

    public void restart() {
        this.startTime = System.currentTimeMillis();
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
    
    public long getElapsedTime() {
        return System.currentTimeMillis() - startTime;
    }

    public long getPerHour(long value) {
        return value * 3600000 / getElapsedTime();
    }

    public String toElapsedString() {
        return Timing.msToString(getElapsedTime());
    }

    public boolean isActive() {
        return timeout > System.currentTimeMillis();
    }

}


 

Hi Flamo353,

Thanks for your time reading my code and reviewing it. 


1. Thanks for the tip I will add a null checker for getRSPlayer
2. Very aware that we do not really wait for the player to get out of combat. The reason I left it this way is I don't want to stop the script if the player is in-combat, as the player could die with stronger monsters. I am still thinking about a more efficient way. to do this tho.
3. see point 2.

A timer object would indeed make life a whole lot easier. I must admit, just like I said to Encoded, I did not think about creating a Timer class. It would indeed be easier. Instead, I copied and pasted my old paint method that collects hour, minute and second. Used that to make it easier to collect these details. 

Once again, yes, a Timer class would be more efficient.

As you can read here I have been away for quite some time, so once again. Thanks for reviewing my code. I won't let your time go to waste.

Thanks

DScripting

  • Like 3

Share this post


Link to post
Share on other sites
8 hours ago, TheD said:

Hi Encoded,

Thanks for taking a moment to review my code and giving me feedback, I really appreciate it. 

The option you gave me would be a really efficient way to get the running time etc. Thanks for that. I also like how you made your timer class short and simple. :)

My goal with writing this was mainly to practice and to help new scripters with a stand-alone class including a simple set-up GUI for using EndTimer, as I saw a lot of scripts do not yet have this feature. 

Second to that, I wanted it to be as dynamic as possible for everyone so you can use it for everything. I must admit I did not know about "Timing.msToString" really efficient method! 
 

As you can read here I have been away for quite some time, so once again. Thanks for reviewing my code. I won't let your time go to waste, and will use it see how I can improve my code while still reaching my goals with the class.

Thanks

DScripting

 

Hi Flamo353,

Thanks for your time reading my code and reviewing it. 


1. Thanks for the tip I will add a null checker for getRSPlayer
2. Very aware that we do not really wait for the player to get out of combat. The reason I left it this way is I don't want to stop the script if the player is in-combat, as the player could die with stronger monsters. I am still thinking about a more efficient way. to do this tho.
3. see point 2.

A timer object would indeed make life a whole lot easier. I must admit, just like I said to Encoded, I did not think about creating a Timer class. It would indeed be easier. Instead, I copied and pasted my old paint method that collects hour, minute and second. Used that to make it easier to collect these details. 

Once again, yes, a Timer class would be more efficient.

As you can read here I have been away for quite some time, so once again. Thanks for reviewing my code. I won't let your time go to waste.

Thanks

DScripting

Excellent attitude

  • Like 2

Share this post


Link to post
Share on other sites
On 6/28/2016 at 9:16 PM, Flamo353 said:
                if(Player.getRSPlayer().isInCombat()) General.sleep(500,3000); //We could be in combat, so we wait a sec.
                if(Player.getRSPlayer().isInCombat()) return false; //still in combat, not going to spam log-out.

- Player#getRSPlayer can and will return null using your current logic. This will crash the script after an exception is thrown
- Using static sleeps won't guarantee that you've exited combat, use dynamic 
- I doubt 0.5 to 3 seconds is even close to the average longest amount of time  a player is in combat for
 

A lot of your code can be simplified. Having a timer object would make your life a lot easier:

import org.tribot.api.Timing;

public class Timer {

    private long startTime;
    private long timeout;

    public Timer() {
        restart();
    }

    public Timer(long timeout) {
        this.timeout = timeout + startTime;
        restart();
    }

    public void restart() {
        this.startTime = System.currentTimeMillis();
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
    
    public long getElapsedTime() {
        return System.currentTimeMillis() - startTime;
    }

    public long getPerHour(long value) {
        return value * 3600000 / getElapsedTime();
    }

    public String toElapsedString() {
        return Timing.msToString(getElapsedTime());
    }

    public boolean isActive() {
        return timeout > System.currentTimeMillis();
    }

}


 

You're a twat.

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, TheD said:

Updated my own code, also edited topic to include shortcuts to both @Encoded's part and @Flamo353's part to help people who are looking for such a class. :)

I will soon extend this guide with an regular/easier timer class including EndTimer & Set-up GUI.

Line 57

Player.getRSPlayer() != null && Player.getRSPlayer().isInCombat() 

Can return a Null Pointer Exception according to the docs.

The return of the two calls to the Player method getRSPlayer are not the same.

ie. the object null checked is not equivalent to the one you are firing the isInCombat method on.

 

Warfront1

  • Like 1

Share this post


Link to post
Share on other sites
10 hours ago, Flamo353 said:

Yeah you're right. Instead of me taking the precious time out of my day to give a total stranger some programming advice, why don't you learn java, learn how to script and help him yourself? 

 

You read this like a week ago and now you decide to give a sarcastic reply? Na fam. I don't even know Java and I have a higher chance of getting scripter than you l0l0l

Share this post


Link to post
Share on other sites
3 hours ago, HeyImJamie said:

 

You read this like a week ago and now you decide to give a sarcastic reply? Na fam. I don't even know Java and I have a higher chance of getting scripter than you l0l0l

You think I'm being sarcastic? Go learn java, go learn how to script, then take the time out of your day to help The D. I would love to see you try.

Share this post


Link to post
Share on other sites
57 minutes ago, Flamo353 said:

You think I'm being sarcastic? Go learn java, go learn how to script, then take the time out of your day to help The D. I would love to see you try.

Why would I bother when it's not something I'm knowledgeable in? You literally asked on Discord for a reply and we joked about this... When did you jump up on your high horse lmao, you're probably still at school cradling your dads balls for irl gp so I don't even know why you're piping up.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By Beg
      One method classes such as Condition, https://tribot.org/doc/org/tribot/api/types/generic/Condition.html , can now be replaced by functional interfaces since Java 8 release.
      @FunctionalInterface public interface Condition07 {     boolean active(); }  
      Why is this useful? 
      We can take advantage of lambda expressions to write a much more compact version of anonymous inner classes.
      Timing.waitCondition(new Condition() { @Override public boolean active() { General.sleep(100); return !isFletching(); } }, General.random(30000, 35000)); VS
      Timing07.waitCondition(() -> !isFletching(), General.random(30000, 35000)); You can also have more than one statement on your lambda expression:
      Timing07.waitCondition(() -> { AntiBan.timedActions(); return !isFletching(); }, General.random(30000, 35000));  
      Setbacks
      You would have to re implement API methods which use Condition such as Timing#waitCondition, which is widely used on most scripts.
      import org.tribot.api.General; import org.tribot.api.Timing; public class Timing07 {     public static boolean waitCondition(Condition07 condition, long timeout) {         long t = Timing.currentTimeMillis() + timeout;         while (!condition.active()) {             if (Timing.currentTimeMillis() >= t)                 return false;             General.sleep(100);         }         return true;     } }  
      @TRiLeZ It wouldn't take that long to replace Condition abstract class with Condition functional interface. You can still use the old fashion way (new Condition() ...) with functional interfaces, so, it's compatible with current existing scripts. 
  • Our picks

    • This release will:

      Fix bytecode manipulation in order to prevent the modification of parameters within the Filter and Condition classes themselves (thanks @wastedbro)


      Fix NPE caused by non-null value in GE API (thanks @erickho123)


      Add and fix equals methods for api2007.types (thanks @JoeDezzy1)


      Modify Mouse#leaveGame to make the mouse leave the game from top, left, right, or bottom (thanks @erickho123)


      Add Entrana area to Ships API (thanks @erickho123)


      Fix raid prayers index/settings in Prayer API (thanks @erickho123)



      Upcoming updates:

      Break handler bug fix


      Improved CLI support


      Much more



      Note: If you are using LG, please restart both the RS client and TRiBot
        • Like
      • 27 replies
    • This update will:

      Implement better canvas locking/synchronization mechanism


      Fix small Login API bug


      Remove the requirement for xbooting Java classes


      Use ExecutorService to perform canvas work in parallel


      Add "Account Management" game tab to GameTab API (thanks @Encoded)


      Fix NPCChat#getMessage (thanks @Encoded )


      Fix NPCChat#selectOption (thanks @Encoded )


      Fix Banking API after today's update (thanks @Encoded )


      Fix in-game world hopper after today's update (thanks @Encoded )



      Upcoming updates:

      Break handler bug fix


      Improved CLI support


      Much more



      Note: If you are using LG, please restart both the RS client and TRiBot
        • Thanks
        • Like
      • 38 replies
    • This release includes:

      Fix updater bug which was causing a bunch of issues


      TRiBot will no longer require manual hook fixes every time the RS client updates - the updater has been fully patched for objects


      Hooked login fields


      Improved the login bot


      Ability to recognize the banned/locked messages again


      Ability to read the current input for username and password fields


      If the username or password is already entered correctly, it won't be erased


      If only part of the username or password is already entered correctly, it won't be erased. The login bot will fill in what's missing.


      If there are a few invalid characters after a valid substring of your username/password, only (approximately) those invalid characters will be erased. The login bot will then proceed to fill in the missing characters.





      Coming soon:

      Skull icon fix


      Improve screen rate and responsiveness of the RS client (both regular client and LG)


      Much more
        • Thanks
        • Like
      • 33 replies
    • This release includes:

      Fix shift clicking option selecting


      Fix high paint delay settings saving


      Update prayer IDs for the quick select menu


      Remove RS3 support


      Fix hooks



      RS3 Support Removed

      The RS3 client hasn't been updated since our Old-School version of TRiBot was released, as many of you may have noticed. Keeping all of the RS3 code in the client made the client as a whole harder to maintain, larger, slower, and messier. As hardly anyone still uses the RS3 client, and since the RS3 API was hardly functioning, we made the decision to completely remove it from TRiBot.

      For the average user, this means that the client will be smaller, cleaner, and faster. Future updates will also take less work meaning there will be more frequent updates.

      If you were one of the few users still using the RS3 client, we apologize for the inconvenience. No future support for RS3 is planned. There are many other botting clients which has support for RS3, so we recommend finding an alternative if you wish to continue botting on RS3.
        • Thanks
        • Like
      • 25 replies
    • Please welcome our new developers, @JoeDezzy1, @erickho123, @Encoded, and @wastedbro.

      These members will be responsible for working on, maintaining, and improving TRiBot.

      This means that bug fixes and improvements will now come at a much faster pace! We're committed to providing users with the best botting experience possible!
        • Thanks
        • Like
      • 30 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×