Modified Track Path Editor + Tracks/Discussion

Loving the new updated Monza RM and RRV RM. Also the jumping junction circuit is heaps of fun as expected :D Keep it coming guys đź‘Ť
 
You'll like my new Special Stage Route 11 track then :)

Yup, it's on my list to try next :) You are doing wonders with the TPE my friend. I just hope the GT6 servers stay open a while longer when GTS releases this November, otherwise all your hard work will be gone forever :( No sign of course maker coming back to GTS either.
 
It's not so much the apk but more the ps3, it just cant handle the scale of the Eifel maps.
that's why most long tracks seem to get made on Andalusia or Death Valley.
 
It's not so much the apk but more the ps3, it just cant handle the scale of the Eifel maps.
that's why most long tracks seem to get made on Andalusia or Death Valley.

Interesting. I thought Andalusia is bigger in area than Eifel. Also more complex too in terms of scenery and elevation. Or is it because most of Eifel is not usable (outside the square border) but still needs to be rendered?

BTW I finally got to try your SSR11. Man the atmosphere is amazing đź‘Ť I don't know you managed to add in all those houses, but it really makes the track feel in the middle of a city (well, village at least :P). The corners and elevation are spot on. Also the underpass still maintains good visibility when the track crosses over. Until PD makes an official one I think this is the best yet. My only complaint would be to make the track narrower. Currently it's too wide and the corners lose their difficulty. The death chicane for example is easy flat now. If you could make a narrow version (keep the wide version for racing) I will be grateful :bowdown:
 
Small update to the elevation editor, adding a feature that from experience I know will be useful: Point the brush over some height data points and press the F key to flatten the section covered by the brush. The editor takes the first and the last data point covered by the brush and performs a linear interpolation of all the data points in between them.

Like this:

eled_flatten1.png

^ Step 1: Place the brush over the section you want to flatten.

eled_flatten2.png

^ Step 2: Press F, and the section goes flat.

Known issue: It doesn't work as intended when the brush overlaps the beginning / end of the track.

You can find the 1.0.1 version in the attached zip file. If you have the 1.0 version of the elevation editor on your computer you don't need to keep all the contents of this zip folder, just take the scripts called elevation editor 1.0.1.py and transformations.py and place them in the same directory where the older elevation editor script is (make sure you replace the old transformations.py script with the new one).
 

Attachments

  • elevation editor 1.0.1.zip
    6.8 KB · Views: 41
Another update, to make the editor easier to live with. What's new in 1.0.2:

  • A slope graph in red was added (or rather, unhidden, as it has been hiding there all along. Like a ninja.)

  • The slope and delta slope graphs now stay centered when you scroll the window up / down. No more scrolling just to check what the graph says.

  • The window now supports resizing.

  • The vertical range of the brush was boosted by 5000% (from a default 80 meters to 4000 meters), so it will now grab height data points even when they're above or below the range covered by the window.
 

Attachments

  • elevation editor 1.0.2.zip
    6.8 KB · Views: 29
Hi everybody, coming late to the ted file dissection party but i wanted to share my findings with you. I dug a little in @Razerman's 010 Editor Templates that he shared in this thread, took the structure specs from them and build a little python script to convert the content of a TED file into python named tuples and back:
Code:
import struct
from collections import namedtuple
from enum import Enum

class Scenery(Enum):
    DeathValley = 1
    Eifel       = 2
    Andalusia   = 3
    EifelFlat   = 5
class FormType(Enum):
    Straight = 0
    Arc1CCW  = 1
    Arc2CCW  = 2
    NearlyStraight = 3
    Arc1CW   = 2147483649 # 2^31 + 1 ???
    Arc2CW   = 2147483650 # 2^31 + 2 ???
class RailType(Enum):
    Grass = 0
    Tree = 1
    TreeGroup = 2
    Flower = 3
    Cactus = 4
    CactusGroup = 5
    Curb = 6
    House = 7
    Rock = 8
    Cliff = 9
    Pole = 10
    StreetLamp = 11
    CircuitGate = 12
    Stand = 13
    MarshalPost = 14
    DiamondVision = 15
    Banner = 16
    AutoCliff = 17
    RallyGate = 18
    Audience = 19
    Billboard = 20
    Tent = 21
    CircuitGateOneSide = 22
    RallyGateOneSide = 23
    Limit = 24
class TrackType(Enum):
    LeftA = 0
    LeftB = 1
    LeftAB = 2
    RightA = 3
    RightB = 4
    RightAB = 5
    LeftCurb= 6
    RightCurb = 7
    Limit = 8
class RailType(Enum):
    Normal = 0
    Start = 1
    Goal = 2
    CheckPoint = 3
    HomeStraight = 4
class Side(Enum):
    Right = 0
    Left = 1
class Track(Enum):
    Null = 0
    Curb = 1
    A    = 2
    B    = 3
    AB   = 4
  
header="""
8s:id
i:version
i:scenery
f:road_width
f:track_width_a
f:track_width_b
f:start
I:datetime
i:is_loop
8s:padding1
f:home_straight_length
f:elevation_diff
i:num_corners
f:finish_line
f:start_line
8s:padding2
I:cp_offset
i:cp_count
I:unknown1_offset
i:unknown1_count
I:unknown2_offset
i:unknown2_count
I:unknown3_offset
i:unknown3_count
I:bank_offset
i:bank_count
I:height_offset
i:height_count
I:checkpoint_offset
i:checkpoint_count
I:road_offset
i:road_count
I:decoration_offset
i:decoration_count
"""
cp="""
I:formtype
f:x
f:y
f:x2
f:y2
"""
bank="""
f:bank
f:shift_prev
f:shift_next
I:div_num
i:unk
f:vpos
f:vlen
"""
height="""
f:height
"""
checkpoint="""
f:vpos_incl_height
"""
road="""
Q:uuid
i:flag
f:vpos_incl_height
f:vpos_incl_height2
"""
decoration="""
Q:cliff
I:railtype
f:vpos_incl_height
f:vpos_incl_height2
I:track_side
"""

def fmt_to_spec_and_fields(fmt):
    spec=""
    fields=""
    for line in fmt.splitlines():
        for token in line.split():
            s,f = token.split(":")
            spec   += s
            fields += f + " "
      
    return spec,fields

def ted_data_to_tuple(name,fmt,data,offset):
    spec, members = fmt_to_spec_and_fields(fmt)
    spec = ">" + spec
    return namedtuple(name,members)._make(struct.unpack_from(spec, data, offset))
def ted_data_to_tuple_list(name,fmt,data,offset,count):
    spec, members = fmt_to_spec_and_fields(fmt)
    spec = ">" + spec
    sz = struct.calcsize(spec)
    lst = []
    for c in range(count):
        t = namedtuple(name,members)._make(struct.unpack_from(spec, data, offset + c*sz))
        lst.append(t)
    return lst

def tuple_to_ted_data(tpl,fmt,data,offset):
    spec, members = fmt_to_spec_and_fields(fmt)
    spec = ">" + spec
    struct.pack_into(spec,data,offset,*tpl._asdict().values())
def tuple_list_to_ted_data(lst,fmt,data,offset,count):
    spec, members = fmt_to_spec_and_fields(fmt)
    spec = ">" + spec
    sz = struct.calcsize(spec)
    for c in range(count):
        struct.pack_into(spec,data,offset + c*sz,*lst[c]._asdict().values())


if __name__ == "__main__":
    with open("example.ted", mode='rb') as file:
        tedfile = file.read()
        modified = bytearray(tedfile) # copy tedfile contents
        print("tedfile contains ",len(tedfile),"bytes")
        hdr     = ted_data_to_tuple("header",header,tedfile,0)
        cps     = ted_data_to_tuple_list("cp",cp,tedfile,hdr.cp_offset,hdr.cp_count)
        #banks   = ted_data_to_tuple_list("bank",bank,tedfile,hdr.bank_offset,hdr.bank_count)
        #heights = ted_data_to_tuple_list("height",height,tedfile,hdr.height_offset,hdr.height_count)
      
        print(hdr)
        print(cps)
      
      
        cps[0] = cps[0]._replace(x=-5.0)
        cps[1] = cps[1]._replace(y=-6.0)
      
        tuple_list_to_ted_data(cps,cp,modified,hdr.cp_offset,hdr.cp_count)
      
        with open("modified.ted", 'wb') as file2:
            file2.write(modified)
          
          
        with open("modified.ted", mode='rb') as file:
            tedfile2 = file.read()
            print("modified tedfile contains ",len(tedfile2),"bytes")
            hdr2     = ted_data_to_tuple("header",header,tedfile2,0)
            cps2     = ted_data_to_tuple_list("cp",cp,tedfile2,hdr.cp_offset,hdr.cp_count)
            #banks   = ted_data_to_tuple_list("bank",bank,tedfile,hdr.bank_offset,hdr.bank_count)
            #heights = ted_data_to_tuple_list("height",height,tedfile,hdr.height_offset,hdr.height_count)
          
            print(hdr2)
            print(cps2)
          
          
            #print(hdr)
            #print(cps)
            #print(banks)
            #print(heights)

Then i tried to find out what the control points are in the ted file: They consist of a type and two x,y coordinates.
The first coordinate is the end point of the track segment, and with the coordinate of the previous control point gives a straight line or an arc. The second coordinate is the center point of the arc that starts at the first coordinate of the previous control point and ends at the first coordinate of this control point. So basically the web editor of @PR1VATEJ0KER could be made into a full fledged ted file control point editor because the code for the biarcs gives the center point of the arc and the control points could be generated from the input -- no previous TED file out of the original Track Path Editor needed. I just toyed around building a control point viewer and will post some displayable code later. Hopefully i can find the time to build a control point editor in the spirit and complementing @eran0004's phantastic height editor.
 
Small update, managed to decode and draw the track outline of @Razerman's example.ted:
upload_2016-9-13_9-41-9.png

Code:
import tkinter as tk
import read_ted as ted # from my other post

import math as m

class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.create_cps()

    def create_cps(self):
        self.canvas = tk.Canvas(self,width=1900,height=1000,scrollregion=(-1000,-1000,1000,1000))
        self.hbar=tk.Scrollbar(self,orient=tk.HORIZONTAL)
        self.hbar.pack(side=tk.BOTTOM,fill=tk.X)
        self.hbar.config(command=self.canvas.xview)
        self.vbar=tk.Scrollbar(self,orient=tk.VERTICAL)
        self.vbar.pack(side=tk.RIGHT,fill=tk.Y)
        self.vbar.config(command=self.canvas.yview)
        self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)

        self.canvas.create_line(-1000,0,1000,0, fill="red")
        self.canvas.create_line(0,-1000,0,1000, fill="red")
       
        with open("example.ted", mode='rb') as file:
            tedfile = file.read()
            hdr     = ted.ted_data_to_tuple("header", ted.header, tedfile, 0)

            if (hdr.id != b"GT6TED\0\0"):
                print("Error: not a GT6 TED file!")
                return
            print (hdr)
            print(hdr.cp_offset, hdr.cp_count)
           
            cps     = ted.ted_data_to_tuple_list("cp", ted.cp, tedfile, hdr.cp_offset, hdr.cp_count)

            #print(hdr)
            for i,cp in enumerate(cps):
                lx = (cps[i-1].x - cp.x)
                ly = (cps[i-1].y - cp.y)
                l = m.sqrt(lx*lx + ly*ly)
                print(i,ted.FormType(cp.formtype),cp.x,cp.y,cp.x2,cp.y2, l)
                self.canvas.create_text(cp.x,cp.y+10,text="%i"%(i))
                if (ted.FormType(cp.formtype) != ted.FormType.Straight):
                    # draw an arc
                    dx = (cps[i-1].x - cp.x2)
                    dy = (cps[i-1].y - cp.y2)
                    dx2 = (cp.x - cp.x2)
                    dy2 = (cp.y - cp.y2)
                 
                    r = m.sqrt(dx*dx + dy*dy)

                    ast = m.atan2(-dy, dx)  * 180/m.pi;
                    aen = m.atan2(-dy2,dx2) * 180/m.pi;
                    aex = aen - ast

                    if (ted.FormType(cp.formtype) == ted.FormType.Arc1CCW or
                        ted.FormType(cp.formtype) == ted.FormType.Arc2CCW):
                        if (aex < 0): aex += 360
                    if (ted.FormType(cp.formtype) == ted.FormType.Arc1CW or
                        ted.FormType(cp.formtype) == ted.FormType.Arc2CW):
                        if (aex > 0): aex -= 360
                   
                    self.canvas.create_arc([cp.x2-r,cp.y2+r,cp.x2+r,cp.y2-r],
                                                    start=ast,extent=aex,style=tk.ARC,outline="blue")
                    self.canvas.create_oval([cp.x2-5,cp.y2-5,cp.x2+5,cp.y2+5],fill="blue") # center of arc
                    self.canvas.create_text(cp.x2,cp.y2+10*i,text="%i"%(i))
                else:
                    # draw a line
                    self.canvas.create_line(cp.x,cp.y,cps[i-1].x,cps[i-1].y,fill="green")
           
        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
        self.canvas.pack(side=tk.LEFT,expand=True,fill=tk.BOTH)

app = App()

app.master.title("The CP Viewer")
app.master.maxsize(1900,1000)

app.mainloop()
 
Small update, managed to decode and draw the track outline of @Razerman's example.ted:
View attachment 585003
Code:
import tkinter as tk
import read_ted as ted # from my other post

import math as m

class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.create_cps()

    def create_cps(self):
        self.canvas = tk.Canvas(self,width=1900,height=1000,scrollregion=(-1000,-1000,1000,1000))
        self.hbar=tk.Scrollbar(self,orient=tk.HORIZONTAL)
        self.hbar.pack(side=tk.BOTTOM,fill=tk.X)
        self.hbar.config(command=self.canvas.xview)
        self.vbar=tk.Scrollbar(self,orient=tk.VERTICAL)
        self.vbar.pack(side=tk.RIGHT,fill=tk.Y)
        self.vbar.config(command=self.canvas.yview)
        self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)

        self.canvas.create_line(-1000,0,1000,0, fill="red")
        self.canvas.create_line(0,-1000,0,1000, fill="red")
    
        with open("example.ted", mode='rb') as file:
            tedfile = file.read()
            hdr     = ted.ted_data_to_tuple("header", ted.header, tedfile, 0)

            if (hdr.id != b"GT6TED\0\0"):
                print("Error: not a GT6 TED file!")
                return
            print (hdr)
            print(hdr.cp_offset, hdr.cp_count)
        
            cps     = ted.ted_data_to_tuple_list("cp", ted.cp, tedfile, hdr.cp_offset, hdr.cp_count)

            #print(hdr)
            for i,cp in enumerate(cps):
                lx = (cps[i-1].x - cp.x)
                ly = (cps[i-1].y - cp.y)
                l = m.sqrt(lx*lx + ly*ly)
                print(i,ted.FormType(cp.formtype),cp.x,cp.y,cp.x2,cp.y2, l)
                self.canvas.create_text(cp.x,cp.y+10,text="%i"%(i))
                if (ted.FormType(cp.formtype) != ted.FormType.Straight):
                    # draw an arc
                    dx = (cps[i-1].x - cp.x2)
                    dy = (cps[i-1].y - cp.y2)
                    dx2 = (cp.x - cp.x2)
                    dy2 = (cp.y - cp.y2)
              
                    r = m.sqrt(dx*dx + dy*dy)

                    ast = m.atan2(-dy, dx)  * 180/m.pi;
                    aen = m.atan2(-dy2,dx2) * 180/m.pi;
                    aex = aen - ast

                    if (ted.FormType(cp.formtype) == ted.FormType.Arc1CCW or
                        ted.FormType(cp.formtype) == ted.FormType.Arc2CCW):
                        if (aex < 0): aex += 360
                    if (ted.FormType(cp.formtype) == ted.FormType.Arc1CW or
                        ted.FormType(cp.formtype) == ted.FormType.Arc2CW):
                        if (aex > 0): aex -= 360
                
                    self.canvas.create_arc([cp.x2-r,cp.y2+r,cp.x2+r,cp.y2-r],
                                                    start=ast,extent=aex,style=tk.ARC,outline="blue")
                    self.canvas.create_oval([cp.x2-5,cp.y2-5,cp.x2+5,cp.y2+5],fill="blue") # center of arc
                    self.canvas.create_text(cp.x2,cp.y2+10*i,text="%i"%(i))
                else:
                    # draw a line
                    self.canvas.create_line(cp.x,cp.y,cps[i-1].x,cps[i-1].y,fill="green")
        
        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
        self.canvas.pack(side=tk.LEFT,expand=True,fill=tk.BOTH)

app = App()

app.master.title("The CP Viewer")
app.master.maxsize(1900,1000)

app.mainloop()

Nice ! :bowdown:
Between the lot of us, we should have started an open source Ted File Editor/Creator by now ! :cheers:
 
Between the lot of us, we should have started an open source Ted File Editor/Creator by now ! :cheers:

That would be cool, maybe @Razerman could set up a github repo, maybe after we have more substantial code. :) I always lured into the findings of this thread, but had no time to contribute yet.

Anyways, i tried to figure out the rest of the TED file, her is an overview from what i've learned (this info is not new but littered all over this thread so i guess it's good to reiterate):

The TED file seems to be used by GT6 to create the track in game and should contain all the data needed for that. It contains a header with various global info:
  • the used scenery: Andalusia, Eifel, etc.
  • three different track widths, might be assignable to different parts of the track
  • the track length
  • the home straight length
  • the elevation span
  • the number of corners
  • where the start/finish line is
It also contains various lists that define the track layout and decoration:
  • control points that define the horizontal track layout, i.e. a curve like what i've posted above: each consecutive control point pair defines a track segment that is either a straight or an arc/circle segment. There is also a NEARLY_STRAIGHT segment type that is presumably used for arcs with a huge radius and a center that is very far away. I guess not the center but it's dual point/circle inversion is stored instead. If someone who can extract a TED file can create a track with one segment almost a straight and post the TED file here i could investigate further.
  • for each curve segment defined by the control points there is banking info: how the track surface is banked and how the banking angle transitions over the track. Also a number of divisions per segment is given, in order to convert the whole track curve from straights and arcs into many short line segments.
  • A list of heights is given for each of the points of this polyline track representation, giving a 3D polyline together with the 2D polyline defined before. I guess this list is created from the 2d polyline combined with the height maps of the scenery extracted from the Track Path Editor.
  • Then comes a list of different road parts defined as start/end arclengths of the 3d polyline covering the full length of the track. I don't know exactly what is given here but i guess the road width is defined together with other stuff, maybe road appearance from some predefined geometry.
  • Finally decoration objects from a fixed list of types (trees,curbs) are given by their arclength position along the 3d polyline
I'm in the process of putting together the conversion from track curve to track 3D polyline using the division info and the height maps to test these findings. If this works out, a full fledged TED Editor might be possible. :dopey:
 
Small update, managed to decode and draw the track outline of @Razerman's example.ted:

That's awesome!

That would be cool, maybe @Razerman could set up a github repo, maybe after we have more substantial code. :) I always lured into the findings of this thread, but had no time to contribute yet.

I've had this github repo open for a while now but to be honest, I don't even remember what all the code in there does :D And I know there is alot of code that is not doing anything/is there twice because I had an idea and then didn't have time to finish it.

I've got this other tool to extract TED from replay and upload the modified one back to PD servers. Unfortunately I don't think I'm allowed to share it here since there is encryption key inside to decrypt the replay.

Some of the features (alot more in the code but doesn't have GUI yet):
c681cabf76f95fb7e9d245233c574062.png

7e24a821caa952260f4210b05c2bcca4.png

Then I stopped developing any of that and instead started working on this:


But now I'm busy with school so not sure if I have time to contribute much for
Ted File Editor/Creator by now
:(

But I still have ALOT of code from the time I was porting the GT6TPE from that Unity s*it to full C# tool. Like *.Bin and *.Meta -> *.Ted or *.Obj.

Asset editor for rail_def and coursemaker -xml files.
https://github.com/Razer2015/GT6_XML_Editor
 
  • A list of heights is given for each of the points of this polyline track representation, giving a 3D polyline together with the 2D polyline defined before. I guess this list is created from the 2d polyline combined with the height maps of the scenery extracted from the Track Path Editor.
As far as I can tell, only the end points of each road segment get their heights from the height map. The rest of the height data seems to be some kind of interpolation between these points.
 
That's awesome!



I've had this github repo open for a while now but to be honest, I don't even remember what all the code in there does :D And I know there is alot of code that is not doing anything/is there twice because I had an idea and then didn't have time to finish it.

I've got this other tool to extract TED from replay and upload the modified one back to PD servers. Unfortunately I don't think I'm allowed to share it here since there is encryption key inside to decrypt the replay.

Some of the features (alot more in the code but doesn't have GUI yet):
c681cabf76f95fb7e9d245233c574062.png

7e24a821caa952260f4210b05c2bcca4.png

Then I stopped developing any of that and instead started working on this:


But now I'm busy with school so not sure if I have time to contribute much for
:(

But I still have ALOT of code from the time I was porting the GT6TPE from that Unity s*it to full C# tool. Like *.Bin and *.Meta -> *.Ted or *.Obj.

Asset editor for rail_def and coursemaker -xml files.
https://github.com/Razer2015/GT6_XML_Editor

*insert .gif of dude continuously taking off his glasses in amazement*
 
As far as I can tell, only the end points of each road segment get their heights from the height map. The rest of the height data seems to be some kind of interpolation between these points.

Good point, the height seems very flexible as your height editor clearly demonstrates. The final road mesh is somehow planted on the terrain, maybe a final shift is done to the heights to make sure the road doesn't cut into terrain too much. Have you tried to get some parts of the road under the terrain?

Interesting things could be done with the height map though, for example finding lines of steepest descent or lines of equal height in the terrain and create the track along these lines. But i'm getting ahead of myself here. :D
 
But I still have ALOT of code from the time I was porting the GT6TPE from that Unity s*it to full C# tool. Like *.Bin and *.Meta -> *.Ted or *.Obj.

Thanks a lot for the dissection of the files and sharing the 010 Editor templates, that was the hard work everybody built upon! :cheers:
Am i right that only the TED file is needed for a GT6 track upload and the BIN and META files are intermediary and come from the Track Path Editor? I have not tried to extract these files myself, i took your example files and played around with them so far.
 
Good point, the height seems very flexible as your height editor clearly demonstrates. The final road mesh is somehow planted on the terrain, maybe a final shift is done to the heights to make sure the road doesn't cut into terrain too much. Have you tried to get some parts of the road under the terrain?

Interesting things could be done with the height map though, for example finding lines of steepest descent or lines of equal height in the terrain and create the track along these lines. But i'm getting ahead of myself here. :D

The terrain is flexible when the course is generated in the game, so when the track goes below it the terrain is simply lowered in that area. It doesn't rise when the track goes above it though, so you can create valleys, but not hills.

Oh, and did you check out the contour maps made from the height maps? :)
 
Of course, they should be in the Track Path Editor by default! :)đź‘Ť
Now imagine an editor with dynamic contour lines and coloring in the backdrop based on zoom level, created on the fly from the height maps... đź’ˇ

Should be doable :D

Can bilinear interpolation be used to convert the pixel data (which is basically a set of sample points) to contour lines?

https://en.m.wikipedia.org/wiki/Bilinear_interpolation
 
Last edited:
Thanks a lot for the dissection of the files and sharing the 010 Editor templates, that was the hard work everybody built upon! :cheers:
Am i right that only the TED file is needed for a GT6 track upload and the BIN and META files are intermediary and come from the Track Path Editor? I have not tried to extract these files myself, i took your example files and played around with them so far.

TPE creates the GT6TED, encrypts/compresses it and then sends it to PD.
 
Back