Hacking I need help extracting Transformer Decepticons DS (2007) models and maps

atlastico001

New Member
Newbie
Joined
Jun 14, 2026
Messages
1
Reaction score
0
Trophies
0
Age
23
XP
8
Country
Puerto Rico
I have tried to decompress and extract the files from the NDS file but nothing works and every attempt makes it even more confusing as to what sort of magic Activision placed on it.
the file including all the models is called mainDCUS.gob and there's another one called mainDCUS.gfc. Exploring inside of the .gob files reveals even more files like .layertiles, .meta, .mps and .pal. If anyone knows how to extract the models and maps please let me know. I'm interested in modding the game aswell
 
GFC functions as an index, and GOB is a compressed data package. I've already managed to extract all the internal files and locate the BINs of the dialogues, as my goal is to translate the game into Brazilian Portuguese.. Since the remaining resources are also within GOB, this tool likely also allows for extracting models and textures.All that remains is to identify the specific format of the BINs that store the models, if that works.

Code:
#!/usr/bin/env python3
argparse
os
importar
zlib
from pathlib import Path
Importar de coleções Contador

def parse_gfc(gfc_path: Path):
    dados = gfc_path.read_bytes()
    se len(dados) < 16:
        raise ValueError("GFC muito pequeno")
    magic, gob_size, num_clusters, num_files = struct.unpack(">IIII", data[:16])
    se magic != 0x8008:
        raise ValueError(f"GFC mágico inesperado: 0x{magic:08X}")
    clusters_off = 0x10
    checksum_off = clusters_off + num_clusters * 0x10
    arquivos_desativados = checksum_desativado + num_clusters * 4
    se files_off + num_files * 0x0C > len(data):
        raise ValueError("Os tamanhos das tabelas GFC excedem o comprimento do arquivo")
    clusters = []
    para o intervalo(num_clusters):
        comp_size, gob_off, nxt, comp = struct.unpack(">IIII", data[clusters_off + i*0x10 : clusters_off + (i+1)*0x10])
        clusters.append({
            "idx": eu,
            "comp_size": comp_size,
            "desligado": gob_off,
            "próximo": próximo,
            "comp": comp,
        })
    arquivos = []
    para i em range(num_files):
        crc, tamanho, primeiro = struct.unpack(">III", data[files_off + i*0x0C : files_off + (i+1)*0x0C])
        arquivos.append({
            "idx": eu,
            "crc": crc,
            "tamanho": tamanho,
            "primeiro": primeiro,
        })
    adquirir {
        "mágica": mágica,
        "tamanho_da_gota": tamanho_da_gota,
        "num_clusters": num_clusters,
        "num_files": num_files,
        "aglomerados": aglomerados,
        "arquivos": arquivos,
    }

def decompress_cluster(gob: bytes, cluster: dict) -> bytes:
    raw = gob[cluster["off"] : cluster["off"] + cluster["comp_size"]]
    comp_kind = (cluster["comp"] >> 24) & 0xFF
    se comp_kind == 0x7A e len(raw) >= 6:
        # Contêiner zlib, mas com o comportamento de checksum do jogo; descompactar carga útil DEFLATE bruto
        # Layout bruto: cabeçalho zlib de 2 bytes, fluxo DEFLATE, Adler32 de 4 bytes
        retornar zlib.decompress(raw[2:-4], wbits=-15)
    Relatar bruto

def reconstruir_arquivo(gob: bytes, clusters: lista, entrada_arquivo: dict, cache: dict) -> bytes:
    se file_entry["size"] == 0 ou file_entry["first"] == 0xFFFFFFFF:
        representar b""
    saída = bytearray()
    idx = file_entry["first"]
    visto = conjunto()
    enquanto Verdadeiro:
        se idx estiverem visto:
            raise RuntimeError(f"Ciclo detectado na cadeia de clusters em {idx}")
        se idx < 0 ou idx >= len(clusters):
            raise RuntimeError(f"Índice do cluster fora do intervalo: {idx}")
        visto.adicionar(idx)
        Se o índice não estiver em cache:
            cache[idx] = descomprimir_cluster(gob, clusters[idx])
        saída += cache[idx]
        nxt = clusters[idx]["next"]
        se nxt == 0x7FFF:
            quebrar
        idx = nxt
    retornar bytes(out[:file_entry["size"]])

def guess_ext(data: bytes) -> str:
    se data.startswith(b"<"):
        retornar ".xml"
    se data.startswith(b"RIFF"):
        retornar ".wav"
    se data.startswith(b"OggS"):
        retornar ".ogg"
    se data.startswith(b"\x89PNG\r\n\x1a\n"):
        retornar ".png"
    se data.startswith(b"BINK") ou data.startswith(b"bink"):
        retornar ".bik"
    se data.startswith(b"\x10\x00"):
        retornar ".lz77"
    se b"<raiz" em data[:256]:
        retornar ".xml"
    retornar ".bin"

def main():
    ap = argparse.ArgumentParser(description="Arquivos extras de arquivos VV .GFC/.GOB.")
    ap.add_argument("gfc", help="Caminho para main.gfc")
    ap.add_argument("gob", help="Caminho para main.gob")
    ap.add_argument("-o", "--out", default="extraído", help="Diretório de saída")
    ap.add_argument("--report", default="extract_report.txt", help="Caminho do arquivo de relatório")
    args = ap.parse_args()

    gfc_path = Path(args.gfc)
    gob_path = Path(args.gob)
    diretório_saída = Caminho(args.saída)
    out_dir.mkdir(parents=True, exist_ok=True)

    meta = parse_gfc(caminho_gfc)
    gob = gob_path.read_bytes()

    se len(gob) != meta["gob_size"]:
        print(f"[aviso] Tamanho do GOB incompatível: o cabeçalho diz {meta['gob_size']}, o arquivo tem {len(gob)}")

    cache = {}
    linhas = []
    linhas.append(f"GFC: {gfc_path}")
    linhas.append(f"GOB: {caminho_gob}")
    linhas.append(f"Clusters: {meta['num_clusters']}")
    linhas.append(f"Arquivos: {meta['num_files']}")
    linhas.append("")

    para f em meta["arquivos"]:
        dados = reconstruir_arquivo(gob, meta["clusters"], f, cache)
        ext = guess_ext(dados)
        nome = f"arquivo_{f['idx']:04d}_crc{f['crc']:08X}_tamanho{f['tamanho']:08X}{ext}"
        caminho = diretório_de_saída /nome
        caminho.escrever_bytes(dados)
        linhas.append(f"{nome} primeiro_cluster={f['primeiro']} tamanho={f['tamanho']}")
    (out_dir / args.report).write_text("\n".join(lines), encoding="utf-8")
    print(f"Extraídos {len(meta['files'])} arquivos para {out_dir}")

se __name__ == "__main__":
    principal()

Command : python vv_gfc_gob_extractor.py mainDCUS.gfc mainDCUS.gob
 
Last edited by thanossemluva,

Site & Scene News

Popular threads in this forum