You'll like my new Special Stage Route 11 track thenLoving the new updated Monza RM and RRV RM. Also the jumping junction circuit is heaps of fun as expected Keep it coming guys đź‘Ť
You'll like my new Special Stage Route 11 track then
Ok. Thanks, buddy.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.
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)
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()
Between the lot of us, we should have started an open source Ted File Editor/Creator by now !
Small update, managed to decode and draw the track outline of @Razerman's example.ted:
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.
Ted File Editor/Creator by now
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.
- 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.
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 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):
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
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.
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.
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.
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... đź’ˇ
Thanks a lot for the dissection of the files and sharing the 010 Editor templates, that was the hard work everybody built upon!
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.
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
Then I stopped developing any of that and instead started working on this:
Nice !
Between the lot of us, we should have started an open source Ted File Editor/Creator by now !