> other stuff snipped out < > > Please understand that this project temporarily is going forward with the > understanding that a pfile wipe will be needed. This project is large > enough and I do not have time to get into how to create a pfile converter. > Believe it or not, writing a binary pfile converter is a snap. Really! As far as the computer is concerned, a binary player file is just a big stream of contigious bytes. When you're reading in your pre-binary file, you simply do a fread() and read in the number of bytes that the sizeof(struct char_file_u) returns. Your awaiting empty structure is then filled in, byte per byte, to the bottom. Lets say that you add something small, like an 'int' value. Let's also make life simple and say you only have one player. You've got an extra sizeof(int) to allocate [1]. How do we get that extra bit in? Well, we know that we don't want to write a line of code to copy over each single value. We want to make life easy. Easy it is, too - when you realize that if you add the int at the bottom of the structure definition, you can read in the entire pfile, and then add the int at the end: struct old_struct { ..stuff here... }; to -> struct new_struct { ..stuff here... int my_new_int; }; "How do I do that?" you may ask. Simple enough, lets take our char_file_u structure, and leave it there. We need to read in that many bytes so it should 'keep' for reference. Let's make an exact copy of it, and add an int to the end - we'll call it 'char_file_new'. Now, we want to load in our old character into a previously allocated char_file_new structure; fread(&our_char_file_new,sizeof(char_file_u),1,old_player_file); Disecting that a bit, we see as the second argument, we're reading in only the number of bytes in the old structure - but we're reading it into the new structure. That leaves us with an int of allocated, but potentially uninitialized data (though calloc does set it to 0). So, init it and then write out a new file: our_char_file_new.my_new_int = 0; fwrite(&our_char_file_new, sizeof(char_file_new),1,new_player_file); At the end, you'll want to copy your new char file over by hand, and remove the old char_file_u structure and replace it with the new one. Then, after bootup, you're ready to go. The fun thing is that if you stick all that code into a while(!feof()) loop, it will do your entire pfile, regardless of the size[2]. Of course, that's not the best part - as long as you stick to adding to the end only, this technique ought to work every time for anything you put in there. Lets see this full code in action, via Mailer Code (ie, untested) - we'll assume we're keeping it in the util dir though. ---begin code--- #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" struct char_file_u_new { /* char_player_data */ char name[MAX_NAME_LENGTH+1]; char description[EXDSCR_LENGTH]; char title[MAX_TITLE_LENGTH+1]; byte sex; byte chclass; byte level; sh_int hometown; time_t birth; /* Time of birth of character */ int played; /* Number of secs played in total */ ubyte weight; ubyte height; char pwd[MAX_PWD_LENGTH+1]; /* character's password */ struct char_special_data_saved char_specials_saved; struct player_special_data_saved player_specials_saved; struct char_ability_data abilities; struct char_point_data points; struct affected_type affected[MAX_AFFECT]; time_t last_logon; /* Time (in secs) of last logon */ char host[HOST_LENGTH+1]; /* host of last logon */ int my_new_int; }; void main(int argc, char *argv[]) { FILE *old_p; FILE *new_p; int size, recs; struct char_file_u_new new_u; if (argc != 2) { printf("Usage: %s playerfile-name\n", argv[0]); exit(); } if (!(old_p = fopen(argv[1], "r+"))) { printf("Can't open %s.", argv[1]); exit(); } new_p = fopen("players.new", "w"); /* this part is duplicated in the stock db.c player load */ fseek(old_p, 0L, SEEK_END); size = ftell(old_p); rewind(old_pl); recs = size / sizeof(struct char_file_u); if (size % sizeof(struct char_file_u)) { fprintf(stderr, "Bad record count for oldfile.\n"); exit(1); } printf("Converting.\n"); for (size = 0; size < recs; size++) { fread(&new_u, sizeof(struct char_file_u), 1, old_p); new_u.my_new_int=0; fwrite(&new_u, sizeof(struct char_file_u_new), 1, new_p); } printf("old: %d new: %d number of records: %d\n", sizeof(struct char_file_u), sizeof(struct char_file_u_new), recs); printf("All done.\n"); fclose(old_p); fclose(new_p); } -- end code --- That didn't take but 5 minutes to type up, and the actual part that does anything is squished between that for loop - it's only 3 lines long! It's a bit more complicated to remove/change size of entries in char_file_u (like changing the title length, etc) - but it's done in nearly the same way...though you would use strcpy or memmove to move chunks over and manually deal with the altered portions, truthfully, it's no more difficult than the above. So, go ahead, write your own pfile converter, test it, and in the future you can make those innovative changes you want without worrying about player wipes. PjD [1] - Technically there's more to it. Depending on your system, byte padding may be inserted at the front, or rear of a structure/variable inorder to insure word-aligned boundries in memory. The trick is just to always write a new struct with everything you want - and not to simply allocate +sizeof(int) more memory. [2] - assuming you correctly open the file and yada-yada-yada all the other stuff that it's simply assumed you're going to do when you read from one file and write to another. +------------------------------------------------------------+ | Ensure that you have read the CircleMUD Mailing List FAQ: | | http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html | +------------------------------------------------------------+
This archive was generated by hypermail 2b30 : 04/10/01 PDT