Propdump
A propdump is a file that contains the properties of the world. It can be used to backup and restore a worlds objects. Together with the atdump (world attributes) and elevdump (world terrain) it is a complete backup of a world.
Propdump structure
Every line in a propdump file is an object. That line contains all data about the object. The first 13 numbers are to be seperated by spaces and tell things about positioning and more, the last part that remains contains non numeric data and tells us about the object name, description and action.
Example of line:
- 359971 1167343043 -800 0 200 0 0 0 0 7 0 99 0 floor01create name gz1wat1, texture water1_top mask=semitrans10,solid no,move 0 0.1 0.5 time=2 smooth sync
- The 1st part (358257) is the citizen number of the owner of the object.
- The 2nd part (1167343043) is the timestamp that contains the date when the object had been created.
- The 3rd part (-800) is the X position of the object.
- The 4th part (0) is the Y position of the object.
- The 5th part (200) is the Z position of the object.
- The 6th part (0) is the YAW orientation of the object.
- The 7th part (0) is the Tilt orientation of the object.
- The 8th part (0) is the Roll orientation of the object.
- The 9th part (0) is the type of the object. (0: Object. 1: Camera. 2: Zone. 3: Particle Emitter. 4: Mover.).
- The 10th part (7) is the length of the model name (floor01).
- The 11th part (0) is the length of the description.
- The 12th part (99) is the length of the action (create name gz1wat1 [...]).
- The 13th part (0) is the length of the object data (for object types other than 0).
- The 14th part (all that remains) contains object information in the length described above.
Newline, or carriage return with line feed \r\n, is replaced with characters 0x80 0x7F (before 3.3: 0x0D 0x7F), and \n with character 0x7F. A solitary \r is not translated.
Code Sniplets
Write Property Format
// // Helper function to convert NL characters in strings // static void codeNL(char* string) { while (*string) { if (*string == '\r' && *(string + 1) == '\n') { // Note, if 128 is without 127, it would be the euro-sign *string = (char)128; string++; *string = (char)127; } else if (*string == '\n') *string = (char)127; string++; } } // // on AW_EVENT_CELL_OBJECT from aw_query() or aw_cell_next() // void handle_cell_object(void) { char* buf = NULL; char* model = NULL; char* description = NULL; char* action = NULL; char* data_hex = NULL; int model_len = 0; int description_len = 0; int action_len = 0; int data_len = 0; int i = 0; #if !defined(UNICODE) model = aw_string(AW_OBJECT_MODEL); description = aw_string(AW_OBJECT_DESCRIPTION); action = aw_string(AW_OBJECT_ACTION); #else model = aw_string_from_unicode(aw_stringW(AW_OBJECT_MODEL)); description = aw_string_from_unicode(aw_stringW(AW_OBJECT_DESCRIPTION)); action = aw_string_from_unicode(aw_stringW(AW_OBJECT_ACTION)); #endif model_len = (int)strlen(model); description_len = (int)strlen(description); action_len = (int)strlen(action); if (aw_int(AW_OBJECT_TYPE)) { unsigned char* data = (unsigned char*)aw_data(AW_OBJECT_DATA, &data_len); if (data_len < 0 || data_len > 4096) return; data_hex = (char*)calloc(1, (data_len * 2) + 1); // binary to hex for (i = 0; i < data_len && data; i++) sprintf(&data_hex[i * 2], "%02x", data[i]); } else { if (model_len <= 0) return; // mandatory data_hex = (char*)calloc(1, 1); } buf = (char*)calloc(1, (9 * 11) + 9 + model_len + description_len + action_len + (data_len * 2) + 1); sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %d %s%s%s%s", aw_int(AW_OBJECT_OWNER), aw_int(AW_OBJECT_BUILD_TIMESTAMP), aw_int(AW_OBJECT_X), aw_int(AW_OBJECT_Y), aw_int(AW_OBJECT_Z), aw_int(AW_OBJECT_YAW), aw_int(AW_OBJECT_TILT), aw_int(AW_OBJECT_ROLL), aw_int(AW_OBJECT_TYPE), model_len, description_len, action_len, data_len, model, description, action, data_hex); codeNL(buf); // TODO: write buf to file, // append NL ('\n') as record delimiter, or use fputs() ... free(data_hex); free(buf); }
Read Property Format
// global static file pointer // open the property file, i.e "propdump.txt" // see propload() below static FILE* fp = NULL; // // Helper function to convert NL characters in strings // static void decodeNL(int bytes, char* string) { while (bytes--) { // Note, if 128 is without 127, it's the euro-sign if ((unsigned char)*string == 128 && (unsigned char)*(string + 1) == 127) { *string = '\r'; string++; *string = '\n'; } else if ((unsigned char)*string == 127) *string = '\n'; string++; } } // // load one object from a property-file into the world // static int load_object(void) { int rc = 0; int owner = 0; int build_time = 0; int x = 0; int y = 0; int z = 0; int yaw = 0; int tilt = 0; int roll = 0; int model_len = 0; int description_len = 0; int action_len = 0; char string[2048] = { 0 }; char buf[8192] = { 0 }; int i = 0; int byte = 0; int object_type = 0; int data_len = 0; char data[4096]; char* bytes = NULL; if (!fp) return -2; object_type = 0; model_len = 0; description_len = 0; action_len = 0; data_len = 0; rc = fscanf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d %d %[^\n]", &owner, &build_time, &x, &y, &z, &yaw, &tilt, &roll, &object_type, &model_len, &description_len, &action_len, &data_len, buf); if (rc == EOF) return -1; while (yaw < 0) yaw += 3600; while (yaw >= 3600) yaw -= 3600; decodeNL(object_len + description_len + action_len, buf); aw_int_set(AW_OBJECT_X, x); aw_int_set(AW_OBJECT_Y, y); aw_int_set(AW_OBJECT_Z, z); aw_int_set(AW_OBJECT_YAW, yaw); aw_int_set(AW_OBJECT_TILT, tilt); aw_int_set(AW_OBJECT_ROLL, roll); aw_int_set(AW_OBJECT_OWNER, owner); aw_int_set(AW_OBJECT_BUILD_TIMESTAMP, build_time); memcpy(string, buf, model_len); string[model_len] = '\0'; #if !defined(UNICODE) aw_string_set(AW_OBJECT_MODEL, string); #else aw_string_setW(AW_OBJECT_MODEL, aw_string_to_unicode(string)); #endif memcpy(string, buf + object_len, description_len); string[description_len] = '\0'; #if !defined(UNICODE) aw_string_set(AW_OBJECT_DESCRIPTION, string); #else aw_string_setW(AW_OBJECT_DESCRIPTION, aw_string_to_unicode(string)); #endif memcpy(string, buf + object_len + description_len, action_len); string[action_len] = '\0'; #if !defined(UNICODE) aw_string_set(AW_OBJECT_ACTION, string); #else aw_string_setW(AW_OBJECT_ACTION, aw_string_to_unicode(string)); #endif if (object_type == AW_OBJECT_TYPE_UNKNOWN) { // skip this object return 0x70000001; } if (object_type < 0) { // skip this object return 0x70000002; } if (object_type && strlen(buf) > (size_t)(object_len + description_len + action_len)) { if ((data_len < 0 || data_len > 4096)) { // skip this object return 0x70000003; } memset(data, 0, sizeof(data)); sscanf(&buf[object_len + description_len + action_len], "%s", data); if (strlen(data) != (size_t)data_len * 2) { // skip this object return 0x70000004; } bytes = (char*)calloc(1, data_len); for (i = 0; i < data_len; i++) { string[0] = data[i * 2]; string[1] = data[(i * 2) + 1]; string[2] = 0x0; byte = 0; sscanf(string, "%02x", &byte); bytes[i] = (unsigned char)byte; } aw_int_set(AW_OBJECT_TYPE, object_type); aw_data_set(AW_OBJECT_DATA, bytes, data_len); free(bytes); } else { if (model_len <= 0) { // skip this object return 0x70000005; } aw_int_set(AW_OBJECT_TYPE, 0); aw_data_set(AW_OBJECT_DATA, NULL, 0); } if ((rc = aw_object_load())) { // an error loading this object to the world occurred return rc; } return 0; } int propload() { int rc = 0; if (fp) // already open return -1001; fp = fopen("propdump.txt", "r"); if (!fp) // failed to open return -1002; if (fscanf(fp, "propdump version %d", &version) != 1 || version != 4) { // wrong format header rc = -1003; goto onFail; } // delete world's property content aw_callback_set(AW_CALLBACK_DELETE_ALL_OBJECTS_RESULT, NULL); if (rc = aw_delete_all_objects()) { // failed to delete world's property objects goto onFail; } aw_callback_set(AW_CALLBACK_OBJECT_RESULT, NULL); do { rc = load_object(); if (rc > 0x70000000 && rc < 0x70000006) { // an invalid line, can skip it, but inform user! rc = 0; } } while (rc == 0); if (rc == -1) // EOF rc = 0; onFail: fclose(fp); fp = NULL; return rc; }