Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

P3M Blender Importer w/ KOM Extractor

Status
Not open for further replies.
Experienced Elementalist
Joined
Aug 27, 2006
Messages
223
Reaction score
183
Blender 2.4x *.p3m Importer w/ KOM (Un)packer

Warning: I have never played Grand Chase and these posts are for sharing knowledge only.

Installation: (Pictorial Steps http://forum.ragezone.com/f311/elu-blender-importer-488857/#post4297496)
  1. Download and install Blender 2.46+ from Blender.org
  2. Download and install Python 2.6.x from (Windows Users)
  3. Save code below
  4. Copy p3m_import.py into your Blender scripts directory.

Usage:
  1. Click File > Import > Perfect 3D Model Import (*.p3m)...
  2. Select *.p3m file
  3. Click Ok

License:


Source:
Copy and save as p3m_import.py
Code:
#!BPY

# Copyright (c) 2009-2012 AJ
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


"""
Name: 'Perfect 3D Model Import (*.p3m)...'
Blender: 246
Group: 'Import'
Tooltip: 'Import Grand Chase: Perfect 3D Model *.p3m game files'
"""


__author__ = 'AJ'
__email__ = ''
__url__ = ('blender', 'elysiun', 'Project homepage, http://www.ragezone.com/')
__version__ = '0.0.2'
__bpydoc__ = """ \
This prototype script imports Grand Chase: Perfect 3D Model *.p3m game files
"""


import Blender
import struct


LEFT_TO_RIGHT = Blender.Mathutils.Matrix([-1.0, 0.0, 0.0, 0.0],
                                         [0.0, 0.0, 1.0, 0.0],
                                         [0.0, 1.0, 0.0, 0.0],
                                         [0.0, 0.0, 0.0, 1.0])


def p3m_read(file_path):
    file_name = Blender.sys.basename(file_path)

    file_name, file_ext = Blender.sys.splitext(file_name)

    file_object = None

    try:
        file_object = open(file_path, 'rb')

        data_chunk = file_object.read(27)

        if data_chunk != 'Perfact 3D Model (Ver 0.5)\0':
            return

        data_chunk = file_object.read(2)

        unknown_0, unknown_1 = struct.unpack_from('<2B', data_chunk)

        for x in xrange(unknown_0):
            file_object.read(24)

        for x in xrange(unknown_1):
            file_object.read(28)

        data_chunk = file_object.read(4)

        vertex_count, face_count = struct.unpack_from('<2H', data_chunk)

        data_chunk = file_object.read(260)

        face_data_chunk = file_object.read(face_count * 3 * 2)

        mesh_object1 = Blender.Object.New('Mesh', file_name + '_1')

        mesh1 = mesh_object1.getData(mesh = True)

        if mesh1 is None:
            mesh1 = Blender.Mesh.New(file_name + '_1')

            mesh_object1.link(mesh1)

        mesh1.vertexUV = True

        data_chunk = file_object.read(vertex_count * 40)

        for x in xrange(vertex_count):
            p = struct.unpack_from('<3f', data_chunk, x * 40)
            n = struct.unpack_from('<3f', data_chunk, x * 40 + 8 + 12)
            t = struct.unpack_from('<2f', data_chunk, x * 40 + 8 + 12 + 12)

            position = Blender.Mathutils.Vector(p)
            normal = Blender.Mathutils.Vector(n)
            uv = Blender.Mathutils.Vector(t)

            mesh1.verts.extend(position)

            vertex = mesh1.verts[-1]
            vertex.no = normal
            vertex.uvco = uv
            vertex.uvco[1] = 1.0 - vertex.uvco[1]

        mesh_object2 = Blender.Object.New('Mesh', file_name + '_2')

        mesh2 = mesh_object2.getData(mesh = True)

        if mesh2 is None:
            mesh2 = Blender.Mesh.New(file_name + '_2')

            mesh_object2.link(mesh2)

        mesh2.vertexUV = True

        data_chunk = file_object.read(vertex_count * 32)

        for x in xrange(vertex_count):
            p = struct.unpack_from('<3f', data_chunk, x * 32)
            n = struct.unpack_from('<3f', data_chunk, x * 32 + 12)
            t = struct.unpack_from('<2f', data_chunk, x * 32 + 12 + 12)

            position = Blender.Mathutils.Vector(p)
            normal = Blender.Mathutils.Vector(n)
            uv = Blender.Mathutils.Vector(t)

            mesh2.verts.extend(position)

            vertex = mesh2.verts[-1]
            vertex.no = normal
            vertex.uvco = uv
            vertex.uvco[1] = 1.0 - vertex.uvco[1]

        for x in xrange(face_count):
            f = struct.unpack_from('<3H', face_data_chunk, x * 6)

            mesh1.faces.extend([mesh1.verts[y] for y in f])

            face = mesh1.faces[-1]
            face.uv = [vertex.uvco for vertex in face.verts]

            mesh2.faces.extend([mesh2.verts[y] for y in f])

            face = mesh2.faces[-1]
            face.uv = [vertex.uvco for vertex in face.verts]

        mesh1.faceUV = True

        mesh2.faceUV = True

        world_matrix = mesh_object1.getMatrix()

        mesh_object1.setMatrix(world_matrix * LEFT_TO_RIGHT)

        world_matrix = mesh_object2.getMatrix()

        mesh_object2.setMatrix(world_matrix * LEFT_TO_RIGHT)

        scene = Blender.Scene.GetCurrent()

        scene.objects.link(mesh_object1)

        scene.objects.link(mesh_object2)
    except IOError, (errno, strerror):
        Blender.Draw.PupMenu("Error%%t|I/O error(%d): %s." % (errno, strerror))
    except Exception, err:
        Blender.Draw.PupMenu("Error%%t|.%s" % err)
    finally:
        if file_object is not None:
            file_object.close()


def main():
    def p3m_file_selector(file_path):
        if file_path and not Blender.sys.exists(file_path):
            Blender.Draw.PupMenu("Error%%t|The file %s does not exist." % file_path)
        else:
            p3m_read(file_path)

    Blender.Window.FileSelector(p3m_file_selector, 'Ok', Blender.sys.makename(ext='.p3m'))

if __name__ == "__main__":
    main()

----------

KOM Unpacker

Usage:
  1. Open Command Prompt/Console/Terminal
  2. Run kom_extract.py in a Python shell followed by the path to *.kom file. Eg. "C:\Python26\python.exe kom_extract.py C:\****soft Online\GrandChase\Model\Model_Pet.kom"

License:

Source:
Copy and save as kom_extract.py​
Code:
#!/usr/bin/python

# Copyright (c) 2009-2012 AJ
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import getopt
import os
import struct
import sys
import zlib


class Entry(object):
    def __init__(self, name, uncompressed_size, compressed_size, relative_offset):
        self.__name = name[0:name.find('\0')]
        self.__uncompressed_size = uncompressed_size
        self.__compressed_size = compressed_size
        self.__relative_offset = relative_offset
    
    def get_name(self):
        return self.__name
    
    def get_uncompressed_size(self):
        return self.__uncompressed_size
    
    def get_compressed_size(self):
        return self.__compressed_size
    
    def get_relative_offset(self):
        return self.__relative_offset
    
    name = property(get_name)
    
    uncompressed_size = property(get_uncompressed_size)
    
    compressed_size = property(get_compressed_size)
    
    relative_offset = property(get_relative_offset)


def main(argv):
    if len(argv) < 1:
        sys.exit(2)
    
    try:
        options, arguments = getopt.getopt(argv, 'vf:', ['verbose', 'file='])
    except getopt.GetoptError:
        sys.exit(2)
    
    verbose = False
    file_name = None
    
    for option, argument in options:
        if option in ('v', '--verbose'):
            verbose = True
        elif option in ('f', '--file'):
            file_name = argument
    
    if file_name is None:
        file_name = argv[0]
    
    if os.path.isfile(file_name) == False:
        sys.exit(2)
    
    file_object = None
    file_data = None
    
    try:
        file_object = open(file_name, 'rb')
        
        if file_object is not None:
            file_data = file_object.read()
    finally:
        if file_object is not None:
            file_object.close()

            file_object = None
    
    offset = 0
    
    version = struct.unpack_from('<26s26x', file_data, offset)[0]
    
    offset += 52
    
    entry_count = struct.unpack_from('<I4x', file_data, offset)[0]
    
    offset += 8
    
    entries = []
    
    for x in xrange(entry_count):
        entry = Entry(*struct.unpack_from('<60s3I', file_data, offset))
        
        entries.append(entry)
        
        offset += 72

    for entry in entries:
        entry_file_data = file_data[offset + entry.relative_offset:offset + entry.relative_offset + entry.compressed_size]
        
        entry_file_data = zlib.decompress(entry_file_data)
        
        try:
            file_object = open(entry.name, 'wb')
            
            if file_object is not None:
                file_object.write(entry_file_data)
        finally:
            if file_object is not None:
                file_object.close()
                
                file_object = None


if __name__ == "__main__":
    main(sys.argv[1:])
 
Last edited:
Newbie Spellweaver
Joined
Mar 20, 2008
Messages
26
Reaction score
0
This is a really good release. Thanks for sharing it with us!

By the way, as I don't know how to program things, I'd like to ask a script to make the reverse process, ie, make again .kom files, but with it contents edited, if it doesn't matter you... :3

Thanks in advance
 
Experienced Elementalist
Joined
Aug 27, 2006
Messages
223
Reaction score
183
This is a really good release. Thanks for sharing it with us!

By the way, as I don't know how to program things, I'd like to ask a script to make the reverse process, ie, make again .kom files, but with it contents edited, if it doesn't matter you... :3

Thanks in advance

Version 1 KOM File Packer

Usage:
  1. Open Command Prompt/Console/Terminal
  2. Run kom_create1.py in a Python shell followed by input directory and output *.kom file. Eg. C:\Python26\python.exe kom_create1.py --in "C:\Phantom\AIPet" --out PhantomAIPet.kom
That will compress all files in the directory C:\Phantom\AIPet to the file PhantomAIPet.kom

License:

Source:
Copy and save as kom_create1.py​
Code:
#!/usr/bin/python

# Copyright (c) 2009-2012 AJ
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import getopt
import os
import struct
import sys
import zlib


def main(argv):
    if len(argv) < 2:
        sys.exit(2)
    
    try:
        options, arguments = getopt.getopt(argv, 'i:o:', ['in=', 'out='])
    except getopt.GetoptError:
        sys.exit(2)
    
    in_path = None
    out_path = None
    
    for option, argument in options:
        if option in ('i', '--in'):
            in_path = argument
        elif option in ('o', '--out'):
            out_path = argument
    
    if in_path is None or out_path is None:
        sys.exit(2)
    
    kom_file_entries = ''
    
    kom_compressed_file_data = ''
    
    if os.path.isdir(in_path) == True:
        for file_name in os.listdir(in_path):
            file_path = os.path.join(in_path, file_name)
            
            if os.path.isfile(file_path):
                if len(file_name) > 60:
                    continue
                
                file_size = os.path.getsize(file_path)
                
                if file_size <= 0:
                    continue
                
                try:
                    file_object = open(file_path, 'rb')
                    
                    file_data = file_object.read()
                except IOError:
                    pass
                else:
                    try:
                        compressed_file_data = zlib.compress(file_data)
                    except zlib.error:
                        pass
                    else:
                        kom_file_entries += struct.pack('<60s3I', file_name, len(file_data), len(compressed_file_data), len(kom_compressed_file_data))
                        
                        kom_compressed_file_data += compressed_file_data
                finally:
                    if file_object is not None:
                        file_object.close()
                        
                        file_object = None
    
    if len(kom_file_entries) > 0 and len(kom_compressed_file_data) > 0:
        try:
            file_object = open(out_path, 'wb')
            
            kom_header = "KOG GC TEAM MASSFILE V.0.1"
            kom_header += struct.pack('<B25x', 0x2E)
            kom_header += struct.pack('<2I', len(kom_file_entries) / 72, 1)
            
            file_object.write(kom_header)
            file_object.write(kom_file_entries)
            file_object.write(kom_compressed_file_data)
        finally:
            if file_object is not None:
                file_object.close()
                
                file_object = None


if __name__ == "__main__":
    main(sys.argv[1:])
 
Last edited:
Experienced Elementalist
Joined
Aug 27, 2006
Messages
223
Reaction score
183
Version 2 KOM File Packer

Dynamically generates the crc.xml file.

Usage:
  1. Open Command Prompt/Console/Terminal
  2. Run kom_create1.py in a Python shell followed by input directory and output *.kom file. Eg. C:\Python26\python.exe kom_create2.py --in "C:\Phantom\AIPet" --out PhantomAIPet.kom
That will compress all files in the directory C:\Phantom\AIPet to the file PhantomAIPet.kom

License:

Source:
Copy and save as kom_create2.py​
Code:
#!/usr/bin/python

# Copyright (c) 2009-2012 AJ
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import getopt
import os
import struct
import sys
import zlib
from xml.dom.minidom import Document

def main(argv):
    if len(argv) < 2:
        sys.exit(2)
    
    try:
        options, arguments = getopt.getopt(argv, 'i:o:', ['in=', 'out='])
    except getopt.GetoptError:
        sys.exit(2)
    
    in_path = None
    out_path = None
    
    for option, argument in options:
        if option in ('i', '--in'):
            in_path = argument
        elif option in ('o', '--out'):
            out_path = argument
    
    if in_path is None or out_path is None:
        sys.exit(2)
    
    crc = Document()
    
    crc_file_info = crc.createElement("FileInfo")
    
    crc.appendChild(crc_file_info)
    
    crc_file_info_version = crc.createElement("Version")
    
    crc_file_info.appendChild(crc_file_info_version)
    
    crc_file_info_version_item = crc.createElement("Item")
    
    crc_file_info_version_item.setAttribute("Name", "V.0.2.")
    
    crc_file_info_version.appendChild(crc_file_info_version_item)
    
    crc_file_info_file = crc.createElement("File")
    
    crc_file_info.appendChild(crc_file_info_file)
    
    kom_file_entries = ''
    
    kom_compressed_file_data = ''
    
    if os.path.isdir(in_path) == True:
        for file_name in os.listdir(in_path):
            if file_name == 'crc.xml':
                continue
            
            file_path = os.path.join(in_path, file_name)
            
            if os.path.isfile(file_path):
                if len(file_name) > 60:
                    continue
                
                file_size = os.path.getsize(file_path)
                
                if file_size <= 0:
                    continue
                
                try:
                    file_object = open(file_path, 'rb')
                    
                    file_data = file_object.read()
                except IOError:
                    pass
                else:
                    try:
                        compressed_file_data = zlib.compress(file_data)
                    except zlib.error:
                        pass
                    else:
                        kom_file_entries += struct.pack('<60s3I', file_name, len(file_data), len(compressed_file_data), len(kom_compressed_file_data))
                        
                        kom_compressed_file_data += compressed_file_data
                        
                        file_data_crc32 = zlib.crc32(compressed_file_data)  & 0xffffffffL # work around for issue 1202
                        
                        crc_file_info_file_item = crc.createElement("Item")
                        
                        crc_file_info_file_item.setAttribute("Name", file_name)
                        crc_file_info_file_item.setAttribute("Size", str(len(file_data)))
                        crc_file_info_file_item.setAttribute("Version", str(0))
                        crc_file_info_file_item.setAttribute("CheckSum", "%08x" % file_data_crc32)
                        
                        crc_file_info_file.appendChild(crc_file_info_file_item)
                finally:
                    if file_object is not None:
                        file_object.close()
                        
                        file_object = None
    
    if len(kom_file_entries) > 0 and len(kom_compressed_file_data) > 0:
        crc_file_data = crc.toprettyxml(indent="    ")
        
        try:
            crc_compressed_file_data = zlib.compress(crc_file_data)
        except zlib.error:
            sys.exit(2)
        else:
            kom_file_entries += struct.pack('<60s3I', "crc.xml", len(crc_file_data), len(crc_compressed_file_data), len(kom_compressed_file_data))
            
            kom_compressed_file_data += crc_compressed_file_data
        
        try:
            file_object = open(out_path, 'wb')
            
            kom_header = "KOG GC TEAM MASSFILE V.0.2."
            kom_header += struct.pack('<25x')
            kom_header += struct.pack('<2I', len(kom_file_entries) / 72, 1)
            
            file_object.write(kom_header)
            file_object.write(kom_file_entries)
            file_object.write(kom_compressed_file_data)
        finally:
            if file_object is not None:
                file_object.close()
                
                file_object = None


if __name__ == "__main__":
    main(sys.argv[1:])
 
Last edited:
Skilled Illusionist
Joined
Jan 9, 2009
Messages
359
Reaction score
43
Thanks for the share. Mind explaining what it is for and what it does? Your first post seems... to lack that info.
 
Newbie Spellweaver
Joined
Jul 30, 2009
Messages
37
Reaction score
0
Thanks for the share. Mind explaining what it is for and what it does? Your first post seems... to lack that info.

Instructions are not that much in depth, my friend tried it and couldn't get the thing to work in Python and I tried it and the same happens.

The only part I focused on was the extraction of the KOM file, since thats where all the item images are, and the images names are the Items ID.jpg.

Can truely make a English client if we can open these aswell.
 
&#12368;&#12435;&#12387;l&#12354;&#12391; &#12431;
Joined
May 17, 2007
Messages
302
Reaction score
9
Great now your talking... interesting bro keep it up! and thans for the share hope i can dev again , cheers!
 
Last edited:
Initiate Mage
Joined
Nov 22, 2009
Messages
1
Reaction score
0
KoG has made a new version of their packer.

Would you be able to make a new extractor/repacker?

I can probably get you the files, as long as I know which files they are.
 
Last edited:
Initiate Mage
Joined
Apr 25, 2009
Messages
4
Reaction score
0
Yup they changed packing algorithm i think. Sadly. If you have time pls make new version of this great script.
 
Experienced Elementalist
Joined
Aug 27, 2006
Messages
223
Reaction score
183
KoG has made a new version of their packer.

Would you be able to make a new extractor/repacker?

I can probably get you the files, as long as I know which files they are.

Sorry, but my only interests are for the development of private servers.
 
Newbie Spellweaver
Joined
Jun 12, 2008
Messages
30
Reaction score
1
Sorry, but my only interests are for the development of private servers.

I, personally need a new KOM Extractor for my private server, I was going to add the new pet, Mini Elesis, but was unable to do it due to the changed Algorithm.
 
Initiate Mage
Joined
Apr 25, 2009
Messages
4
Reaction score
0
Do you have any plans to make .p3m exporter? It would be great to have custom models on your server.:thumbup:
 
Initiate Mage
Joined
Apr 30, 2009
Messages
1
Reaction score
0
wheres gc_prototypes.zip download link?

Someone can re-upload gc_prototypes.zip or p3m_import.py?
 
Last edited:
Newbie Spellweaver
Joined
Dec 22, 2008
Messages
40
Reaction score
4
Yay, It worked for me. I used a different Kom extractor I found elsewhere. I copied what he has there in the code box, then opened up notepad and pasted it in there then named the file p3m_import.py. Because there are other Kom extractors out there the need for gc_prototypes.zip isnt really necessary. I used Blender 2.49b and Python 2.6.2, and Grand Chase Version 1 files.


Phantom* - P3M Blender Importer w/ KOM Extractor - RaGEZONE Forums


Well, that was fun, and it's something I always wanted to do with Grand Chase files, which is to be able to view the images in Blender.
Thanks Phantom. ; )​
 
Experienced Elementalist
Joined
Aug 27, 2006
Messages
223
Reaction score
183
Do you have any plans to make .p3m exporter? It would be great to have custom models on your server.:thumbup:

Always a possibility.

wheres gc_prototypes.zip download link?

Someone can re-upload gc_prototypes.zip or p3m_import.py?

Uploaded as source until I can add as attachments.


...Well, that was fun, and it's something I always wanted to do with Grand Chase files, which is to be able to view the images in Blender.
Thanks Phantom. ; )​

You're welcome. Still lots to complete when time permits.

FYI two overlapping meshes get imported per p3m file. One is deformed which you can ignore for the time.
 
Last edited:
Newbie Spellweaver
Joined
Feb 24, 2010
Messages
8
Reaction score
0
Excuse me I am somewhat ignorant of the subject but to serve it.

Sera that this server is used to create or do not understand the operation and because it is in Grand Chanse
 
Initiate Mage
Joined
May 20, 2012
Messages
1
Reaction score
0
where is the gc_prototypes.zip cant find it? any lunks or whatever things can I get that?
 
Status
Not open for further replies.
Back
Top