Important information: this site is currently scheduled to go offline indefinitely by end of the year.

Import Tuner Challenge [XBOX360]

Post questions about game models here, or help out others!
User avatar
Machinedramon
advanced
Posts: 77
Joined: Mon Apr 08, 2019 6:13 pm
Has thanked: 13 times
Been thanked: 42 times

Re: Import Tuner Challenge [XBOX360]

Post by Machinedramon »

JohnHudeski wrote: Sun May 19, 2019 7:31 pm How many of you here can actually program? I did not use BMS for my extraction
also How did you figure out what texture matches what models
Did you use oberhummers ucl compression library to open the files?
JohnHudeski
mega-veteran
mega-veteran
Posts: 177
Joined: Wed Mar 02, 2011 10:38 pm
Has thanked: 10 times
Been thanked: 58 times

Re: Import Tuner Challenge [XBOX360]

Post by JohnHudeski »

Machinedramon wrote: Sun May 19, 2019 8:00 pm
JohnHudeski wrote: Sun May 19, 2019 7:31 pm How many of you here can actually program? I did not use BMS for my extraction
also How did you figure out what texture matches what models
we have one programer on C, one for Javascript, and i kind of understand a bit python, but being honest, we are rather new to it and not really what you would call very helpfull, with textures here comes one of the problems, we know that textures are stored in xpr, in cars... we dont fully understand but we can check in xenia with intel GPA for the correct textures on each material, for tracks there is something peculiar going on, most of the sdb are more like a package, those packages might contain the texture inside depending whether it is stand alone; that means, things like roads, lamps and so on, as are the same all across the whole map, use comon textures that are stored separately, but buildings, or signs, have the textures stored in the sdb file, at least, thats what i have understood so far, we are actually working with csplit to split the textures from sdb files while trying to keep the naming to know exactly to which file it does belong to
Holy cow. That is dedication. You run xenia and manually identify what textures. Cos this was a problem i faced. I got all the models and i could not match the textures

I wrote my own extractor. It was the easiest thing about reversing this game
User avatar
Machinedramon
advanced
Posts: 77
Joined: Mon Apr 08, 2019 6:13 pm
Has thanked: 13 times
Been thanked: 42 times

Re: Import Tuner Challenge [XBOX360]

Post by Machinedramon »

yeah... we have to work with the tools we have, even if that means brute forcing it, as i said, as long as it works, we trying as much as we can with what we have in our hands
User avatar
Machinedramon
advanced
Posts: 77
Joined: Mon Apr 08, 2019 6:13 pm
Has thanked: 13 times
Been thanked: 42 times

Re: Import Tuner Challenge [XBOX360]

Post by Machinedramon »

So, its been some months already and though it might look like the thing has been stuck, been working lots on the hex part and using Model Researcher Pro to come to a semi finished import script for MRP, the script has explained all the steps for any newcomers, im not quite sure if anyone is interested into researching further, i have few theories of my own how the common texture container works, its kinda stated something about it between D0 and 130...

anyways, feel free to dig in and question anything related to it
sorry for the long ass common variable, 800 texts packed there
the image is from the segment B4.sdb
note: this script only works for the course files (sdb) up to 176(thats the first common texture container), subsequent files have their own code for textures in the next texture folder(its the separation between weathers and also types of geometry(parkings and test area are after the 3 instances of the whole map(night, midnight, dawn) and also, given that .obj might only handle 1 uv channel, i did the code to create a mesh for each subsequent uv block(there might be up to 3 uv blocks(uv channels) for each part of the geometry, depending what type of texture it uses might be mapped differently(diffuse, normal, emmisive...)

Code: Select all

import mrp
import random
f = mrp.get_bfile()
f.set_byte_order(">")
#these are the header statements, mrp is the module for model researcher pro, random is to create
#random numbers, f= mrp.get_file() is a shortcut for the mrp statements, f.set_byte_order(">") is
#a statement to make the program read the bytes in Big endian order.

#-----------------------------------------------------------------------------------------------
#this is the common texture folder located in 176.dat
common = ['mat_4go_ro_kakiwari','4go_ro_parts00','4go_ro_waku00','4go_ro_waku01','4go_ro_waku03','4go_ro_waku04','4go_ro_waku05','4go_ro_waku06','4go_ro_waku07','4go_ro_waku08','4go_ro_waku09','4go_ro_waku10','4go_ro_waku11','4go_ro_wall00','4go_ro_wall01','4go_ro_wall02','4go_ro_wall03','4go_ro_window00','4go_ro_window01','4go_ro_window02','4go_ro_window03','4go_ro_window05','4go_ro_window09','4go_ro_window10','4go_ro_window11','4go_ro_window12','4go_ro_window_black','HF_TS_a','HF_TS_waku','HF_TS_waku_nml','LD0730m_j','able_00','able_01','able_02','able_03','able_sibuya_00','able_sibuya_01','able_sibuya_02','ami','aruze_00','aruze_01','asagami_00','asagami_01','asahi_a_00','asahi_a_01','asahi_a_02','asahi_b_00','asahi_b_01','asfa00','asfa01','asfa02','auto_back_tx','botom_s_01','botom_s_01_dirty','botom_s_01_nml','botom_s_02','botom_s_02_dirty','botom_s_02_nml','botom_s_03','botom_s_03_nml','botom_s_04','botom_s_04_nml','botom_u_01','botom_u_01_nml','botom_u_02','botom_u_02_nml','botom_u_03','botom_u_03_nml','botom_u_05','botom_u_05_nml','botom_u_06','botom_u_06_nml','botom_u_07','botom_u_07_nml','botom_u_09','botom_u_09_nml','botom_u_10','botom_u_10_nml','brother_00','brother_01','brother_02','brother_03','brother_04','brother_05','brother_06','brother_07','cbon_00','cbon_01','check_00','check_01','chika2_01','chika2_01_00','chika2_01_00_nml','chika2_01_01','chika2_01_02','chika2_01_03','chika2_01_nml','chiobita_a_00','chiobita_a_01','chiobita_a_02','chiobita_a_03','chiobita_a_04','chiobita_a_05','chiobita_a_06','chiobita_b','chiobita_b_00','chiobita_b_01','chiobita_b_02','chiobita_b_03','chiyoda_tnl_top','chiyoda_tnl_top_nml','chiyoda_tnl_wall_01','chiyoda_tnl_wall_01_nml','chiyoda_tnl_wall_02','chiyoda_tnl_wall_02_nml','clarion_00','clarion_01','clarion_02','clarion_03','clarion_04','cora_00','cora_01','cora_02','cora_03','cora_04','cora_05','cup_00','daikan_00','daikan_01','dc_card_00','dc_card_01','denko_r_00','denko_r_00_nml','denko_r_01','denko_r_02','denko_r_03','dhc_00','dhc_01','excelHuman_00','excite_00','excite_01','excite_02','excite_03','excite_04','fence_01','fence_01_nml','fence_02','fence_02_nml','fence_03','fence_03_nml','fence_04','fence_04_dirty','fence_04_nml','fence_05','fence_05_nml','fence_06','fence_06_nml','fence_07','fence_07_nml','fence_09','fence_09_nml','fence_10','fence_10_nml','fence_11','fence_11_door','fence_11_door_nml','fence_12','fence_12_nml','fence_13','fence_13_nml','fence_14','fence_14_grass','fence_16','fence_16_nml','fence_18','fence_18_nml','fence_19','fence_19_nml','fence_20','fence_20_nml','fence_4go_01','fence_4go_01_nml','fence_b','fence_kanaami','fence_kanaami2','fence_kanaami3','fence_kanaami3_nml','fence_kanaami_nml','fence_top','fence_top_nml','first_00','first_01','fujitsu_00','fujitsu_01','g4_ro_a','g4_ro_b','g4_ro_c','gensan_tx','gr3_car','gr3_eneos','gr3_uwall','gr3_wall','gr3_wall2','gr3_wall3','gr3_wall4','gr3_wall5','gr3_wallw','grd_01','grd_01_nml','gyakusou_00','gyakusou_01','hanaharu_a_00','hanaharu_a_01','hanaharu_a_02','hanaharu_a_03','hanaharu_a_04','hanaharu_b_00','hanaharu_b_01','hanaharu_b_02','hanaharu_b_03','hanaharu_b_04','hashira_4go_01','hashira_4go_01_nml','hashira_kon_01','hashira_kon_01_dirty','hashira_kon_01_nml','hashira_kon_02','hashira_kon_02_dirty','hashira_kon_02_nml','hashira_tetsu_01','hashira_tetsu_01_dirty','hashira_tetsu_01_nml','hashira_yoko_01','hashira_yoko_03','hasira_b02','hokusin_00','hokusin_01','hokusin_02','hyundai_00','hyundai_01','jinro_00','jinro_01','jinro_02','jinro_03','jinro_04','jinro_05','jinro_06','jinro_07','jinro_08','jinro_09','jinro_10','jinro_11','joint_a','joint_a_nml','kan_p1_00','kan_p1_01','kan_p1_02','kan_p1_03','kan_p1_04','kan_p1_05','kan_p1_06','kan_p1_07','kan_p1_08','kan_p1_09','kan_p1_10','kan_p1_11','kan_p1_12','kan_p1_13','kan_p1_14','kan_p1_15','kan_p1_16','kan_p1_17','kan_p1_18','kan_p1_19','kan_p1_20','kan_p1_21','kan_p1_22','kan_p1_23','kan_p1_24','kan_p1_25','kan_p1_26','kan_p1_27','kan_p1_28','kan_p1_29','kan_p1_30','kan_p1_31','kan_p1_32','kan_p1_33','kan_p1_34','kan_p1_35','kan_p1_36','kan_p1_37','kan_p1_38','kan_p1_39','kan_p1_40','kan_p1_41','kan_p1_42','kan_p1_43','kan_p1_44','kan_p1_45','kan_p1_46','kan_p1_47','kan_p1_48','kan_p1_49','kanban3go_a','kanban3go_b','kanban3go_c','kanban4go_a','kanban4go_c','kanban4go_e','kanban9go_a','kanban9go_b','kanban9go_c','kanban_4gro_01','kanban_4gro_02','kanban_4gro_03','kanban_4gro_04','kanbanc1_a','kanbanc1_b','kanbanc1_c','kanbanc1_d','kansai_a_00','kansai_a_01','kansai_b','katoolec_00','katoolec_01','katoolec_02','katoolec_03','keep_out_00','keep_out_01','keep_out_02','keep_out_03','keep_out_04','keep_out_05','keep_out_06','keep_out_07','keep_out_08','keep_out_09','keep_out_10','keep_out_11','keep_out_12','keep_out_13','keep_out_14','keep_out_15','ken_00','ken_01','kk_00','kk_01','kk_02','koga_a_00','koga_a_01','koga_a_02','koga_a_03','koga_a_04','koga_a_05','koga_a_06','koga_a_07','koga_b_00','kyosera_00','kyosera_01','kyosera_02','kyosera_03','kyosera_04','lake_00','lake_01','lamp101','lamp201','lamp301','lamp311','lamp701','lamp801','lamp_a','lamp_h','lamp_obj_a','lamp_tnl_01','lanb_gray','leiku_sibu_00','leiku_sibu_01','light','line','line_br','line_br_02','line_br_02_nml','line_br_nml','line_nml','line_y','line_y_nml','mikipuru_00','mikipuru_01','mikipuru_02','mikipuru_03','mikipuru_04','mitui_00','mitui_01','mitui_11go_00','mitui_11go_01','mmc_00','mmc_01','mmc_02','nikon_00','nikon_01','nikon_02','nikon_03','nikon_04','nikon_05','obj_dkk_a','obj_dkk_a_00','obj_dkk_a_00_nml','obj_dkk_a_01','obj_dkk_a_nml','obj_kjkb_01','obj_kjkb_01_nml','obj_pylon_01','obj_pylon_01_nml','oki_00','oki_01','onward_00','onward_01','pa_00','pa_01','parts','parts10','parts11','parts12','parts13','parts14','parts15','parts16','parts17','parts18','parts19','parts2','parts20','parts21','parts22','parts23','parts24','parts25','parts26','parts27','parts28','parts29','parts3','parts30','parts31','parts32','parts33','parts4','parts5','parts8','parts9','parts_hiru00','parts_hiru01','parts_hiru02','parts_ripu00','parts_sibu','parts_sibu2','parts_sibu_ripu','parts_sita00','pentax_00','pentax_01','pilar_foot_1','pilar_foot_1_nml','pl_light','pl_red_01_00','pl_red_01_01','pl_red_01_02','pl_red_02_00','pl_red_02_01','pl_red_02_02','road_01','road_01_dirty','road_01_nml','road_02','road_02_nml','road_haisui_02','road_haisui_02_nml','road_ip_01','rolex_00','rolex_01','saisoncard_00','saisoncard_01','saku_01','saku_01_nml','saku_02','saku_02_nml','saku_03_02','saku_03_02_nml','saku_04','saku_04_nml','saku_05','saku_06','saku_08','saku_08_01','saku_08_02','saku_08_nml','saku_09','saku_09_nml','saku_10','saku_10_nml','saku_11','saku_11_nml','saku_12','saku_12_nml','saku_13','saku_13_nml','saku_14','saku_14_nml','saku_15','saku_15_nml','saku_17','saku_17_nml','samsung_00','sato','sato_4go_00','sato_4go_01','sato_4go_02','sato_4go_03','sato_4go_04','sato_4go_05','sato_4go_06','sato_anim_00','sato_anim_01','sato_yunke','senda_4__5','sglgta_00','sglgta_01','sglgta_02','sglgta_03','shingou_light_0','shingou_light_00','shingou_light_01','shingou_light_02','shingou_light_03','shingou_light_b','shinnihon_00','shinnihon_01','shlgta_00','shlgta_01','shlgta_02','shlgta_03','shock_rw','shock_rw_nml','shock_rwyb','shock_rwyb_nml','shock_shingou','shock_shingou_0','shock_shingou_00','shock_shingou_01','shock_shingou_02','shock_shingou_03','shock_shingou_nml','shock_yb','shock_yb_nml','sibu_car','singou_e','sitamiti00','sitamiti01','starts_00','starts_01','starts_02','starts_03','sumitomo_00','sumitomo_01','syowa_00','syowa_01','syowa_02','syowa_03','syowa_04','syowa_05','syowa_06','syowa_07','syowa_08','syowa_09','syowa_10','syowa_11','syowa_12','syowa_13','syowa_14','syowa_15','syowa_16','syowa_17','syowa_18','syowa_19','syowa_20','syowa_21','syowa_22','syowa_23','syowa_24','syowa_25','syowa_26','syowa_27','syowa_28','syowa_29','syowa_30','syowa_31','syowa_32','syowa_33','syowa_34','syowa_35','syowa_36','syowa_37','syowa_38','syowa_39','syowa_40','syowa_41','syowa_42','syowa_43','syowa_44','syowa_45','syowa_46','t00','t00w','takefuji_00','takefuji_01','tate_kanban00','tate_kanban01','tdk_00','tdk_01','tdk_02','tdk_03','tdk_04','tdk_05','tele_00','tele_01','tele_02','tele_03','tele_04','tele_05','tikei_11go','tochou00','tochou01','tochou02','tochou03','tochou04','tokyotower','toshiba_00','toshiba_01','totan','train_monorail','train_soubu','train_tyuou','train_window','train_yamanote','train_yurikamome','tree_00','tree_01','tree_02','tree_02_lod','tree_03','tree_03_lod','tree_04','tree_04_lod','tree_05','tree_05_lod','tree_06','tree_06_01','tree_06_02','tree_06_nml','tree_07','tree_08_01','tree_11','tree_11_01','tree_grass_01','tree_kakiwari_01','u_wall','u_window','u_window_auto','ufj_00','ufj_01','w_wall_hiru00','w_wall_hiru01','w_wall_hiru02','wal_01','wal_01_dirty','wal_01_nml','wal_02','wal_02_dirty','wal_02_nml','wal_03','wal_03_dirty','wal_03_nml','wal_04','wal_04_dirty','wal_04_nml','wal_05','wal_05_dirty','wal_05_nml','wal_07','wal_07_dirty','wal_07_nml','wal_08','wal_08_nml','wal_11_nml','wal_13','wal_13_nml','wal_14','wal_14_nml','wal_out_01','wal_out_01_nml','wal_pan_01','wal_pan_01_nml','wal_tesuri_01','wal_tesuri_02','wal_tesuri_02_nml','wal_tesuru_01','wall_aka','wall_aka2','wall_aka3','wall_aka4','wall_aka5','wall_ao','wall_ao2','wall_ao3','wall_ao4','wall_ao5','wall_block','wall_bunka','wall_cha','wall_cha2','wall_cha3','wall_cha4','wall_cha5','wall_cha6','wall_cha7','wall_gray','wall_gray10','wall_gray11','wall_gray2','wall_gray3','wall_gray4','wall_gray5','wall_gray6','wall_gray7','wall_gray8','wall_gray9','wall_hiru00','wall_hiru01','wall_hiru02','wall_hiru03','wall_ki','wall_kuro','wall_kuro2','wall_kuro3','wall_kuro4','wall_kuro5','wall_midori','wall_siro','wall_siro2','wall_siro3','wall_siro4','wall_siro5','wall_siro6','wall_toumei','walls_sibu','wallw_aka','wallw_aka10','wallw_aka11','wallw_aka12','wallw_aka13','wallw_aka14','wallw_aka2','wallw_aka3','wallw_aka4','wallw_aka5','wallw_aka6','wallw_aka7','wallw_aka8','wallw_aka9','wallw_ao','wallw_ao2','wallw_ao3','wallw_ao4','wallw_ao5','wallw_ao6','wallw_cha','wallw_cha10','wallw_cha11','wallw_cha12','wallw_cha13','wallw_cha14','wallw_cha15','wallw_cha18','wallw_cha2','wallw_cha3','wallw_cha4','wallw_cha5','wallw_cha6','wallw_cha7','wallw_cha8','wallw_cha9','wallw_glass','wallw_gray','wallw_gray2','wallw_gray3','wallw_gray4','wallw_gray5','wallw_gray6','wallw_gray7','wallw_gray8','wallw_gray9','wallw_kuro','wallw_kuro10','wallw_kuro11','wallw_kuro2','wallw_kuro3','wallw_kuro4','wallw_kuro5','wallw_kuro6','wallw_kuro7','wallw_kuro8','wallw_kuro9','wallw_lodat','wallw_siro','wallw_siro10','wallw_siro11','wallw_siro12','wallw_siro13','wallw_siro14','wallw_siro15','wallw_siro16','wallw_siro17','wallw_siro18','wallw_siro19','wallw_siro2','wallw_siro20','wallw_siro21','wallw_siro22','wallw_siro23','wallw_siro24','wallw_siro25','wallw_siro26','wallw_siro27','wallw_siro28','wallw_siro3','wallw_siro4','wallw_siro5','wallw_siro6','wallw_siro7','wallw_siro8','wallw_siro9','window','window2','window3','window4','window5','window6','window7','window8','window_lod','windowtt','wktunnel_ceil','wktunnel_wall','yahoo_00','yahoo_01','yahoo_02','yoyogi_st_home','zeb','zeb_b','zeb_b_nml','gt_sky0','gt_sky1','gt_sky2','gt_sky3','cube_a_0']
#-----------------------------------------------------------------------------------------------
anim = mrp.create_material("Null")
anim.set_color(10, 10, 10)
#just a material with null, its used for anims given those are special, color (10, 10, 10)

xpr = []
xprmat = {}
#xpr is a container for the selfcontained textures, and xprmat is a dictionary(descontinued in the code)

verts = []
#faces = []
uvs = []
#verts is the vertex container, faces has been moved to per mesh faces container and uvs might have been discontinued

uv1 = []
uv2 = []
uv3 = []
#these are containers just for the uvblocks, that can be up to 3

materials = []
magic_byte = 32
#mat = open('mat.txt', 'w')
#materials is a container for material names, might be discontinued.
#magic_byte is a really interesting thing about the binaries of ITC, most offsets for data fetch are
#by a 0x20 offset, thus why 32

#endofvariables

#f.seek is a move pointer statement, this way i tell the program to go to a certain byte offset
#if f.seek has only one number (656), means that offset from the start, if it has (656, 1), 1 means
#to add that value to current pointer offset, 2 means to count from the end of the file backwards
f.seek(656)
lenght = f.readInt() #number of meshes in the file
#print (str(lenght) + " Elements",file = mat)
f.seek(672)
#print (f.tellHex())

f.seek(1076)
uvblocks = 0 #this is just a initiator for the variable
for i in range(lenght): #this is a loop for as many elements handled
    cursize = f.readInt() #we read a value
    #print (uvblocks, f.tellHex())
    if cursize > uvblocks: # compare the value, if it is bigger it will take the new value
        uvblocks = cursize
    f.seek(508,1)
#this is a loop to check that all the meshes have a certain ammount of uvblocks for the data collection
uvpadding = (uvblocks*4)
#creating the uvpadding by knowing the ammount of uv blocks handled

#print("---------next section----------")
#print("------"+str(uvblocks)+" uv blocks found-------")
#uvpadding = 12
#---------------UVS-------------------
#currentuv = 1
materia = {} #this might have been discontinued
#-------------------------------------
#print (uvblocks)
f.seek(96)
uvstart = (f.readInt() + 32) #where the uv bytes start
f.seek(352)
vc = (f.readInt()) #vertex count
f.seek(8,1)
vertstart = (f.readInt() + uvstart) #start of vertex bytes
f.seek(vertstart)
for i in range(int(vc)): # repeat as many times as vertex count in integer form(real number)
    verts.append(f.read3Float()) #data fetch, means to grab 3 floats in form (x, y, z)
for i in range(uvblocks): #repeat as many times as uvblocks are in the file
    startjump = (i+1)*4 #we create a start jump for each time the file goes through, this means that for each time it will add 1(because i starts at 0) and multiply by 4; 1st time = 4, 2nd time = 8....
    f.seek(uvstart)
    f.seek(startjump,1)
    curruv = i + 1 #given i starts at 0 we add 1, this will be the current uv block handled
    for i in range(int(vc)): #there are as many uvs as Vertex count
        u = f.readHalfFloat()
        v = f.readHalfFloat() *(-1) #we flip vertical
        exec('uv'+str(curruv)+'.append((u,v))') #this is a execution rutine, here we make the programm add the current uv to the variable string and add the uvs to the corresponding uv block container
        f.seek(uvpadding,1) #lastly, we jump the padding we calculated before

#so this part might be a bit confusing, a little explanation, given each file might have own textures, we have to grab them before creating materials, here the break down
#print(uvblocks, len(uv3))
f.seek(104)
jump = (f.readInt()+32) #so, at 104 we find the first clue, we jump to that adress
f.seek(jump)
extra = (f.readInt()*32 + 40)#we come to the shader properties, we want to jump these too, so read how many we have first
jump = (f.readInt() + extra)#also the container has a length of its own, we add them and jump them
f.seek(jump,1)
#time to grab xprtexts
f.seek(12,1) #a very last jump to skip the 0000 indicators for the game
xprtexnum = f.readInt() #number of textures in the xpr container
jump = (xprtexnum*16 + 4) #we jump the offsets for each texture(those will be usefull for the xpr2tga)
f.seek(jump,1)
#print("---------Materials----------",file = mat)
xprcur = 0 #we initialize the current xpr by 0
name = "" #and create an empty name for the code to add characters to
while xprcur < xprtexnum: #while the current xpr is less than the number of textures, loop
    byte = f.readByte() #we read byte by byte
    char = chr(byte) #we convert that byte to character
    if byte == 0: #if the byte is 0, means its end of line(full name completed)
        xpr.append(name) #so we add the name to the container
        xprmat[xprcur] = name #this is the dictionary, means that for the current xpr = name
        name = "" #we reset our name string for the next name
        byte = f.readByte() #and start reading again the first byte
        char = chr(byte)
        xprcur = xprcur + 1 #and lastly we add 1 to the current xpr count
    name = str(name) + str(char) #this is the magic, we add each character to the name as long as we dont get a 0

#this is the mesh creation loop
for i in range(lenght): #for as many elements we have
    curmesha = 0 #initialization for three meshes
    curmeshb = 0
    curmeshc = 0
    faces = [] #and reseting the faces so each mesh has its own faces(that can be used in the three abc, but not along different elements
    #print("Element " + str(i+1),file = mat)
    jump = (672 + i*512) #this is a correcter for the offsets starts, we know that each segment for each element in the header list is 0x200 bytes long(512) and starts at 0x2A0(672)
    f.seek(jump)
    f.seek(128,1)#we jump inside the segment where we locate the information about materials
    texnum = f.readInt()#this is the number of textures each element uses
    #print (str(texnum) + " Tex",file = mat)
    f.seek(12,1)
    a = f.readInt()#here are the indicators for what type of texture(1 is the common folder, 2 is self contained ones)
    b = f.readInt()
    c = f.readInt()
    #print(c , f.tellHex())
    f.seek(20,1)#jump to the exact numbering for each texture
    curelement = i + 1#we create a current element variable that starts by 1(0+1=1)
    numa = f.readInt()#this will be then the number for the exact texture within the folder specified for the uv1
    #print(numa)
    #print(f.tellHex())
    if a == 1:#if the texture is from the common folder
        #print ("UV1 common " + common[numa],file = mat)
        crmta = ('mat_'+common[numa]+' = mrp.create_material("'+str(common[numa])+'")')#we create 2 variables that will be executed to create a mesh with the name of the texture and also the texture path
        crtexa = ('mat_'+common[numa]+'.set_texture(r\"E:\\itc\\textures\\'+str(common[numa])+'.tga\")')#texture path will be E:\itc\textures\(here the texture name).tga
        random0 = random.randint(0,255)#these are random numbers created from 0 to 255 for the color of the faces, might be discontinued
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)#now we jam the 3 together for the (r, g, b)
        crclra = ('mat_'+common[numa]+'.set_color'+str(ran))#and create a code to run an create the color dinamic varibale that uses the name of the material created before
        exec (crmta)#now we execute the 3 codes for the dinamic variables
        exec (crclra)
        exec (crtexa)
        curmesha = common[numa]+str(i)#and then we create a current mesh a name
        curmata = 'mat_'+common[numa]#and also the current material a
        #uv1.append(common[num])
    if a == 2:#if the texture is from the self contained xpr
        #print ("UV1 xpr " + xpr[numa]+" = mat"+str(i),file = mat)
        crmta = ('mat_'+xpr[numa]+' = mrp.create_material("'+str(xpr[numa])+'")')
        crtexa = ('mat_'+xpr[numa]+'.set_texture(r\"E:\\itc\\textures\\'+str(xpr[numa])+'.tga\")')
        random0 = random.randint(0,255)
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)
        crclra = ('mat_'+xpr[numa]+'.set_color'+str(ran))
        exec (crmta)
        exec (crclra)
        exec (crtexa)
        curmesha = xpr[numa]+str(i)
        curmata = 'mat_'+xpr[numa]
        #uv1.append(xpr[num])
    if a == 0:#with a might be special, cause animations might have a 0 index, unlike b or c, so we create 2 instances
        if texnum == 1:#if there is a texture but the index tells us that is 0, we asume its an animation
            #print ("Anim",file = mat)
            curmesha = 'Anim'+(str(curelement))#and just asign the name Anim+number of element
            curmata = 'anim'#just a simple material that is common for all animations(those need to be reworked in 3d editor)
            #uv1.append("Anim")
        else:#but if for some reason we dont have any texture listed and also no index, then we will set the current mesh to Zero(this will also be done for b and c)
            #print ("Null",file = mat)
            curmesha = 0
            #uv1.append("null")
    numb = f.readInt()#this is the number for b texture
    #print(numb)
    if b == 1:#for more information read how a works
        #print ("UV2 common " + common[numb],file = mat)
        crmtb = ('mat_'+common[numb]+' = mrp.create_material("'+str(common[numb])+'")')
        crtexb = ('mat_'+common[numb]+'.set_texture(r\"E:\\itc\\textures\\'+str(common[numb])+'.tga\")')
        random0 = random.randint(0,255)
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)
        crclrb = ('mat_'+common[numb]+'.set_color'+str(ran))
        exec (crmtb)
        exec (crclrb)
        exec (crtexb)
        curmeshb = common[numb]+str(i)
        curmatb = 'mat_'+common[numb]
        #uv2.append(common[num])
    if b == 2:
        #print ("UV2 xpr " + xpr[numb]+" = mat"+str(i),file = mat)
        crmtb = ('mat_'+xpr[numb]+' = mrp.create_material("'+str(xpr[numb])+'")')
        crtexb = ('mat_'+xpr[numb]+'.set_texture(r\"E:\\itc\\textures\\'+str(xpr[numb])+'.tga\")')
        random0 = random.randint(0,255)
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)
        crclrb = ('mat_'+xpr[numb]+'.set_color'+str(ran))
        exec (crmtb)
        exec (crclrb)
        exec (crtexb)
        curmeshb = xpr[numb]+str(i)
        curmatb = 'mat_'+xpr[numb]
        #uv2.append("mat"+str(i))
    if b == 0:
        #print ("Null",file = mat)
        curmeshb = 0
        #uv2.append("null")
    numc = f.readInt()#number for texture C
    #print(numc)
    #print (numa, numb, numc)
    #print(f.tellHex(), len(faces), curmesha, curmeshb, curmeshc)
    
    if c == 1:#same as b and a
        #print ("UV3 common " + common[numc],file = mat)
        crmtc = ('mat_'+common[numc]+' = mrp.create_material("'+str(common[numc])+'")')
        crtexc = ('mat_'+common[numc]+'.set_texture(r\"E:\\itc\\textures\\'+str(common[numc])+'.tga\")')
        #print (crtexc)
        random0 = random.randint(0,255)
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)
        crclrc = ('mat_'+common[numc]+'.set_color'+str(ran))
        exec (crmtc)
        exec (crclrc)
        exec (crtexc)
        curmeshc = common[numc]+str(i)
        curmatc = 'mat_'+common[numc]
        #uv3.append(common[num])
    if c == 2:
        #print ("UV3 xpr " + xpr[numc]+" = mat"+str(i),file = mat)
        crmtc = ('mat_'+xpr[numc]+' = mrp.create_material("'+str(xpr[numc])+'")')
        crtexc = ('mat_'+xpr[numc]+'.set_texture(r\"E:\\itc\\textures\\'+str(xpr[numc])+'.tga\")')
        random0 = random.randint(0,255)
        random1 = random.randint(0,255)
        random2 = random.randint(0,255)
        ran = (random0, random1, random2)
        crclrc = ('mat_'+xpr[numc]+'.set_color'+str(ran))
        exec (crmtc)
        exec (crclrc)
        exec (crtexc)
        curmeshc = xpr[numc]+str(i)
        curmatc = 'mat_'+xpr[numc]
        #uv3.append("mat"+str(i))
    if c == 0:
        #print ("Null",file = mat)
        curmeshc = 0
        #uv3.append("null")
    #for i in range(1):
        #a mesh

    f.seek(jump)#now we jump back to the start of the segment(didnt want to variably calculate the offsets)
    f.seek(336,1)#and jump the material data
    fic = f.readInt ()   #here we read the Face indices for the current segment
    f.seek(44,1)
    fis = (f.readInt() + 32) #and here the start of those faces
    f.seek(fis) #we jump there
    for i in range(int(fic)):#and for as many as there are we scan them and add them to the container faces
        fi = f.readShort()
        #if fi == 65535:
        #    fuckc = fuckc + 1
        faces.append(fi)
    #last = faces[-1]
    #materials.append(last)
    faces.append(65535)#we add as last FFFF to separate each element, else we get faulty tris(well maybe not now that each element is separated xD)
    
    if curmesha != 0:#if the current mesh a is different than 0
        #print(curmesha)
        mrp.create_mesh(curmesha)#we create a mesh with the name of current mesh a
        mesh = mrp.get_mesh(curmesha)#we retrieve the mesh
        mesh.set_vertices(verts)#set vertices the common vertex container
        mesh.swap_vertices("XYZ", "x")#we flip x
        mesh.set_uvs(uv1)#set the uvs for a as uv1(b is uv2 and c uv3)
        mesh.set_uvs_indices(faces,fm="TStripFF")#set the indices of those uvs to be the same as the face indices, in triangle strip FFFF format
        mesh.set_faces(faces,fm="TStripFF")#now the faces
        exec('mesh.set_material('+str(curmata)+')')#and last we set the material for that element
    if curmeshb != 0:#same thing for current mesh b(uv2)
        #print(curmeshb)
        mrp.create_mesh(curmeshb)
        mesh = mrp.get_mesh(curmeshb)
        mesh.set_vertices(verts)
        mesh.swap_vertices("XYZ", "x")
        mesh.set_uvs(uv2)
        mesh.set_uvs_indices(faces,fm="TStripFF")
        mesh.set_faces(faces,fm="TStripFF")
        exec('mesh.set_material('+str(curmatb)+')')
    if curmeshc != 0:#and also for current mesh c(uv3)
        #print(curmeshc)
        mrp.create_mesh(curmeshc)
        mesh = mrp.get_mesh(curmeshc)
        mesh.set_vertices(verts)
        mesh.swap_vertices("XYZ", "x")
        #print(uv3)
        mesh.set_uvs(uv3)
        mesh.set_uvs_indices(faces,fm="TStripFF")
        mesh.set_faces(faces,fm="TStripFF")
        exec('mesh.set_material('+str(curmatc)+')')
    #f.seek(324,1)            
    #end of loop, it will restart faces for the next segment
#this all after is discontinued and thus why as comentary, used most of it for debuging
#crmt = (xpr[i]+' = mrp.create_material("'+str(xpr[i])+'")')
#random0 = random.randint(0,255)
#random1 = random.randint(0,255)
#random2 = random.randint(0,255)
#ran = (random0, random1, random2)
#crclr = (xpr[i]+'.set_color'+str(ran))
#exec (crmt)
#exec (crclr)

#exec('print(dir())')

#for i in range(3):
#    print(uv1[i+640],uv2[i+640],uv3[i+640])
#print ("---------------ok-----------------")
#print(xprmat)
print("check no problems")#if the file has been parsed from start to finish without any problem, it should print this in the console
You do not have the required permissions to view the files attached to this post.
TheFalcon19
ultra-n00b
Posts: 6
Joined: Wed Sep 25, 2019 2:42 pm
Has thanked: 5 times
Been thanked: 2 times

Re: Import Tuner Challenge [XBOX360]

Post by TheFalcon19 »

Great job figuring out how everything is connected in the course files AND putting together a script.
But because I didn't check this thread since it was posted, I did it the hard way and extracted things without materials and assigned them one by one...oh well.

https://www.youtube.com/watch?v=GGIQO3jiM20
User avatar
REDZOEU
veteran
Posts: 151
Joined: Thu Mar 10, 2011 8:03 am
Location: Jakarta, Indonesia
Has thanked: 74 times
Been thanked: 50 times
Contact:

Re: Import Tuner Challenge [XBOX360]

Post by REDZOEU »

Wow! Are you gonna release that track? You should get yourself involved with SRP via discord. Or are you already involved? I’m way behind the news, so idk.
TheFalcon19
ultra-n00b
Posts: 6
Joined: Wed Sep 25, 2019 2:42 pm
Has thanked: 5 times
Been thanked: 2 times

Re: Import Tuner Challenge [XBOX360]

Post by TheFalcon19 »

Sorry for the late reply.

Well I plan to release it, I just don't know if there's a "demand" for it, I mean srp already added Shibuya with correct window textures and soon will have Shinjuku. The only things my maps would look different is the objects with multiple uv channels, since I use a different solution for them, but probably even people who played the original games wouldn't really notice it.

I didn't make much progress with my ITC map since that video, because I was also looking at Wangan Midnight's extractor if I can fix it or at least modify it to get correct file1 uv maps...let's just say there's probably going to be video about it in Wangan Midnight thread in a week or two.
User avatar
Machinedramon
advanced
Posts: 77
Joined: Mon Apr 08, 2019 6:13 pm
Has thanked: 13 times
Been thanked: 42 times

Re: Import Tuner Challenge [XBOX360]

Post by Machinedramon »

I basically did the whole script as a way of helping SRP, and yeah shinjuku might be on the works.

Also, did you do it through ninja ripping???? XD
TheFalcon19
ultra-n00b
Posts: 6
Joined: Wed Sep 25, 2019 2:42 pm
Has thanked: 5 times
Been thanked: 2 times

Re: Import Tuner Challenge [XBOX360]

Post by TheFalcon19 »

no, for the most of it I used the free version of model researcher manually putting in adresses and counts
edy
ultra-n00b
Posts: 1
Joined: Thu Jun 15, 2023 7:43 am

Re: Import Tuner Challenge [XBOX360]

Post by edy »

Hey, I've been following this topic for a bit now and have been trying to extract the models on my own. I managed to extract the textures but I'm stuck on trying to get the actual 3D models itself. Is there anyway I can convert/extract anything out of the .xmd files? Any help would be great, thanks! :D
UB833
advanced
Posts: 73
Joined: Tue Jan 04, 2022 9:55 am
Has thanked: 13 times
Been thanked: 3 times

Re: Import Tuner Challenge [XBOX360]

Post by UB833 »

any idea where can I find the ITC mesh converter tool? I just wanted to convert Mitsubishi Concept X car into the game and, I looked at this forum but I had no luck for that but only I got luck for textures script part.

link is appreciated.
Post Reply