The Guitar Hero 3 Bot [Obsolete!]


Part 4 - Software

Please note, all software will be freely available with source. See bottom of page for links.
Also: I cannot legally (and therefore do not) provide the xen files. Ask google. I know other sites have visual representations of the 'charts' ripped from the disc, this is bascially what my cheat files are but in text format. Im not sure if I can legally distribute them. If anyone knows please contact me.


In my oppinion, this was the part of the project that would make it successful, or deem it a waste of money. (I say this because I was fairly confident that the hardware side would work).

I'm not really sure why, but I chose Through the Fire and Flames on hard to test my work so far. I started by working out the tempo (beats per minute) which was 200 for full speed and 160 for 'Slow'.
My initial idea was to use a file in the format of #|bbbbbb where # is the beat (as a double) and the 6 b's are bits representing green-orange and strum. The file was ordered by beat with one on each line.
I manually wrote the file in notepad with the first 1200 notes of TTFAF.

My program, written in Visual Basic .NET 2008 uses the Now.Ticks value. Ticks is a number that represents the date as time of a given instance, 10000 ticks is one millisecond (I think). I used a loop and it waited for the next beat (which was converted to a measure of ticks from when the program started).

(If this doesn't make sense to you don't worry, its not really important, and I'm not the best at phrasing things when I'm in a hurry.)

Anyway...this worked, very well (as in it got a perfect 1200 note streak) but it took me about 10 hours to do those 1200 notes by going through the training mode on slower or very slow!

Ouch, now what?!

Well, obviously doing every song that way would take far, far too long. I bought GH3 for the PC a while back for custom modding the songs so, I thought if people can insert MIDI files as the 'Chart' to be played then why can't it be extracted, so I copied the files from the DATA\SONGS directory (which is where the custom songs were saved) and started to look at them in VS.NET.
After about 10 minutes I was convinced I would never work it out, so I turned to Google. After a further 40 minutes of web browsing I found a topic on ScoreHero (many thanks to the people who worked on that thread) which started with some C code on the first page, and by page 3 provided a link to 3 downloadable executables.

So, the 3 EXEs.

UnPak.exe - Extracts Mid.Qb and Qb files from the pak.xen file in the DATA\SONGS directory (but it does require DATA\PAK\dbg.pak.xen).
UnPakMidQb.exe - Extracts allsorts of files from the Mid.Qb files (but it does require DATA\PAK\dbg.pak.xen).
DumpChart.exe - Reads the files extracted from Mid.Qb and outputs in Command Prompt the Chart (I will show the format later).

TTFAF, Expert, using my newfound EXE's

Yes it was ambitious, but this is how it went:

WAIT! Quick note on the file system!

Ok, I just want to show you how I set up my filesystem so that I could easily find all the files I needed:
Please note the GH3CheatExplorer and GH3IndexGen(explained later) app I wrote relies on this structure, this can be changed in the source code.
Contains the 3 exe's plus the ones I made (will be discussed later on)

Files converted from raw to my gh3cheat format using an app I wrote (will be discussed later on)

The result of running DumpChart.exe %songname%_song_%difficulty% %songname%_%difficulty%_Star > %SongName%.raw in command prompt

Files that result from running UnPakMidQb.exe on a %songname%.mid.qb file

Files that result from running UnPak.exe on a %songname%.pak.xen file

These are all the files from that DATA\SONGS GH3PC directory and dbg.pak.xen

Step 1 - UnPak.exe
GHIII PAK file extractor v1.0 by Invo

Usage: UnPAK.exe < Path to dbg.pak.xen > <.pak input file> < Output dir >

An example:
C:\GH3CheatSystem\bin>UnPAK.exe ..\data\xen\dbg.pak.xen ..\data\xen\thrufireandf
lames_song.pak.xen ..\data\unpak
GHIII PAK file extractor v1.0 by Invo

Reading the dbg.pak.xen header... Done! (1361 entries)
Preparing CRC32 cache... Done! (100082 entries cached)
Reading the input PAK file... Done! (8 entries)
Writing files:

ID: 0   Length: 841716  FileCRC:890eae52        ObjectCRC: 40797add
        File Name:      thrufireandflames.mid.qb
        Object Name:    thrufireandflames

ID: 1   Length: 72      FileCRC:6d29ac68        ObjectCRC: be3ed261
        File Name:      thrufireandflames_song_scripts.qb

ID: 2   Length: 667016  FileCRC:bb456986        ObjectCRC: bb456986
        File Name:      GH3_Singer_Male_ThruFireNFlames_1
        Object Name:    GH3_Singer_Male_ThruFireNFlames_1

ID: 3   Length: 684936  FileCRC:224c383c        ObjectCRC: 224c383c
        File Name:      GH3_Singer_Male_ThruFireNFlames_2
        Object Name:    GH3_Singer_Male_ThruFireNFlames_2

ID: 4   Length: 456968  FileCRC:554b08aa        ObjectCRC: 554b08aa
        File Name:      GH3_Singer_Male_ThruFireNFlames_3
        Object Name:    GH3_Singer_Male_ThruFireNFlames_3

ID: 5   Length: 695048  FileCRC:cb2f9d09        ObjectCRC: cb2f9d09
        File Name:      GH3_Singer_Male_ThruFireNFlames_4
        Object Name:    GH3_Singer_Male_ThruFireNFlames_4

ID: 6   Length: 271240  FileCRC:bc28ad9f        ObjectCRC: bc28ad9f
        File Name:      GH3_Singer_Male_ThruFireNFlames_5
        Object Name:    GH3_Singer_Male_ThruFireNFlames_5

ID: 7   Length: 697224  FileCRC:2521fc25        ObjectCRC: 2521fc25
        File Name:      GH3_Singer_Male_ThruFireNFlames_6
        Object Name:    GH3_Singer_Male_ThruFireNFlames_6
This generates:

We only want thrufireandflames.mid.qb as that contains the 'charts' that we want the program to play.

Step 2 - UnPakMidQb.exe

GHIII MID.QB file extractor v1.0 by Invo

Usage: UnPAKMidQB.exe < Path to dbg.pak.xen > <.mid.qb input file> 

An Example:
C:\GH3CheatSystem\bin>UnPAKMidQB.exe ..\data\xen\dbg.pak.xen ..\data\unpak\thruf
ireandflames.mid.qb ..\data\unmidqb
GHIII MID.QB file extractor v1.0 by Invo

Reading the dbg.pak.xen header... Done! (1361 entries)
Preparing CRC32 cache... Done! (100082 entries cached)
Reading file (841716 Bytes)... Done!

Dumping file:

Found object at offset 0x1c:
Found object at offset 0x33e4:
Found object at offset 0x8978:
Found object at offset 0x1093c:
Found object at offset 0x1b7d4:
Found object at offset 0x1bab0:
Found object at offset 0x1bd8c:
Found object at offset 0x1c068:
Found object at offset 0x1c344:
Found object at offset 0x1c770:
Found object at offset 0x1cb9c:
Found object at offset 0x1cfc8:
Found object at offset 0x1d3f4:
Found object at offset 0x1d414:
Found object at offset 0x1d434:
Found object at offset 0x1d454:
Found object at offset 0x1d474:
Found object at offset 0x1d494:
Found object at offset 0x1d4b4:
Found object at offset 0x1d4d4:
Found object at offset 0x1d4f4:
Found object at offset 0x1d514:
Found object at offset 0x1d534:
Found object at offset 0x1d554:
Found object at offset 0x1d574:
Found object at offset 0x2099c:
Found object at offset 0x25e40:
Found object at offset 0x2dcf0:
Found object at offset 0x38534:
Found object at offset 0x386c0:
Found object at offset 0x3884c:
Found object at offset 0x389d8:
Found object at offset 0x38b64:
Found object at offset 0x38b84:
Found object at offset 0x38ba4:
Found object at offset 0x38bc4:
Found object at offset 0x38be4:
Found object at offset 0x3bb80:
Found object at offset 0x40868:
Found object at offset 0x47d70:
Found object at offset 0x515f4:
Found object at offset 0x51780:
Found object at offset 0x5190c:
Found object at offset 0x51a98:
Found object at offset 0x51c24:
Found object at offset 0x51c44:
Found object at offset 0x51c64:
Found object at offset 0x51c84:
Found object at offset 0x51ca4:
Found object at offset 0x52474:
Found object at offset 0x52c8c:
Found object at offset 0x52cac:
Found object at offset 0x52ccc:
Found object at offset 0x52d04:
Found object at offset 0x543c4:
Found object at offset 0x54964:
Found object at offset 0x54984:
Found object at offset 0x6d2d8:
Found object at offset 0x6d2f8:
Found object at offset 0x6dd28:
Found object at offset 0x85e10:
Found object at offset 0x8607c:
Found object at offset 0xcb910:
Found object at offset 0xcb9d8:
Found object at offset 0xcba50:
Found object at offset 0xcba70:
Found object at offset 0xcba90:
Found object at offset 0xcbab0:
Found object at offset 0xcc550:
Found object at offset 0xcc570:
Found object at offset 0xcc590:

To get the 'charts' for a single player song from these files we need thrufireandflames_song_Expert and thrufireandflames_Expert_Star as these are what DumpChart.exe requires.
You can get it from co-op songs, look for guitarcoop and rhythmcoop.

GHIII chart extractor v1.0 by Invo

Usage: DumpChart.exe < notes input file > < star power input file >

An Example:
C:\GH3CheatSystem\bin>DumpChart.exe ..\data\unmidqb\thrufireandflames_song_Exper
t ..\data\unmidqb\thrufireandflames_Expert_Star > ..\data\raw\thrufireandflames.

The "> ...raw" dumps the output into the raw file. If you look at the raw file you will see it is in the format:
GHIII chart extractor v1.0 by Invo

Reading file (44696 Bytes)... Done!
Dumping chart file (times are in milliseconds):

Timestamp:2414		Duration:50		Note:   R 
Timestamp:2489		Duration:37		Note:    G
Timestamp:2565		Duration:50		Note:  Y  
Timestamp:2640		Duration:37		Note:    G
Timestamp:2715		Duration:50		Note: B   
Timestamp:2791		Duration:37		Note:    G
Timestamp:2866		Duration:50		Note:   R 

Reading file (732 Bytes)... Done!
Dumping star power (times are in milliseconds):

	Number of star power verses: 25
Timestamp:4828		Number of notes:8
Timestamp:17431		Number of notes:8
Timestamp:30052		Number of notes:12
Timestamp:48025		Number of notes:9

A change to my program!

Now the timestamp and duration are in milliseconds, so I ditched the BPM idea, so that I don't have to work out the BPM for every song.
The program now just uses the timestamp, but it still uses my original format of #|bbbbbb (though the last b is just always just 1 now).
I wrote a program called GH3RawToGH3.exe which converts the .raw files to .gh3cheat files and gives an output like this:

It subtracts the first timestamp from all the timestamps so it starts at 0, and multiplies them by 10000 so they are in ticks. Due to this you must start the cheat program (by pressing enter) just as the song should start...(which may require some practise).

GH3RawToGH3.exe SourceFile|DestinationFile

Finally - My App (GH3Cheat.exe)

It's a simple console application which starts by opening the file specified in the command line arguement, connects to the usb board, then waits for the enter key to be pressed. Once pressed it starts playing the file until the end.

It does not use the duration of the note. It strums and plays every not, white or not (because there is not distinction in dumpchart.exe) and just relases the strum half way between the current note and the next note, therefore working with long notes, but never releasing the strum too late.

At the moment it auto-star-powers, in other words, ever time it strums it also presses back so that if there is star power, it uses it.
Later on I shall probably make a more user fiendly program with optional star powering and tweak buttons for the timing so if you start it too soon or late you don't have to restart the song.

The Code:
Module Module1
    Private Declare Function OpenDevice Lib "k8055d.dll" (ByVal CardAddress As Integer) As Integer
    Private Declare Sub CloseDevice Lib "k8055d.dll" ()
    Private Declare Function ReadAnalogChannel Lib "k8055d.dll" (ByVal Channel As Integer) As Integer
    Private Declare Sub ReadAllAnalog Lib "k8055d.dll" (ByRef Data1 As Integer, ByRef Data2 As Integer)
    Private Declare Sub OutputAnalogChannel Lib "k8055d.dll" (ByVal Channel As Integer, ByVal Data As Integer)
    Private Declare Sub OutputAllAnalog Lib "k8055d.dll" (ByVal Data1 As Integer, ByVal Data2 As Integer)
    Private Declare Sub ClearAnalogChannel Lib "k8055d.dll" (ByVal Channel As Integer)
    Private Declare Sub SetAllAnalog Lib "k8055d.dll" ()
    Private Declare Sub ClearAllAnalog Lib "k8055d.dll" ()
    Private Declare Sub SetAnalogChannel Lib "k8055d.dll" (ByVal Channel As Integer)
    Private Declare Sub WriteAllDigital Lib "k8055d.dll" (ByVal Data As Integer)
    Private Declare Sub ClearDigitalChannel Lib "k8055d.dll" (ByVal Channel As Integer)
    Private Declare Sub ClearAllDigital Lib "k8055d.dll" ()
    Private Declare Sub SetDigitalChannel Lib "k8055d.dll" (ByVal Channel As Integer)
    Private Declare Sub SetAllDigital Lib "k8055d.dll" ()
    Private Declare Function ReadDigitalChannel Lib "k8055d.dll" (ByVal Channel As Integer) As Boolean
    Private Declare Function ReadAllDigital Lib "k8055d.dll" () As Integer
    Private Declare Function ReadCounter Lib "k8055d.dll" (ByVal CounterNr As Integer) As Integer
    Private Declare Sub ResetCounter Lib "k8055d.dll" (ByVal CounterNr As Integer)
    Private Declare Sub SetCounterDebounceTime Lib "k8055d.dll" (ByVal CounterNr As Integer, ByVal DebounceTime As Integer)
    Const gGreen As Integer = 1
    Const gRed As Integer = 2
    Const gYellow As Integer = 4
    Const gBlue As Integer = 8
    Const gOrange As Integer = 16
    Const gStar As Integer = 32
    Const gStrum As Integer = 64
    Sub Main()
        Dim CardAddress As Integer
        Dim h As Integer
        Console.Write("Connecting to card 0...")
        CardAddress = 0
        h = OpenDevice(CardAddress)
        Select Case h
            Case 0, 1, 2, 3
            Case -1
                Console.WriteLine("Card not found!")
                GoTo nd
            Case -2
                Console.WriteLine("EXE NOT FOUND?!")
                GoTo nd
        End Select
        Dim cs As String = Replace(Command, """", "")
        Console.WriteLine("Loading File..." & cs)
        FileOpen(1, cs, OpenMode.Input)
        Dim Data(10000, 3) As Double
        Dim n As Integer = 0
        Dim s As Double = -1
        Do Until EOF(1)
            Dim d As String = ""
            Input(1, d)
            If d <> "" And Left(d, 1) <> "#" Then
                n += 1
                Dim ds() As String = Split(d, "|")
                Data(n, 0) = ds(0)
                If s = -1 Then s = ds(0)
                Data(n, 1) = Play(Mid(ds(1), 1, 1), Mid(ds(1), 2, 1), Mid(ds(1), 3, 1),_
                 Mid(ds(1), 4, 1), Mid(ds(1), 5, 1), Mid(ds(1), 6, 1))
                Data(n, 3) = Play(Mid(ds(1), 1, 1), Mid(ds(1), 2, 1), Mid(ds(1), 3, 1),_
                 Mid(ds(1), 4, 1), Mid(ds(1), 5, 1), 0)
                Data(n, 2) = Mid(ds(1), 6, 1)
            End If
        Console.WriteLine(n & " lines of data read.")
        Dim b As Double
        Dim c As Integer = 1
        Console.WriteLine("Press enter to start")
        Dim OldTicks As Long = Now.Ticks - 100000
        Do Until c > n
            b = Now.Ticks - OldTicks
            'b = ((Now.Ticks - OldTicks) / Difference)
            If b >= Data(c, 0) - s Then
                Console.WriteLine("Beat (ticks): " & b & ", Data: " & Data(c, 1))
                WriteAllDigital(Data(c, 1))
                c += 1
            End If
            If Data(c, 2) = 1 And Data(c - 1, 2) = 1 And b >= Data(c - 1, 0) +_
             ((Data(c, 0) - Data(c - 1, 0)) / 2) - s Then WriteAllDigital(Data(c - 1, 3))
        WriteAllDigital(Data(c - 1, 3))
        Console.WriteLine("Done, press enter to exit")
    End Sub
    Function Play(ByVal Green As Boolean, ByVal Red As Boolean, ByVal Yellow As Boolean,_
      ByVal Blue As Boolean, ByVal Orange As Boolean, ByVal Strum As Boolean) As Integer
        Dim d As Integer = 0

        If Green Then d = d + gGreen
        If Red Then d = d + gRed
        If Yellow Then d = d + gYellow
        If Blue Then d = d + gBlue
        If Orange Then d = d + gOrange
        If Strum Then d = d + gStrum + gStar 'Remove + gStar if you dont want auto-starring
        Play = d
    End Function
End Module

Yes it's not the tidyest thing but I don't care. It works!

Other Apps

I also wrote an GH3CheatIndexGen.exe (Cheat Index Generator) which, if you use my file system layout and fill the xen folder with the required files will do all the work and populate the gh3cheat folder. Note you need unpak.exe unpakmidqb.exe dumpchart.exe and gh3rawtogh3.exe in the bin folder for this to work.
There is also a GH3CheatExplorer.exe which lists all the files in the gh3cheat directory (also using my file system) and sorts them by difficulty. Double click it and it will shell the file, so if you associate gh3cheat with the gh3cheat.exe it will automatically open the file with the exe.

File Downloads

All GH3Bot downloads.

Copyright © Paul Ridgway 2009 | Pictures by Amanda Taylor | HTML Layout & Base code by James Ridgway