Uptime and reading from files

Posted by Zeno on Thu 25 Nov 2004 05:06 AM — 24 posts, 87,252 views.

USA #0
I'm looking for a way to show the MUD uptime in the "time" command, but not sure how to record it. Increase a variable saved in system data every update?

Also, with the "last" command, I am wondering if there is a way to also display the IP that was last logged on, along with the last logon time. If not, I may just install the finger snippet for Immortals.
USA #1
The MUD stores its startup time, doesn't it? Can't you just take current time, subtract startup time, and there you go? Making a whole new variable in update really seems like a lot of effort for a really simple problem - even if the MUD doesn't already store the startup time (and I think it does) you can just store it yourself.

For your modification to 'last', you'll have to go in and actually read the file, I think. Just make sure you don't save it or anything, because that will break the last command, which, IIRC, works by looking at when the file was last written.
USA #2
Hmm, not sure how to do that if the time is read as a string. str_boot_time is also a string. Could you provide an example of how to do this?

Meh. Might as well just install finger, more useful.
USA #3
Here's what I have in comm.cpp:
secBootTime = time(0);
strcpy( str_boot_time, ctime( &secCurrentTime ) );

Now, I've edited it all, so it's probably not called secBootTime on your version... but I'm pretty darn sure it's still there one way or another.

So, to do the uptime, you would use time(0), subtract from that the boot time, and you obtain the number of seconds you have been running. (To be perfectly correct, you should use the difftime function, but since a time_t is a number on any POSIX system, normal subtraction is fine.)

From the number of seconds, getting the number of days/hours/minutes should be fairly straightforward.

In fact, I think I'm going to add this functionality to my MUD - good idea. :-)
USA #4
Right, with a little extra help from a friend, I've got it working for those who also wish to use it. I put this in my time function:

    time_t current;
    time_t diff;

    current = time(0);
    diff = current - boot_time;
    ch_printf( ch, "The MUD has been up:      %d hours, %d minutes, %d seconds.\n\r", diff/3600, diff/60, diff%60 );


USA #5
This won't work...
ch_printf( ch, "The MUD has been up:      %d hours, %d minutes, %d seconds.\n\r", diff/3600, diff/60, diff%60 );


If time = 3671, you will get:
hours = 1
minutes = 61
seconds = 11

As you can see, the minutes are wrong. What you actually want would be more like:
ch_printf( ch, "The MUD has been up:      %d hours, %d minutes, %d seconds.\n\r", diff/3600, (diff-3600*(diff/3600))/60, diff%60 );


This way, you'll get:
hours = 1
minutes = 1 (EDIT #2: oops, I had this as 0)
seconds = 11
Which is what you'd expect.

EDIT:
Or, you could use:
ch_printf( ch, "The MUD has been up:      %d hours, %d minutes, %d seconds.\n\r", diff/3600, (diff%3600)/60, diff%60 );

This is perhaps a little clearer than the above version.
Amended on Sat 27 Nov 2004 02:47 AM by David Haley
USA #6
Ah, didn't even look into that. Would have realized it though, when it would have happened. Thanks.
#7
I just came up with the code above (the one with the mistake) off the top of my head. In any case, it would probably be easier to just do:

ch_printf( ch, "The MUD has been up:      %d hours, %d minutes, %d seconds.\n\r", diff/3600, (diff/60)%60, diff%60 );


All solutions to the same problem...
Amended on Sat 27 Nov 2004 02:45 AM by Horus
USA #8
If I wanted to also display days, what would be the changes? I'm not entirely sure, and can't really see the immediate solution. It's simple I know.
USA #9
This should help you see what's going on:
-- diff.lua
-- 4 seconds and 3 minutes and 2 hours and 7 days
time = 4 + 60*3 + 60*60*2 + 60*60*24*7
timeorig = time

days = math.floor(time/86400)

time = math.mod(time, 86400)
hours = math.floor(time/3600)

time = math.mod(time, 3600)
minutes = math.floor(time/60)

seconds = math.mod(time, 60)


print("Days", days, "Hours", hours)
print("Minutes", minutes, "Seconds", seconds)

time = timeorig
print("Days", math.floor(time/86400), "Hours", math.mod(math.floor(time/3600), 24) )
print("Minutes", math.mod(math.floor(time/60), 60), "Seconds", math.mod(time, 60))
The answer to your question is in the last two lines.

Days = time/86400
Hours = (time/3600) % 24
Minutes = (time/60) % 60
Seconds = time % 60

Note that math.floor is needed in Lua to make sure we have integer division, which is automatic in C.
USA #10
Yeah, I figured it out while I was about to go to sleep. I love it how I couldn't figure it out while staring at the problem/code, but got it when I was trying to sleep. I thought "Wait, I just multiplay 24 by 3600, and divide the number by that." Thanks for the detailed explaination.
USA #11
Well, you can't just get the number of days. If you compute the number of days, you have to adjust the number of hours as well (since 25 hours is no longer 25 but instead 1 day and 1 hour).

But yes, as they say, sometimes problems are best solved when you're sleeping, or about to sleep. Which is why I wish I could get some sleep these days, and not be forced to be up for nearly the entire night. :-)
USA #12
Quote:
Well, you can't just get the number of days. If you compute the number of days, you have to adjust the number of hours as well (since 25 hours is no longer 25 but instead 1 day and 1 hour).

Yeah, I didn't mention that because I had thought it was obvious/assumed.
USA #13
Ok, now I'm very curious what you've come up with as the final product so that do_time will display the mud's uptime correctly even if it's been multiple days.. would you be willing to post it?

Also, Zeno, in answer to your other question about having the IP display in your last command, I use Xerves' logon history snippet on my mud and it works very well. I can do 'last 10' to see the last 10 logons (with IP) or 'last today' to see everyone who's logged on since midnight, or 'last <player> #' to see a particular player's last # of logons (up to the limit of my last log file which I have set to 5000, but the default in the snippet is 500) or I can do 'last -1' to see the last 5000 logons or I can do 'last <player>' to see the old version that you're used to. Was a fairly easy snippet and has never given me any problems at all.
USA #14
This is what I have:
    current = time(0);
    diff = current - boot_time;
    ch_printf( ch, "The MUD has been up  :    %d day%s, %d hour%s, %d minute%s and %d second%s.\n\r",
         diff/86400, diff/86400 == 1 ? "" : "s", (diff/3600)%24, (diff/3600)%24 == 1 ? "" : "s",
        (diff%3600)/60, (diff%3600)/60 == 1 ? "" : "s", diff%60, diff%60 == 1 ? "" : "s" );

It should work, but if anyone notices a problem let me know.
USA #15
Now I'm having an issue with it. =P

With the code using ch_printf, it's fine. But using sprintf, I get these warnings:
update.c:3806: warning: format '%d' expects type 'int', but argument 3 has type 'long int'
update.c:3806: warning: format '%d' expects type 'int', but argument 5 has type 'long int'
update.c:3806: warning: format '%d' expects type 'int', but argument 7 has type 'long int'
update.c:3806: warning: format '%d' expects type 'int', but argument 9 has type 'long int'


Doesn't make much sense, except ch_printf is being used and not sprintf. How would I fix those warnings?
USA #16
I think all you need to do is to use %l instead of %d, to avoid the warning.
USA #17
You sure that wouldn't be %ld rather than %l or %d?
USA #18
Oops, I left out the d. Yes, of course, it's %ld, because the l is a length modifier ('long') on the conversion specifier (d, the integer).
USA #19
Silly me. It's been too long since I did code with long int. Thanks.
USA #20
Try to be to totally off the subject here.. well I kinda am since you mentioned finger, but if you can make finger work in smaugfuss... would you post it or something? I've tried for the life of me, but cant seem to do it.
USA #21
Worked fine for me in FUSS. Are you getting compile errors or something? If so, start a new topic. Keeps things organized.
USA #22
A point of efficiency, even if it's a slight one. Smaug has the current_time variable declared globally and it is updated every game_loop, which is roughly 0.25sec. So this bit here:

    current = time(0);
    diff = current - boot_time


Could be done as:

diff  = current_time - boot_time;


One less variable to declare and use, and one less function call to make each time the command is issued. It's little things like this to keep in mind for overall resource efficiency :)
USA #23
It's true that that would be more efficient, technically speaking, but the gain would be negligible. time(0) is a very cheap operation and this function is not called very frequently. In a sense it's not even a blip on the radar in terms of efficiency, even if it is faster. If you think about it in assembly terms, it's clearer why it's not very important. One function call every once in a while is really nothing. If this function were called very often (as in several thousand times per second or even more), this optimization would be more important.

I would argue that it's important to use the global variable to ensure that you're operating on the same time units. If the time were to be changed and counted in, say, nanoseconds, then using time(0) would break things whereas using the global would be somewhat easier to fix. (Your end result would be off, instead of subtracting nanoseconds from milliseconds or something weird like that.)