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

PS3 - Metal Gear Rising Revengeance - WMB format

Post questions about game models here, or help out others!
ratanegra
n00b
Posts: 17
Joined: Wed May 23, 2012 10:12 am
Has thanked: 9 times
Been thanked: 7 times

PS3 - Metal Gear Rising Revengeance - WMB format

Post by ratanegra »

Hi all.
I used the script "dataunpack.bms" of aluigi to try to extract "Metal Gear Rising Revengeance" 3d models
because this game and "Bayonetta" seems to use the same compression system.

Code: Select all

  offset   filesize   filename
------------------------------
00001000 1476400    ba00d5.wmb
  0016a000 272        ba00d5.wta
  0016b000 61392      ba00d5.eff
  0017a000 5840       ba00d5_col.hkx
  0017b6d0 93         ba00d5_param.bxm
  0017b730 389        CutInfo.bxm
  0017b8c0 233207     ba00d5.bnk
  001b47c0 272        ba00d5_0000.mot
  001b48d0 360        ba00d5_0000_0_seq.bxm
  001b4a40 272        ba00d5_0001.mot
  001b4b50 272        ba00d5_0002.mot
  001b4c60 272        ba00d5_0003.mot
  001b4d70 272        ba00d5_0004.mot
  001b4e80 272        ba00d5_0005.mot

- 14 files found in 1 seconds
And then, the extracting a .dat file of "Bayonetta"

Code: Select all

  offset   filesize   filename
------------------------------
00000980 382112     pl0031.wmb
  0005de80 886348     pl0031.wtb
  00136500 22348      pl0031texA.wtb
  0013bc80 22348      pl0031texB.wtb
  00141400 22348      pl0031texC.wtb
  00146b80 360        pl0031_0_4.clp
  00146cf0 172        pl0031_0_4.clw
  00146da0 172        pl0031_1_4.clw
  00146e50 116        pl0031_2_4.clw
  00146ed0 228        pl0031_3_4.clw
  00146fc0 116        pl0031_4_4.clw
  00147040 116        pl0031_5_4.clw
  001470c0 116        pl0031_8_4.clw
  etc....

- 86 files found in 5 seconds
Well, using wmb_exporter.exe with the .wmb of "Bayonetta", the conversion to. obj is simple but impossible to convert the
.wmb of "MGRR" .Using a hex editor the header is different, and it might be due to what the user "loridaz" says in this post.
The problem is I'm not coder and I can not prove it.

Image

Image

If someone has the solution, please do not hesitate to expose.
Thank you.

If you need more "information", you may request.

Note;
The textures are in the .dtt files ( .etf & wtp) that are actually gtf files. You can use gtf2dds.exe.
Many times these files contain multiple gtf files. You can identify the header:

Image
Gh0stBlade
Moderator
Posts: 719
Joined: Mon Jul 05, 2010 8:55 pm
Has thanked: 20 times
Been thanked: 496 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by Gh0stBlade »

Can you send me a few model samples?
Click the thanks button if I helped!
siro1987
ultra-n00b
Posts: 7
Joined: Sun Jun 13, 2010 12:02 am
Has thanked: 4 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by siro1987 »

So... no one is interested in this game?
and this's the sample I extracted from 360 image
http://www.sendspace.com/file/l9vm27
rensole
beginner
Posts: 39
Joined: Mon Feb 25, 2013 9:34 pm
Has thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by rensole »

I actually registered here because of this!
I'd LOVE to have these models.
I'm quite good at 3d modelling but I hardly know anything of "hacking" a game.

Is there any way I could help ?
howfie
double-veteran
double-veteran
Posts: 929
Joined: Fri Jul 08, 2011 12:06 pm
Location: Torrance, CA
Has thanked: 10 times
Been thanked: 274 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by howfie »

Mariokart wrote a model script for xbox already and I got a texture extractor for the ps3. Texture quality on xbox is much better, ps3 version got shafted.
darksoul
beginner
Posts: 27
Joined: Wed Apr 20, 2011 4:49 pm
Has thanked: 1 time
Been thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by darksoul »

howfie wrote:Mariokart wrote a model script for xbox already and I got a texture extractor for the ps3. Texture quality on xbox is much better, ps3 version got shafted.
Can you share or pm me the texture extractor for PS3
i was attempting to make a .bms script for it
but after reading this and there is already something for it
howfie
double-veteran
double-veteran
Posts: 929
Joined: Fri Jul 08, 2011 12:06 pm
Location: Torrance, CA
Has thanked: 10 times
Been thanked: 274 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by howfie »

I would wait for codeman to update his bayo tools. Very similar format... In one file there a list of offsets and at the bottom a list of 52-byte items where 2nd to last value determines texture dimensions. 940x940 xbox 512x512 ps3. Ps3 got shafted lol.
rensole
beginner
Posts: 39
Joined: Mon Feb 25, 2013 9:34 pm
Has thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by rensole »

So now we just got to wait for a new toolset and then we can extract the models ?
rensole
beginner
Posts: 39
Joined: Mon Feb 25, 2013 9:34 pm
Has thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by rensole »

By the way, was someone ever succesfull in extracting the models for metal gear solid 4 ?
darksoul
beginner
Posts: 27
Joined: Wed Apr 20, 2011 4:49 pm
Has thanked: 1 time
Been thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by darksoul »

howfie wrote:I would wait for codeman to update his bayo tools. Very similar format... In one file there a list of offsets and at the bottom a list of 52-byte items where 2nd to last value determines texture dimensions. 940x940 xbox 512x512 ps3. Ps3 got shafted lol.
what file are you refering too?
im only interested in the textures for PS3 ,dont have xbox lol
i can extract them manually with an hex editor but that just takes ages going to all those .dtt files
making a .bms script failed for me

i know the header of the .gtf contains the size(@ 0x20 from start of header 4 bytes long) of the .gtf + 0x80 bytes for the header so it would be easy for it to be implemented in a bms script
im just not that skilled in making them lol

so sharing/pming the extractor for textures is my best shot lol
rensole
beginner
Posts: 39
Joined: Mon Feb 25, 2013 9:34 pm
Has thanked: 2 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by rensole »

darksoul wrote:
howfie wrote:I would wait for codeman to update his bayo tools. Very similar format... In one file there a list of offsets and at the bottom a list of 52-byte items where 2nd to last value determines texture dimensions. 940x940 xbox 512x512 ps3. Ps3 got shafted lol.
what file are you refering too?
im only interested in the textures for PS3 ,dont have xbox lol
i can extract them manually with an hex editor but that just takes ages going to all those .dtt files
making a .bms script failed for me

i know the header of the .gtf contains the size(@ 0x20 from start of header 4 bytes long) of the .gtf + 0x80 bytes for the header so it would be easy for it to be implemented in a bms script
im just not that skilled in making them lol

so sharing/pming the extractor for textures is my best shot lol
And how could we extract the models ? (I'm kindof new to this so sorry).
Would I need special tools?
siro1987
ultra-n00b
Posts: 7
Joined: Sun Jun 13, 2010 12:02 am
Has thanked: 4 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by siro1987 »

Still no progress?
mariokart64n
ultra-veteran
ultra-veteran
Posts: 586
Joined: Sun Jun 05, 2005 12:00 pm
Location: Ontario, Canada
Has thanked: 36 times
Been thanked: 243 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by mariokart64n »

I was going to explore modding the game, but fell lazy of solving the rest of the structures.

credit goes to chrrox as to helping me discover the face info

Overview:
Files are archived in CRIware's CPK Container. I Used Luigi's BMS script to unpack the files -> http://aluigi.altervista.org/quickbms.htm

Once files are unpacked you'll be seeing two common file extensions (*.DAT,*.DTT)

DAT is a general resource container and DTT from what I can tell is just a texture dump file.
The xbox360 DTT has no headers, however the PS3 DTT has GTF headers.
GTF is a PS3 format, there file structure is documented in the PS3 SDK literature.
I cannot post the structs from the SDK doc {illegal?}, but I'll be sharing the struct I had prior to finding the structs in the SDK

As for files within the DAT once unpacked, there is ALOT. I'll document only two; (WMB,WPA)
WMB is there model binary format, WTA, is an offset table that relates to the DTT file.

> Format for Xbox360: Data is Big Endian and all integers in are unsigned unless otherwise noted

DAT Format
Description:
you collect the count and the offsets, then jump to each table.
the tables hold basic info like file offset, file size, filename, file extension, etc..

you can then parse the DAT file and dump the containing files.
dat_header { // all offsets relative to begining of DAT header
LONG file_count
LONG offset_file_table
LONG offset_extension_table
LONG offset_name_table
LONG offset_size_table
LONG offset_unknown_data
LONG null
}

file_table { // n = file_count
LONG[n] offset
}

extension_table { // string length fixed at 4
STRING file_ext // Example: "wmb", "wta", "bxm", "mot", "eff"
}

name_table {
LONG string_length
}

name_table_entries { // n = string_length
STRING name[n]
}

size_table { // n = file_count
LONG[n] size
}
WMB Format ("WMB4" Only) "WonderfulModelBinary4"??
Description:
Gah O_o it would take alot of paragraphs to explain this so yeah PM me if you need specifics

Just bare in mind I didn't document all the tables, cause franky they'd just be a bunch of unknowns..
so still alot of work ahead for whom ever wants to continue it --vertex def is also incomplete
wmb_header { // all offsets relative to begining of WMB header
LONG magic "WMB4"
LONG version // ? always -1
SHORT vertex_stride // ? vertex stride 0x00 = 24 | 0x01 = 32
SHORT ukn02
SHORT primitive_type // 0x00=trilist | 0x01= trilist
SHORT ukn03
LONG ukn04
LONG ukn05
LONG ukn06
LONG ukn07
LONG ukn08
LONG ukn09
LONG buffer_table_offset // offset to vertex buffer header offset? lol
LONG buffer_count
LONG element_table_offset // offset to unknown data, after faces buffer
LONG element_count
LONG material_table_offset
LONG bone_table_offset
LONG bone_count
LONG ukn17_offset
LONG ukn17_count
LONG ukn18_offset
LONG ukn18_count
LONG ukn19_offset // material related?
LONG ukn19_count
LONG ukn20_offset
LONG ukn20_count
LONG mesh_table_offset
LONG mesh_count
LONG ukn21_offset // offsets to another table, that then offsets to mesh names
LONG ukn22 //always 0?
LONG ukn23 //always 0?
LONG ukn24 //always 0?
LONG ukn25 //always 0?
}

buffer_table {
LONG vert_offset // offset to vertex buffer
LONG ukn33 // offset to vertex colour buffer?
LONG ukn34 // always 0?
LONG ukn35 // always 0?
LONG num_verts
LONG face_offset
LONG num_faces
}

element_table {
LONG buffer_index
LONG vert_start
LONG face_start
LONG vert_count
LONG face_count
}

material_table {
LONG ukn31_table_offset
LONG count
LONG ukn33
LONG ukn34
LONG ukn35
LONG ukn36
LONG ukn37
LONG ukn38
}

ukn31_table {
LONG index
LONG name_index
SHORT ukn40
SHORT ukn41
LONG ukn42
}
vertex_def { // stride either 24 or 32, based off flag from WMB4 header? unconfirmed
FLOAT32 pos_x
FLOAT32 pos_x
FLOAT32 pos_x
FLOAT16 tex_u
FLOAT16 tex_v
}

WTA Format "WonderfulTextureAddresses"??
Description:
I only document the header not the tables after, sorry.. but the tables are nearly self-explainitory
wta_header { // all offsets relative to begining of WTA header
LONG magic // "WTB"
LONG version // ?
LONG count
LONG offset_texture_offsets
LONG offset_texture_sizes
LONG offset_flag_data
LONG offset_file_hashes
LONG offset_XPR2_headers
}
Luigi's CPK BMS

Code: Select all

# CRI CPK archives (script 0.2.2)
#   derived from cpk_unpack of hcs (http://hcs64.com/vgm_ripping.html)
# script for QuickBMS http://quickbms.aluigi.org

quickbmsver 0.3.12
endian big
comtype cpk

idstring "CPK "

set query->offset long 0
set query->index long 0
set query->name string "TocOffset"
callfunction query_utf 1
set toc_offset long UTF_VALUE

set query->offset long 0
set query->index long 0
set query->name string "ContentOffset"
callfunction query_utf 1
set content_offset long UTF_VALUE

set query->offset long 0
set query->index long 0
set query->name string "Files"
callfunction query_utf 1
set CpkHeader_count long UTF_VALUE

goto toc_offset
getdstring signature 4
if signature != "TOC "
    print "TOC signature not found"
    cleanexit
endif

set query->offset long toc_offset
set query->index long 0
set query->name string ""
callfunction query_utf 1
set CpkHeader_count long UTF_VALUE
set toc_entries long table_info.rows    # it remains saved after the call

if content_offset < 0           # "if" can't be unsigned
    set add_offset long toc_offset
elif toc_offset < 0
    set add_offset long content_offset
elif content_offset < toc_offset
    set add_offset long content_offset
else
    set add_offset long toc_offset
endif

for mytoc = 0 < toc_entries
    set query->offset long toc_offset
    set query->index long mytoc
    set query->name string "DirName"
    callfunction query_utf 1
    set file_name string UTF_VALUE

    set query->offset long toc_offset
    set query->index long mytoc
    set query->name string "FileName"
    callfunction query_utf 1
    set file_name2 string UTF_VALUE

    string file_name += /
    string file_name += file_name2

    set query->offset long toc_offset
    set query->index long mytoc
    set query->name string "FileSize"
    callfunction query_utf 1
    set file_size long UTF_VALUE

    set query->offset long toc_offset
    set query->index long mytoc
    set query->name string "ExtractSize"
    callfunction query_utf 1
    set extract_size long UTF_VALUE

    set query->offset long toc_offset
    set query->index long mytoc
    set query->name string "FileOffset"
    callfunction query_utf 1
    set file_offset long UTF_VALUE

    math file_offset += add_offset
    if extract_size > file_size
        clog file_name file_offset file_size extract_size
    else
        log file_name file_offset file_size
    endif
next mytoc



startfunction query_utf
    set COLUMN_STORAGE_MASK        long 0xf0
    set COLUMN_STORAGE_PERROW      long 0x50
    set COLUMN_STORAGE_CONSTANT    long 0x30
    set COLUMN_STORAGE_ZERO        long 0x10
    set COLUMN_TYPE_MASK           long 0x0f
    set COLUMN_TYPE_DATA           long 0x0b
    set COLUMN_TYPE_STRING         long 0x0a
    set COLUMN_TYPE_FLOAT          long 0x08
    set COLUMN_TYPE_8BYTE2         long 0x07
    set COLUMN_TYPE_8BYTE          long 0x06
    set COLUMN_TYPE_4BYTE2         long 0x05
    set COLUMN_TYPE_4BYTE          long 0x04
    set COLUMN_TYPE_2BYTE2         long 0x03
    set COLUMN_TYPE_2BYTE          long 0x02
    set COLUMN_TYPE_1BYTE2         long 0x01
    set COLUMN_TYPE_1BYTE          long 0x00

    set UTF_VALUE string ""
    math offset = query->offset
    math offset += 0x10     # needed by the tool
    goto offset

    set table_info.table_offset long offset
    getdstring UTF_signature 4
    if UTF_signature != "@UTF"
        print "not a @UTF table at %offset%"
        cleanexit
    endif
    get table_info.table_size long
    set table_info.schema_offset long 0x20
    get table_info.rows_offset long
    get table_info.string_table_offset long
    get table_info.data_offset long
    get table_name_string long
    get table_info.columns short
    get table_info.row_width short
    get table_info.rows long

    for i = 0 < table_info.columns
        get schema.type byte
        get schema.column_name long
        putarray 0 i schema.type
        putarray 1 i schema.column_name
        putarray 2 i -1     # schema.constant_offset

        math TMP = schema.type
        math TMP &= COLUMN_STORAGE_MASK
        if TMP == COLUMN_STORAGE_CONSTANT
            savepos schema.constant_offset
            putarray 2 i schema.constant_offset

            math TMP = schema.type
            math TMP &= COLUMN_TYPE_MASK
            if TMP == COLUMN_TYPE_STRING
                getdstring DUMMY 4
            elif TMP == COLUMN_TYPE_DATA
                getdstring DUMMY 8
            elif TMP == COLUMN_TYPE_FLOAT
                getdstring DUMMY 4
            elif TMP == COLUMN_TYPE_8BYTE2
                getdstring DUMMY 8
            elif TMP == COLUMN_TYPE_8BYTE
                getdstring DUMMY 8
            elif TMP == COLUMN_TYPE_4BYTE2
                getdstring DUMMY 4
            elif TMP == COLUMN_TYPE_4BYTE
                getdstring DUMMY 4
            elif TMP == COLUMN_TYPE_2BYTE2
                getdstring DUMMY 2
            elif TMP == COLUMN_TYPE_2BYTE
                getdstring DUMMY 2
            elif TMP == COLUMN_TYPE_1BYTE2
                getdstring DUMMY 1
            elif TMP == COLUMN_TYPE_1BYTE
                getdstring DUMMY 1
            else
                print "unknown type for constant"
                cleanexit
            endif
        endif
    next i

    math TMP = table_info.string_table_offset
    math TMP += 8
    math TMP += offset
    math string_table_size = table_info.data_offset
    math string_table_size -= table_info.string_table_offset
    log MEMORY_FILE TMP string_table_size

    for i = query->index < table_info.rows
        math TMP = i
        math TMP *= table_info.row_width
        math row_offset = table_info.table_offset
        math row_offset += 8
        math row_offset += table_info.rows_offset
        math row_offset += TMP

        for j = 0 < table_info.columns
            getarray type 0 j
            getarray column_name 1 j
            getarray constant_offset 2 j

            if constant_offset >= 0
                math data_offset = constant_offset
            else
                math data_offset = row_offset
            endif

            math TMP = type
            math TMP &= COLUMN_STORAGE_MASK
            if TMP == COLUMN_STORAGE_ZERO
                set value long 0
            else
                goto data_offset
                math TMP = type
                math TMP &= COLUMN_TYPE_MASK
                if TMP == COLUMN_TYPE_STRING
                    get string_offset long
                    goto string_offset MEMORY_FILE
                    get value string MEMORY_FILE
                elif TMP == COLUMN_TYPE_DATA
                    get vardata_offset long
                    get vardata_size long
                    goto vardata_offset MEMORY_FILE
                    getdstring value vardata_size MEMORY_FILE
                elif TMP == COLUMN_TYPE_FLOAT
                    get value long
                elif TMP == COLUMN_TYPE_8BYTE2
                    get DUMMY long  # no 64 bit support!
                    get value long
                elif TMP == COLUMN_TYPE_8BYTE
                    get DUMMY long  # no 64 bit support!
                    get value long
                elif TMP == COLUMN_TYPE_4BYTE2
                    get value long
                elif TMP == COLUMN_TYPE_4BYTE
                    get value long
                elif TMP == COLUMN_TYPE_2BYTE2
                    get value short
                elif TMP == COLUMN_TYPE_2BYTE
                    get value short
                elif TMP == COLUMN_TYPE_1BYTE2
                    get value byte
                elif TMP == COLUMN_TYPE_1BYTE
                    get value byte
                else
                    print "unknown normal type"
                    cleanexit
                endif

                if constant_offset < 0
                    savepos row_offset  # row_offset += bytes_read
                endif
            endif

            goto column_name MEMORY_FILE
            get column_name string MEMORY_FILE
            if column_name == query->name
                set UTF_VALUE string value  # result.value.value (qthis)
                math i = table_info.rows    # break
                math j = table_info.columns # break
            endif
        next j
    next i
endfunction
My MaxScript

Code: Select all

fsource = GetOpenFileName \
caption:"Select a File" \
types: "All files (*.*)|*.dat|"

delete $*

tristrip = false


fn readBElong fstream = (bit.swapBytes (bit.swapBytes (readlong fstream #unsigned) 1 4) 2 3)
fn readBEshort fstream = (bit.swapBytes (readshort fstream #unsigned) 1 2)
fn readBEtriplet fstream = (((readbyte f #unsigned)*0x00010000)+((readbyte f #unsigned)*0x00000100)+((readbyte f #unsigned)*0x00000001))
fn ReadBEfloat fstream = (
bit.intAsFloat (bit.swapBytes (bit.swapBytes (readlong fstream #unsigned) 1 4) 2 3)
)
fn readBEHalfFloat fstream = (
hf=bit.swapBytes (readshort fstream #unsigned) 1 2
sign = bit.get hf 16
exponent = (bit.shift (bit.and hf (bit.hexasint "7C00")) -10) as integer - 16
fraction = bit.and hf (bit.hexasint "03FF")
if sign==true then sign = 1 else sign = 0
exponentF = exponent + 127
outputAsFloat = bit.or (bit.or (bit.shift fraction 13) \
(bit.shift exponentF 23)) (bit.shift sign 31)
return bit.intasfloat outputasfloat*2)
fn readFixedString bstream fixedLen = (
local str = ""
for i = 1 to fixedLen do (
str += bit.intAsChar (ReadByte bstream #unsigned))
str
)
fn writeBElong fstream num = (
writelong fstream (bit.swapBytes (bit.swapBytes (num) 1 4) 2 3) #unsigned)
fn paddstring len instring = (
instring=instring as string
local str="";if instring.count <=len then(
for i = 1 to (len-instring.count) do(str+="0")
str = (str+instring))else(
for i = 1 to len do(str+="0";str[i]=instring[i]));str
)
fn uppercase instring = (
local upper, lower, outstring
upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lower="abcdefghijklmnopqrstuvwxyz"
outstring=copy instring
for i=1 to outstring.count do (
j=findString lower outstring[i]
if (j != undefined) do outstring[i]=upper[j])
outstring)
fn printblockpos bname badr = (
str=((bit.intAsHex badr)as string)
if str[str.count]=="L" do(str = substring str 1 (str.count-1))
format "% @ 0xDD%\n" bname (paddstring 6 (uppercase str))
)
fn printblockpos bname badr = (
str=((bit.intAsHex badr)as string)
if str[str.count]=="L" do(str = substring str 1 (str.count-1))
format "% @ 0x%\n" bname (paddstring 8 (uppercase str))
)
fn writeDDSheader fstream texW texH texM texC = (
texP=0
writelong fstream 0x20534444 #unsigned -- File ID
writelong fstream 0x7C #unsigned -- Header Size
case of( -- dwFlags
(texC==#DXT1): (writelong fstream 0x00081007 #unsigned;texP=((texW*texH)/0x02))
(texC==#DXT3): (writelong fstream 0x00081007 #unsigned;texP=(texW*texH))
(texC==#DXT5): (writelong fstream 0x00081007 #unsigned;texP=(texW*texH))
(texC==#ATI1): (writelong fstream 0x000A1007 #unsigned;texP=((texW*texH)/0x20))
(texC==#ATI2): (writelong fstream 0x000A1007 #unsigned;texP=(texW*texH))
(texC==#P8): (writelong fstream 0x000A1007 #unsigned;texP=((texW*texH)/0x02))
(texC==#ARGB16): (writelong fstream 0x00081007 #unsigned;texP=(((texW*texH)/0x8)*0x10))
(texC==#ARBG32): (writelong fstream 0x00081007 #unsigned;texP=(((texW*texH)/0x4)*0x10)))
writelong fstream texW #unsigned -- Texture Width
writelong fstream texH #unsigned -- Texture Height
writelong fstream texP #unsigned -- Pitch (#of bytes in a single row across the texture)
writelong fstream 0x00 #unsigned -- Image Depth? Not Used, for Image Volume
writelong fstream texM #unsigned -- Texture MIP Count
for i = 1 to 11 do writelong fstream 0x00 #unsigned -- Reserved Space
writelong fstream 0x20 #unsigned -- Size of PIXEL_FORMAT info, always 32bytes;
case of(
(texC==#DXT1): (writelong fstream 0x04;writelong fstream 0x31545844 #unsigned
writelong s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writelong fstream 0x00001000 #unsigned)
(texC==#DXT3): (writelong fstream 0x04;writelong fstream 0x33545844 #unsigned
writelong s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte s 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned)
(texC==#DXT5): (writelong fstream 0x04;writelong fstream 0x35545844 #unsigned
writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned)
(texC==#ATI1): (writelong fstream 0x04;writelong fstream 0x31495441 #unsigned
writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned)
(texC==#ATI2): (writelong fstream 0x04;writelong fstream 0x32495441 #unsigned
writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned)
(texC==#P8): (writelong fstream 0x20;writelong fstream 0x20203850 #unsigned
writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned)
(texC==#ARGB16): (writelong fstream 0x41;writelong fstream 0x00000000 #unsigned
writelong fstream 0x10;writebyte fstream 0x00;writebyte fstream 0x0F;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0xF0;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x0F;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xF0;writebyte fstream 0x00
writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned)
(texC==#ARBG32): (writelong fstream 0x41;writelong fstream 0x00000000 #unsigned
writelong fstream 0x20;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xFF
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xFF;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0xFF;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
writebyte fstream 0xFF;writelong fstream 0x00001000 #unsigned))
for i = 1 to 4 do writelong fstream 0x00 #unsigned -- Reserved Space for CAPS
)
fn Get_PS3FORMAT id = (
case id of ( -- replaced a few from offical ones, for backwards compatiblity
0x86: #DXT1
0x88: #DXT5
default: #UNKNOWN
)
)

if (fsource!=undefined) then (
fpath=getFilenamePath fsource
fname=getFilenameFile fsource
fsize=getFileSize fsource
fext=getFilenameType fsource
if ((doesFileExist fsource)==true) then (
clearlistener ()
f = fopen fsource "rb"



struct package_resource (offset,type,name,size,data)
struct model_binary_4 (header,buffer,element,skeleton,ukn10,ukn11,material,ukn12,mesh)
struct model_binary_4_header (magic,ukn01,ukn02,ukn03,ukn04,ukn05,info,ukn06,ukn07,ukn08,ukn09)
struct offset_and_count (offset,count)
datArray = (package_resource \
	offset:#() \
	type:#() \
	name:#() \
	size:#() \
	data:#())

case (readFixedString f 4) of (
"DAT":(
dat_offsets = #()

dat_01 = readBElong f -- count: files
dat_02 = readBElong f -- offset: offset table
dat_03 = readBElong f -- offset: extension table
dat_04 = readBElong f -- offset: name table
dat_05 = readBElong f -- offset: size table
dat_06 = readBElong f -- offset: ?? unknown data
dat_07 = readBElong f -- Blank? Reserved?

fseek f dat_02 #seek_set
for i = 1 to dat_01 do (datArray.offset[i] = readBElong f)
fseek f dat_03 #seek_set
for i = 1 to dat_01 do (datArray.type[i] = uppercase (readFixedString f 4))
fseek f dat_04 #seek_set;str_len = readBElong f
for i = 1 to dat_01 do (datArray.name[i] = readFixedString f str_len)
fseek f dat_05 #seek_set
for i = 1 to dat_01 do (datArray.size[i] = readBElong f)
for i = 1 to dat_01 do (datArray.data[i] = #())
for d = 1 to dat_01 do (
fseek f datArray.offset[d] #seek_set
case datArray.type[d] of (
"WTA":(
ukn00 = readBElong f -- "WTB"
ukn01 = readBElong f -- version?
ukn02 = readBElong f -- count
ukn03 = (readBElong f)+datArray.offset[d] -- offset to texture offsets
ukn04 = (readBElong f)+datArray.offset[d] -- offset to texture sizes
ukn05 = (readBElong f)+datArray.offset[d] -- offset to flag data?
ukn06 = (readBElong f)+datArray.offset[d] -- offset to file hashes?
ukn07 = (readBElong f)+datArray.offset[d] -- offset to XPR2 headers


fn stringtobytes str fstream= (
str = str as string
for t = 1 to 24 do (
if t<=str.count then (
writebyte fstream (bit.charAsInt str[t]) #unsigned
)else(writebyte fstream 0)
)
)
	


for i = 1 to ukn02 do (
g = fopen (fpath+fname+".dtt") "rb"
s = fopen (fpath+fname+(paddstring 3 (i as string))+".xpr") "wb"

fseek f (ukn03+((i-1)*4)) #seek_set
pos = readBElong f
fseek f (ukn04+((i-1)*4)) #seek_set
dumpsize = readBElong f

fseek g (pos+0x1000) #seek_set

writeBElong s 0x58505232
writeBElong s 0x00000800
writeBElong s dumpsize
writeBElong s 0x00000001
writeBElong s 0x54583244
writeBElong s 0x00000030
writeBElong s 0x00000034
writeBElong s 0x00000018
writeBElong s 0x00000000
stringtobytes (fname+(paddstring 3 (i as string))) s
fseek f (ukn07+((i-1)*(4*13))) #seek_set
for x = 1 to (4*11) do (writebyte s (readbyte f #unsigned) #unsigned)
writeBElong s 0x00000000
writeBElong s 0x00000A00
for x = 1 to 1948 do (writebyte s 0)
for x = 1 to dumpsize do (writebyte s (readbyte g #unsigned) #unsigned)

fclose s
fclose g
)
)
"WTA (PS3)":( -- disabled
ukn00 = readBElong f -- "WTB"
ukn01 = readBElong f -- version?
ukn02 = readBElong f -- count
ukn03 = (readBElong f)+datArray.offset[d] -- offset to texture offsets
ukn04 = (readBElong f)+datArray.offset[d] -- offset to texture sizes
ukn05 = (readBElong f)+datArray.offset[d] -- offset to flag data?
ukn06 = (readBElong f)+datArray.offset[d] -- offset to file hashes?
ukn07 = (readBElong f)+datArray.offset[d] -- offset to XPR2 headers

for i = 1 to ukn02 do (
ssource = (fpath+fname+".dtt")
if ((doesFileExist ssource)==true) then (
g = fopen ssource "rb"
s = fopen (fpath+fname+(paddstring 3 (i as string))+".dds") "wb"
fseek f (ukn03+((i-1)*4)) #seek_set;pos = readBElong f
fseek f (ukn04+((i-1)*4)) #seek_set;dumpsize = readBElong f
fseek g (pos+0x1000) #seek_set
struct gft_header (
magic, -- "0x02010100" Version, possibly a fourcc
streamsize,
num_textures, -- forced to 1? :-P
ukn02, -- always 0?
stream_offset,
ukn03, -- offsets to end of stream?
d3d_format, -- fourCC, probably describes d3d compression
ukn04, --offset?
height,
width,
depth,
ukn05, -- always 0?
null -- reserved space
)
gftArray = (gft_header \
magic:(readBElong g) \
streamsize:(readBElong g) \
num_textures:(readBElong g) \
ukn02:(readBElong g) \
stream_offset:(readBElong g) \
ukn03:(readBElong g) \
d3d_format:([(readbyte g #unsigned),(readbyte g #unsigned),(readbyte g #unsigned),(readbyte g #unsigned)]) \
ukn04:(readBElong g) \ --remap?
height:(readBEshort g) \
width:(readBEshort g) \
depth:(readBEshort g) \
ukn05:(readBEshort g) \
null:#() \
);fseek g 88 #seek_cur
format "%: (% x %) \tFormat:%\n" (paddstring 3 i) (paddstring 4 gftArray.width) (paddstring 4 gftArray.height) gftArray.d3d_format
writeDDSheader s gftArray.width gftArray.height 1 (Get_D3DFORMAT gftArray.d3d_format[1])
for x = 1 to dumpsize do (writebyte s (readbyte g #unsigned) #unsigned)

fclose s
fclose g
)else(messagebox "failed to find relating dtt file")
)
)
"WMB":(magic = uppercase (readFixedString f 4)
case magic of (
"WMB4":(


ukn01 = readBElong f -- always -1
ukn02a = readBEshort f -- vertex stride?: 0x00 = 24 | 0x01 = 32
ukn02b = readBEshort f
ukn03a = readBEshort f -- primitive type flag 0x00=trilist | 0x01= trilist
ukn03b = readBEshort f
ukn04 = readBElong f
ukn05 = readBElong f
ukn06 = readBElong f
ukn07 = readBElong f
ukn08 = readBElong f
ukn09 = readBElong f

ukn10 = (readBElong f)+datArray.offset[d] -- offset to vertex buffer header offset? lol

ukn11 = readBElong f -- unknown count?

ukn12 = (readBElong f)+datArray.offset[d] -- offset to unknown data, after faces buffer
ukn13 = readBElong f

ukn14 = (readBElong f)+datArray.offset[d]

ukn15 = (readBElong f)+datArray.offset[d]
ukn16 = readBElong f

ukn17 = (readBElong f)+datArray.offset[d]
ukn18 = readBElong f

ukn19 = (readBElong f)+datArray.offset[d]
ukn20 = readBElong f

ukn21 = (readBElong f)+datArray.offset[d]
ukn22 = readBElong f

ukn23 = (readBElong f)+datArray.offset[d]
ukn24 = readBElong f

ukn25 = (readBElong f)+datArray.offset[d]
ukn26 = readBElong f

ukn27 = (readBElong f)+datArray.offset[d] -- offsets to another table, that then offsets to mesh names

ukn28 = readBElong f -- always 0?
ukn29 = readBElong f -- always 0?
ukn30 = readBElong f -- always 0?
ukn31 = readBElong f -- always 0?




bufferArray = #()
printblockpos ("Mesh/Buffer Table: ("+(ukn11 as string)+")") ukn10
fseek f ukn10 #seek_set
for i = 1 to ukn11 do (
vert_offset = (readBElong f)+datArray.offset[d] -- offset to vertex buffer
ukn33 = (readBElong f)+datArray.offset[d] -- offset to colour buffer
ukn34 = readBElong f -- always 0?
ukn35 = readBElong f -- always 0?
num_verts = readBElong f
face_offset = (readBElong f)+datArray.offset[d]
num_faces = readBElong f -- count
bufferArray[i]=[num_verts,num_faces,vert_offset,face_offset]
printblockpos "Vert" vert_offset
printblockpos "Face" face_offset	
)
printblockpos "\tMesh/Buffer Table END" (ftell f);format "\n"

printblockpos "Buffers" (bufferArray[1][3]);format "\n"




printblockpos ("Element Table: ("+(ukn13 as string)+")") ukn12
fseek f ukn12 #seek_set
struct element (buffer_index,vert_start,face_start,vert_count,face_count)
mshArray=(element buffer_index:#() vert_start:#() face_start:#() vert_count:#() face_count:#())
for i = 1 to ukn13 do (
mshArray.buffer_index[i] = (readBElong f)+1 -- buffer index
mshArray.vert_start[i] = readBElong f -- vert start
mshArray.face_start[i] = readBElong f -- face start
mshArray.vert_count[i] = readBElong f -- vert count
mshArray.face_count[i] = readBElong f -- face count
format "%\n" mshArray.buffer_index[i]
)
printblockpos "\tElement Table END" (ftell f);format "\n"


fseek f ukn14 #seek_set
ukn31 = (readBElong f)+datArray.offset[d]
ukn32 = readBElong f -- count
ukn33 = readBElong f -- always 0?
ukn34 = readBElong f -- always 0?
ukn35 = readBElong f -- always 0?
ukn36 = readBElong f -- always 0?
ukn37 = readBElong f -- always 0?
ukn38 = readBElong f -- always 0?
printblockpos ("Material Names?: ("+(ukn32 as string)+")") ukn14
fseek f ukn31 #seek_set
for i = 1 to ukn32 do (
ukn38 = readBElong f -- index
ukn39 = readBElong f -- indexing to name
ukn40a = readBEshort f -- flag?
ukn40b = readBEshort f -- flag?
ukn41 = readBElong f -- always 0x00 01 00 00 ?
format "% | % | % | %\n" ukn39 ukn39 ukn40a ukn40b
)
printblockpos "\tMaterial Names? END" (ftell f);format "\n"


printblockpos ("Bones: ("+(ukn16 as string)+")") ukn15
fseek f ukn15 #seek_set
for i = 1 to ukn16 do ( -- bones?
ukn42 = readBEshort f -- ???
ukn43 = readBEshort f -- ???
ukn44 = readBEshort f -- parent
ukn45 = readBEshort f -- always 0?
ukn46 = readBEfloat f -- position?
ukn47 = readBEfloat f
ukn48 = readBEfloat f
ukn49 = readBEfloat f
ukn50 = readBEfloat f
ukn51 = readBEfloat f
)
printblockpos "\tBones END" (ftell f);format "\n"

printblockpos ("Block5: ("+(ukn18 as string)+")") ukn17
fseek f ukn17 #seek_set
for i = 1 to ukn18 do (
ukn52 = readbyte f #unsigned --? float, divide by 0xFF
)
printblockpos "\tBlock5 END" (ftell f);format "\n"

printblockpos ("Block6: ("+(ukn20 as string)+")") ukn19
fseek f ukn19 #seek_set
tempArray = #()
for i = 1 to ukn20 do (
ukn53 = (readBElong f)+datArray.offset[d]
ukn54a = readbyte f #unsigned -- count
ukn54b = readbyte f #unsigned -- 0?
ukn54c = readbyte f #unsigned -- 0?
ukn54d = readbyte f #unsigned -- 0?
tempArray[i] = [ukn53,ukn54a]
)
for i = 1 to ukn20 do (
fseek f tempArray[i][1] #seek_set
for x = 1 to tempArray[i][2] do (
ukn57 = readbyte f #unsigned -- indexes
)
)
printblockpos "\tBlock6 END" (ftell f);format "\n"

printblockpos ("Material Table?: ("+(ukn22 as string)+")") ukn21
fseek f ukn21 #seek_set
for i = 1 to ukn22 do (
ukn58 = (readBElong f)+datArray.offset[d] -- offset to string
ukn59 = (readBElong f)+datArray.offset[d] -- offset to stuff after string
ukn60 = readBElong f -- always 0?
ukn61 = (readBElong f)+datArray.offset[d] -- offset to matrix data?
ukn62 = readBEshort f
ukn63 = readBEshort f
ukn64 = readBEshort f
ukn65 = readBEshort f -- string count
)
printblockpos "\tMaterial Table? END" (ftell f);format "\n"

printblockpos ("Block8: ("+(ukn24 as string)+")") ukn23
fseek f ukn23 #seek_set
for i = 1 to ukn24 do (
ukn66 = readBElong f -- count?
ukn67 = readBElong f -- float or hash?
)
printblockpos "\tBlock8 END" (ftell f);format "\n"

printblockpos ("Mesh Properties: ("+(ukn26 as string)+")") ukn25
pos = ukn25
nameArray=#()
for i = 1 to ukn26 do (
fseek f pos #seek_set
ukn68 = (readBElong f)+datArray.offset[d] -- offset to name
ukn69 = readBEfloat f -- position ?
ukn70 = readBEfloat f
ukn71 = readBEfloat f
ukn72 = readBEfloat f -- rotation ?
ukn73 = readBEfloat f
ukn74 = readBEfloat f
ukn75 = (readBElong f)+datArray.offset[d] -- offset to index data that comes after name
ukn76 = readBElong f -- count for above offset
ukn77 = readBElong f -- 0?
ukn78 = readBElong f -- 0?
ukn79 = readBElong f -- 0?
ukn80 = readBElong f -- 0?
ukn81 = readBElong f -- 0?
ukn82 = readBElong f -- 0?
ukn83 = (readBElong f)+datArray.offset[d] -- offset to index data that comes after name
ukn84 = readBElong f -- count for above offset
pos = ftell f
fseek f ukn68 #seek_set
mshName = (readstring f);print mshName
append nameArray mshName
fseek f ukn75 #seek_set
for x = 1 to ukn76 do (
ukn85 = (readBEshort f)+1
)
fseek f ukn83 #seek_set
for x = 1 to ukn84 do (
ukn86 = (readBEshort f)+1
)
)
printblockpos "\tBlock9 END" (ftell f);format "\n"


if ukn03a == 1 do (tristrip = true)
-- ukn13=0 --ignore faces
for i = 1 to ukn13 do (
vertArray=#()
normArray=#()
uvwArray=#()
faceArray=#()
matidArray=#()


num_verts=mshArray.vert_count[i] --bufferArray[(mshArray.buffer_index[i])][1]
num_faces=mshArray.face_count[i] --bufferArray[(mshArray.buffer_index[i])][2]

-- num_verts=bufferArray[(mshArray.buffer_index[i])][1]
-- num_faces=bufferArray[(mshArray.buffer_index[i])][2]

vert_offset=bufferArray[(mshArray.buffer_index[i])][3]
face_offset=bufferArray[(mshArray.buffer_index[i])][4]
-- stride = ((face_offset-vert_offset)/num_verts) as integer
-- format "Calculated Stride: %\n" stride
case ukn02a of (
0x00:(stride = 24)
0x01:(stride = 32)
default:(stride = 32;format "New Stride: %\n" ukn02a)
)
stride = 32

vert_offset+=mshArray.vert_start[i]*stride
face_offset+=mshArray.face_start[i]*2





fseek f vert_offset #seek_set
for x = 1 to num_verts do (
pos = (ftell f)+stride
vx = ReadBEfloat f
vy = ReadBEfloat f
vz = ReadBEfloat f
tu = readBEHalfFloat f
tv = readBEHalfFloat f
-- nx = ReadBEfloat f
-- ny = ReadBEfloat f
-- nz = ReadBEfloat f
-- b1 = readbyte f #unsigned
-- b2 = readbyte f #unsigned
-- b3 = readbyte f #unsigned
-- b4 = readbyte f #unsigned
-- w1 = (readbyte f #unsigned)/255.0
-- w2 = (readbyte f #unsigned)/255.0
-- w3 = (readbyte f #unsigned)/255.0
-- w4 = (readbyte f #unsigned)/255.0
append vertArray ([vx,-vz,vy]*100)
append uvwArray [tu,(1-tv),0]
fseek f pos #seek_set
)






fseek f face_offset #seek_set

format "% Faces % + % @ 0x%\n" i num_faces num_verts ((bit.intAsHex(ftell f))as string)


fa=fb=fc=1
face_flip = false
face_reset = true
face_add = 1
if tristrip == true then (

x=1;while x<= num_faces do (x+=1
if face_reset == true then (
x+=2;face_reset=false;face_flip = false;append matidArray i
fa = (ReadBEshort f) + face_add
fb = (ReadBEshort f) + face_add
fc = (ReadBEshort f) + face_add
if face_flip == true then (append faceArray [fa,fb,fc];face_flip=false)
else(append faceArray [fa,fc,fb];face_flip=true)
)else(fa = fb;fb = fc;fc = ReadBEshort f
if fc!=0xFFFF then (fc += face_add;append matidArray i
if face_flip == true then (append faceArray [fa,fb,fc];face_flip=false)
else(append faceArray [fa,fc,fb];face_flip=true)
)else(face_reset=true)
)
)

)else(

for x = 1 to (num_faces/3) do (
fa = (ReadBEshort f) + face_add
fb = (ReadBEshort f) + face_add
fc = (ReadBEshort f) + face_add
faceArray[x]=[fa,fc,fb]
matidArray[x]=i
)

)

-- while IndexCounter !=num_faces
format "\t\t\t\t\tFaceEnd @ 0x%\n" ((bit.intAsHex(ftell f))as string)


-- faceArray=#()
msh = mesh vertices:vertArray tverts:uvwArray faces:faceArray --materialIDs:matidArray
buildTVFaces msh
-- msh.name = nameArray[i]
msh.material = multimaterial numsubs:ukn13
msh.displayByLayer = false
msh.backfacecull = on
msh.wirecolor = random (color 0 0 0) (color 255 255 255)
-- convertTo msh PolyMeshObject
-- select msh
-- subobjectLevel = 1
for j = 1 to uvwArray.count do setTVert msh j uvwArray[j]
for j = 1 to faceArray.count do setTVFace msh j faceArray[j]
for j = 1 to msh.material.count do (msh.material.materialList[j].Diffuse = random (color 0 0 0) (color 255 255 255))
)





















)
default:(printblockpos ("WMB Not Supported: "+magic) datArray.offset[d])
)
)
default:(printblockpos ("Type Unknown: "+datArray.type[d]) datArray.offset[d])
)
)
)
default:(format "File Unknown: %\n" (magic as string))
)
format "Last Read @ 0x%\n" ((bit.intAsHex(ftell f))as string)
format "Flie Closed: %\n" fname
fclose f
) else (Print "Failed to Locate File")) else (Print "Aborted.")
Maxscript and other finished work I've done can be found on my DeviantArt account
yanneric
ultra-n00b
Posts: 7
Joined: Sat Oct 29, 2011 11:15 pm
Has thanked: 3 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by yanneric »

really impressive, great job and thanks for explanations...
howfie
double-veteran
double-veteran
Posts: 929
Joined: Fri Jul 08, 2011 12:06 pm
Location: Torrance, CA
Has thanked: 10 times
Been thanked: 274 times

Re: PS3 - Metal Gear Rising Revengeance - WMB format

Post by howfie »

lol @mariokart
i almost ate up all my popcorn reading that facepunch thread.
u would think after all stuff that happened with chrrox over there u'd think twice about posting there hahaha.
Post Reply