#include "int_storage.hpp" #include "../common/db.hpp" #include "../common/lock.hpp" #include "../common/mmo.hpp" #include "../common/socket.hpp" #include "char.hpp" #include "inter.hpp" #include #include // ファイル名のデフォルト // inter_config_read()で再設定される char storage_txt[1024] = "save/storage.txt"; static struct dbt *storage_db; // 倉庫データを文字列に変換 static int storage_tostr(char *str, struct storage *p) { int i, f = 0; char *str_p = str; str_p += sprintf(str_p, "%d,%d\t", p->account_id, p->storage_amount); for (i = 0; i < MAX_STORAGE; i++) if ((p->storage_[i].nameid) && (p->storage_[i].amount)) { str_p += sprintf(str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", p->storage_[i].id, p->storage_[i].nameid, p->storage_[i].amount, p->storage_[i].equip, p->storage_[i].identify, p->storage_[i].refine, p->storage_[i].attribute, p->storage_[i].card[0], p->storage_[i].card[1], p->storage_[i].card[2], p->storage_[i].card[3]); f++; } *(str_p++) = '\t'; *str_p = '\0'; if (!f) str[0] = 0; return 0; } // 文字列を倉庫データに変換 static int storage_fromstr(char *str, struct storage *p) { int tmp_int[256]; int set, next, len, i; set = sscanf(str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next); p->storage_amount = tmp_int[1]; if (set != 2) return 1; if (str[next] == '\n' || str[next] == '\r') return 0; next++; for (i = 0; str[next] && str[next] != '\t' && i < MAX_STORAGE; i++) { if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[10], &len) == 12) { p->storage_[i].id = tmp_int[0]; p->storage_[i].nameid = tmp_int[1]; p->storage_[i].amount = tmp_int[2]; p->storage_[i].equip = tmp_int[3]; p->storage_[i].identify = tmp_int[4]; p->storage_[i].refine = tmp_int[5]; p->storage_[i].attribute = tmp_int[6]; p->storage_[i].card[0] = tmp_int[7]; p->storage_[i].card[1] = tmp_int[8]; p->storage_[i].card[2] = tmp_int[9]; p->storage_[i].card[3] = tmp_int[10]; next += len; if (str[next] == ' ') next++; } else if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &len) == 11) { p->storage_[i].id = tmp_int[0]; p->storage_[i].nameid = tmp_int[1]; p->storage_[i].amount = tmp_int[2]; p->storage_[i].equip = tmp_int[3]; p->storage_[i].identify = tmp_int[4]; p->storage_[i].refine = tmp_int[5]; p->storage_[i].attribute = tmp_int[6]; p->storage_[i].card[0] = tmp_int[7]; p->storage_[i].card[1] = tmp_int[8]; p->storage_[i].card[2] = tmp_int[9]; p->storage_[i].card[3] = tmp_int[10]; next += len; if (str[next] == ' ') next++; } else return 1; } if (i >= MAX_STORAGE && str[next] && str[next] != '\t') printf("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE); return 0; } // アカウントから倉庫データインデックスを得る(新規倉庫追加可能) struct storage *account2storage(int account_id) { struct storage *s; s = (struct storage *) numdb_search(storage_db, account_id); if (s == NULL) { CREATE(s, struct storage, 1); memset(s, 0, sizeof(struct storage)); s->account_id = account_id; numdb_insert(storage_db, s->account_id, s); } return s; } //--------------------------------------------------------- // 倉庫データを読み込む int inter_storage_init(void) { char line[65536]; int c = 0, tmp_int; struct storage *s; FILE *fp; storage_db = numdb_init(); fp = fopen_(storage_txt, "r"); if (fp == NULL) { printf("cant't read : %s\n", storage_txt); return 1; } while (fgets(line, 65535, fp)) { sscanf(line, "%d", &tmp_int); CREATE(s, struct storage, 1); s->account_id = tmp_int; if (s->account_id > 0 && storage_fromstr(line, s) == 0) { numdb_insert(storage_db, s->account_id, s); } else { printf("int_storage: broken data [%s] line %d\n", storage_txt, c); free(s); } c++; } fclose_(fp); return 0; } static void storage_db_final(db_key_t, db_val_t data) { struct storage *p = (struct storage *) data; if (p) free(p); } void inter_storage_final(void) { numdb_final(storage_db, storage_db_final); return; } static void inter_storage_save_sub(db_key_t, db_val_t data, FILE *fp) { char line[65536]; storage_tostr(line, (struct storage *) data); if (*line) fprintf(fp, "%s\n", line); } //--------------------------------------------------------- // 倉庫データを書き込む int inter_storage_save(void) { FILE *fp; int lock; if (!storage_db) return 1; if ((fp = lock_fopen(storage_txt, &lock)) == NULL) { printf("int_storage: cant write [%s] !!! data is lost !!!\n", storage_txt); return 1; } numdb_foreach(storage_db, std::bind(inter_storage_save_sub, ph::_1, ph::_2, fp)); lock_fclose(fp, storage_txt, &lock); // printf("int_storage: %s saved.\n",storage_txt); return 0; } // 倉庫データ削除 int inter_storage_delete(int account_id) { struct storage *s = (struct storage *) numdb_search(storage_db, account_id); if (s) { numdb_erase(storage_db, account_id); free(s); } return 0; } //--------------------------------------------------------- // map serverへの通信 // 倉庫データの送信 static int mapif_load_storage(int fd, int account_id) { struct storage *s = account2storage(account_id); WFIFOW(fd, 0) = 0x3810; WFIFOW(fd, 2) = sizeof(struct storage) + 8; WFIFOL(fd, 4) = account_id; memcpy(WFIFOP(fd, 8), s, sizeof(struct storage)); WFIFOSET(fd, WFIFOW(fd, 2)); return 0; } // 倉庫データ保存完了送信 static int mapif_save_storage_ack(int fd, int account_id) { WFIFOW(fd, 0) = 0x3811; WFIFOL(fd, 2) = account_id; WFIFOB(fd, 6) = 0; WFIFOSET(fd, 7); return 0; } //--------------------------------------------------------- // map serverからの通信 // 倉庫データ要求受信 static int mapif_parse_LoadStorage(int fd) { mapif_load_storage(fd, RFIFOL(fd, 2)); return 0; } // 倉庫データ受信&保存 static int mapif_parse_SaveStorage(int fd) { struct storage *s; int account_id = RFIFOL(fd, 4); int len = RFIFOW(fd, 2); if (sizeof(struct storage) != len - 8) { printf("inter storage: data size error %d %d\n", sizeof(struct storage), len - 8); } else { s = account2storage(account_id); memcpy(s, RFIFOP(fd, 8), sizeof(struct storage)); mapif_save_storage_ack(fd, account_id); } return 0; } // map server からの通信 // ・1パケットのみ解析すること // ・パケット長データはinter.cにセットしておくこと // ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない // ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない int inter_storage_parse_frommap(int fd) { switch (RFIFOW(fd, 0)) { case 0x3010: mapif_parse_LoadStorage(fd); break; case 0x3011: mapif_parse_SaveStorage(fd); break; default: return 0; } return 1; }