Name of the assigned function and model

Posted By: 3run

Name of the assigned function and model - 09/20/16 12:36

Hi there!

Is there anyway to get what function and model names specific model has? F.e. I have an entity that uses 'guard.mdl' and has function 'hero' assigned to it. And inside of that function I want to get the name of the model (guard.mdl) and the name of the function (hero). I checked 'atypes.h' and in entities structure I found this:
Quote:
EVENT local; // client side function
void* model; // mesh/skin info pointer
But 'my.local' is NULL when I try to access it from the hero function. And yet I can't understand how to use 'void* model', I need to save name of the model into the string.

Edit: plus, now I started thinking about how could I save functions name properly, so I could recreate the object and assign that function to it? You may already understand, I'm trying to create some kind of a load/save system, which will save the whole level into the file, and then read it back when needed (could be used for loading levels as well, like in good old resident evil type of games, where each level is a separate room). Any ideas are welcome! Thank you in advance.

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/20/16 16:53

Hi,

str_for_entfile returns the model name. As for the function, not sure but I think you can save it in entity.string1/.string2.
Perhaps engine_getscript (char* name ) is also usefull here.

Are you making a level editor or such? If yes I think you can use entity.string1/2 to save the action in a .wmb. Personally for my level editor I just use a skill to save the action as an ID/number (+DEFINE to make the script readable tongue ).
Posted By: 3run

Re: Name of the assigned function and model - 09/20/16 17:53

No, I'm trying to create save/load system between levels (like in old Resident Evil type of games). So I could separate the game into small rooms and when I'll go from one room into the other one, I'll save progress into the file (so picked up items won't appear again, or already killed enemies won't try to kick my ass over and over again).

Thank you for a tip with 'str_for_entfile', it worked flawlessly. Now I can save NPCs with their unique bounding boxes, plus positions/orientations, but no functions yet. I don't really know, how it would be better to save the function name, maybe saving it into the string before writing it into the file, but then, how I'll be able to restore it to be used with ent_create as an EVENT action? Saving the function name automatically would be better than saving it by hand, but we'll see. Any ideas are welcome!

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/20/16 18:21

In that case I think I would save the action as a string in your save/txt file and when creating the entity on save load / map load use engine_getscript (char* name ) + the saved string in your ent_create function.

OR use game_save/game_load and only to save the functions/level/ents. Could be buggy though.
Posted By: 3run

Re: Name of the assigned function and model - 09/20/16 21:20

I got it working so far, but there is still a lot to do.

F.e. I would like to write all levels into one .txt file (or maybe separate all entities by types in the file), organize it like .ini file:
Quote:
[level1] list of entities
[level2] list of entities
If you guys would give me any advices about this, I would really appreciate it.

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/21/16 09:32

Originally Posted By: 3run
F.e. I would like to write all levels into one .txt file (or maybe separate all entities by types in the file), organize it like .ini file:
Quote:
[level1] list of entities
[level2] list of entities
If you guys would give me any advices about this, I would really appreciate it.
, with writing to txt file (simple example):
Code:
function file_skip1line(var handle_file)
{	
	file_asc_write(handle_file, 13); //new line
	file_asc_write(handle_file, 10);
}

...
function write_to_txtblabla() {
  var handle_file = file_open_write (filepath_str);
  file_str_write(handle_file, "Enemy 1");
  file_skip1line(handle_file);
  file_str_write(handle_file, "Enemy 2");
  file_close(handle_file);
}



For loading than use file_str_readto and str_parse is usefull too. Now for skipping to a certain string/point maybe try file_find , not sure about that one though. For only reading out number you can try file_var_read. Alternatively you can use txt_load if the text is not to big and use lite-c string functions to do your Acknex magic, than you can check with str_cmpni to check delimiters/strings that divide entities or levels or whatever.
For both you want some kind of delimiter/string to divide stuff in your text file, or keywords that help you find specific stuff like 'Damage:'.

This might also be helpfull to find specific stuff when you have it in your string:

Quote:
str_parse_tail(STRING* to,char*from,char* tail)
str_parse_head(STRING* to,char*from,char* head)
Extracts a word out of a string when its last characters (str_parse_tail) or its first characters (str_parse_head) are given.
Posted By: 3run

Re: Name of the assigned function and model - 09/21/16 10:41

Thank you very much! I'll look more into those 'file_' and 'str_' functions! laugh

Edit: maybe I won't save function's name at all, but object's ID instead. So I'll have only one function for NPCs (same for items etc), and inside of that function I'll set specific parameters for each NPC depending on it's ID.

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/21/16 13:16

Originally Posted By: 3run
Thank you very much! I'll look more into those 'file_' and 'str_' functions! laugh

Edit: maybe I won't save function's name at all, but object's ID instead. So I'll have only one function for NPCs (same for items etc), and inside of that function I'll set specific parameters for each NPC depending on it's ID.

Best regards!
, your welcome laugh . I would indeed go for 1 shared function. It saves alot of duplicated code and when expanding or changing your game your happy you have only 1 action. To keep it flexible and clear I personally try to throw as much of the code in small functions that I call in the big action if conditions are met (e.g. if (clip <= 0 && ammo > 0) reload(); ).

Also instead of saving the object ID you could also retrieve the object ID from its filename (if each object ID has a different model ofcourse). Say:
Player.mdl = 0 / PLAYER_ID
Rat.mdl = 1 / RAT_ID
Depends ofcourse what you want to achieve, but its more readable in the text file that way and easier to mod/change. Plus if you ever want to add a map editor, this will speed up the process for mappers since its 1 less variable to worry about.
Posted By: 3run

Re: Name of the assigned function and model - 09/21/16 13:44

About retrieving the objects ID from it's file name. I save only bounding box models (so each object could have it's own BBOX). Because I split collisions and visual part of entities, and each object will have it's own visual model depending on it's ID anyway (created in it's function as a parent). But it's all only in my head right now, let's see how it turns out on practise.

Best regards!
Posted By: 3run

Re: Name of the assigned function and model - 09/22/16 17:04

After thinking about this save/load system once again, I guess I just overthinked everything and made it way too complicated... (well, as I almost always do). I do not need to recreate any entities, cause they are already created with proper model and action attached to them while level loading. All I need to do, is load their settings (position/orientation and some skills) from file, and thats all grin Hopefully this will go right (anyway, I got recreating from file working, saving the function name into the string, then reading it back and using engine_getscript works flawlessly).

Best regards!
Posted By: 3run

Re: Name of the assigned function and model - 09/22/16 22:22

Yes! I got it to work! grin Now, next thing to go is player's transition between levels. And again I'm probably making things too complicated, while trying to think of a best way to handle this. Here is the thing:

I need to spawn player at correct positions, depending on which door he entered. F.e. when player goes from ROOM 1 into ROOM 2, then he should appear at the red circle (in the ROOM 2), same for the other rooms. When player goes from ROOM 3 into ROOM 2, he should appear at the green circle. I can only think of one way of handing this right now. Saving into global variable ID of the door, at which we should appear. Something like linking doors between each other. So door 1 from ROOM 1 is linked to door 1 in ROOM 2.. door 1 from ROOM 3 is linked to door 2 in ROOM 2. But I'm afraid this will get way too complicated at the end, and I'll mess things up, especially if there are going to be a lot of levels (99 level all with doors... linking all of them by hand? crazy ). Maybe tomorrow I'll end up with better idea, but right now need to get a sleep, plus I'm ill this days, so I feel myself not that good...

Edit: yeahh, still trying to keep this forums alive with double, triple posts grin

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/22/16 22:47

Loading only position stuff etc from a txt file in combination with level_load will ofcourse be a bit simpler to make but do keep in mind that won't allow you to save e.g. summonings or 'spawned from script/ent_created' enemies (so only pre-placed enemies). If this doesn't bother you than by all means go for it.

As for you door positions, iirc you can attach an other entity in WED in entity edit/properties menu (look for something like attach or parent or such). You can than use it in script. If that doesn't work out or if you need more attachments, save the ID's in skills of the door ents.

And get well soon wink
Posted By: 3run

Re: Name of the assigned function and model - 09/23/16 12:12

Well, I don't really need 'spawned from file' entities, I could always place then in WED, and make them appear by script, didn't quite get the 'summonings', but I'm pretty good with the way it works right now laugh The only limitation is, that objects can not be removed/deleted from the level. That's because I save them into the list (and because all entities are pre-placed in WED, they get recreated on each level load, so I'll face empty pointer when trying to load parameters from the list.. so it's much easer just to make it passable/invisible), and write that list in it's order into the file. If I remember correctly, I read here on the forum that 'ent_next' list is always different, so I didn't use it, to keep the right order of saving/loading.

Thank you, I feel a bit better today.

Edit: also, I'm thinking about what would be the best way of saving/loading position/orintation of NPCs. In lots of older games, they only used to reset NPCs to their start positions (without saving anything on level change). Maybe that's the way to go? Currently, I save their positions/orientations, so when I load level back, it looks same as right before going to another level.

Edit2: also, when I tried to save/load everything from a single .txt file, I faced a problem with 'file_open_write' as it removes all content from the file.. 'file_open_append' write stuff at the end. Maybe I could save the whole file content into the string, then split it to BEFORE and AFTER the room that I need to change stuff in. Then after changing, add this string with changes to the BEFORE string, and then add to it AFTER string. Or maybe I'm making things too complicated again grin

Greets.
Posted By: 3run

Re: Name of the assigned function and model - 09/23/16 13:16

This is how I've done it (the part with changing specific line in the string):
Code:
void save_into_file(){
	
	STRING* read_str = ""; STRING* write_str = ""; 
	STRING* before_str = ""; STRING* after_str = "";
	
	var fhandle = file_open_read("map.dat");
	if(fhandle == NULL){ error("File wasn't found!"); return; }
	
	var len_var = file_length(fhandle);	
	file_str_readto(fhandle, read_str, ";", len_var);	
	file_close(fhandle);
	
	// BEFORE string:
	var start_var = str_stri(read_str, "[ROOM 2]");
	str_cut(before_str, read_str, 0, start_var + 7);
	
	// AFTER string:
	var end_var = str_stri(read_str, "[ROOM 3]");
	str_cut(after_str, read_str, end_var, len_var);
	
	// get the part of the string, where we need to change stuff:
	str_cut(write_str, read_str, start_var + 8, end_var - 1);
	str_cpy(write_str, "THIS IS NOT THE SECOND ROOM!");
	
	// add empty space:
	str_cat(before_str, " ");
	// use that empty space to move pointer to the next line:
	str_setchr(before_str, str_len(before_str), 10);
	
	// add empty space to the stuff we've changed:
	str_cat(write_str, " ");
	// add changes to BEFORE string:
	str_cat(before_str, write_str);
	// use empty space at the end to move pointer to the next line:
	str_setchr(before_str, str_len(before_str), 10);
	// add AFTER str (so the whole string is complete now)
	str_cat(before_str, after_str);
	
	// write this all into the file:
	var fhandle = file_open_write("map.dat");
	file_str_write(fhandle, before_str);
	file_close(fhandle);
}

This code, changed txt file, with this:
Quote:
[ROOM 1]
This is first room!
[ROOM 2]
This is second room!
[ROOM 3]
This is third room!
[ROOM 4]
This is fourth room!
Into this:
Quote:
[ROOM 1]
This is first room!
[ROOM 2]
THIS IS NOT THE SECOND ROOM!
[ROOM 3]
This is third room!
[ROOM 4]
This is fourth room!
Maybe it may come in handy for someone. Didn't test it any farther, maybe it won't work in some situations grin

Greets!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/23/16 15:17

With summonings I mean enemies (or allies) that are 'summonend/created' by enemies. So e.g. a wolf summonend by a druid, or a soldier summonend by a captain. Its just a word that I like to use to categorize entities created by script (/ by other entities).

Minor point: as for ent_next's list being different everytime; this doesn't matter if you save the unique ID of entities only when first entering the map. It shouldn't matter much if entity with ID 50 gets loaded earlier than entity with ID 1, as long as both entities are loaded with their correct ID's. wink

Quote:
This is how I've done it (the part with changing specific line in the string):
, there should be an easier solution.
What I would do is probably something like this (not in real code but I think you will get the idea):

Code:
while (loop through every txt line of your save file) {
  1) get the current line and convert it to a lite-c string
  
  2) use the str_parse functions to get the value of that line

  3) use str_cmpni's to compare it content/description in some big nested if's to determine what to do with the value
}

Posted By: 3run

Re: Name of the assigned function and model - 09/23/16 19:16

Finally I got it working! grin Now I can save/load from one single file! Next thing to do it doors! Then I'll try to make playable example. Thank you Reconnoiter for poking me in the right direction! laugh

Best regards!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/23/16 20:14

Great. grin I did some other poking too, my.parent (sounds funny lol grin ) can also be used to save pointer when set in script (e.g. item attachment for entity). (offtopic) Sadly it doesn't work with Emre's to .wmb map compile code that I use for my level editor. smirk
Posted By: txesmi

Re: Name of the assigned function and model - 09/24/16 07:50

Hi,
I would use static memory instead of a text file. File text reading, interpreting and rebuilding is pretty slow and intrincated.

Look at this:
Code:
#include <acknex.h>

#define LEVEL_COUNT        20
#define OBJECTS_MAX        10

FONT *fntArial = "Arial#20";

typedef struct OBJECT
{
	var x;
	var y;
	var z;
	var pan;
	var tilt;
	var roll;
	// and so...
} OBJECT;

OBJECT objects[LEVEL_COUNT][OBJECTS_MAX];

void objects_save ()
{
	file_save ( "saved.dat", objects, sizeof(OBJECT) * LEVEL_COUNT * OBJECTS_MAX );
}

void objects_load ()
{
	if ( !file_exists ( "saved.dat" ) )
		return;
	long size = 0;
	void *buffer = file_load ( "saved.dat", NULL, &size );
	memcpy ( objects, buffer, sizeof(OBJECT) * LEVEL_COUNT * OBJECTS_MAX );
	file_load ( NULL, buffer, &size );
}

void objects_zero ()
{
	memset ( objects, 0, sizeof(OBJECT) * LEVEL_COUNT * OBJECTS_MAX );
}

void evnPan ()
{
	var indexX = floor ( LEVEL_COUNT * mouse_pos.x / screen_size.x );
	var indexY = floor ( OBJECTS_MAX * mouse_pos.y / screen_size.y );
	if ( event_type == EVENT_CLICK )
		objects[indexX][indexY].x += 1;
	else if ( event_type == EVENT_RIGHTCLICK )
		objects[indexX][indexY].x -= 1;
}

void main ()
{
	video_mode = 10;
	mouse_mode = 4;
	enable_mouse = 2;
	wait(1);
	
	PANEL *pan = pan_create ( "", 1 );
	pan->size_x = screen_size.x;
	pan->size_y = screen_size.y;
	var stepX = pan->size_x / LEVEL_COUNT;
	var stepY = pan->size_y / OBJECTS_MAX;
	var y = 0;
	for ( ; y<OBJECTS_MAX; y+=1 )
	{
		var x = 0;
		for ( ; x<LEVEL_COUNT; x+=1 )
		{
			pan_setdigits ( pan, 0, (stepX/2)+x*stepX, (stepY/2)+y*stepY, "%.0f", fntArial, 1, &objects[x][y].x );
		}
	}
	pan->event = evnPan;
	pan->flags |= SHOW;
	
	on_s = objects_save;
	on_l = objects_load;
	on_r = objects_zero;
	
	while ( !key_esc )
		wait (1);
	
	pan_remove ( pan );
	sys_exit ( NULL );
}



mouse_left -> encrease
mouse_right -> decrease
R -> zero all values
S -> save data
L -> load data

It saves and loads an array with no interpretations inbetween. Raw data is saved and loaded, so (beforecrazy) after a load everything gets arranged by the array structure you can easily access.

It has other advantajes beside saving and loading like objects linking through levels.

But it also have some disadvantajes like, for example, you can't save pointers with this method, so texts has to be saved into char arrays or object links have to be saved as indexes or offsets into the array. Nothing hard to manage.

Salud!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 09/24/16 10:36

Good idea txesmi. That is actually somewhat similar to the idea how I do it in c# with a container class, but never realized it would be possible this way with lite-c/c.
Do you know if your example can also be used to directly save entity data (pos/rotation/scale+skills and possible flags etc) without using a struct? Like maybe lite-c has already some entity struct that we could use?
Posted By: txesmi

Re: Name of the assigned function and model - 09/24/16 13:37

Not really because the memory has to be contiguous. You will need, somehow, build a buffer that contains all the data you need to save and load to, occupying, at the end, same memory space as a static array to work with.

Salud!
Posted By: Ch40zzC0d3r

Re: Name of the assigned function and model - 09/24/16 13:44

You can iterate all entities and save the whole data using a memcpy(buff, ent, sizeof(ENTITY)) into a buffer, then write this buffer into a file.
You will need some sort of ID system, but thats the easiest approach possible.
Posted By: txesmi

Re: Name of the assigned function and model - 09/24/16 14:34

Originally Posted By: Ch40zzC0d3r
memcpy(buff, ent, sizeof(ENTITY))

You can't overwrite its CLINK struct or the bunch of pointers an entity struct contains without getting in troubles.
Posted By: Ch40zzC0d3r

Re: Name of the assigned function and model - 09/24/16 14:52

Originally Posted By: txesmi
Originally Posted By: Ch40zzC0d3r
memcpy(buff, ent, sizeof(ENTITY))

You can't overwrite its CLINK struct or the bunch of pointers an entity struct contains without getting in troubles.


Good point
Thats why we gotta preserve some values and keep them after loading from the file.
Shouldnt be too much values you have to preserve.
Posted By: txesmi

Re: Name of the assigned function and model - 09/25/16 16:28

Hi,
I did another workaround of the needs I think you could have.

Code:
#include <acknex.h>

STRING *str = "";

TEXT *txtLevels =
{
	string = ( "level00", "level01" );
}

TEXT *txtConfigs =
{
	string = (
		" -pal palette.pcx -az 0 -el 60 -sunrgb 58 58 58 -ambrgb 19 19 19  -fog1 100 100 100  -fog2 19 39 100  -fog3 100 19 19 -noportals -hiprec -litmapsonly -writelog -mesh -mergeacross -terralit -tesselate -close -solidsky -nodetail -quiet -supsam -threads 4 -gamma 2.25 -phongangle 120  -lmambient 50  -sizeshaded 236 -litres 0.37 -litcomp 0.20 -litmax 255 -litscale 0.68 -radsubdiv 64 -radbounce 3 -bound 56000 -fat 64  48  8  -narrow 32  32  0"
		" -pal palette.pcx -az 0 -el 60 -sunrgb 58 58 58 -ambrgb 19 19 19  -fog1 100 100 100  -fog2 19 39 100  -fog3 100 19 19 -noportals -hiprec -litmapsonly -writelog -mesh -mergeacross -terralit -tesselate -close -solidsky -nodetail -quiet -supsam -threads 4 -gamma 2.25 -phongangle 120  -lmambient 50  -sizeshaded 236 -litres 0.37 -litcomp 0.20 -litmax 255 -litscale 0.68 -radsubdiv 64 -radbounce 3 -bound 56000 -fat 64  48  8  -narrow 32  32  0"
	);
}

typedef struct
{
	char buffer[6000];
	char *chr;
	long size;
} ENT_BUFFER;

ENT_BUFFER entBuffer;

void entBuffer_startup ()
{
	entBuffer.chr = entBuffer.buffer;
	entBuffer.size = 0;
}

void entBufferLevel ( STRING *_str )
{
	long _size = str_len ( _str );
	memcpy ( entBuffer.chr, _str->chars, _size );
	entBuffer.chr += _size;
	*entBuffer.chr = 13;
	entBuffer.chr ++;
	*entBuffer.chr = 10;
	entBuffer.chr ++;
	entBuffer.size += _size + 2;
}

void entBufferAdd ( char *_chr, long _size )
{
	memcpy ( entBuffer.chr, _chr, _size );
	entBuffer.chr += _size;
	entBuffer.size += _size;
}

void main ()
{
	wait(1);
	var levelIndex = 0;
	for ( ; levelIndex<txtLevels->strings; levelIndex+=1 )
	{
		entBufferLevel ( (txtLevels->pstring)[levelIndex] );
		var entIndex = 0;
		str_cpy ( str, (txtLevels->pstring)[levelIndex] );
		str_cat ( str, ".$$M" );
		char *entityBlock = NULL;
		long size;
		char *buffer0 = file_load ( str, NULL, &size );
		char *buffer = buffer0;
		char *bufferLast = buffer + size;
		for ( ; buffer<buffer0+size; buffer++ )
		{
			if ( *buffer == 123 ) // {
			{
				var pos = str_stri ( buffer, "model" );
				if ( pos )
					if ( pos < 10 )
						entityBlock = buffer;
			}
			if ( entityBlock )
			{
				if ( *buffer == 125 ) // }
				{
					long size2 = 3 + (long)buffer - (long)entityBlock;
					entBufferAdd ( entityBlock, size2 );
					long size3 = size;
					size3 -= (long)buffer - (long)buffer0;
					memcpy ( entityBlock, buffer+3, size3 );
					size -= size2;
					buffer = entityBlock - 1;
					entityBlock = NULL;
				}
			}
		}
		
		file_save ( str, buffer0, size );
		file_load ( NULL, buffer0, &size );
		
		str_cat ( str, (txtConfigs->pstring)[levelIndex] );
		exec_wait  ( "wwmp2wmb.exe", str );
	}
	
	file_save ( "level_entities.txt", entBuffer.buffer, entBuffer.size );
	
	sys_exit ( NULL );
}



It recompiles a list of levels listed on a TEXT struct but with no models and creates a single txt file with the description of the models taken from the $$M files generated by WED. This way you could load empty levels and create just the models that are active instead or removing unactive ones.

Salud!
Posted By: 3run

Re: Name of the assigned function and model - 09/25/16 17:06

Damn, man you are a genius! Thank you very much for your time and effort you put in this to help me out! This whole thing is a little bit over my head, so I'll need some time to learn. laugh

Best regards!
Posted By: txesmi

Re: Name of the assigned function and model - 09/26/16 05:17

I am glad of helping wink

I forgot to warn you that this last code is not problem free. Be aware of making a backup of level files before using it on your real game. It modifies $$M files on hard disk. I will modify it in order to restore its initial state after recompiling and add some security checks.

Salud!
Posted By: txesmi

Re: Name of the assigned function and model - 09/26/16 18:53

Hi,
I commented all the process and renamed the variables so it is easier to follow. It now restores the level files initial state after compiling the empty levels, so there is no need for making backups of the files.

Code:
#include <acknex.h>

// -----------------------------------------------------------------------------------------------------

STRING *strFilename = NULL;
STRING *strOptions = "";

// -----------------------------------------------------------------------------------------------------

// Levels
TEXT *txtLevels =
{
	string = ( 
		"level00.$$M", 
		"level01.$$M"
	);
}

// Compilation configurations for each level
// They can be copied from 'buildlog.txt' file created by WED compilation process
TEXT *txtConfigs =
{
	string = (
		" -pal palette.pcx -az 0 -el 60 -sunrgb 58 58 58 -ambrgb 19 19 19  -fog1 100 100 100  -fog2 19 39 100  -fog3 100 19 19 -noportals -hiprec -litmapsonly -writelog -mesh -mergeacross -terralit -tesselate -close -solidsky -nodetail -quiet -supsam -threads 4 -gamma 2.25 -phongangle 120  -lmambient 50  -sizeshaded 236 -litres 0.37 -litcomp 0.20 -litmax 255 -litscale 0.68 -radsubdiv 64 -radbounce 3 -bound 56000 -fat 64  48  8  -narrow 32  32  0"
		" -pal palette.pcx -az 0 -el 60 -sunrgb 58 58 58 -ambrgb 19 19 19  -fog1 100 100 100  -fog2 19 39 100  -fog3 100 19 19 -noportals -hiprec -litmapsonly -writelog -mesh -mergeacross -terralit -tesselate -close -solidsky -nodetail -quiet -supsam -threads 4 -gamma 2.25 -phongangle 120  -lmambient 50  -sizeshaded 236 -litres 0.37 -litcomp 0.20 -litmax 255 -litscale 0.68 -radsubdiv 64 -radbounce 3 -bound 56000 -fat 64  48  8  -narrow 32  32  0"
	);
}

// -----------------------------------------------------------------------------------------------------

// A buffer and a position and size control in order to hold all the entity related data
typedef struct
{
	char buffer[6000];
	char *chr;
	long size;
} ENT_BUFFER;

ENT_BUFFER entBuffer;

void entBuffer_startup ()
{
	entBuffer.chr = entBuffer.buffer;
	entBuffer.size = 0;
}

// Add a string to the entities buffer
void entBufferAddString ( STRING *_str )
{
	long _size = str_len ( _str );
	memcpy ( entBuffer.chr, _str->chars, _size );
	entBuffer.chr += _size;
	*entBuffer.chr = 13; // [Enter]
	entBuffer.chr ++;
	*entBuffer.chr = 10; // Linebreak
	entBuffer.chr ++;
	entBuffer.size += _size + 2;
}

// Add a char buffer to the entities buffer
void entBufferAdd ( char *_chr, long _size )
{
	memcpy ( entBuffer.chr, _chr, _size );
	entBuffer.chr += _size;
	entBuffer.size += _size;
}

// -----------------------------------------------------------------------------------------------------

void main ()
{
	wait(1);
	var levelIndex = 0;
	// Loop through all levels
	for ( ; levelIndex<txtLevels->strings; levelIndex+=1 )
	{
		// Get the pointer to the level name string
		strFilename = (txtLevels->pstring)[levelIndex];
		// Check the existence of the level file
		if ( !file_exists ( strFilename ) )
		{
			str_cpy ( strFilename, " file not found!" );
			error ( strFilename );
			break;
		}
		// Add level name to entities buffer
		entBufferAddString ( strFilename );
		
		// A variable will contain the size of the file buffer
		long sizeFile;
		// Load the file into a buffer allocated by the engine
		char *bufferStart = file_load ( strFilename, NULL, &sizeFile );
		// Make a copy of the file buffer in order to restore the file after compiling
		char *bufferBackup = sys_malloc ( sizeFile );
		memcpy ( bufferBackup, bufferStart, sizeFile );
		
		// A pointer to hold the starting byte of a detected entity
		char *entityBlock = NULL;
		// A variable will contain the size of the modified file buffer. It is same as the original file buffer size at the beginning
		long sizeResult = sizeFile;
		// A pointer to go through the buffer
		char *buffer = bufferStart;
		// Go through the buffer byte by byte
		for ( ; buffer<bufferStart+sizeResult; buffer++ )
		{
			// If a description of a model has been previously detected
			if ( entityBlock )
			{
				// If the pointed byte is a closing bracket
				if ( *buffer == 125 ) // }
				{
					// Compute the size of the entity description block
					long sizeBlock = 3 + (long)buffer - (long)entityBlock;
					// Add the entity block to the entities buffer
					entBufferAdd ( entityBlock, sizeBlock );
					// Compute the size of the remaining buffer
					long sizeRemaining = sizeResult - ( (long)buffer - (long)bufferStart );
					// Move the remaining buffer to the starting byte of the entity, so the entity is completelly removed from the file buffer
					memcpy ( entityBlock, buffer+3, sizeRemaining );
					// Reduce the size of the file buffer by the size of the entity block
					sizeResult -= sizeBlock;
					// Move the buffer cheking pointer to the start of the remaining buffer, as it has been moved
					buffer = entityBlock - 1;
					// Remove previously saved starting byte
					entityBlock = NULL;
				}
			}
			else // If a description of a model has not been previously detected
			{
				// If the pointed byte is an opening bracket
				if ( *buffer == 123 ) // {
				{
					// Look for the word 'model' into the remaining buffer
					var pos = str_stri ( buffer, "model" );
					// If it exists
					if ( pos )
					{
						// If it exists near the opening bracket
						if ( pos < 10 )
						{
							// Save the the actual byte as the starting byte of the description of a model
							entityBlock = buffer;
						}
					}
					else // If it does not exists
					{
						// There is no reason to continue looking into the buffer
						// Break the loop
						break;
					}
				}
			}
		}
		
		// Save the modified buffer, with no models, in order to compile the empty level
		file_save ( strFilename, bufferStart, sizeResult );
		
		// Build the configuration for compiling process
		str_cpy ( strOptions, strFilename );
		str_cat ( strOptions, (txtConfigs->pstring)[levelIndex] );
		// Compile the level
		exec_wait  ( "wwmp2wmb.exe", strOptions );
		
		// Restore the level file to its initial state
		file_save ( strFilename, bufferBackup, sizeFile );
		// Remove the level buffer
		file_load ( NULL, bufferStart, &sizeFile );
		// Remove the level buffer copy
		sys_free ( bufferBackup );
	}
	
	// If everything went fine
	if ( levelIndex == txtLevels->strings )
	{
		// Save the entities buffer 
		file_save ( "level_entities.txt", entBuffer.buffer, entBuffer.size );
	}
	
	// Exit the program ;)
	sys_exit ( NULL );
}



Have fun!
Posted By: Reconnoiter

Re: Name of the assigned function and model - 10/14/16 13:49

Incase someone wants a simple save to text solution (for whatever reason like modding or such) I am just gonna drop these functions here (replace tmp_str with the string you are going to use to save/load values/info). I used it for a first description and than on next line the value. But you can also do several values on 1 line if you read them out with e.g. str_parse. Note that as a delimiter (/to seperate the lines) I use a \n / enter-thingy . When you change it just dont forget to change both functions.

Code:
//For loading/reading (go to next line and read)
function read_line(var handle) {
	str_cpy(tmp_str, ""); //reset previous read lines
	file_str_readto(handle, tmp_str, "\n", 10000); //read next line
	str_trim(tmp_str); //remove spaces from value
	str_trunc(tmp_str, 1); //remove \n (/remove delimiter)
}

//For saving/writing (write blank to next line)
function skip_line(var handle) {	
	file_asc_write(handle, 13); //new line
	file_asc_write(handle, 10);
}



So for saving you do file_open_write and use something like file_str_write(handle, "Entity file:"); to write a line and call skip_line(handle); to skip a line (/go to next line for writing), than e.g. file_str_write(handle, str_for_entfile(NULL, ent)); . After you are finished dont forget to close the file.

For reading you do file_open_read and call read_line(handle); when you want to go the next line AND read that line of the file. So say the first line is a description and the second line has the value, call read_line(handle); twice. Than read the string on that line by doing something like ent.x = str_to_num(tmp_str); . Again dont forget to close the file.

For saving/loading multiple entities loop through them by e.g. using ent_next or your entity pointer array if you have one.
© 2024 lite-C Forums