Important Message

You are browsing the archived Lancers Reactor forums. You cannot register or login.
The content may be outdated and links may not be functional.


To get the latest in Freelancer news, mods, modding and downloads, go to
The-Starport

**Tutorial** - Ships/Weapons w/ multiple components

Here you find the different tutorials on editing and MODing Freelancer

Post Tue Jul 15, 2003 12:59 pm

**Tutorial** - Ships/Weapons w/ multiple components

So far i have only completed this for ships but the actual model data in a weapon is in the same format as a ship so this should apply directly. The most obvious difference is the Hps - an HpMount for the base, presumably the same as a ships HpMount, an HpConnect for the base and an HpFire0X for the barrel i doubt these will prove too difficult to understand.

So here is the method for ships. I highly recommend downloading the version of the Battleaxe which has destructable parts as it will provide a good reference point. Get it here. It is also a good idea to look over HCls VMesh guide, which is here. There are 3 main steps to having a ship composed of separate components :

1. Correctly defining what vertexes/triangles from your model form the various components - This information is contained in the VMeshLibrary -> Name_of_ship.lodX.vms -> VMeshData node and the Name_of_ship/component.3db -> Multilevel -> LevelX - VmeshRef nodes.

2. Correctly positioning the components relative to the hull - This information is contained in the Cmpnd -> Cons -> Fix node (for moving parts i.e. weapon barrels it is the Rev node). This node also has alot of other information which so far i dont know anything about. It is involved in how components take damage and how they appear when a ship is destroyed.

3. Setting up the part as a destructable component - This information is contained in the ships entry in shiparch.ini

There are several features of game ships which seem redundant. Removing them all from a game ship seems to make absolutely no difference to how the ship/components behave. As i see no purpose for them i havnt included them, tho it is quite possible i have overlooked something. Things not included :

Components .sur and .3db files.
Components {Simple} entry in shiparch.ini (this points to the .3db file)
Harpoint 'DpName_of_component' on hull.

You can try removing all these things from a game ships and its components appear to behave exactly the same. The kusari blood dragon is a good ship to try it on because it has obvious components.

Also i have not included any LOD information. Setting up the various lod's is the same as for a one part ship. You must make 4 versions of the model, each witha different name i.e. ship.lod0, ship.lod1 etc. and export to 4 .cmps. Then you must import the different VMeshData segments from the 4 .cmps into the same file. Then you must correctly define all the various parts in each lod in its appropriate name_of_component.3db -> Multilevel -> level X node.

Step 1 - Correctly defining what vertexes/triangles form each component.

Create your model as normal in milkshape, remembering to assign a material to each component. Before you add the Hps decide what parts you want as separate components and regroup them - the main hull should still be the first group with the components after it. Game ships have 2 groups for destructable components, the fist of which is destroyed and the second remains so a hole isnt left in the hull. However the same effect can be achieved by hiding all you components in milshape and adding faces to the hull which will only be seen if a component is destroyed. In the Battleaxe they are just flat faces but you could easily added jagged edges with a burnt texture. It does not matter what you call the components in milkshape but you must know the order in which they come after the hull.

Add your Hps as normal. Note down which Hps are going to be associated with each component eg. in the Battleaxe the third group is the port wing and it has HpWeapon04 on it. Now export your model as a .cmp.



Edited by - Chips on 10/31/2004 8:17:06 AM

Post Tue Jul 15, 2003 1:06 pm

You now have a .cmp file which you should open with FLUTF. The first node is VMeshLibrary -> name_of_hull.lod0.vms -> VMeshData . This node contains information on all the vertexas and triangles which form the model and which of these are in each group. However it does not define the groups in the same way as a game ships so you are going to have to manually edit it with a hex editor. Export the VMeshData node to a file and open it with your editor. The first 16 bytes are a header defined as :

header
{
dword 1
dword 4
word number_of_meshes
word total_number_of_referenced_vertices (in short, number_of_triangles * 3)
word fvf (0x112)
word total_number_of_vertices
} = 16 bytes

(from HCls VMesh guide)

The header is fine, you may want to check the value for number_of_meshes is correct tho.

Directly after the header are the mesh segments in the format :

mesh
{
dword materialID
word start_vertex
word end_vertex
word number_of_referenced_vertices (as before, number_of_triangles * 3)
word padding (always 0xcc, may be a padding value, for dword allignment)
} = 12 bytes

One mesh segment for each group. It is the start/end_vertex numbers you are going to be changing. Here is the VMeshData sgement from the Battleaxe with the first mesh segment in bold and the start/end_vertex numbers in italics :

01 00 00 00 04 00 00 00 06 00 A5 15 12 01 AE 07
D5 DF 03 00 00 00 14 06 91 11 CC 00 D5 DF 03 00
15 06 3D 06 6C 00 CC 00 D5 DF 03 00 3E 06 6B 06
6C 00 CC 00 D5 DF 03 00 6C 06 91 06 48 00 CC 00
D5 DF 03 00 92 06 1F 07 7A 01 CC 00 D5 DF 03 00......

Each components start_vertex number must be 00 00. The end_vertex number is what number the end_vertex would be if the start_vertex was 00 00. So for each mesh segment you must change the start_vertex number to 00 00, then to work out the end_vertex number subtract the original start_vertex number from the original end_vertex number. So in the case of the first mesh segment the start_vertex number is already 00 00 and the original end_vertex number minus 00 00 is still 14 06. This is why a single mesh exported to .cmp works fine. However the rest of the mesh segments need changing. Here is the same VMeshData segment with the second mesh segment in bold and the start/end_vertex numbers in italic :

01 00 00 00 04 00 00 00 06 00 A5 15 12 01 AE 07
D5 DF 03 00 00 00 14 06 91 11 CC 00 D5 DF 03 00
15 06 3D 06 6C 00 CC 00 D5 DF 03 00 3E 06 6B 06
6C 00 CC 00 D5 DF 03 00 6C 06 91 06 48 00 CC 00
D5 DF 03 00 92 06 1F 07 7A 01 CC 00 D5 DF 03 00......

So the start_vertex number (15 06) becomes 00 00. The end vertex number becomes 3D 06 - 15 06 = 28 00. For each mesh segment make a note of the original start_vertex number as you need this for the VMeshRef segment. Also make a note of the number of vertexes and number of referenced vertexes each mesh uses. The number of vertexes used is simply your new end_vertex number + 1 (29 00 in the above example), the number of referenced vertexes is given correctly in the mesh segment after the end_vertex number - so in the above mesh segment it is 6C 00. So work through all the mesh segments entering the new start/end_vertex numbers and noting down the original start_vertex number, new end vertex number + 1 and number_of_referenced vertexes. Here is how the above segment looks once it has been modified (with start/end_vertex numbers in bold) :

01 00 00 00 04 00 00 00 06 00 A5 15 12 01 AE 07
D5 DF 03 00 00 00 14 06 91 11 CC 00 D5 DF 03 00
00 00 28 00 6C 00 CC 00 D5 DF 03 00 00 00 2D 00
6C 00 CC 00 D5 DF 03 00 00 00 25 00 48 00 CC 00
D5 DF 03 00 00 00 8D 00 7A 01 CC 00 D5 DF 03 00......

Here are my notes for each segment in the format original start_vertex, new end_vertex + 1, number_of_referenced vertexes :

Hull : 00 00, 15 06, 91 11
TopFin : 15 06, 29 00, 6C 00
LWing : 3E 06, 2E 00, 6C 00
RWing : 6C 06, 26 00, 48 00
LEngine : 92 06, 8E 00, 7A 01

Once you have finished changing all the numbers save the new VMeshData segment and import it back into your .cmp in place of the old one. You next task is to create VMeshRef segements for each component. With your .cmp open in FLUTF look for a node called name_of_hull.3db . It contains a Hardpoints node and a Multilevel -> Level0 -> VMeshPart -> VmeshRef node. You must create a name_of_component.3db node for each component (by clicking on the .\ node and seleting add node).

At this point you can add your hardpoints to each component - add a Hardpoints node to your components .3db node, add a Fixed / Revolute node (or both if your component has both types of Hp) now you just need to transfer the relevant Hps from your name_of_hull.3db -> Hardpoints node to their new location - manually of course. Once you have done that delete the Hps node on the name_of_hull.3db -> Hardpoints node.

Now under each .3db node you have created you must make a Multilevel -> Level0 -> VMeshPart -> VmeshRef node. Once you have done that locate the original VMeshRef node of the hull (under name_of_hull.3db -> Multilevel -> Level0 -> VMeshPart -> VmeshRef ) and export it to a file. The format of the VmeshRef node is :

VMeshRef
{
dword 0x3c
dword VMeshID
word start_vert
word end_vert
word start_vert_reference
word end_vert_reference
word mesh_number
word number_of_meshes

float bounding_box[6 (minx, maxx, miny, maxy, minz, maxz)
float unknown[4
} = 60 bytes
(again from HCls guide to VMesh)

The .cmp exporter does not create any data for bounding_box or unknown. This doesnt seem to matter tho as these pieces can be removed from game ships .cmp files with no obvious effect. Open up your VMeshRef segment in your hex editor. The original Battleaxes segment looked like this :

3C 00 00 00 F4 C1 10 F9 00 00 00 00 00 00 00 00
00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00

The reason you get away with this little information is because the only information required to display meshes is the start_vertex number, the start_vertex_reference number, the mesh_number and number_of_meshes. So the above segment tells FL to start at vertex/vertex_reference 00 00 on the first mesh and read in 6 meshes. You now need to create a VMeshRef segment for each component using the values you noted down from before. Start with the hull, here is the new format :

VMeshRef
{
dword 0x3c
dword VMeshID
word original start_vertex number from VMeshData segment
word number of vertexes (new end_vertex number from VMeshData + 1)
word start_vert_reference (total of number_of_vertexes_references for all preceding parts)
word number of vertexes referenced (from VMeshData segment )
word mesh_number
word number_of_meshes

float bounding_box[6 (minx, maxx, miny, maxy, minz, maxz)
float unknown[4
} = 60 bytes

The only calculation you have to do here is working out the start_vert_reference number which is the total of number of vertexes referenced for all previous parts. As a check you can also make sure your start_vertex number for each component is equal to the total of all previous number_of_vertexes. So here is the new VMeshRef segment for the hull of the Battleaxe :

3C 00 00 00 F4 C1 10 F9 00 00 15 06 00 00 91 11
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00

As you can see i have added in the number_of_vertexes (15 06) and number_of_vertexes referenced (91 11). The start_vertex/vertex reference numbers remain the same. I have also changed number_of_meshes to 01 as the hull is only one mesh. Save this new file as hullvmeshref (or similar) and import into the name_of_hull.3db -> Multilevel -> Level0 -> VMeshPart -> VmeshRef node of your .cmp.

Now go back to your hulls VmeshRef segment in the hex editor. You now need to edit it so it applys to your first component (in the Battleaxe this is the TopFin). You have the following numbers noted down for this component :

TopFin : 15 06, 29 00, 6C 00

The only number you need to calculate is the start_vertex_reference number which is the total of number_of_vertexes_referenced for each previous part. As the only previous part is the hull the start_vertex_reference number is 91 11. Here is the VMeshRef segment for the TopFin :

3C 00 00 00 F4 C1 10 F9 15 06 29 00 91 11 6C 00
01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00

Again i have plugged in the relevant values. Also mesh_number has changed to 01 00 as the TopFin is mesh number 1. Note that the VMeshID (in this case F4 C1 10 F9) is the same for all components and is the VMeshID of the hull. Again save this file as topfinvmeshref (or similar) and import into name_of_component.3db -> Multilevel -> Level0 -> VMeshPart -> VmeshRef node of your .cmp.

The next component in the Battleaxe is the Left Wing. From the VmeshData segment i have the following information :

LWing : 3E 06, 2E 00, 6C 00

Again the only number we need to calculate if the start_vertex_reference number which is the total of number_of_vertexes_referenced for each previous component. So before the Left Wing there is the hull and top fin giving a total of 91 11 + 6C 00 = FD 11. Here is the VMeshRef segment for the Left Wing :

3C 00 00 00 F4 C1 10 F9 3E 06 2E 00 FD 11 6C 00
02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00

Values from above plugged in and start_mesh number changed to 02. Again save this and import into the relevant VMeshRef node in your .cmp.

Repeat this process until all your components have the correct VMeshRef segments in the .cmp. That is Step 1 complete.


Edited by - redeye on 15-07-2003 14:18:41

Post Tue Jul 15, 2003 1:06 pm

Step 2 - Relative positoning of components and hull

If you have managed to get this far you have done most of the hard work. Your next task is to create a node in your .cmp under Cmpnd called Cons (presumably for 'Connections'). Create a node under Cons called Fix (for parts that can move i.e. baydoors/weapon barrels this is called Rev ). This part is required for correct display of your component. Until the data contained in it is fully worked out you are going to have to steal one from a game ship.

When deciding what ship to steal it from there are a few things to be taken into consideration. Firstly you must steal the Fix segment from the ship whose .sur file you intend to use. Mismatching Fix segments and .sur files mean a ship takes damage as the .sur file tells it to but the components dont. Secondly you must hijack one of the game ships components for each of your components. What original component you hijack for your component will affect how much damage it takes. For the Battleaxe i used the Eagles .sur file and Fix segment. The wings on the Battleaxe use the segment of Fix which related to the Eagles wings, the Engines use the part that related to the Eagles engines and the Topfin uses the Eagles Topfin segment. A point to note here is that the Eagles engines are not destructable. It does not matter whether the segment of Fix you hijack for your component is destructable or not, any one will do (i.e. all ships have the glass in the cockpit as a separate part, you can steal the segment of Fix for this for a destructable component). However the relative sizes of the component you hijack affects how much damage that part will take. So the wings on the Battleaxe are far easier to destroy than the engines, even tho they have the same hit points, because the Eagles wings are far bigger than its engines. Once you have picked what ships .sur file you are going to use open up that ships .cmp file and export the Cmpnd -> Cons -> Fix segment to a file. Open with your hex editor. Each components entry is in the following format :

"Root"
60 bytes (unknown purpose)
"'name_of_component'_lod1"
<112 bytes

Total = 176 bytes

Basically the "'name_of_component'_lod1" and the rest of the segment total 112 bytes. Here is the segment of the Eagles Fix node which relates to the Eagles Starboard Wing :

'R' 'o' 'o' 't' 00 3D 7C 12 A1 F7 41 00 E0 CF 13 00
10 D9 24 02 03 00 00 00 34 62 87 00 00 00 00 00
C8 A6 41 00 AB 14 00 11 C1 FB 41 00 39 B4 41 00
5B B4 41 00 03 00 00 00 68 3D 7C 12 10 10 02 28
'c' 'v' '_' 's' 't' 'a' 'r' '_' 'w' 'i' 'n' 'g' '_' 'l' 'o' 'd'
'1'
00 7C 12 88 E6 13 00 28 F9 EB 01 68 3D 7C 12
9A A2 ED 08 68 3D 7C 12 88 E6 13 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
64 4C D3 40 6E 2E F3 3E C6 39 17 40 00 00 80 3F
40 DE 4C 26 4C DE 4C A6 3F DE 4C A6 00 00 80 3F
00 00 80 33 4D DE 4C 26 00 00 80 B3 00 00 80 3F

I have replaced the hex for the text with the text it codes for and put it in bold.
The only bit of this i understand is the bit in italics. It defines where the origin is for each component (relative to the hull) as three floats. The game ships VMeshData segment appears to encode all the components meshes as if they are centred on the x,y,z axis. Not as they appear on the ship. As you have made your model with the components in the correct place on the ship the correct origin for the components is 0, 0, 0.

So for each component in your ship you must pick an original component in the Fix segment and change the origin of that component to 0, 0, 0. As three floats this will be 00 00, 00 00, 00 00. Personally i dont like putting blocks of zeros in things (stupid i know) so i usually change the origin to 0.00000001, 0.00000001, 0.00000001 which is BD 37 86 35, BD 37 86 35, BD 37 86 35 in hex.

Basically you need to pick an original component for each of your new components, change the origin (decimal address 128 - 139 in that components segment in the Fix node - where the 'R' of Root is address 0) to 0, 0, 0 and note down the name of the component i.e. 'cv_star_wing_lod1' in above example. Once you have changed the origin for as many components as you have to 0, 0, 0 save the Fix segment and import into your .cmp under Cmpnd -> Cons -> Fix .

That is all the hex editing you are going to have to do

Now you need to create a node for each of your components under the Cmpnd node in the .cmp. The name of this node should be "Part_'name_of_component'". 'name_of_component' in this case can probably be anything. However to be on the safe side use 'name_of_component' from the Fix segment. So for the Battleaxes right wing i am using the Eagles star wing entry in the Fix segment. Therefore the Cmpnd -> Part_'name_of_component' node for this is called Part_cv_star_wing_lod1 . Add a Part_'name_of_component' node for each one of your ships components. Each Part_'name_of_component' node has 3 sub nodes :

File name - String -'name_of_component.3db' this must match the name of the .3db node you created for your component in Step 1.
Index - 8 byte integer array - 1, 0 for first component, 2, 0 for second etc. Doesnt seem to matter, you can probably miss this node out
Object name - 'name_of_component' from Fix segment.

So for the Battleaxes right wing i used the cv_star_wing_lod1 segment of the Fix node. I also called the 'name_of_component.3db' node 'cv_star_wing_lod1.3db' but i could have called it 'Battleaxe_right_wing.3db' as long as i entered that as the Cmpnd -> Part_cv_star_wing_lod1 -> File name node. So the three sub nodes for the
Cmpnd -> Part_cv_star_wing_lod1 node in the Battleaxe are :

File name - cv_star_wing_lod1.3db
Index - 03 00 00 00 00 00 00 00
Object name - cv_star_wing_lod1

Once you have added a Cmpnd -> 'Part_name_of_component' node and 3 sub nodes for each component you have finished Step 2. At this stage if you save your .cmp and put the ship in game it should appear corretly as the complete model with all components in place. However none of the parts will be destructable yet.

Step 3 - Defining your components as being destructable in shiparch.ini

This is the easiest part. There are two entries after the main {Ship} entry for each component, a {CollisionGroup} entry and a {Simple} entry. I see no purpose in the {Simple} entry, it refers to the components .3bd/.sur file however removal of these files and the {Simple} entry for a game ships components does not seem to make any difference. This means the only entry you need to worry about is the {CollisionGroup} one. The easiest way to make these is to steal the {CollisionGroup} entry from another ships component. Here is the Eagles starboard wing {CollisionGroup} entry :

{CollisionGroup}
obj = cv_star_wing_lod1
separable
parent_impulse = 120.000000
child_impulse = 60.000000
debris_type = debris_small_ship
separation_explosion = explosion_small_ship_breakoff
mass = 5.000000
type = Starboard_Wing
dmg_hp = DpDmg_starwing
dmg_obj = cv_fighter4_star_wing_cap
hit_pts = 550
root_health_proxy = true

For each of your components {CollisionGroup} entrys set obj = 'name_of_component', where 'name_of_component' is the components name in the Fix segment (also the same as the Cmpnd -> Part_'name_of_component' -> Object name node).

Parent/Child impulses seem to be to do with how the component is blown off. If you hugely increase child_impulse then the component is blow miles away and you never see it.

Debris_type and separation_explosion are fairly obvious. As is mass, it possibly affects how the component behaves after is has been blown off.

Type doesnt seem to make any difference, to be tidy set it to the type of object your component is (i.e. Top_Fin, Starboard_Engine etc.)

dmg_hp refers to a hardpoint on the hull with the same name. Again removing this Hp from the hull and/or screwing around with its name in the {CollisionGroup} entry seem to make no difference so you can leave this alone.

dmg_obj refers to the {Simple} entry for the component. As we are not even putting in a {Simple} entry for the component you can leave this alone too.

hit_pts is obvious too. This is how much damage your component will take before it is blown off. Remember that the amount of damage your component takes relates to which original components entry in the Fix segment you hijacked. So for the Battleaxe the wings take far more damage from randomly directed fire than the engines because the Eagles wings are a much bigger target than the engines. Unfortunately the component will take full missile damage even without a .sur file. Hopefully when the Fix segment and/or the .sur files are worked out this issue will be resolved. For the time being you will have to work out some kind of compromise. If your component is much bigger than the original component you will have to set the hit_pts quite low as only a small percentage of the damage the ship takes will get to it. However if you set it too low then one hit from a crappy missile will blow off all the components.

root_health_proxy = true is the same for all components. I havnt tried changing this but i expect if you do the component wont recieve damage. Tho it is possible if you set this to false that it may start using the components .3db and .sur files to calculate damage. I doubt this tho so just leave it as it is.

Once you have completed a {CollisionGroup} entry for all your components save shiparch.ini. Copy the .sur file from the ship which you stole the Fix segment from to your ships directory and rename it yourshipname.sur. Load up FL. Once your shield is depleted (sell your shield to test the ship) all the components should start taking damage. Setting each components hit_pts entries (in {CollisionGroup} in shiparch.ini) to something really low like 10 or 20 is a good way to test if everything is working, then you can increase them accordingly.

Thats it. Hopefully you now have a ship with components which blow off after taking a certain amount of damage, taking any Hps on them away. Remember to check the Battleaxes .cmp file if you are getting lost, it might even be a good idea to use battleaxe.cmp as a template, importing your various VMeshData/Ref segments into it and renaming nodes accordingly. Good luck.

Edited by - redeye on 15-07-2003 16:03:10

Post Wed Mar 10, 2004 3:46 pm

Thanks for the tutorial, it helped a lot.

Post Sat Mar 13, 2004 3:29 pm

Wow! That's a lot of hex. Don't suppose someone is willing to write an editor to make this kind of thing any easier?

(This site is best viewed with your eyes open)

Post Sun Mar 28, 2004 5:30 am

Harrier seems to be on top of the overall issue, so maybe he's the man to get the whole issue wrapped up in a util.

Meantime, alot of the tedious hex editing can be removed by using this util.

Post Wed May 04, 2005 10:04 pm

Is there an updated tutorial for making a multi component ship with meshconv that i missed or has that just not been done yet?

Return to Freelancer Editing Tutorial Forum