View Issue Details

IDProjectCategoryView StatusLast Update
0000626FSSCPgameplaypublic2006-06-01 05:16
ReporterGoober5000 Assigned Totaylor  
PrioritynormalSeverityblockReproducibilityalways
Status resolvedResolutionfixed 
Summary0000626: "Timer Rolled" causes game lockup
DescriptionIt seems that the "Timer Rolled" code in timer.cpp causes the game to freeze. Commenting out the line "Timer_base = time_now" fixes it.

With the line uncommented, FSO simply locks up and is completely unresponsive. The music keeps playing, but at the end of the current track it too stops. I'm able to force-close the game if I'm running it in a window, but if I'm running it full-screen I have to do a hard reboot.

I'm surprised nobody else has reported it, since it's a rather severe error. Perhaps it's my system, although it hasn't popped up until recently.
Additional InformationI'm guessing the TIMER ROLLED code was added to prevent clock rollovers at midnight, but it's just popping up at random times. I added a line to print the difference to fs.log, which I've attached. The difference by which time_now is behind Timer_last_value isn't very big, typically 1, but it's occasionally as high as 50ish.

The fs.log was taken during a run-through of the second demo mission. Search for "TIMER ROLLED" to find the instances.
TagsNo tags attached.

Activities

2005-11-21 04:49

 

fs.log (196,322 bytes)

taylor

2005-11-21 05:05

administrator   ~0003904

timeGetTime() returns the Windows system time in milliseconds since the system started. It only wraps every 49 days or so, so you really shouldn't ever see it more than once during a single game much less one mission. The Timer_base variable is used to determine how much time the game has been running and always needs to be accurate to what timeGetTime() is going to give, hence the roll check.

What is time_now actually coming out to be when it wraps?

2005-11-21 06:07

 

fs.log (292,949 bytes)

Goober5000

2005-11-21 06:10

administrator   ~0003905

Well I attached another fs.log with printouts of the three variables each time the roll event occurs. This is playing through both missions of the demo campaign.

Time_now is around 40M, but earlier tonight it was around 38 or 39M. It doesn't actually "wrap" though; Timer_last_value just gets ahead of time_now for some reason.

Incidentally, I kept getting "Assert: Mission_events[*e1 & 0xffff].born_on_date != 0" in the first mission of the campaign, after I had destroyed the first wing of fighters that comes after Command says "you might want to rearm". I'm wondering if it's related to the event directive bug.

taylor

2005-11-21 06:54

administrator   ~0003907

Hmm, a precision error perhaps? What's the return value of timeBeginPeriod() in timer_init()? It should return 0 if there was no problem.

Goober5000

2005-11-22 03:37

administrator   ~0003911

Well, this is interesting. It seems timeBeginPeriod is called twice. Both times it returns 0, but it really shouldn't be called twice, I'm guessing. :)

Both times are in game_init. The first time it's called through timer_init, but the second time it's called near the end of the function, right before mprinting VALID or INVALID.

Oh, and by the way, I encountered a problem in weapon_explosions::PageIn where i is not yet initialized. I'm assuming that should be idx?

Goober5000

2005-11-22 04:32

administrator   ~0003912

Last edited: 2005-11-22 04:33

Well, unfortunately that didn't solve the problem. :( I'm still getting the timer rolls, they're still causing freezes, and now they're ranging all over the place. I've uploaded a third fs.log for you to look at if you want.

edited on: 11-21-05 23:33

2005-11-22 04:32

 

fs.log (506,693 bytes)

taylor

2005-11-22 04:34

administrator   ~0003913

It's ok to call timeBeginPeriod more than once, just so long as there is a corresponding EndPeriod call for each. I would have preferred to only use the one but I left room for the call in timer_init to have a different precision setting. The EndPeriod call has to match the same precision which is why I left it with the two sets. The set after the timer_init call could be removed I think, I didn't test it. MSDN said that was perfectly ok to leave it as is though.

And the i thing is supposed to be idx. That's what I get for chaning how PageIn worked back to like WMC had it without testing that it still worked. Making that change now. :)

taylor

2005-11-22 04:44

administrator   ~0003914

Add something like this to timer_init():

TIMECAPS mtime;
timeGetDevCaps(&mtime, sizeof(TIMECAPS));

and check the value of mtime.wPeriodMin to see what the minimum precision actually gets reported as. Might just have to adjust it to choose the best precision and compensate for that in later math.

Inquisitor

2005-11-25 16:06

administrator   ~0003935

Last edited: 2005-11-25 16:08

Who submitted the original code (CVS Logs)?

Whoever it is should own this bug.

edited on: 11-25-05 11:08

taylor

2005-11-25 17:28

administrator   ~0003936

I changed the code. It was one of the very few ways that's safe on SMP and dual core machines so I'm hesitant to change it unless more people (so far only Goober) start reporting a similar problem.

Goober5000

2005-11-25 21:18

administrator   ~0003938

I'm home right now so I can't give any more updates, but I'll be able to resume testing on Monday.

Goober5000

2006-01-13 18:23

administrator   ~0004244

*bump* because I intend to get back to this bug this evening. :)

BTW, the phrase "add something like this to timer_init" sounds dangerous. I can add *exactly* that code snippet to timer_init, but if that's not the proper code I won't know what to change it to. :p

taylor

2006-01-13 19:09

administrator   ~0004248

Those two lines should be exact, I just haven't tested it myself to know for sure if it's compilable as is in the current code. It won't interfere with any of the other timer code (so don't replace anything) but will just give you some extra info to debug with.

The idea with that is to make sure what precision the computer is reporting. If it's 5 or even 10ms, and we are doing math as if it's 1ms, then that could cause the issue. We may just need to add some basic fudge support in there.

Goober5000

2006-01-14 06:44

administrator   ~0004263

K, I added it in the block where it says TIMER ROLLED. Here are the results:

wPeriodMin 1
wPeriodMax 65535

Goober5000

2006-02-23 18:26

administrator   ~0004903

*bump* :p

taylor

2006-02-23 19:36

administrator   ~0004909

I'm thinking...

;)

Crusader

2006-05-21 04:37

reporter   ~0005542

Last edited: 2006-05-23 07:23

Hello. i'm not a programmer, so this entire discussion is far beyond my head. i feel as if i'm cluttering Mantis just by posting... but here goes. i'm using Win98SE, DX8.1b, OpenAL 1.1, a Radeon 9200, Catalyst 6.2, 400MB RAM and a 1.2Ghz P3.

Prior to using the 2/20/06 redmenace CVS build, i did not notice this timer bug. Upon using the build, i may have gotten the error, i don't recall. i stopped playing FS_Open entirely for some time, then very recently tried the karajorma CVS builds for April/May. All of them generate the timer bug within about 15 minutes of gameplay. If i wait about 20 minutes, the crash unfreezes and play can resume for another 15 minutes before another crash.

After discovering all that, i went back to the 2/20/06 build. It doesn't generate the timer bug anywhere near as often as the karajorma builds; i get maybe one crash in 45 minutes.

Edit 5/23/06: Several hours of testing seem to indicate that the bug does not occur if registry DWORD "MaxFPS" is set to >50.

edited on: 05-23-06 03:23

2006-05-29 04:38

 

timer.cpp (11,901 bytes)   
/*
 * Copyright (C) Volition, Inc. 1999.  All rights reserved.
 *
 * All source code herein is the property of Volition, Inc. You may not sell 
 * or otherwise commercially exploit the source or things you created based on the 
 * source.
 *
*/ 

/*
 * $Logfile: /Freespace2/code/Io/Timer.cpp $
 * $Revision: 2.14 $
 * $Date: 2006/03/30 04:15:20 $
 * $Author: Goober5000 $
 *
 * Include file for timer stuff
 *
 * $Log: timer.cpp,v $
 * Revision 2.14  2006/03/30 04:15:20  Goober5000
 * hehe, grammar
 * --Goober5000
 *
 * Revision 2.13  2005/10/12 05:45:35  taylor
 * new timer code that shouldn't suffer from multi-cpu (or dual core) systems
 * clean out all old Windows timer code since that was just a mess at this point
 *
 * Revision 2.12  2005/05/26 09:21:28  taylor
 * forgot to take into account F1_0 on timer_get_fixed_seconds(), remove those stupid CRs too
 *
 * Revision 2.11  2005/05/26 04:27:11  taylor
 * timer changes to fix game_busy() on the loading screen and 100% incorrect values on some machines,
 *   don't know if this is going to work that great but it's more like the Linux SDL code now which
 *   has worked for years without major problems
 *
 * Revision 2.10  2005/04/11 10:15:11  taylor
 * un-revert previous revert since it does apparently affect MinGW (Alpha0)
 *
 * Revision 2.9  2005/04/11 05:50:35  taylor
 * some limits.h fixes to make GCC happier
 * revert timer asm change since it doesn't even get used with Linux and couldn't have been the slowdown problem
 *
 * Revision 2.8  2005/03/27 08:57:52  taylor
 * will hopefully fix the slowdown from mission to mission (thanks Alpha0)
 *
 * Revision 2.7  2005/03/03 16:18:19  taylor
 * lockup fixes, and it's Linux friendly too :)
 *
 * Revision 2.6  2005/02/04 10:12:30  taylor
 * merge with Linux/OSX tree - p0204
 *
 * Revision 2.5  2004/07/26 20:47:33  Kazan
 * remove MCD complete
 *
 * Revision 2.4  2004/07/12 16:32:51  Kazan
 * MCD - define _MCD_CHECK to use memory tracking
 *
 * Revision 2.3  2003/03/02 05:46:28  penguin
 * Added gcc-compatible asm blocks
 *  - penguin
 *
 * Revision 2.2  2002/08/01 01:41:06  penguin
 * The big include file move
 *
 * Revision 2.1  2002/07/07 19:55:59  penguin
 * Back-port to MSVC
 *
 * Revision 2.0  2002/06/03 04:02:24  penguin
 * Warpcore CVS sync
 *
 * Revision 1.4  2002/05/24 16:46:47  mharris
 * Fixed stupid error I made in timer_get_fixed_seconds()
 *
 * Revision 1.3  2002/05/17 06:45:53  mharris
 * More porting tweaks.  It links!  but segfaults...
 *
 * Revision 1.2  2002/05/09 13:50:50  mharris
 * temporarily ifdef out asm
 *
 * Revision 1.1  2002/05/02 18:03:08  mharris
 * Initial checkin - converted filenames and includes to lower case
 *
 * 
 * 4     5/26/99 3:19p Dave
 * Fixed release build errors.
 * 
 * 3     5/17/99 6:03p Dave
 * Added new timing code. Put in code to allow camera speed zooming.
 * 
 * 2     10/07/98 10:53a Dave
 * Initial checkin.
 * 
 * 1     10/07/98 10:49a Dave
 * 
 * 14    4/13/98 10:16a John
 * Switched gettime back to timer_get_milliseconds, which is now thread
 * safe.
 * 
 * 13    4/13/98 10:11a John
 * Made timer functions thread safe.  Made timer_init be called in all
 * projects.
 * 
 * 12    4/13/98 8:09a John
 * Made timer_get functions thread safe.
 * 
 * 11    12/02/97 3:56p John
 * fixed a bug with timestamp_until, created one with it rolling over.
 * 
 * 10    9/11/97 7:12p Hoffoss
 * Added more functionality to training sexp handling code.
 * 
 * 9     8/29/97 4:49p Allender
 * added mprintf to check for wrap problems with timestamp ticker
 * 
 * 8     8/28/97 1:38p Allender
 * from John:  changes to timer func to detect early rollever
 * 
 * 7     7/29/97 5:30p Lawrance
 * move gettime() from keyboard module to timer module
 * 
 * 6     7/16/97 4:42p Mike
 * Make afterburner shake viewer, not ship.
 * Shake for limited time.
 * Add timestamp_until() function to timer library.
 * 
 * 5     2/17/97 5:18p John
 * Added a bunch of RCS headers to a bunch of old files that don't have
 * them.
 *
 * $NoKeywords: $
 */

#ifdef _WIN32
#include <windows.h>
#endif

#include <limits.h>

#include "globalincs/pstypes.h"
#include "io/timer.h"
#include "graphics/2d.h"
#include "globalincs/alphacolors.h"

#define THREADED	// to use the proper set of macros
#include "osapi/osapi.h"	// for multi-thread macros



#ifndef NDEBUG
	#define USE_TIMING
#endif

#ifdef _WIN32
static longlong Timer_last_value = 0, Timer_base = 0, Timer_freq = 0;
static const int precision = 1;
#endif

static int Timer_inited = 0;

static CRITICAL_SECTION Timer_lock;

void timer_close()
{
	if ( Timer_inited )	{
		Timer_inited = 0;
#ifdef _WIN32
		timeEndPeriod(precision); 
#endif
		DELETE_CRITICAL_SECTION( Timer_lock );
	}
}

void timer_init()
{
	if ( !Timer_inited )	{
		INITIALIZE_CRITICAL_SECTION( Timer_lock );

#ifdef _WIN32
		timeBeginPeriod(precision);
		Timer_base = Timer_last_value = timeGetTime();
#endif

		Timer_inited = 1;

		atexit(timer_close);
	}
}

static uint timer_get()
{
#ifdef _WIN32
	longlong time_now;

	time_now = timeGetTime();

	ENTER_CRITICAL_SECTION( Timer_lock );

	if ( time_now < Timer_last_value ) {
		// the clock has rolled!
		Timer_base = time_now;
		mprintf(("TIMER ROLLED!\n"));
	}

	Timer_last_value = time_now;

	LEAVE_CRITICAL_SECTION( Timer_lock );

	return (uint)(time_now - Timer_base);
#else
	return SDL_GetTicks();
#endif
}


fix timer_get_fixed_seconds()
{
	if (!Timer_inited) {
		Int3();					// Make sure you call timer_init before anything that uses timer functions!
		return 0;
	}

	longlong a = timer_get();

	a *= 65536;

	return (fix)(a / 1000);
}

fix timer_get_fixed_secondsX()
{
	return timer_get_fixed_seconds();
}

fix timer_get_approx_seconds()
{
	return timer_get_fixed_seconds();
}

int timer_get_milliseconds()
{
	if (!Timer_inited) {
		Int3();					// Make sure you call timer_init before anything that uses timer functions!
		return 0;
	}

	return timer_get();
}

int timer_get_microseconds()
{
	if (!Timer_inited) {
		Int3();					// Make sure you call timer_init before anything that uses timer functions!
		return 0;
	}

	return timer_get() * 1000;
}

// 0 means invalid,
// 1 means always return true
// 2 and above actually check the time
int timestamp_ticker = 2;

void timestamp_reset()
{
	timestamp_ticker = 2;
}

// Restrict all time values between 0 and MAX_TIME
// so we don't have to use UINTs to calculate rollover.
// For debugging & testing, you could set this to 
// something like 1 minute (6000).
#define MAX_TIME (INT_MAX/2)

void timestamp_inc(float frametime)
{
	timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);

	if ( timestamp_ticker > MAX_TIME )	{
		timestamp_ticker = 2;		// Roll!
	}

	if (timestamp_ticker < 2 ) {
		mprintf(("Whoa!!!  timestamp_ticker < 2 -- resetting to 2!!!\n"));
		timestamp_ticker = 2;
	}
}

int timestamp(int delta_ms )
{
	int t2;
	if (delta_ms < 0 ) return 0;
	if (delta_ms == 0 ) return 1;
	t2 = timestamp_ticker + delta_ms;
	if ( t2 > MAX_TIME )	{
		// wrap!!!
		t2 = delta_ms - (MAX_TIME-timestamp_ticker);
	}
	if (t2 < 2 ) t2 = 2;	// hack??
	return t2;
}

//	Returns milliseconds until timestamp will elapse.
//	Negative value gives milliseconds ago that timestamp elapsed.
int timestamp_until(int stamp)
{
	// JAS: FIX
	// HACK!! This doesn't handle rollover!
	// (Will it ever happen?)
	
	return stamp - timestamp_ticker;

/*
	uint	delta;

	delta = stamp - timestamp_ticker;
	

	if (delta > UINT_MAX/2)
		delta = UINT_MAX - delta + 1;
	else if (delta < - ( (int) (UINT_MAX/2)))
		delta = UINT_MAX + delta + 1;

	return delta;
*/
}

// alternate timestamp functions.  The way these work is you call xtimestamp() to get the
// current counter value, and then call
int timestamp()
{
	return timestamp_ticker;
}

int timestamp_has_time_elapsed(int stamp, int time)
{
	int t;

	if (time <= 0)
		return 1;

	t = stamp + time;
	if (t <= timestamp_ticker)
		return 1;  // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.

	return 0;
}

// timing functions -------------------------------------------------------------------------------

#define MAX_TIMING_EVENTS		15

// timing struct
#ifdef USE_TIMING

typedef struct timing {
	char name[64];
	int microseconds_total;
	int start;
	int ref_count;
} timing;

timing Timing_frame;
timing Timing_events[MAX_TIMING_EVENTS];
int Timing_event_count = 0;

#endif

// lookup a timing event
int timing_event_lookup(char *event_name)
{
#ifndef USE_TIMING
	return -1;
#else
	int idx;

	// sanity
	if(event_name == NULL){
		return -1;
	}

	// look through all events
	for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
		if(!stricmp(Timing_events[idx].name, event_name)){
			return idx;
		}
	}

	return -1;
#endif
}

// start timing frame stuff
void timing_frame_start()
{
#ifndef USE_TIMING
	return;
#else
	int idx;

	// restart the frame
	Timing_event_count = 0;
	Timing_frame.start = timer_get_microseconds();
	for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
		Timing_events[idx].microseconds_total = 0;
		strcpy(Timing_events[idx].name, "");
		Timing_events[idx].ref_count = 0;
	}
#endif
}

// done timing the frame
void timing_frame_stop()
{
#ifndef USE_TIMING
	return;
#else	
	int stop_time;

	// stop time
	stop_time = timer_get_microseconds();

	// calc times
	Timing_frame.microseconds_total = stop_time - Timing_frame.start;	
#endif
}

// get the total frame time in microseconds
int timing_frame_total()
{
#ifndef USE_TIMING
	return 0;
#else
	return Timing_frame.microseconds_total;
#endif
}

// time an individual event
void timing_event_start(char *event_name)
{
#ifndef USE_TIMING
	return;
#else
	int event;

	// sanity
	if(event_name == NULL){
		return;
	}

	// try and find the event
	event = timing_event_lookup(event_name);

	// if we already have one
	if(event != -1){
		Assert(Timing_events[event].ref_count == 0);
		Timing_events[event].start = timer_get_microseconds();
		Timing_events[event].ref_count++;
	}
	// if we need to add a new one
	else {
		if(Timing_event_count < MAX_TIMING_EVENTS){
			strcpy(Timing_events[Timing_event_count].name, event_name);
			Timing_events[Timing_event_count].start = timer_get_microseconds();
			Timing_events[Timing_event_count++].ref_count++;
		}
	}
#endif
}

// stop timing an event
void timing_event_stop(char *event_name)
{
#ifndef USE_TIMING
	return;
#else
	int event;

	// sanity
	if(event_name == NULL){
		return;
	}

	// try and find the event
	event = timing_event_lookup(event_name);

	// if we already have one
	if(event != -1){
		Assert(Timing_events[event].ref_count == 1);
		Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
		Timing_events[event].ref_count--;
	}
#endif
}

// get the total time for an event in microseconds
int timing_event_total(char *event_name)
{
#ifndef USE_TIMING
	return -1;
#else
	int event;

	// sanity
	if(event_name == NULL){
		return -1;
	}

	// try and find the event
	event = timing_event_lookup(event_name);
	if(event == -1){
		return -1;
	}
	
	return Timing_events[event].microseconds_total;
#endif
}

// get the percentage of total frametime for the event (0.0 to 1.0)
float timing_event_pct(char *event_name)
{
#ifndef USE_TIMING
	return 0.0f;
#else
	int event;

	// sanity
	if(event_name == NULL){
		return -1.0f;
	}

	// try and find the event
	event = timing_event_lookup(event_name);
	if(event == -1){
		return -1.0f;
	}

	return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
#endif
}

// display timing 
void timing_display(int x, int y)
{
#ifndef USE_TIMING
	return;
#else
	int idx;

	gr_set_color_fast(&Color_bright_blue);

	// total time
	gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
	y += 10;

	// each event percentage
	for(idx=0; idx<Timing_event_count; idx++){
		gr_printf(x, y, "%s: %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));
		y += 10;
	}
#endif
}
timer.cpp (11,901 bytes)   

taylor

2006-05-29 04:41

administrator   ~0005665

Last edited: 2006-05-29 04:43

Please check and see if the attacked timer.cpp file works any better.

Not much is different, I just added an ENTER/LEAVE_CRITICAL_SECTION macro set in timer_get(). Not sure if that will do much, but I've exhausted pretty much every other idea.

EDIT: Oh and the *_CRITICAL_SECTION calls were there originally. Not sure why I didn't add them back when I did the changes to fix the SMP issues. I'm also not sure why I didn't notice they were missing before :/.

edited on: 05-29-06 00:43

taylor

2006-05-30 03:14

administrator   ~0005670

Change is now in CVS too btw.

Crusader

2006-05-30 04:58

reporter   ~0005673

[double-checking] Were you addressing me, taylor?

If so, then i can't do anything with timer.cpp; i'm a worthless, groveling end-user with no knowledge of compilers. Everything i posted came of using binaries.

If not, then 'oops' and just ignore this comment.

Goober5000

2006-05-30 05:02

administrator   ~0005674

I think the comment was addressed to me. I'll have to play a few missions before I know if it's fixed (been busy this weekend).

taylor

2006-05-30 05:05

administrator   ~0005675

Last edited: 2006-05-30 05:06

It was addressed at Goober mostly.

You'll get the change with the next build though (hence the CVS commit update) so keep that in mind when you're testing and if it's working now just let me know. If no one else puts up a build in the next day or two then I'll post one for you to play with.

EDIT: Oops, should have refreshed before posting. :)

edited on: 05-30-06 01:06

Crusader

2006-05-30 05:09

reporter   ~0005676

Last edited: 2006-05-30 05:12

Ah, duly noted; sorry for the interruption. (And hello, Goober5000.)

Though, i would like to remention the edit i added to my other post: setting the MaxFPS variable to >50 solves the problem for me completely, as i've been playing FS_Open without a single crash since then. Hence, i've been wondering if that information was/is relevant or useful to you?

Edit: Doh--thanks for offering to make a binary, taylor; no hurry, only do it if you feel like it.

edited on: 05-30-06 01:12

taylor

2006-05-30 05:22

administrator   ~0005677

The MaxFPS thing is curious, but didn't really help me any. Actually I just sat down at my desk and thought "did mutex locking get put back on in that function?", at which point I looked, and it didn't. Oh well, whatever. ;)

The MaxFPS thing does change how often it (the process) sleeps though, which may be why that works. Of course that's not really a fix and just hides the real problem. You would likely still get the hangs/crashes if you upgraded to a faster computer for instance, or used a slower one.

Crusader

2006-05-30 05:29

reporter   ~0005678

[light bulb] Ahhh.

It's a shame the math co-processor of my brain is defective; the whys and wherefores of bugs are so intriguing (plus i imagine you might not refuse another hand to help out?).

At any rate, thanks again for humouring my curiosity.

taylor

2006-06-01 04:12

administrator   ~0005680

@Crusader: Try this build - http://fs2source.warpcore.org/exes/latest/May2006/FS2_Open_Kara_20060531.rar

It has some reported problems, but it also has the timer fix (if it actually is a fix). Let me know whether that makes a difference with this lockup/crash issue.

Crusader

2006-06-01 04:57

reporter   ~0005681

Indeed, taylor, i downloaded that build earlier today from the forums. i still appreciate you providing a link though. As may be inferred, i'm here to report my findings: i tested the build with 'MaxFPS' off, whereafter a half hour of gameplay yielded no crashes. i'd say, good work.

(And i may know what you mean about 'reported problems', because at present OpenAL will not initialise at all in this build. i could only do my testing by disabling all sound and music. But, i digress.)

taylor

2006-06-01 05:16

administrator   ~0005682

Cool. Thanks. I'll go ahead and resolve this then, but if you get the same problem again (or if Goober can still recreate it) then just reopen and I'll take another shot at it.

taylor

2006-06-01 05:16

administrator   ~0005683

Fixered.

Issue History

Date Modified Username Field Change
2005-11-21 04:49 Goober5000 New Issue
2005-11-21 04:49 Goober5000 File Added: fs.log
2005-11-21 05:05 taylor Note Added: 0003904
2005-11-21 06:07 Goober5000 File Added: fs.log
2005-11-21 06:10 Goober5000 Note Added: 0003905
2005-11-21 06:54 taylor Note Added: 0003907
2005-11-22 03:37 Goober5000 Note Added: 0003911
2005-11-22 04:32 Goober5000 Note Added: 0003912
2005-11-22 04:32 Goober5000 File Added: fs.log
2005-11-22 04:33 Goober5000 Note Edited: 0003912
2005-11-22 04:34 taylor Note Added: 0003913
2005-11-22 04:44 taylor Note Added: 0003914
2005-11-25 16:06 Inquisitor Note Added: 0003935
2005-11-25 16:08 Inquisitor Note Edited: 0003935
2005-11-25 16:47 taylor Status new => assigned
2005-11-25 16:47 taylor Assigned To => taylor
2005-11-25 17:28 taylor Note Added: 0003936
2005-11-25 21:18 Goober5000 Note Added: 0003938
2006-01-13 18:23 Goober5000 Note Added: 0004244
2006-01-13 19:09 taylor Note Added: 0004248
2006-01-14 06:44 Goober5000 Note Added: 0004263
2006-02-23 18:26 Goober5000 Note Added: 0004903
2006-02-23 19:36 taylor Note Added: 0004909
2006-05-21 04:37 Crusader Note Added: 0005542
2006-05-23 07:23 Crusader Note Edited: 0005542
2006-05-29 04:38 taylor File Added: timer.cpp
2006-05-29 04:41 taylor Note Added: 0005665
2006-05-29 04:43 taylor Note Edited: 0005665
2006-05-30 03:14 taylor Note Added: 0005670
2006-05-30 04:58 Crusader Note Added: 0005673
2006-05-30 05:02 Goober5000 Note Added: 0005674
2006-05-30 05:05 taylor Note Added: 0005675
2006-05-30 05:06 taylor Note Edited: 0005675
2006-05-30 05:09 Crusader Note Added: 0005676
2006-05-30 05:12 Crusader Note Edited: 0005676
2006-05-30 05:22 taylor Note Added: 0005677
2006-05-30 05:29 Crusader Note Added: 0005678
2006-06-01 04:12 taylor Note Added: 0005680
2006-06-01 04:57 Crusader Note Added: 0005681
2006-06-01 05:16 taylor Note Added: 0005682
2006-06-01 05:16 taylor Status assigned => resolved
2006-06-01 05:16 taylor Resolution open => fixed
2006-06-01 05:16 taylor Note Added: 0005683