Important information: this site is currently scheduled to go offline indefinitely by end of the year.
Cabal Online File Format
- Rimbros
- ultra-veteran
- Posts: 495
- Joined: Fri Jul 09, 2010 12:23 am
- Has thanked: 41 times
- Been thanked: 16 times
Cabal Online File Format
The contents of this post was deleted because of possible forum rules violation.
Renders Art by Rimbros
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
- CriticalError
- double-veteran
- Posts: 678
- Joined: Sun Jul 05, 2009 2:03 am
- Has thanked: 104 times
- Been thanked: 41 times
Re: Cabal Online File Format
umm yes I try rip this game before, and found some interesting things, the model and texture are attached into same file, anyway here some examples, you need something, know where can found me
PD: I attached .MAX and OBJ you want see.
PD: I attached .MAX and OBJ you want see.
You do not have the required permissions to view the files attached to this post.
-
- ultra-veteran
- Posts: 423
- Joined: Mon Aug 11, 2008 11:30 pm
- Has thanked: 27 times
- Been thanked: 15 times
Re: Cabal Online File Format
I didn't quite understand all you said but the tool that he made can load models, maps and animations. What I have seen all characters load ALL models in one pack so you manually have to delete everything you don't want to see
- CriticalError
- double-veteran
- Posts: 678
- Joined: Sun Jul 05, 2009 2:03 am
- Has thanked: 104 times
- Been thanked: 41 times
Re: Cabal Online File Format
what tool you mean? about animations are not supported think, I read something but not sure about thatpixellegolas wrote:I didn't quite understand all you said but the tool that he made can load models, maps and animations. What I have seen all characters load ALL models in one pack so you manually have to delete everything you don't want to see
PD: I say before is the model+textures are in same file .EBM
- Rimbros
- ultra-veteran
- Posts: 495
- Joined: Fri Jul 09, 2010 12:23 am
- Has thanked: 41 times
- Been thanked: 16 times
Re: Cabal Online File Format
.EBM files can be unpacked this its posible i remember with something blender script, now the .ebm files can be exported back to the game file format of course, i talk abouth .ech format, .ech format its the format of the armors and costumes stored in this files, i talk abouth maybe its posible first make a importer for .ech files then in the future make exporter.
Renders Art by Rimbros
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
Re: Cabal Online File Format
For Bleder 2.46, copy and save as: ebm_import.py
Source:
http://forum.ragezone.com/f458/ebm-blen ... er-449555/
Code: Select all
#!BPY
# Copyright (c) 2007-2011 Randall Stevens
#
# 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.
#
# -----------------------------------------------------------------------------
#
# Version 0.0.1
# * Initial release
#
# Version 0.0.2
# * Fixed setting face mode to double sided
# * Fixed mirroring the UV coordinates
# * Fixed reading vertex influences
# * Added setting material mode to texture face with alpha
#
# Version 0.0.3
# * Fixed importing textures in Microsoft Windows
#
# Version 0.0.4
# * Fixed armature edit bone matrix
# * Added animation importing
"""
Name: 'CABAL (.ebm)...'
Blender: 246
Group: 'Import'
Tooltip: 'Import CABAL game (*.ebm) files'
"""
__author__ = 'Peter S. Stevens'
__email__ = 'pstevens:cryptomail*org'
__url__ = ('blender', 'elysiun', 'Project homepage, http://www.ragezone.com/')
__version__ = '0.0.4'
__bpydoc__ = """ \
This script imports CABAL game (*.ebm) files.
"""
import Blender
import struct
import tempfile
import math
import re
EBM_BONE_NAMES = []
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])
class MagicError(ValueError):
pass
def ebm_read_material(file_object):
diffuse = struct.unpack('<4f', file_object.read(16))
ambient = struct.unpack('<4f', file_object.read(16))
specular = struct.unpack('<4f', file_object.read(16))
emissive = struct.unpack('<4f', file_object.read(16))
power = struct.unpack('<f', file_object.read(4))[0]
material = Blender.Material.New()
material.setRGBCol(diffuse[0:3])
material.setAlpha(diffuse[3])
material.setMirCol(ambient[0:3])
material.setAmb(ambient[3])
material.setSpecCol(specular[0:3])
material.setSpec(power)
material.setEmit(emissive[3])
return material
def ebm_read_texture(file_object):
name_length = struct.unpack('<H', file_object.read(2))[0]
name = file_object.read(name_length)
texture_data_size = struct.unpack('<I', file_object.read(4))[0]
texture_data = file_object.read(texture_data_size)
file_object.read(26) # ?, 00 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 04 00 00 00 DXT3
# Clean the file name
rec = re.compile('[^\w\.]*')
name = rec.sub('', name)
# Create a temporary texture file
texture_file = open(Blender.sys.join(tempfile.gettempdir(), name), 'wb')
texture_file.write(texture_data)
texture_file.close()
texture = None
try:
texture = Blender.Texture.Get(name)
except:
texture = Blender.Texture.New(name)
texture.setType('Image')
image = None
try:
image = Blender.Image.Get(name)
except:
try:
image = Blender.Image.Load(Blender.sys.join(tempfile.gettempdir(), name))
except:
raise
finally:
if image is not None:
texture.setImage(image)
return texture
def ebm_read_mesh(file_object, materials):
name_length = struct.unpack('<H', file_object.read(2))[0]
name = file_object.read(name_length)
world_matrix = Blender.Mathutils.Matrix(struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)))
local_matrix = Blender.Mathutils.Matrix(struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)))
unknown_0 = struct.unpack('<I', file_object.read(4))[0] # 0xFFFFFF
material_index = struct.unpack('<B', file_object.read(1))[0]
vertex_count = struct.unpack('<H', file_object.read(2))[0]
face_count = struct.unpack('<H', file_object.read(2))[0]
if vertex_count == 0 or face_count == 0:
return None
mesh_object = Blender.Object.New('Mesh', name)
mesh = mesh_object.getData(mesh = True)
if mesh is None:
mesh = Blender.Mesh.New(name)
mesh_object.link(mesh)
mesh.vertexUV = True
material = materials[material_index]
mesh.materials = [material]
textures = material.getTextures()
image = None
if len(textures) > 0:
texture = textures[0].tex
image = texture.getImage()
for x in xrange(vertex_count):
position = Blender.Mathutils.Vector(struct.unpack('<3f', file_object.read(12)))
normal = Blender.Mathutils.Vector(struct.unpack('<3f', file_object.read(12)))
uv = Blender.Mathutils.Vector(struct.unpack('<2f', file_object.read(8)))
mesh.verts.extend(position)
vertex = mesh.verts[-1]
vertex.no = normal
vertex.uvco = uv
vertex.uvco[1] = 1.0 - vertex.uvco[1]
for x in xrange(face_count):
mesh.faces.extend([mesh.verts[y] for y in struct.unpack('<3H', file_object.read(6))])
face = mesh.faces[-1]
face.uv = [vertex.uvco for vertex in face.verts]
if image is not None:
face.mode = Blender.Mesh.FaceModes.TEX + Blender.Mesh.FaceModes.TWOSIDE
face.image = image
mesh.faceUV = True
mesh_object.setMatrix(LEFT_TO_RIGHT) # mesh_object.setMatrix(world_matrix)
return mesh_object
def ebm_read_influence(file_object, mesh, armatures):
armature_object = armatures[-1]
mesh_object = mesh
armature_object.makeParent([mesh_object])
armature_modifier = mesh_object.modifiers.append(Blender.Modifier.Types.ARMATURE)
armature_modifier[Blender.Modifier.Settings.OBJECT] = armature_object
armature = armature_object.getData()
mesh = mesh_object.getData(mesh = True)
for x in xrange(0, len(EBM_BONE_NAMES)):
vertex_influences_count = struct.unpack('<I', file_object.read(4))[0]
group_id = EBM_BONE_NAMES[x]
mesh.addVertGroup(group_id)
if vertex_influences_count != 0:
vertex_influences = []
for y in xrange(vertex_influences_count):
vertex_index = struct.unpack('<I', file_object.read(4))[0]
vertex_influences.append(vertex_index)
for y in xrange(vertex_influences_count):
vertex_weight = struct.unpack('<f', file_object.read(4))[0]
mesh.assignVertsToGroup(group_id, \
[vertex_influences[y]], \
vertex_weight, \
Blender.Mesh.AssignModes.ADD)
# else: # problems on bike_10, comment out
# mesh.assignVertsToGroup(group_id, \
# [vertex.index for vertex in mesh.verts], \
# 1.0, \
# Blender.Mesh.AssignModes.ADD)
def ebm_read_bone(file_object, bones):
global EBM_BONE_NAMES
name_length = struct.unpack('<H', file_object.read(2))[0]
name = file_object.read(name_length)
parent_bone_index = struct.unpack('<I', file_object.read(4))[0]
armature_space_matrix = Blender.Mathutils.Matrix(struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)))
parent_armature_space_matrix = Blender.Mathutils.Matrix(struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)), \
struct.unpack('<4f', file_object.read(16)))
armature_space_matrix.invert()
edit_bone = Blender.Armature.Editbone()
edit_bone.name = name
edit_bone.matrix = armature_space_matrix
if parent_bone_index != 0xFFFFFFFF:
edit_bone.parent = bones[parent_bone_index]
bones.append(edit_bone)
EBM_BONE_NAMES.append(name)
return edit_bone
def ebm_read_animation(file_object, magic, armatures):
name_length = struct.unpack('<H', file_object.read(2))[0]
name = file_object.read(name_length)
armature_object = armatures[-1]#EBM_ARMATURES[-1]
armature = armature_object.getData()
action = Blender.Armature.NLA.NewAction(name)
action.setActive(armature_object)
# ipo = Blender.Ipo.New('Object', name)
armature_pose = armature_object.getPose()
armature_pose_bones = armature_pose.bones
bone_count = struct.unpack('<H', file_object.read(2))[0]
for x in xrange(bone_count):
bone_name_length = struct.unpack('<H', file_object.read(2))[0]
bone_name = file_object.read(bone_name_length)
translation_count = struct.unpack('<I', file_object.read(4))[0]
key_frames = {}
for y in xrange(translation_count):
key_frame_second = struct.unpack('<f', file_object.read(4))[0]
x, y, z = struct.unpack('<3f', file_object.read(12))
key_frame_index = int(math.floor(key_frame_second * 100))
if key_frame_index < 1:
key_frame_index = 1
translation = Blender.Mathutils.Vector(x, y, z)
key_frames[key_frame_index] = Blender.Mathutils.TranslationMatrix(translation)
rotation_count = struct.unpack('<I', file_object.read(4))[0]
for y in xrange(rotation_count):
key_frame_second = struct.unpack('<f', file_object.read(4))[0]
x, y, z, w = struct.unpack('<4f', file_object.read(16))
key_frame_index = int(math.floor(key_frame_second * 100))
if key_frame_index < 1:
key_frame_index = 1
xx = x * x
xy = x * y
xz = x * z
xw = x * w
yy = y * y
yz = y * z
yw = y * w
zz = z * z
zw = z * w
rotation_matrix = Blender.Mathutils.Matrix([1.0 - 2.0 * (yy + zz), 2.0 * (xy - zw), 2.0 * (xz + yw), 0.0], \
[2.0 * (xy + zw), 1.0 - 2.0 * (xx + zz), 2.0 * (yz - xw), 0.0], \
[2.0 * (xz - yw), 2.0 * (yz + xw), 1.0 - 2.0 * (xx + yy), 0.0], \
[0.0, 0.0, 0.0, 1.0])
if key_frame_index in key_frames:
key_frames[key_frame_index] = rotation_matrix * key_frames[key_frame_index]
else:
bone = armature.bones[bone_name]
rest_bone_matrix = bone.matrix['ARMATURESPACE'].copy()
if bone.parent is not None:
parent_bone = bone.parent
parent_rest_bone_matrix = parent_bone.matrix['ARMATURESPACE'].copy()
parent_rest_bone_matrix.invert()
rest_bone_matrix *= parent_rest_bone_matrix
translation = rest_bone_matrix.translationPart()
translation_matrix = Blender.Mathutils.TranslationMatrix(translation)
key_frames[key_frame_index] = rotation_matrix * translation_matrix
if bone_name in armature.bones.keys():
for key_frame_index, key_frame_transformation in key_frames.iteritems():
local_matrix = key_frame_transformation.copy()
bone = armature.bones[bone_name]
rest_bone_matrix = bone.matrix['ARMATURESPACE'].copy()
if bone.parent is not None and magic != 0x3EF03:
parent_bone = bone.parent
parent_rest_bone_matrix = parent_bone.matrix['ARMATURESPACE'].copy()
parent_rest_bone_matrix.invert()
local_matrix *= (rest_bone_matrix * parent_rest_bone_matrix).invert()
else:
rest_bone_matrix.invert()
local_matrix *= rest_bone_matrix
armature_pose_bones[bone_name].localMatrix = local_matrix
armature_pose_bones[bone_name].insertKey(armature_object, key_frame_index, [Blender.Object.Pose.ROT, Blender.Object.Pose.LOC])
# else:
# mesh_object = Blender.Object.Get(bone_name)
#
# mesh_object.setIpo(ipo)
#
# for key_frame_index, key_frame_transformation in key_frames.iteritems():
# Blender.Set("curframe", key_frame_index)
#
# mesh_object.setMatrix(key_frame_transformation)
#
# mesh_object.insertIpoKey(Blender.Object.LOCROT)
#
# Blender.Set("curframe", 1)
armature_pose.update()
def ebm_read_material_chunk(file_object, materials):
material_count = struct.unpack('<H', file_object.read(2))[0]
for x in xrange(material_count):
material = ebm_read_material(file_object)
texture = ebm_read_texture(file_object)
if texture is not None:
material.setTexture(0, texture, Blender.Texture.TexCo.UV)
material.setMode(Blender.Material.Modes.TEXFACE + Blender.Material.Modes.TEXFACE_ALPHA)
materials.append(material)
def ebm_read_influence_chunk(file_object, mesh, armatures):
influence_count = struct.unpack('<H', file_object.read(2))[0]
for x in xrange(influence_count):
ebm_read_influence(file_object, mesh, armatures)
def ebm_read_mesh_chunk(file_object, materials, meshes, armatures):
mesh_count = struct.unpack('<H', file_object.read(2))[0]
for x in xrange(mesh_count):
mesh_object = ebm_read_mesh(file_object, materials)
if mesh_object is not None:
chunk_id = struct.unpack('<I', file_object.read(4))[0]
if chunk_id == 0x41470205:
ebm_read_influence_chunk(file_object, mesh_object, armatures)
else: # WTF? fix...
file_object.seek(-5, os.SEEK_CUR)
meshes.append(mesh_object)
def ebm_read_armature_chunk(file_object):
bone_count = struct.unpack('<H', file_object.read(2))[0]
armature_object = Blender.Object.New('Armature')
armature_object.drawMode = Blender.Object.DrawModes.XRAY
armature = armature_object.getData()
if armature is None:
base_name = Blender.sys.basename(file_object.name)
armature_name = Blender.sys.splitext(base_name)[0]
armature = Blender.Armature.New(armature_name)
armature_object.link(armature)
armature.drawType = Blender.Armature.STICK
armature.envelopes = False
armature.vertexGroups = True
armature.makeEditable()
bones = []
for x in xrange(bone_count):
edit_bone = ebm_read_bone(file_object, bones)
armature.bones[edit_bone.name] = edit_bone
armature_object.setMatrix(LEFT_TO_RIGHT)
armature.update()
return armature_object
def ebm_read_animation_chunk(file_object, magic, armatures):
animation_count = struct.unpack('<H', file_object.read(2))[0]
for x in xrange(animation_count):
ebm_read_animation(file_object, magic, armatures)
def ebm_import(file_path):
file_object = None
materials = []
meshes = []
armatures = []
try:
Blender.Window.WaitCursor(1)
file_object = open(file_path, 'rb')
magic = struct.unpack('<I', file_object.read(4))[0]
if magic != 0x3ED03 and \
magic != 0x3EE03 and \
magic != 0x3EF03:
raise MagicError, "Bad magic number, %08x" % magic
print hex(magic)
unknown_0 = struct.unpack('<H', file_object.read(2))[0] # 0x100 (256)
unknown_1 = struct.unpack('<I', file_object.read(4))[0] # ?
bounding_box_min = Blender.Mathutils.Vector(struct.unpack('<3f', file_object.read(12)))
bounding_box_max = Blender.Mathutils.Vector(struct.unpack('<3f', file_object.read(12)))
unknown_2 = struct.unpack('<I', file_object.read(4))[0] # 0x64 (100)
while True:
data = file_object.read(4)
if len(data) == 0: # Clean break
break
chunk_id = struct.unpack('<I', data)[0]
if chunk_id == 0x41470201:
ebm_read_material_chunk(file_object, materials)
continue
if chunk_id == 0x41470202:
ebm_read_mesh_chunk(file_object, materials, meshes, armatures)
continue
if chunk_id == 0x41470203:
armature_object = ebm_read_armature_chunk(file_object)
armatures.append(armature_object)
continue
if chunk_id == 0x41470204:
ebm_read_animation_chunk(file_object, magic, armatures)
continue
except IOError:
raise
else:
scene = Blender.Scene.GetCurrent()
for mesh_object in meshes:
scene.objects.link(mesh_object)
for armature_object in armatures:
scene.objects.link(armature_object)
finally:
if file_object is not None:
file_object.close()
Blender.Window.WaitCursor(0)
def main():
def ebm_file_selector(file_path):
if file_path and \
not Blender.sys.exists(file_path):
Blender.Draw.PupMenu("Warning%%t|The file %s does not exist." % file_path)
else:
ebm_import(file_path)
Blender.Window.FileSelector(ebm_file_selector, 'Ok', Blender.sys.makename(ext='.ebm'))
if __name__ == "__main__":
main()
http://forum.ragezone.com/f458/ebm-blen ... er-449555/
-
- M-M-M-Monster veteran
- Posts: 2382
- Joined: Sat Apr 09, 2011 1:22 am
- Has thanked: 170 times
- Been thanked: 307 times
Re: Cabal Online File Format
If textures are stored as part of the format, it is most likely stored at a specific offset or the offset is referenced by some material or mesh.Rimbros wrote:.EBM files can be unpacked this its posible i remember with something blender script, now the .ebm files can be exported back to the game file format of course, i talk abouth .ech format, .ech format its the format of the armors and costumes stored in this files, i talk abouth maybe its posible first make a importer for .ech files then in the future make exporter.
I would handle it the same way the blender script does it so people don't have to unpack it.
-
- ultra-veteran
- Posts: 423
- Joined: Mon Aug 11, 2008 11:30 pm
- Has thanked: 27 times
- Been thanked: 15 times
Re: Cabal Online File Format
I remember opening up model files. All the characters where at origin and I had to manually delete costumes untill I found witch one I wanted, very heavy files because all was loaded. But costumes, animations and everything loaded.* Added animation importing
The script is from ragezone forum and will probably not be updated any more. The guy has done some other importers for perfect world etc
-
- ultra-veteran
- Posts: 467
- Joined: Thu Dec 07, 2006 11:25 pm
- Has thanked: 9 times
- Been thanked: 95 times
Re: Cabal Online File Format
You can extract the .dds files using this very useful utility:I would handle it the same way the blender script does it so people don't have to unpack it.
http://wiki.xentax.com/index.php/Extrac ... e_Stripper
- CriticalError
- double-veteran
- Posts: 678
- Joined: Sun Jul 05, 2009 2:03 am
- Has thanked: 104 times
- Been thanked: 41 times
Re: Cabal Online File Format
easy using bms script like this.Karpati wrote:You can extract the .dds files using this very useful utility:I would handle it the same way the blender script does it so people don't have to unpack it.
http://wiki.xentax.com/index.php/Extrac ... e_Stripper
Code: Select all
#locate first header
findloc RES_START string "X9´;"
goto RES_START
savepos RES_START
math FILES += 0xFFF
for i = 0 < FILES
getdstring NULL1 0x14
get NSIZE short
getdstring NAME NSIZE
get SIZE long
savepos OFFSET
log NAME OFFSET SIZE
math RES_START += SIZE
goto RES_START
findloc RES_START string "X9´;"
goto RES_START
next i
- Rimbros
- ultra-veteran
- Posts: 495
- Joined: Fri Jul 09, 2010 12:23 am
- Has thanked: 41 times
- Been thanked: 16 times
Re: Cabal Online File Format
The guy its phantom a genius of 3D file formats encrypted like the guys here in xentax, but he leave the forums long time ago.pixellegolas wrote:I remember opening up model files. All the characters where at origin and I had to manually delete costumes untill I found witch one I wanted, very heavy files because all was loaded. But costumes, animations and everything loaded.* Added animation importing
The script is from ragezone forum and will probably not be updated any more. The guy has done some other importers for perfect world etc
Renders Art by Rimbros
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
http://s303.photobucket.com/albums/nn12 ... E/Renders/
Personal Game repository samples, send PM
-
- veteran
- Posts: 138
- Joined: Mon Oct 04, 2010 1:15 am
- Has thanked: 5 times
- Been thanked: 3 times
-
- mega-veteran
- Posts: 292
- Joined: Wed May 05, 2010 8:21 pm
- Location: Poland Głogów
- Has thanked: 21 times
- Been thanked: 742 times
Re: Cabal Online File Format
The contents of this post was deleted because of possible forum rules violation.
- CriticalError
- double-veteran
- Posts: 678
- Joined: Sun Jul 05, 2009 2:03 am
- Has thanked: 104 times
- Been thanked: 41 times
Re: Cabal Online File Format
The contents of this post was deleted because of possible forum rules violation.
-
- M-M-M-Monster veteran
- Posts: 2382
- Joined: Sat Apr 09, 2011 1:22 am
- Has thanked: 170 times
- Been thanked: 307 times