I've been trying to check the smod file format in python (just for fun, nothing serious), using the info from this post:
My plan was to try to convert the smod to .obj (Wavefront) format Wavefront_.obj_file or something similar, and then convert it back to smod.
For testing I'm using a very basic model: 'Data\Entity\Building\b5_dun_bossroombottom.SMOD'
which is a simple flat square, (4 vertex and 2 faces I guess), something like this: [\]
But I can't figure out what the 'yellow parts' are.
I think 02 00 00 00 00 00 03 00 01 00 03 00 00 00 02 00 means '2 faces, (i1 i2 i3) x 2', but I don't know the rest.
The format provided with your previous post (that quoted some old info I gave?) is not complete.
Here is a more complete description of .smod structure.
Code:
struct String {
long count; // number of character to follow
char *buffer;// array of characters
};
struct Vertice {
float x, y, z; // coords in 3D space
float nx, ny, nz; // normal of this pt (for light computation)
float unk; // float or COLORREF
float u, v; // mapping of this pt on the 2D texture
};
struct Vertices {
long count;
Vertice* vertcs;
};
struct Face {
// the 3 shorts are indexes within the Vertice array
// to read three 3D points(& tex info), these 3 pts
// define a triangle (all shaiya shapes are built with
// triangle as elementary unit
unsigned short i1, i2, i3;
};
struct Faces {
long count;
Face* facs;
};
struct Module {
// texture file for this module; .tga should be changed to .dds
// a few files (likely bugged or not fianlized) have empty string
String textureFilename;
// 3D shape definition
Vertices vertices;
Faces faces;
};
struct Point3D{
float x, y, z; // coords in 3D space
};
struct ExtraModule {
// puzzling block apparently w/o texture
// I never draw it when I draw .smod and nothing seems missing
long countPoints;
Point3D* point3D;
long countFaces;
Face* facs;
};
// SuperModule ::= content of a .smod file
struct SuperModule {
// coords of center of the whole 3D shape
float xCenter, yCenter, zCenter;
// int32 or float; all those I've checked individually have a null value (4x00)
// it may be possible that this is a String value and thus a length which is
// quite always equals to zero, and thus not followed by chars; if someone
// found a smod with a not null value there, thank to post the info
long unk; // int32 or float, possibly a glow
// min & max coords of the whole 3D shape
float xMin, yMin, zMin;
float xMax, yMax, zMax;
// embedded module(s)
long count;
Module* modules;
// 2 fPoint3D (repeated min & max values (to be confirmed))
float unkPt1, unkPt2;
// extra block with 3D info without a texture name, unless
// "unk" above is part of such tex info
long countExtra; // 0 for quite all files
ExtraModule* extraMod;
};
Entity/Building/b5_dun-bossroombottom.smod reads as follows:
Code:
SuperModule module = {
( -1.201763f, -2.950162f, +1.623264f), // center
+67.644630f, // unknow
(-52.017746f, -2.950162f,-43.025726f), // min coords
(+49.614220f, -2.950162f,+46.272255f), // masx coords
// array of Module
{
// Module 1
{
"L_R1_DUN2_2F_10.tga", // texture name
// array of vertex
{
{ -52.017746f, -2.950162f, -43.025719f, +0.000000f, +1.000000f, +0.000000f, 0xFFFFFFFF, -2.040799f, +2.732449f },
{ +49.614212f, -2.950162f, -43.025726f, +0.000000f, +1.000000f, +0.000000f, 0xFFFFFFFF, +3.040798f, +2.732450f },
{ -52.017738f, -2.950162f, +46.272255f, +0.000000f, +1.000000f, +0.000000f, 0xFFFFFFFF, -2.040798f, -1.732450f },
{ +49.614220f, -2.950162f, +46.272247f, +0.000000f, +1.000000f, +0.000000f, 0xFFFFFFFF, +3.040799f, -1.732449f }
},
// array of faces: the shape consists in 2 triangles
{
{ 0, 3, 1 }, // 1st triangle is build with vertex 0, 3 & 1 above
{ 3, 0, 2 } // 2nd triangle is build with vertex 3, 0 & 2 above
},
},
}
// 2 fPoint3D (repeated min & max ?!?
(-52.017746f, -2.950162f,-43.025726f)
(+49.614220f, -2.950162f,+46.272255f)
// no "ExtraModules"
}
I gave a try using c++ (which I don't know), with this code
Code:
struct SuperModule {
float xCenter, yCenter, zCenter;
long unk;
float xMin, yMin, zMin;
float xMax, yMax, zMax;
};
//...
FILE *fp;
struct SuperModule Rec1;
if ((fp = fopen(FMOD, "r")) != NULL)
{
fread(&Rec1, sizeof(SuperModule), 1, fp);
printf("Center: x %ff y %ff z %ff \n", Rec1.xCenter, Rec1.yCenter, Rec1.zCenter);
printf("Unk: %f \n", Rec1.unk);
printf("Min: x %f y %f z %f \n", Rec1.xMin, Rec1.yMin, Rec1.zMin );
printf("Max: x %f y %f z %f \n", Rec1.xMax, Rec1.yMax, Rec1.zMax );
fclose(fp);
}
...//
And it gives me this result:
Code:
Center: x -1.201763f y -2.950162f z 1.623264f
Unk: 0.000000
Min: x -52.017746 y -2.950162 z 107373248.000000
Max: x -107374176.000000 y -107374176.000000 z -107374176.000000
All good until the MinZ float, (not a float).
I dont know if it's a problem related to the way C manages data (endianess, etc)
%f does print a float and on Wintel all numbers value are little-endian encoded.
So the printf is not the issue (obviously).
In C/C++, the content of uninitialized variables is not specified, with Microsoft compilers, it is usually 0xCC and 0xCCCCCCCC read as a float gives the value -107374176.
So the issue is simply why your code is reading only 25 bytes (6 floats *plus* 1 byte) instead of 40?
Fortunately, we are still dealing with the same file; here is its content (beginning):
the 26th byte is '1A' ... which is ... not printable.
'20' was read as a space char, '0D' as a CR, '12' as a FF, but '1A' is rejected stopping the stream processing, so the initialization of the struct and the -107374176 value.
Your error was to NOT specify the file mode, so the file in opened in text mode and filtering of printable (vs illegal) characters apply. You SHALL use "rb" to specify "Reading in Binary mode" (or "rt" read.text when required) but never "r" that always leads to error.
A 1 line response may have been enough but now I'm sure you'll never redo the mistake.
Quote:
Originally Posted by sominus
I asume nx, ny, nz are 'vertex normal' and 'u, v' texture coordinates ?
I'll see if I can't translate that to the .OBJ format, which is in plain text.
I don't understand what 'coords of center' and 'min max coords' are for in the game engine, axis of rotation and bounding box may be?
BTW, yes, (nx, ny, nz) is a vector normal to the point, and (u,v) the texture coords.
The center coords are likely used to insert a shape in a field,
the min & max can be (directly) used to manage collisions with other items (including players).
the last couple of points is less obvious, they are not always the min & max, never outside these limits but something smaller than them (smaller by abs value for neg values).
Btw, I'm not sure all "simple" 3D structs were published.
.mlt, .itm, .3de, .3do & .3dc are described below.
Code:
// generic types
struct String {
long length; // number of characters to follow
char *chars; // characters (usually zero terminated)
};
// .MLT
// known structures: 1 ("ML2")
struct RecordMLT {
long index3DC; // index of a .3DC filename
long indexDDS; // index of a .DDS filename
long alphaFlg; // alpha channel flag (0: alpha channel defines visibility, 1: alpha defines glow)
};
struct FileMLT {
char sign[3]; // signature: 'M','L','2'
long count3DC; // number of .3DC filenames to follow
String *names3DC; // array of filenames
long countDDS; // number of .DDS filenames to follow
String *namesDDS; // array of filenames
long countRec; // number of records to follow
RecordMLT *records; // array of the RecordMLT
};
// .ITM
// known structures: 2 ("ITM" & "IT2")
struct RecordITM {
long index3DO; // index of a .3DO filename
long indexDDS; // index of a .DDS filename
long glow; // glow mode
long unk2;
long format; // 0 or 1
long unk3;
long rgba; // present if format == 1
long unk4; // present if format == 1
long scale; // present if format == 1
long unk5; // present if format == 1
long unk6[1024]; // present in struct "IT2" (32 block of 8 int32)
};
struct FileITM {
char sign[3]; // format: 'I','T','M' or 'I','T','2'
long count3DO; // number of .3DO filenames to follow
String *names3DO; // array of filenames
long countDDS; // number of .DDS filenames to follow
String *namesDDS; // array of filenames
long countRec; // number of records to follow
RecordITM *records; // array of the RecordITM
};
// common to .3D?
typedef struct _Faces {
unsigned short i1, i2, i3;
} Faces;
// .3DE
typedef struct _Vertex3DE {
float x, y, z;
long bone;
float u, v;
} Vertex3DE;
typedef struct _Anim3DE {
float dx, dy, dz; // seems to be spatial movement
float u, v; // possibly tex mapping or shift on tex coords
} Anim3DE;
typedef struct _Block3DE {
long index; // index of anim (even value)
Anim3DE* steps; // [cntVertices]
} Block3DE;
typedef struct _3DE {
long signature; // '00000000'
long cntVertices;
Vertex3DE* vertices;
long cntFaces;
Faces* faces;
long maxAnimIndex; // anim steps range 0 up to animIndex by step of 2
long cntBlock; // = maxAnimIndex / 2 + 1
Block3DE* blocks; // each block contains cntVertices steps
} File3DE;
// .3DO
typedef struct _Vertex3DO {
float x, y, z;
float nx, ny, nz;
float u, v;
} Vertex3DO;
typedef struct _3DO {
String texName;
long cntVertices;
Vertex3DO* vertices;
long cntFaces;
Faces* faces;
} File3DO;
// .3DC
typedef struct _Quaternion {
float m[4][4];
} Quaternion;
typedef struct _Vertex3DC {
float x, y, z, w;
float e, f; // present in format 6
unsigned char bone1, bone2;
short alignment; // always '0000'
float nx, ny, nz;
float u, v;
} Vertex3DC;
typedef struct _3DC {
long tag; // 0 for format 5, 0x000001BC for format 6
long cntBones;
Quaternion* bones;
long cntVertices;
Vertex3DC* vertices;
long cntFaces;
Faces* faces;
} File3DC;
(long is as per C98, it's a 32bit value, not the C#/Java 64-bit type).
Yes, anyway I was doing it the wrong way, trying to convert smod to .obj, since that's useless (no point in editing existant smod files).
So it's better to make just a .obj2smod converter, that way people can model original new structures (rocks, walls, buildings), and put them in original new maps (we already know how to model new terrains with Unity but seems that nobody is doing it).
Several 3D objects can be translated to a single Module (will take good uv mapping skills tho).
The only left problem would be the lightmaps file (to simulate shadows on the terrain), but again, seems that people are not interested in the visuals).
Just a question: is c++ mandatory? Or the old C will work also? C# is not practical for this stuff (because the unmanaged types)
The language is up to you; C or C++ or C# can be used, each with its own characteristics but none will be definitively not practical.
The structs themselves introduce constraints, mainly for alignment, and these lang can all manage these details.
When the goal is to manage each and every vertex (from conversion to one format to another, for instance) you only care about the usability of the structs, so make them explicit & clear.
OOH, when the goal is to draw tens of shapes all kept concurrently in mem, one may prefer to keep some big buffers and perform pointer arithmetic.
As for the lights, ""the sun belongs to the sky and not to the object that is lit"" ... so for 3D shapes, you just have to manage the reflection (the normal vector of each 3D point); if the landscape already exists (a terrestrial field or a dungeon), the light or lights already exist. Of course, working with a brand new card will raise problems that I have not seen before. Thank for this interesting idea
Do min and max coord always the same as the first and last vertex coord?
In b5_dun_bossroombottom.SMOD:
min coord x: -52.017746
vertex[0] x: -52.017746
max coord x: +49.614220
vertex[3] x: +49.614220
Or is it just a coincidence?
Center of the Object, can it be '0,0,0' ?
The .obj model Im trying to convert (a single cube in this case), only have this info:
-vertex position (xyz)
-texture mapping coord (xyz)
-face info (a/a b/b c/c)
Coincidence.
Several usual techniques of drawing generate these particularities; but there is no formal reason for the min, max or center to correspond to a particular point.
The center can therefore be (0, 0, 0), it even has a big chance of being so if the object is regular and was symmetrically constructed.
Regarding conversion of shaiya formats to another formats, and especially the wavefront (.obj) format;
I started looking at the application to see if it could allow (eventually) worlds (.wld, .svmap) visual-editing.
Have you evaluated this product?
Do you have any reading tips related to existing libs (.py or other) to generate wavefont files?
Yes, I've tried blender since it's free, but I've been using 3dStudio for years, so I know how it works, and don't have time to learn blender from scratch (blender is made toward productivity, so is not too much new-user friendly)
To allow wld editing you would need to convert the terrain and all the smods to a blender-compatible data, but that would be a lot of work. Now, blender is open source if you want to look:
To generate a (very basic, but valid) .obj file it could be something like:
Code:
# this line is a comment
v -39.8107 37.2684 0.0000
v -39.8107 -36.7885 0.0000
v 39.0661 37.2684 0.0000
v 39.0661 -36.7885 0.0000
# 4 vertices
vt 0.0043 0.9920 0.5000
vt 0.0005 0.0005 0.5000
vt 0.9995 0.9995 0.5000
vt 0.9995 0.0005 0.5000
# 4 texture coords
f 1/1 2/2 3/3
f 4/4 3/3 2/2
# 2 faces
.obj has many more options (vertex normals, smoothing groups, etc)
but just indicating vertices, texture coord, and faces, you have a valid OBJ
this is how that code above looks like:
Since you already know how to open smods and extract info, you would just need to choose a small smod (single module),
and write the
-vertex coord array (v)
-texture coord array (vt)
-face array (f)
-(no materials needed)
to a plain text file (.obj), then open that file on any 3d viewer to see if the conversion was correct.
Then you may go with a more complex OBJ, with textures, and multiple objects, try converting it to a multi-module smod
EDIT:
I've made a flat plane object in waveform format if you want to test with it, it has a dds texture, uv and vertex normal coordinates.
It includes a material library (.mtl), you should edit it (it's just text) to indiacate the path to the texture you want to use.
Issue: OBJ files has 3 UV coordinates (vt records) , while SMOD has only 2. No idea how to solve that. I've tried using just the first 2 coord, but it resulted in a invalid smod file.
This is the plane1.obj converted to smod, opened in SStudio. Something went wrong with the Faces, one of them is missing.
I'm testing with the 3dsMax own scripting language
Sample code:
Code:
//mesh object
o = $mymesh
//some vars
minCoord = o.min
maxCoord = o.max
...
//get vertices into array
for i = 1 to vtxCount do
(
v[i] = getVert o i
)
...
My question is: In 3dsMax UVs are 3 points (U,V,W). And smod needs 2 points (U,V).
Example:
My mesh is a plane, has 4 vertices so I do
Code:
//3dsmax arrays are 'base 1'
for i = 1 to vtxCount do
(
uvCoord[i] = getTVert o i
print uvCoord[i]
)
Result:
[0, 2.98321,0]
[1, 0, 0]
[1.78993, 1 ,0]
[1, 1, 0]
So, do I use just the first 2 values to indicate 'u, v' in the smod ?
Something is wrong but I don't know what, wrong vertices order, or wrong face building may be?
See this test:
The part below is the source 3D shape in 3D Studio, with faces marked in Red.
The numbers in yellow are the vertices index order.
The part in green doesn't show in SStudio, but the info says all vertex and faces are there (6 vertex and 4 faces, same as source model).
In the source shape in Max, faces are built in this vertices order:
(vertices index)
[4,1,5]
[2,5,1]
[5,2,6]
[3,6,2]
I think I found the problem. Shaiya use base 0 index, and in 3dsmax base 1 index.
So faces were translated to a +1 value. Eg: Instead of [0,3,1 ] Max were saving faces as [1,4,2]
Now the model itself looks right. This 3D text in max
If anyone want to test, I've attached the test smod file (0test2.smod)
You have to put in in 'Data\Entity\Building' and add it to any map with SStudio
If it works, I'll arrange the convert script to make it a little easier to use and post it. (you will need to have 3dsmax installed tho, I use 3dsmax 2010)
For anyone who has 3DS Max (I use version 2010), this script will let you convert any Mesh Type model, into a smod, then you can insert it into a map with SStudio.
The script is far from finished, it doesn't have a visual form and controls yet. But if you know how to use 3dmax you will have not problems to use it.
I'll put and example of how to use it (I asume you have a at least a very basic knowledge of 3dsmax):
1) Create a 3D object, in this example a single 3D text.
2) Convert the object to a Mesh (Right click on the object, and Conver to: Editable Mesh) and name the object MYMESH (this is very important!)
3) Apply a texture from the game data folder (just to see how it looks, this is not mandatory)
4) When your model is done, rotate it 90º to it's back direction (use the Left view)
The object should be perpendicular to the Grid in the Perspective view. This is necessary since the game use a diferent position.
You have to change the output path and filename: Search for a line that says smodFileName = "D:\3dsmax\0max_test123.smod" and change the path and filename there, to the one you need (it could be any folder you want, just be sure it exist!)
Save the changes (File > Save) and close the code window.
7) CLick on Run Script and select the script (mes2smod.ms) file again, it should run without problems.
If everything went OK, you sould see something like this in the MAXScript Listener window:
And that's all, now you can add it to any map with SStudio.
Then make a patch with the new smod file and the WLD file you edited, and apply to the game client, go to the game and check it.
This is a sample, those objects are rotating but I don't have video recording tools.
You can edit the script with any text editor, to experiment. There are tutorials on max scripting, just remember to look for one that is supported by your 3dsmax version. ALso the script has many comments on what is going on in each line.
The script is attached to this post.
Offtopic: A question for @ How many vertices has the terrain part of a FLD map? (It was 512x512 lines ?) A script to generate a flat plane, edit the heights and export the raw data ready to be inserted in a WLD, should be possible.
What about distances in Shaiya? Are they pixels? Meters? Custom?
This is how a terrain data could be fomed:
4 vertices, then half the distance between them to make the 5th vertice in the center, then build faces from vertices 1, 2 and 5, then 2, 3 and 5, then 3, 4 and five.
It will require many maths tho.
if mapType is Field-Map ('FLD\0') the following format applies:
Int32 mapSize; // either 1024 or 2048
Nota: shStudio considers any value different than 1024 and 2048 as an error and stops the parsing of the .wld file.
This is a bit overdone, possibly the client-game is only able to manage these 2 sizes, but possibly the fact that all AGE maps use one of these 2 figures is not due to a game limitation.
The field is always square and is divided in small squared tiles.
The number of tiles in one direction is the mapSize divided by 2.
And the field (the ground) is defined by the azimut of its 4 corners, there are so (mapSize / 2) + 1 points one each line, and the whole map-height consists in ((size / 2) + 1)² azimut (Y coordinates).
The "size on the ground" (meaning the scaling of X & Z axis) is not defined by the data; it is an internal parameter of the shayia rendering system.
The coordinates of all items (.smod for buildings but also NPC and weapons) seem to share the same scaling system, but nothing grants that.
Regarding the filling of the map, your last schema is - as far as I understand it - not correct; each tile of the field is not split into 4 triangles, each filled from a texture and 3 {u, v} coordinates; this process is used by everything (including dungeons) but not the fields.
Instead, the textures of each tile of the field is defined by 4 square textures that are used to fill the tile.
The field-textures are the .dds stored in the .Terrain\Detail folder.
If the texture identifiers of the 4 corners of a tile are identical ... that texture is used.
If several (2+) values are present, a composite texture is built by some gradient merge mechanism.
shStudio uses a poorly optimized routine to merge textures (with likely some shortcuts to not handle all cases because it was too slow)[1], possibly some better (far faster) methods exist in DirectX, I never investigate that.
Regarding your question related to the metrics of the map; the sole reply which is not a bet is: let's give a try!
Possibly, using a mapSize of 1024 and inserting a .smod at coordiantes 512.0f, 512.0f it will be right on the center (and to avoid boring maths we would want that) but honestly I don't know [2].
[1]
[2] I finalized the .world and .svmap editors after my own server was down and I never was able to make such basic tests.
Amc-Datei-Format in Conf-Datei-Format konvertieren 01/01/2014 - Technical Support - 5 Replies Hallo allerseits,
ich benötige Hilfe mit meiner Sharkoon Drakonia Gaming Maus.
Wenn man bei dieser Maus die Makros bzw. Profile speichert,
muss man diese als Einzeldatei (Configure = .conf) irgendwo abspeichern.
Es gibt nicht wie bei anderen Gaming Mäusen einen Makro-Ordner.
Ich kann nur die Profile einzelnd laden, welche .conf-Dateien- und .amc-Dateien, wie bei den meisten anderen Mäusen, sind.
Daher frage ich mich, ob mir hier irgendwer, ohne irrelevante Beiträge, irgendwie...