Search code examples
windowsbatch-filecmd

Looping timer/progress bar in batch file fails on the second loop, counts down into the negatives


I have a chunk of code with a series of commands to essentially make a progress bar in the title of the console. It shows the seconds remaining on a timer and a progressive "Working. . ." animation where it adds dots until it hits three before looping back to one. The idea is to start a .exe file, wait for a timer to count down to zero, then start another .exe and count down before ending the script, looping twice in total.

When run, the first startup (for the server) goes through smoothly, it counts down and echoes "Finished" to the console before moving on. When it tries the second startup (for the launcher) however, it continues counting down past zero and into the negatives without ever running the code after the if %loopcount%==0 line, presumably because it never triggers. You can see it here.

I've tried a handful of different things to get this to work, most notably copy and pasting the loop code for both launches and eliminating the set serverstatus=0 and if %serverstatus%==1 system entirely, but no luck.

Here's a cut down version of the code that can run on its own and has the same issue as the main file:

@echo off
for /f "tokens=* delims==" %%G in (variables.txt) do set %%G
rem pulls variables listed in 'variables.txt' and defines them

:serverstart

set serverstatus=0
ECHO Starting Server ^(Aki.Server.exe^)...
@start Aki.Server.exe

if %driveType%==0 (
        echo Working... ^(%serverStartTimeSSD% Seconds, Using SSD Preset^)
        set loopcount=%serverStartTimeSSD%
        
) else if %driveType%==1 (
        echo Working... ^(%serverStartTimeHDD% Seconds, Using HDD Preset^)
        set loopcount=%serverStartTimeHDD%
)
:loop
        title Console - Saru's SPT Auto ^Start Script - WORKING.      (%loopcount% Seconds Remaining)
                rem timeout code
                rem the next three lines add a 1sec delay
                for /f "tokens=*" %%a in ('
                timeout /t 1 /nobreak 2^>Nul
                ') do echo | break
        set /a loopcount=loopcount-1
        title Console - Saru's SPT Auto ^Start Script - WORKING. .    (%loopcount% Seconds Remaining)
                rem timeout code
                for /f "tokens=*" %%a in ('
                timeout /t 1 /nobreak 2^>Nul
                ') do echo | break
        set /a loopcount=loopcount-1
        title Console - Saru's SPT Auto ^Start Script - WORKING. . .  (%loopcount% Seconds Remaining)
                rem timeout code
                for /f "tokens=*" %%a in ('
                timeout /t 1 /nobreak 2^>Nul
                ') do echo | break
        set /a loopcount=loopcount-1

        if %loopcount%==0 echo Finished. && if %serverstatus%==0 goto :launcherstart
        goto :loop

:launcherstart

if %serverstatus%==1 goto :endstartup
ECHO Starting Launcher ^(Aki.Launcher.exe^)...
@start Aki.Launcher.exe
if %driveType%==0 (
        echo Working... ^(%launcherStartTimeSSD% Seconds, Using SSD Preset^)
        set loopcount=%launcherStartTimeSSD%
        set serverstatus=1
        goto :loop
        
) else if %driveType%==1 (
        echo Working... ^(%launcherStartTimeHDD% Seconds, Using HDD Preset^)
        set loopcount=%launcherStartTimeHDD%
        set serverstatus=1
        goto :loop
)

:endstartup
echo All processes finished.
pause

And here's my variables.txt file:

directory=C:/SinglePlayerTarkov
serverStartTimeSSD=6
serverStartTimeHDD=40
launcherStartTimeSSD=5
launcherStartTimeHDD=10
showErrorCodes=1
driveType=0

the showErrorCodes variable shouldn't be relevant to this, but I've included it for the sake of being thorough.

Probably the weirdest thing of all here is that if I swap the launcher and server startup order, (excluding the set serverstatus=0 and if %serverstatus%==1 goto :endstartup lines) the timer glitch happens first instead of second. Essentially, the timer only counts into the negatives when starting the launcher, despite the fact that the code for both the launcher and server startups are identical aside from the variables used. Changing those variables or even removing them outright in favor of integers doesn't seem to make a difference either.

I've been staring at this for hours now, a suggestion alone would make my week, let alone a solution. Thanks for taking the time to read all this, it turned out a whole lot longer than I thought it would.


Solution

  • @ECHO OFF
    SETLOCAL
    for /f "tokens=* delims==" %%G in (q75839960.txt) do set %%G
    rem pulls variables listed in 'variables.txt' and defines them
    
    :serverstart
    
    set serverstatus=0
    ECHO Starting Server (Aki.Server.exe^)...
    :: start Aki.Server.exe
    
    if %driveType%==0 (
     echo Working... (%serverStartTimeSSD% Seconds, Using SSD Preset^)
     set loopcount=%serverStartTimeSSD%
    ) 
    if %driveType%==1 (
      echo Working... (%serverStartTimeHDD% Seconds, Using HDD Preset^)
      set loopcount=%serverStartTimeHDD%
    )
    
    
    :loop
    title Console - Saru's SPT Auto ^Start Script - WORKING.      (%loopcount% Seconds Remaining)
    rem timeout code
    timeout /t 1 /nobreak >nul
    set /a loopcount=loopcount-1
    
    if %loopcount% gtr 0 GOTO loop
    echo Finished.
    
    :launcherstart
    
    if %serverstatus%==1 goto endstartup
    ECHO Starting Launcher (Aki.Launcher.exe^)...
    :: @start Aki.Launcher.exe
    set serverstatus=1
    if %driveType%==0 (
     echo Working... (%launcherStartTimeSSD% Seconds, Using SSD Preset^)
     set loopcount=%launcherStartTimeSSD%
    ) 
    if %driveType%==1 (
     echo Working... (%launcherStartTimeHDD% Seconds, Using HDD Preset^)
     set loopcount=%launcherStartTimeHDD%
    )
    goto loop
    
    :endstartup
    echo All processes finished.
    PAUSE
    GOTO :EOF
    

    Your fundamental problem is that the delay loop is 3 seconds, so in order to have loopcount exactly equal zero, its initial value must be a multiple of 3.

    There appears to be no reason that you could not simply reduce the delay to 1 sec.

    You could leave your original 3 sec delay in place; using gtr will loop if loopcount is greater than 0.

    Your interpretation of drivetype seems to be overly complex. I've simplified it. The top section sets servertatus to 0, then goes to loop. The revised lower section now does the same.

    You haven't taken into consideration the possibility that drivetype is neither 0 nor 1. This may or may not be relevant.

    I've commented-out the start code since I don't have those executables and changed the variables.txt filename to suit my system.