• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

3DSMAX Script - Map Viewer [Unfinished]

Joined
Aug 27, 2013
Messages
800
Reaction score
1,969
After discussing with a friend, who made this and getting hit permission, I've decided to share this unfinished 3DSMAX script to view any Cabal Online Map.

This is ONLY a VIEWER! It cannot edit maps!

What it CAN DO:
  • View Maps in all angles.
  • Zoom in/out.

What it CANNOT DO:
  • Edit Maps
  • Add objects
  • Move Objects from their locations
  • Change anything!

PROBLEMS and UNFINISHED BITS (IMPORTANT!)
  • Messed up shaders, that's why maps are not displayed as they should be.
  • Object importer doesn't work - so no need Yamachi's Scripts to launch this one.

This script might give a head-start for some sort of a viewer launcher, and, although code is far from perfect, it's still better than nothing :8: If someone wants to finish it - go ahead!
If someone would be willing to fix it / if even worth it, hopefully, it will be shared with the community, not leeched away and/or sold behind the scenes.
:junglejane:​



Instructions [a.k.a. Quick Instalation]:
  • Launch 3DS Max, run script.
  • Or, place script into %LOCALAPPDATA%\Autodesk\3dsMax\3DS_MAX_VERSION\ENU\scripts\startup
  • Usage - SELF EXPLANATORY.
  • Enjoy using script

Copyright (c) The Leviathan Team 2016 and penetrator9000

\\=\\=\\ //=//=//

Image Preview​

[URL="
MrSensei - 3DSMAX Script - Map Viewer [Unfinished] - RaGEZONE Forums



Script code in spoiler

Code:
/*
 *            _ __      _________ 
 *           | |\ \    / /__   __|
 *           | | \ \  / /   | |   
 *           | |  \ \/ /    | |   
 *           | |___\  /     | |   
 *           |______\/      |_|   
 *           
 ---------------------------------------- 
 *         MCL Importer For 3DS Max
 *  Copyright (c) The Leviathan Team 2016
 *
 */
 
global import_flag = false
global CabalMCLTools
global hmap_bin
global tmap_bin

callbacks.removeScripts id:#resetImport

function readHeader pFile =
(
    print "(|) Loading..."
    readLong pFile #unsigned                                                         -- magic key 
    readFloat pFile; readFloat pFile; readFloat pFile                            -- unkv0
    readLong pFile #unsigned                                                        -- unkui0
    readFloat pFile; readFloat pFile; readFloat pFile                            -- unkv1
    readFloat pFile; readFloat pFile; readFloat pFile; readFloat pFile    -- unkq0
    readLong pFile #unsigned                                                        -- unkui1
    readFloat pFile; readFloat pFile; readFloat pFile; readFloat pFile    -- unkq1
    readLong pFile #unsigned                                                        -- unkui2
    readLong pFile #unsigned                                                        -- unkui3
    readLong pFile #unsigned                                                        -- unkui4    
    readFloat pFile; readFloat pFile; readFloat pFile                            -- unkv2
    readLong pFile #unsigned                                                        -- unkui5    
    readLong pFile #unsigned                                                        -- unkui6    
    readLong pFile #unsigned                                                        -- unkui7    
    readLong pFile #unsigned                                                        -- unkui8    
    readLong pFile #unsigned                                                        -- unkui9    
    readLong pFile #unsigned                                                        -- unkuiA    
    readLong pFile #unsigned                                                        -- unkuiB    
    readLong pFile #unsigned                                                        -- unkuiC
    readLong pFile #unsigned                                                        -- unkuiD
    readLong pFile                                                                     -- unki0
    print "(/) Loading..."
)

function readEffects pFile =
(
    print "(-) Loading..."
    effectCount = readLong pFile #unsigned
    
    for i = 1 to effectCount do
    (
        effectTextLen = readShort pFile #unsigned    -- text len
        fseek pFile effectTextLen #seek_cur            -- text
        readFloat pFile                                            -- unkf0
        readFloat pFile                                            -- unkf1
        readLong pFile #unsigned                            -- unkui0
        readLong pFile #unsigned                            -- unkui1
    )
    
    print "(\) Loading..."
)

function readTextures pFile =
(
    print "(|) Loading..."
    textureCount = readLong pFile #unsigned
    
    if import_flag == true then
        global in_materials = #()
    
    for i = 1 to textureCount do
    (
        size = readLong pFile #unsigned
        
        if size == 0
            do continue;
        
        texName = stringstream ""
        format "texture_%.dds" (i - 1) to:texName
        aout = (pathconfig.getdir #import) + "/" + texName
        pTexFile = fopen aout "wb"

        for j = 1 to size do
        (
            byte = readByte pFile
            writeByte pTexFile byte
        )
        
        fclose pTexFile
        
        if import_flag == true then
        (
            tex = openbitmap aout
            tex_bmp = bitmaptexture bitmap:tex
            
            local new_mat = standard name:texName
            new_mat.adlock = false
            new_mat.diffusemap = tex_bmp
            new_mat.showinviewport = true
            append in_materials new_mat
        )
    )
    
    print "(/) Loading..."
)

function readTileTextures pFile =
(
    print "(-) Loading..."
        
    for i = 1 to 64 do
    (
        size = readLong pFile #unsigned
        
        texName = stringstream ""
        format "tile_texture_%.dds" (i - 1) to:texName
        aout = (pathconfig.getdir #import) + "/" + texName
        pTexFile = fopen aout "wb"

        for j = 1 to size do
        (
            byte = readByte pFile
            writeByte pTexFile byte
        )
        
        fclose pTexFile
    )

    print "(\) Loading..."    
)

function readLayer pFile first symbol = 
(
    print symbol
    face_count = readLong pFile #unsigned
    vertex_count = readLong pFile #unsigned
    
    vertex = #()
    face = #()
    uv = #()
    vcolor = #()
    
    vertex.count = vertex_count
    face.count = face_count
    uv.count = vertex_count
    vcolor.count = vertex_count
    
    for i = 1 to vertex_count do
    (
        -- position
        x = readFloat pFile;
        y = readFloat pFile;
        z = readFloat pFile;
                
        if first then
        (
            -- vertex color
            r = readByte pFile #unsigned -- r
            g = readByte pFile #unsigned -- g
            b = readByte pFile #unsigned -- b
            a = readByte pFile #unsigned -- a
            vcolor[i] = [r, g, b, a]
        )

        -- uv
        uv_x = readFloat pFile;
        uv_y = readFloat pFile;
        
        vertex[i] = [x, y, z]
        uv[i] = [uv_x, uv_y, 0]
    )

    for i = 1 to face_count do
    (
        f1 = readshort pFile 
        f2 = readshort pFile
        f3 = readshort pFile
            
        face[i] = [f1 + 1, f2 + 1, f3 + 1]
    )
    
    local sbTextureId = #()
    local sbTextureIndex = #()
    
    sbTextureIndex.count = face_count
    sbTextureId.count = face_count
    
    prevTextureId = -1
    k = 1;
    
    for i = 1 to face_count do
    (
        texId = readLong pFile -- face texture id
        if prevTextureId != texId then
        (
            sbTextureIndex[k] = i - 1
            sbTextureId[k] = texId
            prevTextureId = texId
            k += 1
        )
    )

    usedTextures = readLong pFile

    for i = 1 to usedTextures do
    (
        readLong pFile    -- used texture id
    )
    
    if import_flag == false then
    (
        mapMesh = mesh vertices:vertex faces:face tverts:uv
                    
        if vertex_count > 0 then
            buildtvfaces mapMesh
        
        for j = 1 to mapMesh.numfaces do
            setTVFace mapMesh j (getFace mapMesh j)
        
        m = mirror()
        addModifier mapMesh m
        m.mirror_axis = 0
        rotate mapMesh (angleaxis 90 [1,0,0])
    )
    else
    (
        startIndex = 1
        endIndex = 1

        if k > 2 then
            endIndex = sbTextureIndex[2];
        else
            endIndex = k
            
        for i = 1 to k - 1 do
        (
            tmpFaces = #()
            tmpFaces.count = endIndex - startIndex

            tmpI = 1
            for j = startIndex to endIndex do
            (
                tmpFaces[tmpI] = face[j]
                tmpI = tmpI + 1    
            )
            
            mapMesh = mesh vertices:vertex faces:tmpFaces tverts:uv
                    
            if vertex_count > 0 then
                buildtvfaces mapMesh
        
            for j = 1 to mapMesh.numfaces do
                setTVFace mapMesh j (getFace mapMesh j)
            
            if first then
            (
                setNumCPVVerts mapMesh mapMesh.numverts
                defaultVCFaces mapMesh
                
                for j = 1 to vertex_count do
                    setVertColor mapMesh j vcolor[j]
            )

            mapMesh.material = in_materials[sbTextureId[i]]
            
            m = mirror()
            addModifier mapMesh m
            m.mirror_axis = 0
            
            rotate mapMesh (angleaxis 90 [1,0,0])
            
            startIndex = endIndex
            
            if i + 2 >= k then
                endIndex = face_count
            else
                endIndex = sbTextureIndex[i + 2]
        )
    )
)

function readTile pFile =
(
    print "(|) Loading..."
    symbolChange = 1
    
    for i = 1 to 64 do
    (
        if symbolChange == 1 then
        (
            symbol = "(-) Loading..."
            symbolChange = 2
        )
        else if symbolChange == 2 then
        (
            symbol = "(\) Loading..."
            symbolChange = 3
        )
        else if symbolChange == 3 then
        (
            symbol = "(|) Loading..."
            symbolChange = 4
        )
        else
        (
            symbol = "(/) Loading..."
            symbolChange = 1
        )
        
        readFloat pFile; readFloat pFile; readFloat pFile    -- bound min
        readFloat pFile; readFloat pFile; readFloat pFile    -- bound max        
        has1stLayer = readLong pFile
                
        if has1stLayer != 0 then
            readLayer pFile true symbol
        
        has2ndLayer = readLong pFile
        
        if has2ndLayer != 0 then
            readLayer pFile false symbol
    )    
    
    print "(/) Loading..."
)

function resetImportValue =
(
    if CabalMCLTools != undefined then
        CabalMCLTools.imported = false
)

function export_hmap pFile =
(
    if pFile == undefined then
        return messagebox "Please select a file to export!" title:"Error"
    
    hmapFile = fopen pFile "wb"
    
    for i = 1 to 264196 do
    (
        writeByte hmapFile hmap_bin[i]
    )
    
    fclose hmapFile    
    
    messagebox "Height Map exporting process is done!" title:"Done"
)

function export_tmap pFile =
(
    if pFile == undefined then
        return messagebox "Please select a file to export!" title:"Error"
        
    tmapFile = fopen pFile "wb"
    
    for i = 1 to 262144 do
    (
        writeByte tmapFile tmap_bin[i]
    )
    
    fclose tmapFile    
    
    messagebox "Thread Map exporting process is done!" title:"Done"
)

function readText pFile tLength =
(
    local result = ""
    
    -- Read each byte, convert it to a character, and append it to our string
    for i = 1 to tLength do
    (
        next_byte = readbyte pFile
        result += bit.intaschar(next_byte)
    )
    
    -- Return the resulting string
    result
)

function readFirstData pFile =
(
    modelCount = readLong pFile #unsigned        -- model count
    
    for i = 1 to modelCount do
    (
        textLength = readShort pFile #unsigned    -- text length
        fseek pFile textLength #seek_cur            -- text
        
        -- position
        posX = readFloat pFile; posY = readFloat pFile; posZ = readFloat pFile
        
        -- rotation
        rotX = readFloat pFile; rotY = readFloat pFile; rotZ = readFloat pFile; rotW = readFloat pFile
        
        -- scale
        scaleX = readFloat pFile; scaleY = readFloat pFile; scaleZ = readFloat pFile
        
        modelId = readLong pFile #unsigned        -- model id
        readLong pFile                                     -- type
        readLong pFile #unsigned                        -- flags
        readLong pFile #unsigned                        -- npc id
        
        mybox = box length:20 width:20 height:20
        mybox.pos = [posX, posZ, posY]
        --mybox.rotation = [rotX, rotY, rotZ, rotW]
        mybox.scale = [100 * scaleX, 100 * scaleY, 100 * scaleZ]
        mybox.name = modelList[modelId - 1]
    )
)

function readSecondData pFile =
(
    modelCount = readLong pFile #unsigned        -- model count
    
    for i = 1 to modelCount do
    (    
        -- position
        posX = readFloat pFile; posY = readFloat pFile; posZ = readFloat pFile
        
        -- rotation
        rotX = readFloat pFile; rotY = readFloat pFile; rotZ = readFloat pFile; rotW = readFloat pFile
        
        -- scale
        scaleX = readFloat pFile; scaleY = readFloat pFile; scaleZ = readFloat pFile
        
        modelId = readLong pFile #unsigned        -- model id
        
        mybox = box length:20 width:20 height:20
        mybox.pos = [posX, posZ, posY]
        --mybox.rotation = [rotX, rotY, rotZ, rotW]
        mybox.scale = [100 * scaleX, 100 * scaleY, 100 * scaleZ]
        mybox.name = modelList[modelId - 1]
    )
)

function readThirdData pFile =
(
    readLong pFile #unsigned                            -- unk_count
    modelCount = readLong pFile #unsigned        -- model count
    
    for i = 1 to modelCount do
    (    
        -- position
        posX = readFloat pFile; posY = readFloat pFile; posZ = readFloat pFile
        
        -- rotation
        rotX = readFloat pFile; rotY = readFloat pFile; rotZ = readFloat pFile; rotW = readFloat pFile
        
        -- scale
        scaleX = readFloat pFile; scaleY = readFloat pFile; scaleZ = readFloat pFile
        
        modelId = readLong pFile #unsigned        -- model id
        
        mybox = box length:20 width:20 height:20
        mybox.pos = [posX, posZ, posY]
        --mybox.rotation = [rotX, rotY, rotZ, rotW]
        mybox.scale = [100 * scaleX, 100 * scaleY, 100 * scaleZ]
        mybox.name = modelList[modelId]
    )
)

function importModels pFile =
(
    global modelList = #()
    
    modelCount = readLong pFile #unsigned
    modelList.count = modelCount                            -- model count
    
    for i = 1 to modelCount do
    (
        mNameLength = readShort pFile #unsigned        -- name length
        mName = readText pFile mNameLength            -- name
        readFloat pFile; readFloat pFile; readFloat pFile    -- bound min
        readFloat pFile; readFloat pFile; readFloat pFile    -- bound max
        modelList[i] = mName;
    )
            
    readFirstData pFile                                            -- reading first data; "interactive models"
    --readSecondData pFile                                        -- reading second data
    --readThirdData pFile                                            -- reading third data
)

function import_mcl file_name =
(
    if file_name == undefined then
        return messagebox "Please select a map to import!" title:"Error"
        
    import_msg = "Import Map with materials? It might take more time to load.";
    import_msg += "(Use only if you need materials!)\n\n";
    import_msg += "Press yes to import with materials.\n";
    import_msg += "Press no to import without materials.\n\n";
    import_msg += "NOTICE: Import process might take some time, please be patient!";
        
    import_flag = queryBox import_msg title:"Map Import"
    
    import_msg = "Import Map with models? It might take more time to load.\n\n";
    import_msg += "Press yes to import with models. You will be asked to select Objects folder.\n";
    import_msg += "Press no to import without models.\n\n";
    import_msg += "NOTICE: You will need to have ebm importer in your 3DS scripts folder!";
    import_models = queryBox import_msg title:"Models Import"  
    
    if import_models  == true then
    (
        import_script = (pathconfig.getdir #userScripts) + "/import_ebm_cabal.ms" 
        exist = (getfiles import_script).count
        if exist == 0 then
        (
            import_models = false
            messagebox "EBM import script: import_ebm_cabal.ms was not found!\nSkipping models import..." title:"Error"
        )
    )
    
    mapFile = fopen file_name "rb"

    print "(/) Loading..."
    readHeader mapFile                    -- header
        
    print "(-) Loading..."
    readEffects mapFile                    -- effects
        
    print "(\) Loading..."
    readTextures mapFile                -- textures
        
    print "(|) Loading..."
    readLong mapFile #unsigned        -- unkui0
    readLong mapFile #unsigned        -- unkui1
    readLong mapFile #unsigned        -- unkui2

    print "(/) Loading..."
    -- height map
    global hmap_bin = #()
    hmap_bin.count = 264196
        
    for i = 1 to 264196 do
    (
        hmap_bin[i] = readByte mapFile
    )
        
    print "(-) Loading..."
    -- thread map
    global tmap_bin = #()
    tmap_bin.count = 262144
        
    for i = 1 to 262144 do
    (
        tmap_bin[i] = readByte mapFile
    )
        
    print "(\) Loading..."
    readTileTextures mapFile            -- tile textures
        
    print "(|) Loading..."
    readTile mapFile                        -- tile
    
    --if import_models  == true then
        --importModels mapFile
        
    fclose mapFile
            
    if CabalMCLTools != undefined then
        CabalMCLTools.imported = true
        
    print "DONE!"
    messagebox "Importing process is done!" title:"Done"
)        

rollout CabalMCLTools "Cabal MCL Tools"
(
    local imported = false
    
    group "Import:"
    (
        button btn_import_mcl "Open..." width:68 height:18 pos:[45, 20]
    )
    
    group "Export binary:"
    (
        button btn_export_hmap "Height Map" width:68 height:18 pos:[10, 65]
        button btn_export_tmap "Thread Map" width:68 height:18 pos:[85, 65]
    )
    
    group "Export list:"
    (
        button btn_export_models "Map Models" width:68 height:18 pos:[45, 110]
    )
    
    group "Export textures:"
    (
        button btn_export_tiletex "Tile Textures" width:68 height:18 pos:[45, 155]
        button btn_export_maptex "Map Textures" width:68 height:18 pos:[45, 180]
    )
    
    on btn_import_mcl pressed do
    (
        file_name = getopenfilename caption:"Select a world to import..." types:"Cabal Map File(*.mcl)|*.mcl"
        import_mcl(file_name)
    )
    
    on btn_export_hmap pressed do
    (
        if imported == true then
        (
            file_name = getsavefilename caption:"Select a file name to export..." types:"Binary(*.bin)|*.bin"
            export_hmap(file_name)
        )
        else
            messagebox "Please import map first!" title:"Height Map"
    )
    
    on btn_export_tmap pressed do
    (
        if imported == true then
        (
            file_name = getsavefilename caption:"Select a file name to export..." types:"Binary(*.bin)|*.bin"
            export_tmap(file_name)
        )
        else
            messagebox "Please import map first!" title:"Thread Map"
    )
    
    on btn_export_models pressed do
    (
        if imported == true then
        (

        )
        else
            messagebox "Please import map first!" title:"Map Models"
    )
    
    on btn_export_tiletex pressed do
    (
        if imported == true then
        (
            map_textures_msg = "Tile Textures are already exported in ";
            map_textures_msg += (pathconfig.getdir #import) 
            messagebox map_textures_msg title:"Tile Textures"
        )
        else
            messagebox "Please import map first!" title:"Tile Textures"
    )
    
    on btn_export_maptex pressed do
    (
        if imported == true then
        (
            map_textures_msg = "Map Textures are already exported in ";
            map_textures_msg += (pathconfig.getdir #import) 
            messagebox map_textures_msg title:"Map Textures"
        )
        else
            messagebox "Please import map first!" title:"Map Textures"
    )
)

createdialog CabalMCLTools
--cui.registerdialogbar CabalMCLTools style:#(#cui_dock_right, #cui_floatable) minsize:#(272, 160) maxsize:#(272, 160)
--cui.dockdialogbar CabalMCLTools #cui_dock_right

callbacks.addScript #systemPreNew" resetImportValue()" id:#resetImport
 
Last edited:
Newbie Spellweaver
Joined
Jan 3, 2015
Messages
17
Reaction score
1
I've been waiting for this. Thanks :eek:tt:
 
Back
Top