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 key event handling issue


      Fix other event handling issue


      Fix RSServer hook


      Update world hopper to have it use OCR, thanks to Todd


      Use proper disposal of old Graphics objects


      Reformat code


      Rearrange code


      Organize code imports


      Apply around 8000 automated code refactorings


      Make preparations for Java 9


      Fix 11 various bugs


      Add more reliable debugging support


      Fix mouseEntered/Exited event dispatching bug


      Fix minimap walking bug where it opens the map


      Fix broken hooks for today's game update
        • Thanks
        • Like
      • 86 replies
    • This update will:

      Fix GE inventory item positioning bug


      Fix broken object hooks
        • Like
      • 27 replies
    • This release will:

      Fix some ClosedChannelException bug


      Fix bug in RSObject#getAllTiles


      Add game tab support for "Kourend Favour"
        • Like
      • 15 replies
    • This release will:

      Fix Settings UI placement bug


      Fix game object location bug


      Fix small layout bug making the client shift up and down


      Fix client crashing bug where loading the client with a small display area will cause the client to crash


      Fix annoying Linux bug relating to painting events and peers


      Fix settings saving bug where settings are saved to disk more often than they should


      Fix RSInterface#isBeingDrawn bug affecting a limited amount of people


      Drop Java 1.7 bytecode version for 1.8


      Important: Since the downloadable RS client uses Java 7, it will no longer be compatible with Looking Glass. To make up for this, we will add support for using other clients such as RuneLite (at a later date).


      This change was necessary to allow us to use Java 8 syntax. It also paves the way for Java 9/10/11 support.
        • Like
      • 40 replies
    • This update will:

      Fix the RSMenuNode bug which also fixes the bug with bank opening


      Fix the incorrect object positions bug


      Fix and re-enable the LG Objects API Accelerator


      Fix the RSObject#getAllTiles bug
        • Like
      • 22 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×