TXT code has been re uploaded. Please note this does not change the fact that TXT support has been dropped. There is no guarantee the code base will be managed and it will in the near future be REMOVED. If there is in ANY way TXT support in the future, it will be abstracted through a sql interface so only the sql code has to be maintained.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12572 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
Kevin 2008-04-12 08:43:29 +00:00
parent fe1fd152a7
commit 2c1144e804
21 changed files with 12363 additions and 0 deletions

47
src/char/Makefile.in Normal file
View File

@ -0,0 +1,47 @@
COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \
../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
../common/obj_all/strlib.o ../common/obj_all/grfio.o \
../common/obj_all/mapindex.o ../common/obj_all/ers.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
../common/malloc.h ../common/showmsg.h ../common/utils.h \
../common/strlib.h ../common/grfio.h \
../common/mapindex.h ../common/ers.h
CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \
obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o
CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h
@SET_MAKE@
#####################################################################
.PHONY : all char-server clean help
all: char-server
char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ)
@CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@
clean:
rm -rf *.o obj_txt ../../char-server@EXEEXT@
help:
@echo "possible targets are 'char-server' 'all' 'clean' 'help'"
@echo "'char-server' - char server (TXT version)"
@echo "'all' - builds all above targets"
@echo "'clean' - cleans builds and objects"
@echo "'help' - outputs this message"
#####################################################################
obj_txt:
-mkdir obj_txt
obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H)
@CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing common object files
../common/obj_all/%.o:
@$(MAKE) -C ../common txt

4290
src/char/char.c Normal file

File diff suppressed because it is too large Load Diff

54
src/char/char.h Normal file
View File

@ -0,0 +1,54 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _CHAR_H_
#define _CHAR_H_
#include "../common/mmo.h"
#define START_CHAR_NUM 150000
#define MAX_MAP_SERVERS 30
#define DEFAULT_AUTOSAVE_INTERVAL 300*1000
struct character_data {
struct mmo_charstatus status;
int global_num;
struct global_reg global[GLOBAL_REG_NUM];
};
struct mmo_charstatus* search_character(int aid, int cid);
struct mmo_charstatus* search_character_byname(char* character_name);
int search_character_index(char* character_name);
char* search_character_name(int index);
int search_character_online(int aid, int cid);
int mapif_sendall(unsigned char *buf, unsigned int len);
int mapif_sendallwos(int fd,unsigned char *buf, unsigned int len);
int mapif_send(int fd,unsigned char *buf, unsigned int len);
int char_married(int pl1,int pl2);
int char_child(int parent_id, int child_id);
int char_family(int cid1, int cid2, int cid3);
void char_clearparty(int party_id);
int char_log(char *fmt, ...);
int request_accreg2(int account_id, int char_id);
int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int len);
int save_accreg2(unsigned char *buf, int len);
int char_account_reg_reply(int fd,int account_id,int char_id);
extern int char_name_option;
extern char char_name_letters[];
extern int autosave_interval;
extern char db_path[];
extern int guild_exp_rate;
extern int log_inter;
//Exported for use in the TXT-SQL converter.
extern char char_txt[];
int char_config_read(const char *cfgName);
int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num);
int parse_friend_txt(struct mmo_charstatus *p);
#endif /* _CHAR_H_ */

1579
src/char/int_guild.c Normal file

File diff suppressed because it is too large Load Diff

26
src/char/int_guild.h Normal file
View File

@ -0,0 +1,26 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_GUILD_H_
#define _INT_GUILD_H_
struct guild;
struct guild_castle;
int inter_guild_init(void);
void inter_guild_final(void);
int inter_guild_save(void);
int inter_guild_parse_frommap(int fd);
struct guild *inter_guild_search(int guild_id);
int inter_guild_mapif_init(int fd);
int inter_guild_leave(int guild_id,int account_id,int char_id);
int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender);
extern char guild_txt[1024];
extern char castle_txt[1024];
//For the TXT->SQL converter
int inter_guild_fromstr(char *str, struct guild *g);
int inter_guildcastle_fromstr(char *str, struct guild_castle *gc);
#endif /* _INT_GUILD_H_ */

365
src/char/int_homun.c Normal file
View File

@ -0,0 +1,365 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/mmo.h"
#include "../common/malloc.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "char.h"
#include "inter.h"
#include "int_homun.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char homun_txt[1024]="save/homun.txt";
static DBMap* homun_db; // int hom_id -> struct s_homunculus*
static int homun_newid = 100;
int inter_homun_tostr(char *str,struct s_homunculus *p)
{
int i;
str+=sprintf(str,"%d,%d\t%s\t%d,%d,%d,%d,%d,"
"%u,%d,%d,%d,"
"%u,%d,%d,"
"%d,%d,%d,%d,%d,%d\t",
p->hom_id, p->class_, p->name,
p->char_id, p->hp, p->max_hp, p->sp, p->max_sp,
p->intimacy, p->hunger, p->skillpts, p->level,
p->exp, p->rename_flag, p->vaporize,
p->str, p->agi, p->vit, p->int_, p->dex, p->luk);
for (i = 0; i < MAX_HOMUNSKILL; i++)
{
if (p->hskill[i].id && !p->hskill[i].flag)
str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv);
}
return 0;
}
int inter_homun_fromstr(char *str,struct s_homunculus *p)
{
int i, next, len;
int tmp_int[25];
unsigned int tmp_uint[5];
char tmp_str[256];
memset(p,0,sizeof(struct s_homunculus));
i=sscanf(str,"%d,%d\t%127[^\t]\t%d,%d,%d,%d,%d,"
"%u,%d,%d,%d,"
"%u,%d,%d,"
"%d,%d,%d,%d,%d,%d\t%n",
&tmp_int[0],&tmp_int[1],tmp_str,
&tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],
&tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9],
&tmp_uint[1],&tmp_int[10],&tmp_int[11],
&tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17],
&next);
if(i!=21)
return 1;
p->hom_id = tmp_int[0];
p->class_ = tmp_int[1];
memcpy(p->name, tmp_str, NAME_LENGTH);
p->char_id = tmp_int[2];
p->hp = tmp_int[3];
p->max_hp = tmp_int[4];
p->sp = tmp_int[5];
p->max_sp = tmp_int[6];
p->intimacy = tmp_uint[0];
p->hunger = tmp_int[7];
p->skillpts = tmp_int[8];
p->level = tmp_int[9];
p->exp = tmp_uint[1];
p->rename_flag = tmp_int[10];
p->vaporize = tmp_int[11];
p->str = tmp_int[12];
p->agi = tmp_int[13];
p->vit = tmp_int[14];
p->int_= tmp_int[15];
p->dex = tmp_int[16];
p->luk = tmp_int[17];
//Read skills.
while(str[next] && str[next] != '\n' && str[next] != '\r') {
if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2)
return 2;
if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL)
{
i = tmp_int[0] - HM_SKILLBASE;
p->hskill[i].id = tmp_int[0];
p->hskill[i].lv = tmp_int[1];
} else
ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d)\n", tmp_int[0], p->hom_id);
next += len;
if (str[next] == ' ')
next++;
}
return 0;
}
int inter_homun_init()
{
char line[8192];
struct s_homunculus *p;
FILE *fp;
int c=0;
homun_db= idb_alloc(DB_OPT_RELEASE_DATA);
if( (fp=fopen(homun_txt,"r"))==NULL )
return 1;
while(fgets(line, sizeof(line), fp))
{
p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1);
if(p==NULL){
ShowFatalError("int_homun: out of memory!\n");
exit(EXIT_FAILURE);
}
if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){
if( p->hom_id >= homun_newid)
homun_newid=p->hom_id+1;
idb_put(homun_db,p->hom_id,p);
}else{
ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c);
aFree(p);
}
c++;
}
fclose(fp);
return 0;
}
void inter_homun_final()
{
homun_db->destroy(homun_db, NULL);
return;
}
int inter_homun_save_sub(DBKey key,void *data,va_list ap)
{
char line[8192];
FILE *fp;
inter_homun_tostr(line,(struct s_homunculus *)data);
fp=va_arg(ap,FILE *);
fprintf(fp,"%s\n",line);
return 0;
}
int inter_homun_save()
{
FILE *fp;
int lock;
if( (fp=lock_fopen(homun_txt,&lock))==NULL ){
ShowError("int_homun: can't write [%s] !!! data is lost !!!\n",homun_txt);
return 1;
}
homun_db->foreach(homun_db,inter_homun_save_sub,fp);
lock_fclose(fp,homun_txt,&lock);
return 0;
}
int inter_homun_delete(int hom_id)
{
struct s_homunculus *p;
p = (struct s_homunculus*)idb_get(homun_db,hom_id);
if( p == NULL)
return 0;
idb_remove(homun_db,hom_id);
ShowInfo("Deleted homun (hom_id: %d)\n",hom_id);
return 1;
}
int mapif_homun_created(int fd,int account_id, struct s_homunculus *p)
{
WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
WFIFOW(fd, 0) =0x3890;
WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
WFIFOL(fd,4) = account_id;
WFIFOB(fd,8)= p->hom_id?1:0;
memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus));
WFIFOSET(fd, WFIFOW(fd,2));
return 0;
}
int mapif_homun_info(int fd,int account_id,struct s_homunculus *p)
{
WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
WFIFOW(fd,0) = 0x3891;
WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
WFIFOL(fd,4) = account_id;
WFIFOB(fd,8) = 1; // account loaded with success
memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus));
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
int mapif_homun_noinfo(int fd,int account_id)
{
WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9);
WFIFOW(fd,0)=0x3891;
WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9;
WFIFOL(fd,4)=account_id;
WFIFOB(fd,8)=0;
memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus));
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
int mapif_save_homun_ack(int fd,int account_id,int flag)
{
WFIFOHEAD(fd, 7);
WFIFOW(fd,0)=0x3892;
WFIFOL(fd,2)=account_id;
WFIFOB(fd,6)=flag;
WFIFOSET(fd,7);
return 0;
}
int mapif_delete_homun_ack(int fd,int flag)
{
WFIFOHEAD(fd, 3);
WFIFOW(fd,0)=0x3893;
WFIFOB(fd,2)=flag;
WFIFOSET(fd,3);
return 0;
}
int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){
WFIFOHEAD(fd, NAME_LENGTH+12);
WFIFOW(fd, 0) =0x3894;
WFIFOL(fd, 2) =account_id;
WFIFOL(fd, 6) =char_id;
WFIFOB(fd, 10) =flag;
memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
WFIFOSET(fd, NAME_LENGTH+12);
return 0;
}
int mapif_create_homun(int fd)
{
struct s_homunculus *p;
p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1);
if(p==NULL){
ShowFatalError("int_homun: out of memory !\n");
//Sending the received data will pass hom_id == 0 <- fail.
mapif_homun_created(fd,RFIFOL(fd,4),(struct s_homunculus*)RFIFOP(fd,8));
return 0;
}
memcpy(p, RFIFOP(fd,8), sizeof(struct s_homunculus));
p->hom_id = homun_newid++; //New ID
idb_put(homun_db,p->hom_id,p);
mapif_homun_created(fd,RFIFOL(fd,4),p);
return 0;
}
int mapif_load_homun(int fd)
{
struct s_homunculus *p;
int account_id;
account_id = RFIFOL(fd,2);
p = (struct s_homunculus*)idb_get(homun_db,RFIFOL(fd,6));
if(p==NULL) {
mapif_homun_noinfo(fd,account_id);
return 0;
}
mapif_homun_info(fd,account_id,p);
return 0;
}
static void* create_homun(DBKey key, va_list args) {
struct s_homunculus *p;
p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1);
p->hom_id = key.i;
return p;
}
int mapif_save_homun(int fd,int account_id,struct s_homunculus *data)
{
struct s_homunculus *p;
int hom_id;
if (data->hom_id == 0)
data->hom_id = homun_newid++;
hom_id = data->hom_id;
p = (struct s_homunculus*)idb_ensure(homun_db,hom_id,create_homun);
memcpy(p,data,sizeof(struct s_homunculus));
mapif_save_homun_ack(fd,account_id,1);
return 0;
}
int mapif_delete_homun(int fd,int hom_id)
{
mapif_delete_homun_ack(fd,inter_homun_delete(hom_id));
return 0;
}
int mapif_rename_homun(int fd, int account_id, int char_id, char *name){
int i;
// Check Authorised letters/symbols in the name of the homun
if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) == NULL) {
mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
return 0;
}
} else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) != NULL) {
mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
return 0;
}
}
mapif_rename_homun_ack(fd, account_id, char_id, 1, name);
return 0;
}
int mapif_parse_SaveHomun(int fd)
{
mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8));
return 0;
}
int mapif_parse_DeleteHomun(int fd)
{
mapif_delete_homun(fd,RFIFOL(fd,2));
return 0;
}
int mapif_parse_RenameHomun(int fd)
{
mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), (char*)RFIFOP(fd, 10));
return 0;
}
int inter_homun_parse_frommap(int fd)
{
switch(RFIFOW(fd,0)){
case 0x3090: mapif_create_homun(fd); break;
case 0x3091: mapif_load_homun(fd); break;
case 0x3092: mapif_parse_SaveHomun(fd); break;
case 0x3093: mapif_parse_DeleteHomun(fd); break;
case 0x3094: mapif_parse_RenameHomun(fd); break;
default:
return 0;
}
return 1;
}

15
src/char/int_homun.h Normal file
View File

@ -0,0 +1,15 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_HOMUN_H_
#define _INT_HOMUN_H_
int inter_homun_init(void);
void inter_homun_final(void);
int inter_homun_save(void);
int inter_homun_delete(int homun_id);
int inter_homun_parse_frommap(int fd);
extern char homun_txt[1024];
#endif /* _INT_HOMUN_H_ */

732
src/char/int_party.c Normal file
View File

@ -0,0 +1,732 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/cbasetypes.h"
#include "../common/mmo.h"
#include "../common/malloc.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "char.h"
#include "inter.h"
#include "int_party.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char party_txt[1024] = "save/party.txt";
#ifndef TXT_SQL_CONVERT
struct party_data {
struct party party;
unsigned int min_lv, max_lv;
int family; //Is this party a family? if so, this holds the child id.
unsigned char size; //Total size of party.
};
static DBMap* party_db; // int party_id -> struct party_data*
static int party_newid = 100;
int mapif_party_broken(int party_id, int flag);
int party_check_empty(struct party *p);
int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id);
int party_check_exp_share(struct party_data *p);
int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag);
//Updates party's level range and unsets even share if broken.
static int int_party_check_lv(struct party_data *p) {
int i;
unsigned int lv;
p->min_lv = UINT_MAX;
p->max_lv = 0;
for(i=0;i<MAX_PARTY;i++){
if(!p->party.member[i].online)
continue;
lv=p->party.member[i].lv;
if (lv < p->min_lv) p->min_lv = lv;
if (lv > p->max_lv) p->max_lv = lv;
}
if (p->party.exp && !party_check_exp_share(p)) {
p->party.exp = 0;
mapif_party_optionchanged(0, &p->party, 0, 0);
return 0;
}
return 1;
}
//Calculates the state of a party.
static void int_party_calc_state(struct party_data *p)
{
int i;
unsigned int lv;
p->min_lv = UINT_MAX;
p->max_lv = 0;
p->party.count =
p->size =
p->family = 0;
//Check party size.
for(i=0;i<MAX_PARTY;i++){
if (!p->party.member[i].lv) continue;
p->size++;
if(p->party.member[i].online)
p->party.count++;
}
if(p->size == 3) {
//Check Family State.
p->family = char_family(
p->party.member[0].char_id,
p->party.member[1].char_id,
p->party.member[2].char_id
);
}
//max/min levels.
for(i=0;i<MAX_PARTY;i++){
lv=p->party.member[i].lv;
if (!lv) continue;
if(p->party.member[i].online &&
//On families, the kid is not counted towards exp share rules.
p->party.member[i].char_id != p->family)
{
if( lv < p->min_lv ) p->min_lv=lv;
if( p->max_lv < lv ) p->max_lv=lv;
}
}
if (p->party.exp && !party_check_exp_share(p)) {
p->party.exp = 0; //Set off even share.
mapif_party_optionchanged(0, &p->party, 0, 0);
}
return;
}
// パ?ティデ?タの文字列への?換
int inter_party_tostr(char *str, struct party *p) {
int i, len;
len = sprintf(str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item);
for(i = 0; i < MAX_PARTY; i++) {
struct party_member *m = &p->member[i];
len += sprintf(str + len, "%d,%d,%d\t", m->account_id, m->char_id, m->leader);
}
return 0;
}
#endif //TXT_SQL_CONVERT
// パ?ティデ?タの文字列からの?換
int inter_party_fromstr(char *str, struct party *p) {
int i, j;
int tmp_int[16];
char tmp_str[256];
#ifndef TXT_SQL_CONVERT
struct mmo_charstatus* status;
#endif
memset(p, 0, sizeof(struct party));
if (sscanf(str, "%d\t%255[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4)
return 1;
p->party_id = tmp_int[0];
memcpy(p->name, tmp_str, NAME_LENGTH);
p->exp = tmp_int[1]?1:0;
p->item = tmp_int[2];
for(j = 0; j < 3 && str != NULL; j++)
str = strchr(str + 1, '\t');
for(i = 0; i < MAX_PARTY; i++) {
struct party_member *m = &p->member[i];
if (str == NULL)
return 1;
if (sscanf(str + 1, "%d,%d,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3)
return 1;
m->account_id = tmp_int[0];
m->char_id = tmp_int[1];
m->leader = tmp_int[2]?1:0;
str = strchr(str + 1, '\t');
#ifndef TXT_SQL_CONVERT
if (!m->account_id) continue;
//Lookup player for rest of data.
status = search_character(m->account_id, m->char_id);
if (!status) continue;
memcpy(m->name, status->name, NAME_LENGTH);
m->class_ = status->class_;
m->map = status->last_point.map;
m->lv = status->base_level;
#endif //TXT_SQL_CONVERT
}
return 0;
}
#ifndef TXT_SQL_CONVERT
// パ?ティデ?タのロ?ド
int inter_party_init() {
char line[8192];
struct party_data *p;
FILE *fp;
int c = 0;
int i, j;
party_db = idb_alloc(DB_OPT_RELEASE_DATA);
if ((fp = fopen(party_txt, "r")) == NULL)
return 1;
while(fgets(line, sizeof(line), fp))
{
j = 0;
if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) {
party_newid = i;
continue;
}
p = (struct party_data*)aCalloc(sizeof(struct party_data), 1);
if (p == NULL){
ShowFatalError("int_party: out of memory!\n");
exit(EXIT_FAILURE);
}
memset(p, 0, sizeof(struct party_data));
if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) {
int_party_calc_state(p);
if (p->party.party_id >= party_newid)
party_newid = p->party.party_id + 1;
idb_put(party_db, p->party.party_id, p);
party_check_empty(&p->party);
} else {
ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1);
aFree(p);
}
c++;
}
fclose(fp);
return 0;
}
void inter_party_final()
{
party_db->destroy(party_db, NULL);
return;
}
// パ?ティ?デ?タのセ?ブ用
int inter_party_save_sub(DBKey key, void *data, va_list ap) {
char line[8192];
FILE *fp;
inter_party_tostr(line, &((struct party_data*)data)->party);
fp = va_arg(ap, FILE *);
fprintf(fp, "%s\n", line);
return 0;
}
// パ?ティ?デ?タのセ?ブ
int inter_party_save() {
FILE *fp;
int lock;
if ((fp = lock_fopen(party_txt, &lock)) == NULL) {
ShowError("int_party: can't write [%s] !!! data is lost !!!\n", party_txt);
return 1;
}
party_db->foreach(party_db, inter_party_save_sub, fp);
lock_fclose(fp,party_txt, &lock);
return 0;
}
// パ?ティ名?索用
int search_partyname_sub(DBKey key,void *data,va_list ap) {
struct party_data *p = (struct party_data *)data,**dst;
char *str;
str = va_arg(ap, char *);
dst = va_arg(ap, struct party_data **);
if (strncmpi(p->party.name, str, NAME_LENGTH) == 0)
*dst = p;
return 0;
}
// パ?ティ名?索
struct party_data* search_partyname(char *str) {
struct party_data *p = NULL;
party_db->foreach(party_db, search_partyname_sub, str, &p);
return p;
}
// Returns whether this party can keep having exp share or not.
int party_check_exp_share(struct party_data *p) {
return (p->party.count < 2|| p->max_lv - p->min_lv <= party_share_level);
}
// パ?ティが空かどうかチェック
int party_check_empty(struct party *p) {
int i;
for(i = 0; i < MAX_PARTY; i++) {
if (p->member[i].account_id > 0) {
return 0;
}
}
mapif_party_broken(p->party_id, 0);
idb_remove(party_db, p->party_id);
return 1;
}
// キャラの競合がないかチェック用
int party_check_conflict_sub(DBKey key, void *data, va_list ap) {
struct party_data *p = (struct party_data *)data;
int party_id, account_id, char_id, i;
party_id=va_arg(ap, int);
account_id=va_arg(ap, int);
char_id=va_arg(ap, int);
if (p->party.party_id == party_id) //No conflict to check
return 0;
for(i = 0; i < MAX_PARTY; i++) {
if(p->party.member[i].account_id == account_id &&
p->party.member[i].char_id == char_id)
{
ShowWarning("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party.party_id);
mapif_parse_PartyLeave(-1, p->party.party_id, account_id, char_id);
}
}
return 0;
}
// キャラの競合がないかチェック
int party_check_conflict(int party_id, int account_id, int char_id) {
party_db->foreach(party_db, party_check_conflict_sub, party_id, account_id, char_id);
return 0;
}
//-------------------------------------------------------------------
// map serverへの通信
// パ?ティ作成可否
int mapif_party_created(int fd,int account_id, int char_id, struct party *p) {
WFIFOHEAD(fd, 39);
WFIFOW(fd,0) = 0x3820;
WFIFOL(fd,2) = account_id;
WFIFOL(fd,6) = char_id;
if (p != NULL) {
WFIFOB(fd,10) = 0;
WFIFOL(fd,11) = p->party_id;
memcpy(WFIFOP(fd,15), p->name, NAME_LENGTH);
ShowInfo("Created party (%d - %s)\n", p->party_id, p->name);
} else {
WFIFOB(fd,10) = 1;
WFIFOL(fd,11) = 0;
memset(WFIFOP(fd,15), 0, NAME_LENGTH);
}
WFIFOSET(fd,39);
return 0;
}
// パ?ティ情報見つからず
int mapif_party_noinfo(int fd, int party_id) {
WFIFOHEAD(fd, 8);
WFIFOW(fd,0) = 0x3821;
WFIFOW(fd,2) = 8;
WFIFOL(fd,4) = party_id;
WFIFOSET(fd,8);
ShowWarning("int_party: info not found %d\n", party_id);
return 0;
}
// パ?ティ情報まとめ送り
int mapif_party_info(int fd, struct party *p) {
unsigned char buf[2048];
WBUFW(buf,0) = 0x3821;
memcpy(buf + 4, p, sizeof(struct party));
WBUFW(buf,2) = 4 + sizeof(struct party);
if (fd < 0)
mapif_sendall(buf, WBUFW(buf,2));
else
mapif_send(fd, buf, WBUFW(buf,2));
return 0;
}
// パ?ティメンバ追加可否
int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) {
WFIFOHEAD(fd, 15);
WFIFOW(fd,0) = 0x3822;
WFIFOL(fd,2) = party_id;
WFIFOL(fd,6) = account_id;
WFIFOL(fd,10) = char_id;
WFIFOB(fd,14) = flag;
WFIFOSET(fd,15);
return 0;
}
// パ?ティ設定?更通知
int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag) {
unsigned char buf[15];
WBUFW(buf,0) = 0x3823;
WBUFL(buf,2) = p->party_id;
WBUFL(buf,6) = account_id;
WBUFW(buf,10) = p->exp;
WBUFW(buf,12) = p->item;
WBUFB(buf,14) = flag;
if (flag == 0)
mapif_sendall(buf, 15);
else
mapif_send(fd, buf, 15);
return 0;
}
// パ?ティ?退通知
int mapif_party_leaved(int party_id,int account_id, int char_id) {
unsigned char buf[16];
WBUFW(buf,0) = 0x3824;
WBUFL(buf,2) = party_id;
WBUFL(buf,6) = account_id;
WBUFL(buf,10) = char_id;
mapif_sendall(buf, 14);
return 0;
}
// パ?ティマップ更新通知
int mapif_party_membermoved(struct party *p, int idx) {
unsigned char buf[20];
WBUFW(buf,0) = 0x3825;
WBUFL(buf,2) = p->party_id;
WBUFL(buf,6) = p->member[idx].account_id;
WBUFL(buf,10) = p->member[idx].char_id;
WBUFW(buf,14) = p->member[idx].map;
WBUFB(buf,16) = p->member[idx].online;
WBUFW(buf,17) = p->member[idx].lv;
mapif_sendall(buf, 19);
return 0;
}
// パ?ティ解散通知
int mapif_party_broken(int party_id, int flag) {
unsigned char buf[7];
WBUFW(buf,0) = 0x3826;
WBUFL(buf,2) = party_id;
WBUFB(buf,6) = flag;
mapif_sendall(buf, 7);
ShowInfo("Party broken (%d)\n", party_id);
return 0;
}
// パ?ティ??言
int mapif_party_message(int party_id, int account_id, char *mes, int len, int sfd) {
unsigned char buf[2048];
WBUFW(buf,0) = 0x3827;
WBUFW(buf,2) = len + 12;
WBUFL(buf,4) = party_id;
WBUFL(buf,8) = account_id;
memcpy(WBUFP(buf,12), mes, len);
mapif_sendallwos(sfd, buf,len + 12);
return 0;
}
//-------------------------------------------------------------------
// map serverからの通信
// パ?ティ
int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) {
struct party_data *p;
int i;
for(i = 0; i < NAME_LENGTH && name[i]; i++) {
if (!(name[i] & 0xe0) || name[i] == 0x7f) {
ShowInfo("int_party: illegal party name [%s]\n", name);
mapif_party_created(fd, leader->account_id, leader->char_id, NULL);
return 0;
}
}
if ((p = search_partyname(name)) != NULL) {
ShowInfo("int_party: same name party exists [%s]\n", name);
mapif_party_created(fd, leader->account_id, leader->char_id, NULL);
return 0;
}
// Check Authorised letters/symbols in the name of the character
if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) == NULL) {
mapif_party_created(fd, leader->account_id, leader->char_id, NULL);
return 0;
}
} else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) != NULL) {
mapif_party_created(fd, leader->account_id, leader->char_id, NULL);
return 0;
}
}
p = (struct party_data *) aCalloc(sizeof(struct party_data), 1);
if (p == NULL) {
ShowFatalError("int_party: out of memory !\n");
mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
return 0;
}
p->party.party_id = party_newid++;
memcpy(p->party.name, name, NAME_LENGTH);
p->party.exp = 0;
p->party.item=(item?1:0)|(item2?2:0);
memcpy(&p->party.member[0], leader, sizeof(struct party_member));
p->party.member[0].leader = 1;
int_party_calc_state(p);
idb_put(party_db, p->party.party_id, p);
mapif_party_created(fd, leader->account_id, leader->char_id, &p->party);
mapif_party_info(fd, &p->party);
return 0;
}
// パ?ティ情報要求
int mapif_parse_PartyInfo(int fd, int party_id)
{
struct party_data *p;
p = (struct party_data*)idb_get(party_db, party_id);
if (p != NULL)
mapif_party_info(fd, &p->party);
else {
mapif_party_noinfo(fd, party_id);
char_clearparty(party_id);
}
return 0;
}
// パーティ追加要求
int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member)
{
struct party_data *p;
int i;
p = (struct party_data*)idb_get(party_db, party_id);
if( p == NULL || p->size == MAX_PARTY ) {
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1);
return 0;
}
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 );
if( i == MAX_PARTY )
{// Party full
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1);
return 0;
}
memcpy(&p->party.member[i], member, sizeof(struct party_member));
p->party.member[i].leader = 0;
if (p->party.member[i].online) p->party.count++;
p->size++;
if (p->size == 3) //Check family state.
int_party_calc_state(p);
else //Check even share range.
if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) {
if (p->family) p->family = 0; //Family state broken.
int_party_check_lv(p);
}
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0);
mapif_party_info(-1, &p->party);
return 0;
}
// パ?ティ?設定?更要求
int mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, int exp, int item)
{
struct party_data *p;
int flag = 0;
p = (struct party_data*)idb_get(party_db, party_id);
if (p == NULL)
return 0;
p->party.exp = exp;
if (exp>0 && !party_check_exp_share(p)) {
flag |= 0x01;
p->party.exp = 0;
}
p->party.item = item&0x3;
mapif_party_optionchanged(fd, &p->party, account_id, flag);
return 0;
}
// パ?ティ?退要求
int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
{
struct party_data *p;
int i,lv;
p = (struct party_data*)idb_get(party_db, party_id);
if (!p) return 0;
for(i = 0; i < MAX_PARTY; i++) {
if(p->party.member[i].account_id == account_id &&
p->party.member[i].char_id == char_id)
{
mapif_party_leaved(party_id, account_id, char_id);
lv = p->party.member[i].lv;
if(p->party.member[i].online) p->party.count--;
memset(&p->party.member[i], 0, sizeof(struct party_member));
p->size--;
if (lv == p->min_lv || lv == p->max_lv || p->family)
{
if(p->family) p->family = 0; //Family state broken.
int_party_check_lv(p);
}
if (party_check_empty(&p->party) == 0)
mapif_party_info(-1, &p->party);
return 0;
}
}
return 0;
}
int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv)
{
struct party_data *p;
int i;
p = (struct party_data*)idb_get(party_db, party_id);
if (p == NULL)
return 0;
for(i = 0; i < MAX_PARTY &&
(p->party.member[i].account_id != account_id ||
p->party.member[i].char_id != char_id); i++);
if (i == MAX_PARTY) return 0;
if (p->party.member[i].online != online)
{
p->party.member[i].online = online;
if (online)
p->party.count++;
else
p->party.count--;
// Even share check situations: Family state (always breaks)
// character logging on/off is max/min level (update level range)
// or character logging on/off has a different level (update level range using new level)
if (p->family ||
(p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) ||
(p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv))
)
{
p->party.member[i].lv = lv;
int_party_check_lv(p);
}
//Send online/offline update.
mapif_party_membermoved(&p->party, i);
}
if (p->party.member[i].lv != lv) {
if(p->party.member[i].lv == p->min_lv ||
p->party.member[i].lv == p->max_lv)
{
p->party.member[i].lv = lv;
int_party_check_lv(p);
} else
p->party.member[i].lv = lv;
//There is no need to send level update to map servers
//since they do nothing with it.
}
if (p->party.member[i].map != map) {
p->party.member[i].map = map;
mapif_party_membermoved(&p->party, i);
}
return 0;
}
// パ?ティ解散要求
int mapif_parse_BreakParty(int fd, int party_id) {
idb_remove(party_db, party_id);
mapif_party_broken(fd, party_id);
return 0;
}
// パ?ティメッセ?ジ送信
int mapif_parse_PartyMessage(int fd, int party_id, int account_id, char *mes, int len) {
return mapif_party_message(party_id, account_id, mes, len, fd);
}
// パ?ティチェック要求
int mapif_parse_PartyCheck(int fd, int party_id, int account_id, int char_id) {
return party_check_conflict(party_id, account_id, char_id);
}
int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id)
{
struct party_data *p;
int i;
p = (struct party_data*)idb_get(party_db, party_id);
if (p == NULL)
return 0;
for (i = 0; i < MAX_PARTY; i++)
{
if(p->party.member[i].leader)
p->party.member[i].leader = 0;
if(p->party.member[i].account_id == account_id &&
p->party.member[i].char_id == char_id)
p->party.member[i].leader = 1;
}
return 1;
}
// map server からの通信
// ?1パケットのみ解析すること
// ?パケット長デ?タはinter.cにセットしておくこと
// ?パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない
// ?エラ?なら0(false)、そうでないなら1(true)をかえさなければならない
int inter_party_parse_frommap(int fd) {
RFIFOHEAD(fd);
switch(RFIFOW(fd,0)) {
case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break;
case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break;
case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break;
case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break;
case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break;
case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break;
case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break;
case 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
default:
return 0;
}
return 1;
}
// サ?バ?から?退要求(キャラ削除用)
int inter_party_leave(int party_id, int account_id, int char_id) {
return mapif_parse_PartyLeave(-1, party_id, account_id, char_id);
}
#endif //TXT_SQL_CONVERT

20
src/char/int_party.h Normal file
View File

@ -0,0 +1,20 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_PARTY_H_
#define _INT_PARTY_H_
struct party;
int inter_party_init(void);
void inter_party_final(void);
int inter_party_save(void);
int inter_party_parse_frommap(int fd);
int inter_party_leave(int party_id,int account_id, int char_id);
extern char party_txt[1024];
//For the TXT->SQL converter
int inter_party_fromstr(char *str, struct party *p);
#endif /* _INT_PARTY_H_ */

380
src/char/int_pet.c Normal file
View File

@ -0,0 +1,380 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/mmo.h"
#include "../common/malloc.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "char.h"
#include "inter.h"
#include "int_pet.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char pet_txt[1024]="save/pet.txt";
#ifndef TXT_SQL_CONVERT
static DBMap* pet_db; // int pet_id -> struct s_pet*
static int pet_newid = 100;
int inter_pet_tostr(char *str,struct s_pet *p)
{
int len;
if(p->hungry < 0)
p->hungry = 0;
else if(p->hungry > 100)
p->hungry = 100;
if(p->intimate < 0)
p->intimate = 0;
else if(p->intimate > 1000)
p->intimate = 1000;
len=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,%d,%d,%d,%d",
p->pet_id,p->class_,p->name,p->account_id,p->char_id,p->level,p->egg_id,
p->equip,p->intimate,p->hungry,p->rename_flag,p->incuvate);
return 0;
}
#endif //TXT_SQL_CONVERT
int inter_pet_fromstr(char *str,struct s_pet *p)
{
int s;
int tmp_int[16];
char tmp_str[256];
memset(p,0,sizeof(struct s_pet));
s=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,%d,%d,%d,%d",&tmp_int[0],&tmp_int[1],tmp_str,&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]);
if(s!=12)
return 1;
p->pet_id = tmp_int[0];
p->class_ = tmp_int[1];
memcpy(p->name,tmp_str,NAME_LENGTH);
p->account_id = tmp_int[2];
p->char_id = tmp_int[3];
p->level = tmp_int[4];
p->egg_id = tmp_int[5];
p->equip = tmp_int[6];
p->intimate = tmp_int[7];
p->hungry = tmp_int[8];
p->rename_flag = tmp_int[9];
p->incuvate = tmp_int[10];
if(p->hungry < 0)
p->hungry = 0;
else if(p->hungry > 100)
p->hungry = 100;
if(p->intimate < 0)
p->intimate = 0;
else if(p->intimate > 1000)
p->intimate = 1000;
return 0;
}
#ifndef TXT_SQL_CONVERT
int inter_pet_init()
{
char line[8192];
struct s_pet *p;
FILE *fp;
int c=0;
pet_db= idb_alloc(DB_OPT_RELEASE_DATA);
if( (fp=fopen(pet_txt,"r"))==NULL )
return 1;
while(fgets(line, sizeof(line), fp))
{
p = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1);
if(p==NULL){
ShowFatalError("int_pet: out of memory!\n");
exit(EXIT_FAILURE);
}
memset(p,0,sizeof(struct s_pet));
if(inter_pet_fromstr(line,p)==0 && p->pet_id>0){
if( p->pet_id >= pet_newid)
pet_newid=p->pet_id+1;
idb_put(pet_db,p->pet_id,p);
}else{
ShowError("int_pet: broken data [%s] line %d\n",pet_txt,c);
aFree(p);
}
c++;
}
fclose(fp);
return 0;
}
void inter_pet_final()
{
pet_db->destroy(pet_db, NULL);
return;
}
int inter_pet_save_sub(DBKey key,void *data,va_list ap)
{
char line[8192];
FILE *fp;
inter_pet_tostr(line,(struct s_pet *)data);
fp=va_arg(ap,FILE *);
fprintf(fp,"%s\n",line);
return 0;
}
int inter_pet_save()
{
FILE *fp;
int lock;
if( (fp=lock_fopen(pet_txt,&lock))==NULL ){
ShowError("int_pet: can't write [%s] !!! data is lost !!!\n",pet_txt);
return 1;
}
pet_db->foreach(pet_db,inter_pet_save_sub,fp);
lock_fclose(fp,pet_txt,&lock);
return 0;
}
int inter_pet_delete(int pet_id)
{
struct s_pet *p;
p = (struct s_pet*)idb_get(pet_db,pet_id);
if( p == NULL)
return 1;
else {
idb_remove(pet_db,pet_id);
ShowInfo("Deleted pet (pet_id: %d)\n",pet_id);
}
return 0;
}
int mapif_pet_created(int fd,int account_id,struct s_pet *p)
{
WFIFOHEAD(fd, 11);
WFIFOW(fd,0)=0x3880;
WFIFOL(fd,2)=account_id;
if(p!=NULL){
WFIFOB(fd,6)=0;
WFIFOL(fd,7)=p->pet_id;
ShowInfo("Created pet (%d - %s)\n",p->pet_id,p->name);
}else{
WFIFOB(fd,6)=1;
WFIFOL(fd,7)=0;
}
WFIFOSET(fd,11);
return 0;
}
int mapif_pet_info(int fd,int account_id,struct s_pet *p)
{
WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
WFIFOW(fd,0)=0x3881;
WFIFOW(fd,2)=sizeof(struct s_pet) + 9;
WFIFOL(fd,4)=account_id;
WFIFOB(fd,8)=0;
memcpy(WFIFOP(fd,9),p,sizeof(struct s_pet));
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
int mapif_pet_noinfo(int fd,int account_id)
{
WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
WFIFOW(fd,0)=0x3881;
WFIFOW(fd,2)=sizeof(struct s_pet) + 9;
WFIFOL(fd,4)=account_id;
WFIFOB(fd,8)=1;
memset(WFIFOP(fd,9),0,sizeof(struct s_pet));
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
int mapif_save_pet_ack(int fd,int account_id,int flag)
{
WFIFOHEAD(fd, 7);
WFIFOW(fd,0)=0x3882;
WFIFOL(fd,2)=account_id;
WFIFOB(fd,6)=flag;
WFIFOSET(fd,7);
return 0;
}
int mapif_delete_pet_ack(int fd,int flag)
{
WFIFOHEAD(fd, 3);
WFIFOW(fd,0)=0x3883;
WFIFOB(fd,2)=flag;
WFIFOSET(fd,3);
return 0;
}
int mapif_create_pet(int fd,int account_id,int char_id,short pet_class,short pet_lv,short pet_egg_id,
short pet_equip,short intimate,short hungry,char rename_flag,char incuvate,char *pet_name)
{
struct s_pet *p;
p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1);
if(p==NULL){
ShowFatalError("int_pet: out of memory !\n");
mapif_pet_created(fd,account_id,NULL);
return 0;
}
// memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex]
p->pet_id = pet_newid++;
memcpy(p->name,pet_name,NAME_LENGTH);
if(incuvate == 1)
p->account_id = p->char_id = 0;
else {
p->account_id = account_id;
p->char_id = char_id;
}
p->class_ = pet_class;
p->level = pet_lv;
p->egg_id = pet_egg_id;
p->equip = pet_equip;
p->intimate = intimate;
p->hungry = hungry;
p->rename_flag = rename_flag;
p->incuvate = incuvate;
if(p->hungry < 0)
p->hungry = 0;
else if(p->hungry > 100)
p->hungry = 100;
if(p->intimate < 0)
p->intimate = 0;
else if(p->intimate > 1000)
p->intimate = 1000;
idb_put(pet_db,p->pet_id,p);
mapif_pet_created(fd,account_id,p);
return 0;
}
int mapif_load_pet(int fd,int account_id,int char_id,int pet_id)
{
struct s_pet *p;
p = (struct s_pet*)idb_get(pet_db,pet_id);
if(p!=NULL) {
if(p->incuvate == 1) {
p->account_id = p->char_id = 0;
mapif_pet_info(fd,account_id,p);
}
else if(account_id == p->account_id && char_id == p->char_id)
mapif_pet_info(fd,account_id,p);
else
mapif_pet_noinfo(fd,account_id);
}
else
mapif_pet_noinfo(fd,account_id);
return 0;
}
static void* create_pet(DBKey key, va_list args) {
struct s_pet *p;
p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1);
p->pet_id = key.i;
return p;
}
int mapif_save_pet(int fd,int account_id,struct s_pet *data)
{
struct s_pet *p;
int pet_id, len;
RFIFOHEAD(fd);
len=RFIFOW(fd,2);
if(sizeof(struct s_pet)!=len-8) {
ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8);
}
else{
pet_id = data->pet_id;
if (pet_id == 0)
pet_id = data->pet_id = pet_newid++;
p = (struct s_pet*)idb_ensure(pet_db,pet_id,create_pet);
if(data->hungry < 0)
data->hungry = 0;
else if(data->hungry > 100)
data->hungry = 100;
if(data->intimate < 0)
data->intimate = 0;
else if(data->intimate > 1000)
data->intimate = 1000;
memcpy(p,data,sizeof(struct s_pet));
if(p->incuvate == 1)
p->account_id = p->char_id = 0;
mapif_save_pet_ack(fd,account_id,0);
}
return 0;
}
int mapif_delete_pet(int fd,int pet_id)
{
mapif_delete_pet_ack(fd,inter_pet_delete(pet_id));
return 0;
}
int mapif_parse_CreatePet(int fd)
{
RFIFOHEAD(fd);
mapif_create_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOW(fd,14),RFIFOW(fd,16),RFIFOW(fd,18),
RFIFOW(fd,20),RFIFOB(fd,22),RFIFOB(fd,23),(char*)RFIFOP(fd,24));
return 0;
}
int mapif_parse_LoadPet(int fd)
{
RFIFOHEAD(fd);
mapif_load_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10));
return 0;
}
int mapif_parse_SavePet(int fd)
{
RFIFOHEAD(fd);
mapif_save_pet(fd,RFIFOL(fd,4),(struct s_pet *)RFIFOP(fd,8));
return 0;
}
int mapif_parse_DeletePet(int fd)
{
RFIFOHEAD(fd);
mapif_delete_pet(fd,RFIFOL(fd,2));
return 0;
}
// map server からの通信
// ・1パケットのみ解析すること
// ・パケット長データはinter.cにセットしておくこと
// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない
// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない
int inter_pet_parse_frommap(int fd)
{
RFIFOHEAD(fd);
switch(RFIFOW(fd,0)){
case 0x3080: mapif_parse_CreatePet(fd); break;
case 0x3081: mapif_parse_LoadPet(fd); break;
case 0x3082: mapif_parse_SavePet(fd); break;
case 0x3083: mapif_parse_DeletePet(fd); break;
default:
return 0;
}
return 1;
}
#endif //TXT_SQL_CONVERT

21
src/char/int_pet.h Normal file
View File

@ -0,0 +1,21 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_PET_H_
#define _INT_PET_H_
struct s_pet;
int inter_pet_init(void);
void inter_pet_final(void);
int inter_pet_save(void);
int inter_pet_delete(int pet_id);
int inter_pet_parse_frommap(int fd);
extern char pet_txt[1024];
//Exported for use in the TXT-SQL converter.
int inter_pet_fromstr(char *str,struct s_pet *p);
#endif /* _INT_PET_H_ */

183
src/char/int_status.c Normal file
View File

@ -0,0 +1,183 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/mmo.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/malloc.h"
#include "../common/showmsg.h"
#include "int_status.h"
#include <stdio.h>
// Contains all the status change data in-memory. [Skotlex]
static DBMap* scdata_db = NULL; // int char_id -> struct scdata*
char scdata_txt[1024]="save/scdata.txt"; //By [Skotlex]
#ifdef ENABLE_SC_SAVING
static void* create_scdata(DBKey key, va_list args)
{
struct scdata *data;
data = (struct scdata*)aCalloc(1, sizeof(struct scdata));
data->account_id = va_arg(args, int);
data->char_id = key.i;
return data;
}
/*==========================================
* Loads status change data of the player given. [Skotlex]
*------------------------------------------*/
struct scdata* status_search_scdata(int aid, int cid)
{
return (struct scdata*)scdata_db->ensure(scdata_db, i2key(cid), create_scdata, aid);
}
/*==========================================
* Deletes status change data of the player given. [Skotlex]
* Should be invoked after the data of said player was successfully loaded.
*------------------------------------------*/
void status_delete_scdata(int aid, int cid)
{
struct scdata* scdata = (struct scdata*)idb_remove(scdata_db, cid);
if (scdata)
{
if (scdata->data)
aFree(scdata->data);
aFree(scdata);
}
}
static void inter_status_tostr(char* line, struct scdata *sc_data)
{
int i, len;
len = sprintf(line, "%d,%d,%d\t", sc_data->account_id, sc_data->char_id, sc_data->count);
for(i = 0; i < sc_data->count; i++) {
len += sprintf(line + len, "%d,%d,%d,%d,%d,%d\t", sc_data->data[i].type, sc_data->data[i].tick,
sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4);
}
return;
}
static int inter_scdata_fromstr(char *line, struct scdata *sc_data)
{
int i, len, next;
if (sscanf(line,"%d,%d,%d\t%n",&sc_data->account_id, &sc_data->char_id, &sc_data->count, &next) < 3)
return 0;
if (sc_data->count < 1)
return 0;
sc_data->data = (struct status_change_data*)aCalloc(sc_data->count, sizeof (struct status_change_data));
for (i = 0; i < sc_data->count; i++)
{
if (sscanf(line + next, "%hu,%d,%d,%d,%d,%d\t%n", &sc_data->data[i].type, &sc_data->data[i].tick,
&sc_data->data[i].val1, &sc_data->data[i].val2, &sc_data->data[i].val3, &sc_data->data[i].val4, &len) < 6)
{
aFree(sc_data->data);
return 0;
}
next+=len;
}
return 1;
}
/*==========================================
* Loads all scdata from the given filename.
*------------------------------------------*/
void status_load_scdata(const char* filename)
{
FILE *fp;
int sd_count=0, sc_count=0;
char line[8192];
struct scdata *sc;
if ((fp = fopen(filename, "r")) == NULL) {
ShowError("status_load_scdata: Cannot open file %s!\n", filename);
return;
}
while(fgets(line, sizeof(line), fp))
{
sc = (struct scdata*)aCalloc(1, sizeof(struct scdata));
if (inter_scdata_fromstr(line, sc)) {
sd_count++;
sc_count+= sc->count;
sc = (struct scdata*)idb_put(scdata_db, sc->char_id, sc);
if (sc) {
ShowError("Duplicate entry in %s for character %d\n", filename, sc->char_id);
if (sc->data) aFree(sc->data);
aFree(sc);
}
} else {
ShowError("status_load_scdata: Broken line data: %s\n", line);
aFree(sc);
}
}
fclose(fp);
ShowStatus("Loaded %d saved status changes for %d characters.\n", sc_count, sd_count);
}
static int inter_status_save_sub(DBKey key, void *data, va_list ap) {
char line[8192];
struct scdata * sc_data;
FILE *fp;
sc_data = (struct scdata *)data;
if (sc_data->count < 1)
return 0;
fp = va_arg(ap, FILE *);
inter_status_tostr(line, sc_data);
fprintf(fp, "%s\n", line);
return 0;
}
/*==========================================
* Saves all scdata to the given filename.
*------------------------------------------*/
void inter_status_save()
{
FILE *fp;
int lock;
if ((fp = lock_fopen(scdata_txt, &lock)) == NULL) {
ShowError("int_status: can't write [%s] !!! data is lost !!!\n", scdata_txt);
return;
}
scdata_db->foreach(scdata_db, inter_status_save_sub, fp);
lock_fclose(fp,scdata_txt, &lock);
}
/*==========================================
* Initializes db.
*------------------------------------------*/
void status_init()
{
scdata_db = idb_alloc(DB_OPT_BASE);
status_load_scdata(scdata_txt);
}
/*==========================================
* Frees up memory.
*------------------------------------------*/
static int scdata_db_final(DBKey k,void *d,va_list ap)
{
struct scdata *data = (struct scdata*)d;
if (data->data)
aFree(data->data);
aFree(data);
return 0;
}
/*==========================================
* Final cleanup.
*------------------------------------------*/
void status_final(void)
{
scdata_db->destroy(scdata_db, scdata_db_final);
}
#endif //ENABLE_SC_SAVING

23
src/char/int_status.h Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_STATUS_H_
#define _INT_STATUS_H_
struct status_change_data;
struct scdata {
int account_id, char_id;
int count;
struct status_change_data* data;
};
extern char scdata_txt[1024];
struct scdata* status_search_scdata(int aid, int cid);
void status_delete_scdata(int aid, int cid);
void inter_status_save(void);
void status_init(void);
void status_final(void);
#endif /* _INT_STATUS_H_ */

481
src/char/int_storage.c Normal file
View File

@ -0,0 +1,481 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/mmo.h"
#include "../common/malloc.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "../common/utils.h"
#include "char.h"
#include "inter.h"
#include "int_storage.h"
#include "int_pet.h"
#include "int_guild.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// ファイル名のデフォルト
// inter_config_read()で再設定される
char storage_txt[1024]="save/storage.txt";
char guild_storage_txt[1024]="save/g_storage.txt";
#ifndef TXT_SQL_CONVERT
static DBMap* storage_db; // int account_id -> struct storage*
static DBMap* guild_storage_db; // int guild_id -> struct guild_storage*
// 倉庫データを文字列に変換
int storage_tostr(char *str,struct storage *p)
{
int i,j,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",
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);
for(j=0; j<MAX_SLOTS; j++)
str_p += sprintf(str_p,",%d",p->storage_[i].card[j]);
str_p += sprintf(str_p," ");
f++;
}
*(str_p++)='\t';
*str_p='\0';
if(!f)
str[0]=0;
return 0;
}
#endif //TXT_SQL_CONVERT
// 文字列を倉庫データに変換
int storage_fromstr(char *str,struct storage *p)
{
int tmp_int[256];
char tmp_str[256];
int set,next,len,i,j;
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%[0-9,-]%n",
&tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
&tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) {
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];
for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++)
p->storage_[i].card[j] = tmp_int[0];
next += len;
if (str[next] == ' ')
next++;
}
else return 1;
}
if (i >= MAX_STORAGE && str[next] && str[next]!='\t')
ShowWarning("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE);
return 0;
}
#ifndef TXT_SQL_CONVERT
int guild_storage_tostr(char *str,struct guild_storage *p)
{
int i,j,f=0;
char *str_p = str;
str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount);
for(i=0;i<MAX_GUILD_STORAGE;i++)
if( (p->storage_[i].nameid) && (p->storage_[i].amount) ){
str_p += sprintf(str_p,"%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);
for(j=0; j<MAX_SLOTS; j++)
str_p += sprintf(str_p,",%d",p->storage_[i].card[j]);
str_p += sprintf(str_p," ");
f++;
}
*(str_p++)='\t';
*str_p='\0';
if(!f)
str[0]=0;
return 0;
}
#endif //TXT_SQL_CONVERT
int guild_storage_fromstr(char *str,struct guild_storage *p)
{
int tmp_int[256];
char tmp_str[256];
int set,next,len,i,j;
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_GUILD_STORAGE;i++){
if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n",
&tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
&tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8)
{
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];
for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++)
p->storage_[i].card[j] = tmp_int[0];
next += len;
if (str[next] == ' ')
next++;
}
else return 1;
}
if (i >= MAX_GUILD_STORAGE && str[next] && str[next]!='\t')
ShowWarning("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", MAX_GUILD_STORAGE);
return 0;
}
#ifndef TXT_SQL_CONVERT
static void* create_storage(DBKey key, va_list args) {
struct storage *s;
s = (struct storage *) aCalloc(sizeof(struct storage), 1);
s->account_id=key.i;
return s;
}
// アカウントから倉庫データインデックスを得る(新規倉庫追加可能)
struct storage *account2storage(int account_id)
{
struct storage *s;
s = (struct storage*)idb_ensure(storage_db, account_id, create_storage);
return s;
}
static void* create_guildstorage(DBKey key, va_list args) {
struct guild_storage *gs = NULL;
gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1);
gs->guild_id=key.i;
return gs;
}
struct guild_storage *guild2storage(int guild_id)
{
struct guild_storage *gs = NULL;
if(inter_guild_search(guild_id) != NULL)
gs = (struct guild_storage*)idb_ensure(guild_storage_db, guild_id, create_guildstorage);
return gs;
}
//---------------------------------------------------------
// 倉庫データを読み込む
int inter_storage_init()
{
char line[65536];
int c=0,tmp_int;
struct storage *s;
struct guild_storage *gs;
FILE *fp;
storage_db = idb_alloc(DB_OPT_RELEASE_DATA);
fp=fopen(storage_txt,"r");
if(fp==NULL){
ShowError("can't read : %s\n",storage_txt);
return 1;
}
while(fgets(line, sizeof(line), fp))
{
sscanf(line,"%d",&tmp_int);
s = (struct storage*)aCalloc(sizeof(struct storage), 1);
if(s==NULL){
ShowFatalError("int_storage: out of memory!\n");
exit(EXIT_FAILURE);
}
// memset(s,0,sizeof(struct storage)); aCalloc does this...
s->account_id=tmp_int;
if(s->account_id > 0 && storage_fromstr(line,s) == 0) {
idb_put(storage_db,s->account_id,s);
}
else{
ShowError("int_storage: broken data [%s] line %d\n",storage_txt,c);
aFree(s);
}
c++;
}
fclose(fp);
c = 0;
guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA);
fp=fopen(guild_storage_txt,"r");
if(fp==NULL){
ShowError("can't read : %s\n",guild_storage_txt);
return 1;
}
while(fgets(line, sizeof(line), fp))
{
sscanf(line,"%d",&tmp_int);
gs = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1);
if(gs==NULL){
ShowFatalError("int_storage: out of memory!\n");
exit(EXIT_FAILURE);
}
// memset(gs,0,sizeof(struct guild_storage)); aCalloc...
gs->guild_id=tmp_int;
if(gs->guild_id > 0 && guild_storage_fromstr(line,gs) == 0) {
idb_put(guild_storage_db,gs->guild_id,gs);
}
else{
ShowError("int_storage: broken data [%s] line %d\n",guild_storage_txt,c);
aFree(gs);
}
c++;
}
fclose(fp);
return 0;
}
void inter_storage_final() {
storage_db->destroy(storage_db, NULL);
guild_storage_db->destroy(guild_storage_db, NULL);
return;
}
int inter_storage_save_sub(DBKey key,void *data,va_list ap)
{
char line[65536];
FILE *fp;
storage_tostr(line,(struct storage *)data);
fp=va_arg(ap,FILE *);
if(*line)
fprintf(fp,"%s\n",line);
return 0;
}
//---------------------------------------------------------
// 倉庫データを書き込む
int inter_storage_save()
{
FILE *fp;
int lock;
if( (fp=lock_fopen(storage_txt,&lock))==NULL ){
ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",storage_txt);
return 1;
}
storage_db->foreach(storage_db,inter_storage_save_sub,fp);
lock_fclose(fp,storage_txt,&lock);
return 0;
}
int inter_guild_storage_save_sub(DBKey key,void *data,va_list ap)
{
char line[65536];
FILE *fp;
if(inter_guild_search(((struct guild_storage *)data)->guild_id) != NULL) {
guild_storage_tostr(line,(struct guild_storage *)data);
fp=va_arg(ap,FILE *);
if(*line)
fprintf(fp,"%s\n",line);
}
return 0;
}
//---------------------------------------------------------
// 倉庫データを書き込む
int inter_guild_storage_save()
{
FILE *fp;
int lock;
if( (fp=lock_fopen(guild_storage_txt,&lock))==NULL ){
ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",guild_storage_txt);
return 1;
}
guild_storage_db->foreach(guild_storage_db,inter_guild_storage_save_sub,fp);
lock_fclose(fp,guild_storage_txt,&lock);
return 0;
}
// 倉庫データ削除
int inter_storage_delete(int account_id)
{
struct storage *s = (struct storage*)idb_get(storage_db,account_id);
if(s) {
int i;
for(i=0;i<s->storage_amount;i++){
if(s->storage_[i].card[0] == (short)0xff00)
inter_pet_delete( MakeDWord(s->storage_[i].card[1],s->storage_[i].card[2]) );
}
idb_remove(storage_db,account_id);
}
return 0;
}
// ギルド倉庫データ削除
int inter_guild_storage_delete(int guild_id)
{
struct guild_storage *gs = (struct guild_storage*)idb_get(guild_storage_db,guild_id);
if(gs) {
int i;
for(i=0;i<gs->storage_amount;i++){
if(gs->storage_[i].card[0] == (short)0xff00)
inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) );
}
idb_remove(guild_storage_db,guild_id);
}
return 0;
}
//---------------------------------------------------------
// map serverへの通信
// 倉庫データの送信
int mapif_load_storage(int fd,int account_id)
{
struct storage *s=account2storage(account_id);
WFIFOHEAD(fd, sizeof(struct storage)+8);
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;
}
// 倉庫データ保存完了送信
int mapif_save_storage_ack(int fd,int account_id)
{
WFIFOHEAD(fd, 7);
WFIFOW(fd,0)=0x3811;
WFIFOL(fd,2)=account_id;
WFIFOB(fd,6)=0;
WFIFOSET(fd,7);
return 0;
}
int mapif_load_guild_storage(int fd,int account_id,int guild_id)
{
struct guild_storage *gs=guild2storage(guild_id);
WFIFOHEAD(fd, sizeof(struct guild_storage)+12);
WFIFOW(fd,0)=0x3818;
if(gs) {
WFIFOW(fd,2)=sizeof(struct guild_storage)+12;
WFIFOL(fd,4)=account_id;
WFIFOL(fd,8)=guild_id;
memcpy(WFIFOP(fd,12),gs,sizeof(struct guild_storage));
}
else {
WFIFOW(fd,2)=12;
WFIFOL(fd,4)=account_id;
WFIFOL(fd,8)=0;
}
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail)
{
WFIFOHEAD(fd, 11);
WFIFOW(fd,0)=0x3819;
WFIFOL(fd,2)=account_id;
WFIFOL(fd,6)=guild_id;
WFIFOB(fd,10)=fail;
WFIFOSET(fd,11);
return 0;
}
//---------------------------------------------------------
// map serverからの通信
// 倉庫データ要求受信
int mapif_parse_LoadStorage(int fd)
{
RFIFOHEAD(fd);
mapif_load_storage(fd,RFIFOL(fd,2));
return 0;
}
// 倉庫データ受信&保存
int mapif_parse_SaveStorage(int fd)
{
struct storage *s;
int account_id, len;
RFIFOHEAD(fd);
account_id=RFIFOL(fd,4);
len=RFIFOW(fd,2);
if(sizeof(struct storage)!=len-8){
ShowError("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;
}
int mapif_parse_LoadGuildStorage(int fd)
{
RFIFOHEAD(fd);
mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6));
return 0;
}
int mapif_parse_SaveGuildStorage(int fd)
{
struct guild_storage *gs;
int guild_id, len;
RFIFOHEAD(fd);
guild_id=RFIFOL(fd,8);
len=RFIFOW(fd,2);
if(sizeof(struct guild_storage)!=len-12){
ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12);
}
else {
gs=guild2storage(guild_id);
if(gs) {
memcpy(gs,RFIFOP(fd,12),sizeof(struct guild_storage));
mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0);
}
else
mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1);
}
return 0;
}
// map server からの通信
// ・1パケットのみ解析すること
// ・パケット長データはinter.cにセットしておくこと
// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない
// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない
int inter_storage_parse_frommap(int fd)
{
RFIFOHEAD(fd);
switch(RFIFOW(fd,0)){
case 0x3010: mapif_parse_LoadStorage(fd); break;
case 0x3011: mapif_parse_SaveStorage(fd); break;
case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
default:
return 0;
}
return 1;
}
#endif //TXT_SQL_CONVERT

25
src/char/int_storage.h Normal file
View File

@ -0,0 +1,25 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INT_STORAGE_H_
#define _INT_STORAGE_H_
struct storage;
struct guild_storage;
int inter_storage_init(void);
void inter_storage_final(void);
int inter_storage_save(void);
int inter_guild_storage_save(void);
int inter_storage_delete(int account_id);
int inter_guild_storage_delete(int guild_id);
int inter_storage_parse_frommap(int fd);
extern char storage_txt[1024];
extern char guild_storage_txt[1024];
//Exported for use in the TXT-SQL converter.
int storage_fromstr(char *str,struct storage *p);
int guild_storage_fromstr(char *str,struct guild_storage *p);
#endif /* _INT_STORAGE_H_ */

711
src/char/inter.c Normal file
View File

@ -0,0 +1,711 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/db.h"
#include "../common/mmo.h"
#include "../common/socket.h"
#include "../common/timer.h"
#include "../common/malloc.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "../common/strlib.h"
#include "char.h"
#include "inter.h"
#include "int_party.h"
#include "int_guild.h"
#include "int_status.h"
#include "int_storage.h"
#include "int_pet.h"
#include "int_homun.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds)
// that is the waiting time of answers of all map-servers
#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list
char accreg_txt[1024] = "save/accreg.txt";
#ifndef TXT_SQL_CONVERT
char inter_log_filename[1024] = "log/inter.log";
char main_chat_nick[16] = "Main";
static DBMap* accreg_db = NULL; // int account_id -> struct accreg*
unsigned int party_share_level = 10;
// sending packet list
// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex]
int inter_send_packet_length[]={
-1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f
-1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0,
35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0,
10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1,
9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
// recv. packet list
int inter_recv_packet_length[]={
-1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f
6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f
-1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f
5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3060-0x306f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3070-0x307f
48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f
-1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3090-0x309f Homunculus packets [albator]
};
struct WisData {
int id, fd, count, len;
unsigned long tick;
unsigned char src[24], dst[24], msg[1024];
};
static DBMap* wis_db = NULL; // int wis_id -> struct WisData*
static int wis_dellist[WISDELLIST_MAX], wis_delnum;
//--------------------------------------------------------
// アカウント変数を文字列へ変換
int inter_accreg_tostr(char *str, struct accreg *reg) {
int j;
char *p = str;
p += sprintf(p, "%d\t", reg->account_id);
for(j = 0; j < reg->reg_num; j++) {
p += sprintf(p,"%s,%s ", reg->reg[j].str, reg->reg[j].value);
}
return 0;
}
#endif //TXT_SQL_CONVERT
// アカウント変数を文字列から変換
int inter_accreg_fromstr(const char *str, struct accreg *reg) {
int j, n;
const char *p = str;
if (sscanf(p, "%d\t%n", &reg->account_id, &n ) != 1 || reg->account_id <= 0)
return 1;
for(j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) {
if (sscanf(p, "%[^,],%[^ ] %n", reg->reg[j].str, reg->reg[j].value, &n) != 2)
break;
}
reg->reg_num = j;
return 0;
}
#ifndef TXT_SQL_CONVERT
// アカウント変数の読み込み
int inter_accreg_init(void) {
char line[8192];
FILE *fp;
int c = 0;
struct accreg *reg;
accreg_db = idb_alloc(DB_OPT_RELEASE_DATA);
if( (fp = fopen(accreg_txt, "r")) == NULL)
return 1;
while(fgets(line, sizeof(line), fp))
{
reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1);
if (reg == NULL) {
ShowFatalError("inter: accreg: out of memory!\n");
exit(EXIT_FAILURE);
}
if (inter_accreg_fromstr(line, reg) == 0 && reg->account_id > 0) {
idb_put(accreg_db, reg->account_id, reg);
} else {
ShowError("inter: accreg: broken data [%s] line %d\n", accreg_txt, c);
aFree(reg);
}
c++;
}
fclose(fp);
return 0;
}
// アカウント変数のセーブ用
int inter_accreg_save_sub(DBKey key, void *data, va_list ap) {
char line[8192];
FILE *fp;
struct accreg *reg = (struct accreg *)data;
if (reg->reg_num > 0) {
inter_accreg_tostr(line,reg);
fp = va_arg(ap, FILE *);
fprintf(fp, "%s\n", line);
}
return 0;
}
// アカウント変数のセーブ
int inter_accreg_save(void) {
FILE *fp;
int lock;
if ((fp = lock_fopen(accreg_txt,&lock)) == NULL) {
ShowError("int_accreg: can't write [%s] !!! data is lost !!!\n", accreg_txt);
return 1;
}
accreg_db->foreach(accreg_db, inter_accreg_save_sub,fp);
lock_fclose(fp, accreg_txt, &lock);
return 0;
}
//--------------------------------------------------------
#endif //TXT_SQL_CONVERT
/*==========================================
*
*------------------------------------------*/
static int inter_config_read(const char *cfgName) {
char line[1024], w1[1024], w2[1024];
FILE *fp;
fp = fopen(cfgName, "r");
if (fp == NULL) {
ShowError("file not found: %s\n", cfgName);
return 1;
}
while(fgets(line, sizeof(line), fp))
{
if (line[0] == '/' && line[1] == '/')
continue;
if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2)
continue;
if (strcmpi(w1, "storage_txt") == 0) {
strncpy(storage_txt, w2, sizeof(storage_txt));
} else if (strcmpi(w1, "party_txt") == 0) {
strncpy(party_txt, w2, sizeof(party_txt));
} else if (strcmpi(w1, "pet_txt") == 0) {
strncpy(pet_txt, w2, sizeof(pet_txt));
} else if (strcmpi(w1, "accreg_txt") == 0) {
strncpy(accreg_txt, w2, sizeof(accreg_txt));
} else if (strcmpi(w1, "guild_txt") == 0) {
strncpy(guild_txt, w2, sizeof(guild_txt));
} else if (strcmpi(w1, "castle_txt") == 0) {
strncpy(castle_txt, w2, sizeof(castle_txt));
} else if (strcmpi(w1, "guild_storage_txt") == 0) {
strncpy(guild_storage_txt, w2, sizeof(guild_storage_txt));
#ifndef TXT_SQL_CONVERT
} else if (strcmpi(w1, "homun_txt") == 0) {
strncpy(homun_txt, w2, sizeof(homun_txt));
} else if (strcmpi(w1, "party_share_level") == 0) {
party_share_level = (unsigned int)atof(w2);
} else if (strcmpi(w1, "inter_log_filename") == 0) {
strncpy(inter_log_filename, w2, sizeof(inter_log_filename));
} else if(strcmpi(w1,"log_inter")==0) {
log_inter = atoi(w2);
} else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza]
strcpy(main_chat_nick, w2);
#endif //TXT_SQL_CONVERT
} else if (strcmpi(w1, "import") == 0) {
inter_config_read(w2);
}
}
fclose(fp);
return 0;
}
#ifndef TXT_SQL_CONVERT
// ログ書き出し
int inter_log(char *fmt,...) {
FILE *logfp;
va_list ap;
va_start(ap,fmt);
logfp = fopen(inter_log_filename, "a");
if (logfp) {
vfprintf(logfp, fmt, ap);
fclose(logfp);
}
va_end(ap);
return 0;
}
// セーブ
int inter_save(void) {
#ifdef ENABLE_SC_SAVING
inter_status_save();
#endif
inter_party_save();
inter_guild_save();
inter_storage_save();
inter_guild_storage_save();
inter_pet_save();
inter_homun_save();
inter_accreg_save();
return 0;
}
#endif //TXT_SQL_CONVERT
// 初期化
int inter_init_txt(const char *file) {
inter_config_read(file);
#ifndef TXT_SQL_CONVERT
wis_db = idb_alloc(DB_OPT_RELEASE_DATA);
inter_party_init();
inter_guild_init();
inter_storage_init();
inter_pet_init();
inter_homun_init();
inter_accreg_init();
#endif //TXT_SQL_CONVERT
return 0;
}
#ifndef TXT_SQL_CONVERT
// finalize
void inter_final(void) {
accreg_db->destroy(accreg_db, NULL);
wis_db->destroy(wis_db, NULL);
inter_party_final();
inter_guild_final();
inter_storage_final();
inter_pet_final();
inter_homun_final();
return;
}
// マップサーバー接続
int inter_mapif_init(int fd) {
inter_guild_mapif_init(fd);
return 0;
}
//--------------------------------------------------------
// sended packets to map-server
// GMメッセージ送信
int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) {
unsigned char buf[2048];
if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex]
WBUFW(buf,0) = 0x3800;
WBUFW(buf,2) = len;
WBUFL(buf,4) = color;
memcpy(WBUFP(buf,8), mes, len - 8);
mapif_sendallwos(sfd, buf, len);
return 0;
}
// Wisp/page transmission to one map-server
int mapif_wis_message2(struct WisData *wd, int fd) {
WFIFOHEAD(fd, 56+wd->len);
WFIFOW(fd, 0) = 0x3801;
WFIFOW(fd, 2) = 56 + wd->len;
WFIFOL(fd, 4) = wd->id;
memcpy(WFIFOP(fd, 8), wd->src, NAME_LENGTH);
memcpy(WFIFOP(fd,32), wd->dst, NAME_LENGTH);
memcpy(WFIFOP(fd,56), wd->msg, wd->len);
wd->count = 1;
WFIFOSET(fd,WFIFOW(fd,2));
return 1;
}
// Wisp/page transmission to all map-server
int mapif_wis_message(struct WisData *wd) {
unsigned char buf[2048];
if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex]
WBUFW(buf, 0) = 0x3801;
WBUFW(buf, 2) = 56 + wd->len;
WBUFL(buf, 4) = wd->id;
memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH);
memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH);
memcpy(WBUFP(buf,56), wd->msg, wd->len);
wd->count = mapif_sendall(buf, WBUFW(buf,2));
return 0;
}
int mapif_wis_fail(int fd, char *src) {
unsigned char buf[27];
WBUFW(buf, 0) = 0x3802;
memcpy(WBUFP(buf, 2), src, NAME_LENGTH);
WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
mapif_send(fd, buf, 27);
return 0;
}
// Wisp/page transmission result to map-server
int mapif_wis_end(struct WisData *wd, int flag)
{
unsigned char buf[27];
WBUFW(buf, 0) = 0x3802;
memcpy(WBUFP(buf, 2), wd->src, 24);
WBUFB(buf,26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
mapif_send(wd->fd, buf, 27);
return 0;
}
// Account registry transfer to map-server
static void mapif_account_reg(int fd, unsigned char *src)
{
WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO
mapif_sendallwos(fd, src, WBUFW(src,2));
}
// アカウント変数要求返信
int mapif_account_reg_reply(int fd,int account_id, int char_id)
{
struct accreg *reg = (struct accreg*)idb_get(accreg_db,account_id);
WFIFOHEAD(fd, ACCOUNT_REG_NUM * 288+ 13);
WFIFOW(fd,0) = 0x3804;
WFIFOL(fd,4) = account_id;
WFIFOL(fd,8) = char_id;
WFIFOB(fd,12) = 2; //Acc Reg
if (reg == NULL) {
WFIFOW(fd,2) = 13;
} else {
int i, p;
for (p=13,i = 0; i < reg->reg_num; i++) {
p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place.
p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1;
}
WFIFOW(fd,2)=p;
}
WFIFOSET(fd,WFIFOW(fd,2));
return 0;
}
//Request to kick char from a certain map server. [Skotlex]
int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason)
{
if (fd < 0)
return -1;
WFIFOHEAD(fd, 7);
WFIFOW(fd,0) = 0x2b1f;
WFIFOL(fd,2) = account_id;
WFIFOB(fd,6) = reason;
WFIFOSET(fd,7);
return 0;
}
//--------------------------------------------------------
// Existence check of WISP data
int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) {
unsigned long tick;
struct WisData *wd = (struct WisData *)data;
tick = va_arg(ap, unsigned long);
if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX)
wis_dellist[wis_delnum++] = wd->id;
return 0;
}
int check_ttl_wisdata(void) {
unsigned long tick = gettick();
int i;
do {
wis_delnum = 0;
wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick);
for(i = 0; i < wis_delnum; i++) {
struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]);
ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst);
// removed. not send information after a timeout. Just no answer for the player
//mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
idb_remove(wis_db, wd->id);
}
} while(wis_delnum >= WISDELLIST_MAX);
return 0;
}
//--------------------------------------------------------
// received packets from map-server
// GMメッセージ送信
int mapif_parse_GMmessage(int fd) {
RFIFOHEAD(fd);
mapif_GMmessage(RFIFOP(fd,8), RFIFOW(fd,2), RFIFOL(fd,4), fd);
return 0;
}
static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char* mes, int meslen)
{
static int wisid = 0;
struct WisData* wd = (struct WisData *)aCalloc(sizeof(struct WisData), 1);
if (wd == NULL){
ShowFatalError("inter: WisRequest: out of memory !\n");
return NULL;
}
wd->id = ++wisid;
wd->fd = fd;
wd->len= meslen;
memcpy(wd->src, src, NAME_LENGTH);
memcpy(wd->dst, dst, NAME_LENGTH);
memcpy(wd->msg, mes, meslen);
wd->tick = gettick();
return wd;
}
// Wisp/page request to send
int mapif_parse_WisRequest(int fd)
{
struct mmo_charstatus* char_status;
struct WisData* wd;
char name[NAME_LENGTH];
int fd2;
if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) {
ShowWarning("inter: Wis message size too long.\n");
return 0;
} else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows...
ShowError("inter: Wis message doesn't exist.\n");
return 0;
}
safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex]
// search if character exists before to ask all map-servers
char_status = search_character_byname(name);
if (char_status == NULL)
return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4));
// Character exists.
// to be sure of the correct name, rewrite it
memset(name, 0, NAME_LENGTH);
strncpy(name, char_status->name, NAME_LENGTH);
// if source is destination, don't ask other servers.
if (strcmp((char*)RFIFOP(fd,4),name) == 0)
return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4));
//Look for online character.
fd2 = search_character_online(char_status->account_id, char_status->char_id);
if (fd2 >= 0) { //Character online, send whisper.
wd = mapif_create_whisper(fd, (char*)RFIFOP(fd, 4), (char*)RFIFOP(fd,28), (char*)RFIFOP(fd,52), RFIFOW(fd,2)-52);
if (!wd) return 1;
idb_put(wis_db, wd->id, wd);
mapif_wis_message2(wd, fd2);
return 0;
}
//Not found.
return mapif_wis_fail(fd, (char*)RFIFOP(fd,4));
}
// Wisp/page transmission result
int mapif_parse_WisReply(int fd) {
int id, flag;
struct WisData *wd;
RFIFOHEAD(fd);
id = RFIFOL(fd,2);
flag = RFIFOB(fd,6);
wd = (struct WisData*)idb_get(wis_db, id);
if (wd == NULL)
return 0; // This wisp was probably suppress before, because it was timeout or because of target was found on another map-server
if ((--wd->count) <= 0 || flag != 1) {
mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
idb_remove(wis_db, id);
}
return 0;
}
// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers)
int mapif_parse_WisToGM(int fd) {
unsigned char buf[2048]; // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
ShowDebug("Sent packet back!\n");
memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2));
WBUFW(buf, 0) = 0x3803;
mapif_sendall(buf, RFIFOW(fd,2));
return 0;
}
static void* create_accreg(DBKey key, va_list args) {
struct accreg *reg;
reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1);
reg->account_id = key.i;
return reg;
}
// アカウント変数保存要求
int mapif_parse_Registry(int fd) {
int j, p, len;
struct accreg *reg;
RFIFOHEAD(fd);
switch (RFIFOB(fd,12)) {
case 3: //Character registry
return char_parse_Registry(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,13), RFIFOW(fd,2)-13);
case 2: //Acc Reg
break;
case 1: //Acc Reg2, forward to login
return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4);
default: //Error?
return 1;
}
reg = (struct accreg*)idb_ensure(accreg_db, RFIFOL(fd,4), create_accreg);
for(j=0,p=13;j<ACCOUNT_REG_NUM && p<RFIFOW(fd,2);j++){
sscanf((char*)RFIFOP(fd,p), "%31c%n",reg->reg[j].str,&len);
reg->reg[j].str[len]='\0';
p +=len+1; //+1 to skip the '\0' between strings.
sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len);
reg->reg[j].value[len]='\0';
p +=len+1;
}
reg->reg_num=j;
mapif_account_reg(fd, RFIFOP(fd,0)); // 他のMAPサーバーに送信
return 0;
}
// Request the value of all registries.
int mapif_parse_RegistryRequest(int fd)
{
RFIFOHEAD(fd);
//Load Char Registry
if (RFIFOB(fd,12))
char_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6));
//Load Account Registry
if (RFIFOB(fd,11))
mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6));
//Ask Login Server for Account2 values.
if (RFIFOB(fd,10))
request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6));
return 1;
}
static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name){
WFIFOHEAD(fd, NAME_LENGTH+13);
WFIFOW(fd, 0) =0x3806;
WFIFOL(fd, 2) =account_id;
WFIFOL(fd, 6) =char_id;
WFIFOB(fd,10) =type;
WFIFOB(fd,11) =flag;
memcpy(WFIFOP(fd, 12), name, NAME_LENGTH);
WFIFOSET(fd, NAME_LENGTH+13);
}
int mapif_parse_NameChangeRequest(int fd)
{
int account_id, char_id, type;
char* name;
int i;
RFIFOHEAD(fd);
account_id = RFIFOL(fd, 2);
char_id = RFIFOL(fd, 6);
type = RFIFOB(fd, 10);
name = (char*)RFIFOP(fd, 11);
// Check Authorised letters/symbols in the name
if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) == NULL) {
mapif_namechange_ack(fd, account_id, char_id, type, 0, name);
return 0;
}
} else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
for (i = 0; i < NAME_LENGTH && name[i]; i++)
if (strchr(char_name_letters, name[i]) != NULL) {
mapif_namechange_ack(fd, account_id, char_id, type, 0, name);
return 0;
}
}
//TODO: type holds the type of object to rename.
//If it were a player, it needs to have the guild information and db information
//updated here, because changing it on the map won't make it be saved [Skotlex]
//name allowed.
mapif_namechange_ack(fd, account_id, char_id, type, 1, name);
return 0;
}
//--------------------------------------------------------
// map server からの通信(1パケットのみ解析すること)
// エラーなら0(false)、処理できたなら1、
// パケット長が足りなければ2をかえさなければならない
int inter_parse_frommap(int fd) {
int cmd, len;
RFIFOHEAD(fd);
cmd = RFIFOW(fd,0);
len = 0;
// inter鯖管轄かを調べる
if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length))
return 0;
if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex]
return 0;
// パケット長を調べる
if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0)
return 2;
switch(cmd) {
case 0x3000: mapif_parse_GMmessage(fd); break;
case 0x3001: mapif_parse_WisRequest(fd); break;
case 0x3002: mapif_parse_WisReply(fd); break;
case 0x3003: mapif_parse_WisToGM(fd); break;
case 0x3004: mapif_parse_Registry(fd); break;
case 0x3005: mapif_parse_RegistryRequest(fd); break;
case 0x3006: mapif_parse_NameChangeRequest(fd); break;
default:
if (inter_party_parse_frommap(fd))
break;
if (inter_guild_parse_frommap(fd))
break;
if (inter_storage_parse_frommap(fd))
break;
if (inter_pet_parse_frommap(fd))
break;
if (inter_homun_parse_frommap(fd))
break;
return 0;
}
RFIFOSKIP(fd, len);
return 1;
}
// RFIFOのパケット長確認
// 必要パケット長があればパケット長、まだ足りなければ0
int inter_check_length(int fd, int length) {
if (length == -1) { // 可変パケット長
RFIFOHEAD(fd);
if (RFIFOREST(fd) < 4) // パケット長が未着
return 0;
length = RFIFOW(fd,2);
}
if ((int)RFIFOREST(fd) < length) // パケットが未着
return 0;
return length;
}
#endif //TXT_SQL_CONVERT

30
src/char/inter.h Normal file
View File

@ -0,0 +1,30 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _INTER_H_
#define _INTER_H_
struct accreg;
int inter_init_txt(const char *file);
void inter_final(void);
int inter_save(void);
int inter_parse_frommap(int fd);
int inter_mapif_init(int fd);
int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason);
int inter_check_length(int fd,int length);
int inter_log(char *fmt,...);
#define inter_cfgName "conf/inter_athena.conf"
extern unsigned int party_share_level;
extern char inter_log_filename[1024];
extern char main_chat_nick[16];
//For TXT->SQL conversion
extern char accreg_txt[];
int inter_accreg_fromstr(const char *str, struct accreg *reg);
#endif /* _INTER_H_ */

46
src/login/Makefile.in Normal file
View File

@ -0,0 +1,46 @@
COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \
../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \
../common/obj_all/ers.o ../common/obj_all/md5calc.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \
../common/grfio.h ../common/mapindex.h \
../common/ers.h ../common/md5calc.h
LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o
LOGIN_H = login.h
@SET_MAKE@
#####################################################################
.PHONY : all login-server clean help
all: login-server
login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ)
@CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@
clean:
rm -rf *.o obj_txt ../../login-server@EXEEXT@
help:
@echo "possible targets are 'login-server' 'all' 'clean' 'help'"
@echo "'login-server' - login server (TXT version)"
@echo "'all' - builds all above targets"
@echo "'clean' - cleans builds and objects"
@echo "'help' - outputs this message"
#####################################################################
obj_txt:
-mkdir obj_txt
obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H)
@CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing common object files
../common/obj_all/%.o:
@$(MAKE) -C ../common sql

879
src/login/admin.c Normal file
View File

@ -0,0 +1,879 @@
#include "../common/cbasetypes.h"
#include "../common/mmo.h"
#include "../common/core.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/timer.h"
#include "../common/malloc.h"
#include "../common/strlib.h"
#include "../common/showmsg.h"
#include "../common/version.h"
#include "../common/md5calc.h"
#include "../common/lock.h"
#include "login.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> // for stat/lstat/fstat
extern struct Login_Config login_config;
#define MAX_SERVERS 30
extern struct mmo_char_server server[MAX_SERVERS];
extern struct mmo_account* auth_dat;
extern uint32 auth_num;
extern int account_id_count;
extern char GM_account_filename[1024];
int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len);
int search_account_index(char* account_name);
int mmo_auth_new(struct mmo_account* account);
void mmo_auth_sync(void);
int mmo_auth_tostr(char* str, struct mmo_account* p);
int read_gm_account(void);
void send_GM_accounts(int fd);
int isGM(int account_id);
//---------------------------------------
// Packet parsing for administation login
//---------------------------------------
int parse_admin(int fd)
{
unsigned int i, j;
char* account_name;
uint32 ipl = session[fd]->client_addr;
char ip[16];
ip2str(ipl, ip);
if( session[fd]->flag.eof )
{
do_close(fd);
ShowInfo("Remote administration has disconnected (session #%d).\n", fd);
return 0;
}
while( RFIFOREST(fd) >= 2 )
{
uint16 command = RFIFOW(fd,0);
switch( command )
{
case 0x7530: // Request of the server version
ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip);
WFIFOHEAD(fd,10);
WFIFOW(fd,0) = 0x7531;
WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
WFIFOB(fd,4) = ATHENA_REVISION;
WFIFOB(fd,5) = ATHENA_RELEASE_FLAG;
WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG;
WFIFOB(fd,7) = ATHENA_SERVER_LOGIN;
WFIFOW(fd,8) = ATHENA_MOD_VERSION;
WFIFOSET(fd,10);
RFIFOSKIP(fd,2);
break;
case 0x7920: // Request of an accounts list
if (RFIFOREST(fd) < 10)
return 0;
{
int st, ed;
uint16 len;
CREATE_BUFFER(id, int, auth_num);
st = RFIFOL(fd,2);
ed = RFIFOL(fd,6);
RFIFOSKIP(fd,10);
WFIFOW(fd,0) = 0x7921;
if (st < 0)
st = 0;
if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0)
ed = END_ACCOUNT_NUM;
ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip);
// Sort before send
for(i = 0; i < auth_num; i++) {
unsigned int k;
id[i] = i;
for(j = 0; j < i; j++) {
if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) {
for(k = i; k > j; k--) {
id[k] = id[k-1];
}
id[j] = i; // id[i]
break;
}
}
}
// Sending accounts information
len = 4;
for(i = 0; i < auth_num && len < 30000; i++) {
int account_id = auth_dat[id[i]].account_id; // use sorted index
if (account_id >= st && account_id <= ed) {
j = id[i];
WFIFOL(fd,len) = account_id;
WFIFOB(fd,len+4) = (unsigned char)isGM(account_id);
memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24);
WFIFOB(fd,len+29) = auth_dat[j].sex;
WFIFOL(fd,len+30) = auth_dat[j].logincount;
if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished
WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s
else
WFIFOL(fd,len+34) = auth_dat[j].state;
len += 38;
}
}
WFIFOW(fd,2) = len;
WFIFOSET(fd,len);
//if (id) free(id);
DELETE_BUFFER(id);
}
break;
case 0x7930: // Request for an account creation
if (RFIFOREST(fd) < 91)
return 0;
{
struct mmo_account ma;
safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), NAME_LENGTH);
safestrncpy(ma.pass, (char*)RFIFOP(fd,26), NAME_LENGTH);
safestrncpy(ma.email, (char*)RFIFOP(fd,51), 40);
memcpy(ma.lastlogin, "-", 2);
ma.sex = RFIFOB(fd,50);
RFIFOSKIP(fd,91);
WFIFOW(fd,0) = 0x7931;
WFIFOL(fd,2) = 0xffffffff; // invalid account id
safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24);
if (strlen(ma.userid) < 4 || strlen(ma.pass) < 4) {
ShowNotice("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", ip);
} else if (ma.sex != 'F' && ma.sex != 'M') {
ShowNotice("'ladmin': Attempt to create an invalid account (account: %s, received pass: %s, invalid sex, ip: %s)\n", ma.userid, ma.pass, ip);
} else if (account_id_count > END_ACCOUNT_NUM) {
ShowNotice("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, pass: %s, sex: %c, ip: %s)\n", ma.userid, ma.pass, ma.sex, ip);
} else {
remove_control_chars(ma.userid);
remove_control_chars(ma.pass);
remove_control_chars(ma.email);
ARR_FIND( 0, auth_num, i, strncmp(auth_dat[i].userid, ma.userid, 24) == 0 );
if( i < auth_num )
ShowNotice("'ladmin': Attempt to create an already existing account (account: %s, pass: %s, received pass: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ma.pass, ip);
else
{
int new_id;
new_id = mmo_auth_new(&ma);
ShowNotice("'ladmin': Account creation (account: %s (id: %d), pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, new_id, ma.pass, ma.sex, auth_dat[i].email, ip);
WFIFOL(fd,2) = new_id;
mmo_auth_sync();
}
}
WFIFOSET(fd,30);
}
break;
case 0x7932: // Request for an account deletion
if (RFIFOREST(fd) < 26)
return 0;
WFIFOW(fd,0) = 0x7933;
WFIFOL(fd,2) = 0xFFFFFFFF;
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
// Char-server is notified of deletion (for characters deletion).
unsigned char buf[65535];
WBUFW(buf,0) = 0x2730;
WBUFL(buf,2) = auth_dat[i].account_id;
charif_sendallwos(-1, buf, 6);
// send answer
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
WFIFOL(fd,2) = auth_dat[i].account_id;
// save deleted account in log file
ShowNotice("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", auth_dat[i].userid, auth_dat[i].account_id, ip);
mmo_auth_tostr((char*)buf, &auth_dat[i]);
ShowNotice("%s\n", buf);
// delete account
memset(auth_dat[i].userid, '\0', sizeof(auth_dat[i].userid));
auth_dat[i].account_id = -1;
mmo_auth_sync();
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,26);
break;
case 0x7934: // Request to change a password
if (RFIFOREST(fd) < 50)
return 0;
WFIFOW(fd,0) = 0x7935;
WFIFOL(fd,2) = 0xFFFFFFFF; /// WTF??? an unsigned being set to a -1
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
memcpy(auth_dat[i].pass, RFIFOP(fd,26), 24);
auth_dat[i].pass[23] = '\0';
remove_control_chars(auth_dat[i].pass);
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip);
mmo_auth_sync();
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,50);
break;
case 0x7936: // Request to modify a state
if (RFIFOREST(fd) < 50)
return 0;
{
char error_message[20];
uint32 statut;
WFIFOW(fd,0) = 0x7937;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
statut = RFIFOL(fd,26);
memcpy(error_message, RFIFOP(fd,30), 20);
error_message[19] = '\0';
remove_control_chars(error_message);
if (statut != 7 || error_message[0] == '\0') { // 7: // 6 = Your are Prohibited to log in until %s
strcpy(error_message, "-");
}
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
WFIFOL(fd,2) = auth_dat[i].account_id;
if (auth_dat[i].state == statut && strcmp(auth_dat[i].error_message, error_message) == 0)
ShowNotice("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip);
else {
if (statut == 7)
ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", auth_dat[i].userid, statut, error_message, ip);
else
ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", auth_dat[i].userid, statut, ip);
if (auth_dat[i].state == 0) {
unsigned char buf[16];
WBUFW(buf,0) = 0x2731;
WBUFL(buf,2) = auth_dat[i].account_id;
WBUFB(buf,6) = 0; // 0: change of statut, 1: ban
WBUFL(buf,7) = statut; // status or final date of a banishment
charif_sendallwos(-1, buf, 11);
}
auth_dat[i].state = statut;
memcpy(auth_dat[i].error_message, error_message, 20);
mmo_auth_sync();
}
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip);
}
WFIFOL(fd,30) = statut;
}
WFIFOSET(fd,34);
RFIFOSKIP(fd,50);
break;
case 0x7938: // Request for servers list and # of online players
{
uint8 server_num = 0;
ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip);
for(i = 0; i < MAX_SERVERS; i++) {
if (server[i].fd >= 0) {
WFIFOL(fd,4+server_num*32) = htonl(server[i].ip);
WFIFOW(fd,4+server_num*32+4) = htons(server[i].port);
memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20);
WFIFOW(fd,4+server_num*32+26) = server[i].users;
WFIFOW(fd,4+server_num*32+28) = server[i].maintenance;
WFIFOW(fd,4+server_num*32+30) = server[i].new_;
server_num++;
}
}
WFIFOW(fd,0) = 0x7939;
WFIFOW(fd,2) = 4 + 32 * server_num;
WFIFOSET(fd,4+32*server_num);
RFIFOSKIP(fd,2);
break;
}
case 0x793a: // Request to password check
if (RFIFOREST(fd) < 50)
return 0;
WFIFOW(fd,0) = 0x793b;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
char pass[25];
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
memcpy(pass, RFIFOP(fd,26), 24);
pass[24] = '\0';
remove_control_chars(pass);
if (strcmp(auth_dat[i].pass, pass) == 0) {
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip);
} else {
ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", auth_dat[i].userid, pass, ip);
}
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,50);
break;
case 0x793c: // Request to modify sex
if (RFIFOREST(fd) < 27)
return 0;
WFIFOW(fd,0) = 0x793d;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
memcpy(WFIFOP(fd,6), account_name, 24);
{
char sex;
sex = RFIFOB(fd,26);
if (sex != 'F' && sex != 'M') {
if (sex > 31)
ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip);
else
ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip);
} else {
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
if (auth_dat[i].sex != ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'))) {
unsigned char buf[16];
WFIFOL(fd,2) = auth_dat[i].account_id;
auth_dat[i].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm');
ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip);
mmo_auth_sync();
// send to all char-server the change
WBUFW(buf,0) = 0x2723;
WBUFL(buf,2) = auth_dat[i].account_id;
WBUFB(buf,6) = auth_dat[i].sex;
charif_sendallwos(-1, buf, 7);
} else {
ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip);
}
} else {
ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip);
}
}
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,27);
break;
case 0x793e: // Request to modify GM level
if (RFIFOREST(fd) < 27)
return 0;
WFIFOW(fd,0) = 0x793f;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
memcpy(WFIFOP(fd,6), account_name, 24);
{
char new_gm_level;
new_gm_level = RFIFOB(fd,26);
if (new_gm_level < 0 || new_gm_level > 99) {
ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip);
} else {
i = search_account_index(account_name);
if (i != -1) {
int acc = auth_dat[i].account_id;
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
if (isGM(acc) != new_gm_level) {
// modification of the file
FILE *fp, *fp2;
int lock;
char line[512];
int GM_account, GM_level;
int modify_flag;
char tmpstr[24];
time_t raw_time;
if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) {
if ((fp = fopen(GM_account_filename, "r")) != NULL) {
time(&raw_time);
strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time));
modify_flag = 0;
// read/write GM file
while(fgets(line, sizeof(line), fp))
{
while(line[0] != '\0' && (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r'))
line[strlen(line)-1] = '\0'; // TODO: remove this
if ((line[0] == '/' && line[1] == '/') || line[0] == '\0')
fprintf(fp2, "%s\n", line);
else {
if (sscanf(line, "%d %d", &GM_account, &GM_level) != 2 && sscanf(line, "%d: %d", &GM_account, &GM_level) != 2)
fprintf(fp2, "%s\n", line);
else if (GM_account != acc)
fprintf(fp2, "%s\n", line);
else if (new_gm_level < 1) {
fprintf(fp2, "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level);
modify_flag = 1;
} else {
fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level);
modify_flag = 1;
}
}
}
if (modify_flag == 0)
fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, acc, new_gm_level);
fclose(fp);
} else {
ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip);
}
if (lock_fclose(fp2, GM_account_filename, &lock) == 0) {
WFIFOL(fd,2) = acc;
ShowNotice("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip);
// read and send new GM informations
read_gm_account();
send_GM_accounts(-1);
} else {
ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip);
}
} else {
ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip);
}
} else {
ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip);
}
} else {
ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip);
}
}
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,27);
break;
case 0x7940: // Request to modify e-mail
if (RFIFOREST(fd) < 66)
return 0;
WFIFOW(fd,0) = 0x7941;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
memcpy(WFIFOP(fd,6), account_name, 24);
{
char email[40];
memcpy(email, RFIFOP(fd,26), 40);
if (e_mail_check(email) == 0) {
ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip);
} else {
remove_control_chars(email);
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
memcpy(auth_dat[i].email, email, 40);
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip);
mmo_auth_sync();
} else {
ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip);
}
}
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,66);
break;
case 0x7942: // Request to modify memo field
if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26)))
return 0;
WFIFOW(fd,0) = 0x7943;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
int size_of_memo = sizeof(auth_dat[i].memo);
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
memset(auth_dat[i].memo, '\0', size_of_memo);
if (RFIFOW(fd,26) == 0) {
strncpy(auth_dat[i].memo, "-", size_of_memo);
} else if (RFIFOW(fd,26) > size_of_memo - 1) {
memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1);
} else {
memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26));
}
auth_dat[i].memo[size_of_memo - 1] = '\0';
remove_control_chars(auth_dat[i].memo);
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip);
mmo_auth_sync();
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,28 + RFIFOW(fd,26));
break;
case 0x7944: // Request to found an account id
if (RFIFOREST(fd) < 26)
return 0;
WFIFOW(fd,0) = 0x7945;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip);
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,26);
break;
case 0x7946: // Request to found an account name
if (RFIFOREST(fd) < 6)
return 0;
WFIFOW(fd,0) = 0x7947;
WFIFOL(fd,2) = RFIFOL(fd,2);
memset(WFIFOP(fd,6), '\0', 24);
for(i = 0; i < auth_num; i++) {
if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) {
strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24);
ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip);
break;
}
}
if (i == auth_num) {
ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip);
strncpy((char*)WFIFOP(fd,6), "", 24);
}
WFIFOSET(fd,30);
RFIFOSKIP(fd,6);
break;
case 0x7948: // Request to change the validity limit (timestamp) (absolute value)
if (RFIFOREST(fd) < 30)
return 0;
{
time_t timestamp;
char tmpstr[2048];
WFIFOW(fd,0) = 0x7949;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
timestamp = (time_t)RFIFOL(fd,26);
strftime(tmpstr, 24, login_config.date_format, localtime(&timestamp));
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip);
auth_dat[i].expiration_time = timestamp;
WFIFOL(fd,2) = auth_dat[i].account_id;
mmo_auth_sync();
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip);
}
WFIFOL(fd,30) = (unsigned int)timestamp;
}
WFIFOSET(fd,34);
RFIFOSKIP(fd,30);
break;
case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value)
if (RFIFOREST(fd) < 30)
return 0;
{
time_t timestamp;
char tmpstr[2048];
WFIFOW(fd,0) = 0x794b;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
timestamp = (time_t)RFIFOL(fd,26);
if (timestamp <= time(NULL))
timestamp = 0;
strftime(tmpstr, 24, login_config.date_format, localtime(&timestamp));
i = search_account_index(account_name);
if (i != -1) {
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
WFIFOL(fd,2) = auth_dat[i].account_id;
ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip);
if (auth_dat[i].unban_time != timestamp) {
if (timestamp != 0) {
unsigned char buf[16];
WBUFW(buf,0) = 0x2731;
WBUFL(buf,2) = auth_dat[i].account_id;
WBUFB(buf,6) = 1; // 0: change of statut, 1: ban
WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment
charif_sendallwos(-1, buf, 11);
}
auth_dat[i].unban_time = timestamp;
mmo_auth_sync();
}
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip);
}
WFIFOL(fd,30) = (unsigned int)timestamp;
}
WFIFOSET(fd,34);
RFIFOSKIP(fd,30);
break;
case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change)
if (RFIFOREST(fd) < 38)
return 0;
{
time_t timestamp;
struct tm *tmtime;
char tmpstr[2048];
WFIFOW(fd,0) = 0x794d;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
WFIFOL(fd,2) = auth_dat[i].account_id;
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL))
timestamp = time(NULL);
else
timestamp = auth_dat[i].unban_time;
tmtime = localtime(&timestamp);
tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26);
tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28);
tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30);
tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32);
tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34);
tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36);
timestamp = mktime(tmtime);
if (timestamp != -1) {
if (timestamp <= time(NULL))
timestamp = 0;
strftime(tmpstr, 24, login_config.date_format, localtime(&timestamp));
ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip);
if (auth_dat[i].unban_time != timestamp) {
if (timestamp != 0) {
unsigned char buf[16];
WBUFW(buf,0) = 0x2731;
WBUFL(buf,2) = auth_dat[i].account_id;
WBUFB(buf,6) = 1; // 0: change of statut, 1: ban
WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment
charif_sendallwos(-1, buf, 11);
}
auth_dat[i].unban_time = timestamp;
mmo_auth_sync();
}
} else {
strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time));
ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip);
}
WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time;
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip);
WFIFOL(fd,30) = 0;
}
}
WFIFOSET(fd,34);
RFIFOSKIP(fd,38);
break;
case 0x794e: // Request to send a broadcast message
if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4)))
return 0;
WFIFOW(fd,0) = 0x794f;
WFIFOW(fd,2) = 0xFFFF; // WTF???
if (RFIFOL(fd,4) < 1) {
ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip);
} else {
// at least 1 char-server
for(i = 0; i < MAX_SERVERS; i++)
if (server[i].fd >= 0)
break;
if (i == MAX_SERVERS) {
ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip);
} else {
unsigned char buf[32000];
char message[32000];
WFIFOW(fd,2) = 0;
memset(message, '\0', sizeof(message));
memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4));
message[sizeof(message)-1] = '\0';
remove_control_chars(message);
if (RFIFOW(fd,2) == 0)
ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip);
else
ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip);
// send same message to all char-servers (no answer)
memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4));
WBUFW(buf,0) = 0x2726;
charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4));
}
}
WFIFOSET(fd,4);
RFIFOSKIP(fd,8 + RFIFOL(fd,4));
break;
case 0x7950: // Request to change the validity limite (timestamp) (relative change)
if (RFIFOREST(fd) < 38)
return 0;
{
time_t timestamp;
struct tm *tmtime;
char tmpstr[2048];
char tmpstr2[2048];
WFIFOW(fd,0) = 0x7951;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
WFIFOL(fd,2) = auth_dat[i].account_id;
memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24);
timestamp = auth_dat[i].expiration_time;
if (timestamp == 0 || timestamp < time(NULL))
timestamp = time(NULL);
tmtime = localtime(&timestamp);
tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26);
tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28);
tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30);
tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32);
tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34);
tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36);
timestamp = mktime(tmtime);
if (timestamp != -1) {
strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time));
strftime(tmpstr2, 24, login_config.date_format, localtime(&timestamp));
ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip);
auth_dat[i].expiration_time = timestamp;
mmo_auth_sync();
WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time;
} else {
strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time));
ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip);
WFIFOL(fd,30) = 0;
}
} else {
memcpy(WFIFOP(fd,6), account_name, 24);
ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip);
WFIFOL(fd,30) = 0;
}
}
WFIFOSET(fd,34);
RFIFOSKIP(fd,38);
break;
case 0x7952: // Request about informations of an account (by account name)
if (RFIFOREST(fd) < 26)
return 0;
WFIFOW(fd,0) = 0x7953;
WFIFOL(fd,2) = 0xFFFFFFFF; // WTF???
account_name = (char*)RFIFOP(fd,2);
account_name[23] = '\0';
remove_control_chars(account_name);
i = search_account_index(account_name);
if (i != -1) {
WFIFOL(fd,2) = auth_dat[i].account_id;
WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id);
memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24);
WFIFOB(fd,31) = auth_dat[i].sex;
WFIFOL(fd,32) = auth_dat[i].logincount;
WFIFOL(fd,36) = auth_dat[i].state;
memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20);
memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24);
memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16);
memcpy(WFIFOP(fd,100), auth_dat[i].email, 40);
WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time;
WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time;
WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo);
if (auth_dat[i].memo[0]) {
memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo));
}
ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip);
WFIFOSET(fd,150+strlen(auth_dat[i].memo));
} else {
memcpy(WFIFOP(fd,7), account_name, 24);
WFIFOW(fd,148) = 0;
ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip);
WFIFOSET(fd,150);
}
RFIFOSKIP(fd,26);
break;
case 0x7954: // Request about information of an account (by account id)
if (RFIFOREST(fd) < 6)
return 0;
WFIFOW(fd,0) = 0x7953;
WFIFOL(fd,2) = RFIFOL(fd,2);
memset(WFIFOP(fd,7), '\0', 24);
for(i = 0; i < auth_num; i++) {
if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) {
ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip);
WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id);
memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24);
WFIFOB(fd,31) = auth_dat[i].sex;
WFIFOL(fd,32) = auth_dat[i].logincount;
WFIFOL(fd,36) = auth_dat[i].state;
memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20);
memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24);
memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16);
memcpy(WFIFOP(fd,100), auth_dat[i].email, 40);
WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time;
WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time;
WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo);
if (auth_dat[i].memo[0]) {
memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo));
}
WFIFOSET(fd,150+strlen(auth_dat[i].memo));
break;
}
}
if (i == auth_num) {
ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip);
strncpy((char*)WFIFOP(fd,7), "", 24);
WFIFOW(fd,148) = 0;
WFIFOSET(fd,150);
}
RFIFOSKIP(fd,6);
break;
case 0x7955: // Request to reload GM file (no answer)
ShowStatus("'ladmin': Request to re-load GM configuration file (ip: %s).\n", ip);
read_gm_account();
// send GM accounts to all char-servers
send_GM_accounts(-1);
RFIFOSKIP(fd,2);
break;
default:
ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip);
set_eof(fd);
return 0;
}
}
RFIFOSKIP(fd,RFIFOREST(fd));
return 0;
}

2362
src/login/login.c Normal file

File diff suppressed because it is too large Load Diff

94
src/login/login.h Normal file
View File

@ -0,0 +1,94 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _LOGIN_H_
#define _LOGIN_H_
#include "../common/mmo.h" // NAME_LENGTH
#define LOGIN_CONF_NAME "conf/login_athena.conf"
#define LAN_CONF_NAME "conf/subnet_athena.conf"
// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both
#define PASSWORDENC 3
struct login_session_data {
int account_id;
long login_id1;
long login_id2;
char sex;
char userid[NAME_LENGTH];
char passwd[NAME_LENGTH];
int passwdenc;
char md5key[20];
uint16 md5keylen;
char lastlogin[24];
uint8 level;
int version;
int fd;
};
struct mmo_char_server {
char name[20];
int fd;
uint32 ip;
uint16 port;
uint16 users; // user count on this server
uint16 maintenance; // in maintenance mode?
uint16 new_; // allows creating new chars?
};
struct Login_Config {
uint32 login_ip; // the address to bind to
uint16 login_port; // the port to bind to
unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs)
bool log_login; // whether to log login server actions or not
char date_format[32]; // date format used in messages
bool console; // console input system enabled?
bool new_account_flag; // autoregistration via _M/_F ?
int start_limited_time; // new account expiration time (-1: unlimited)
// bool case_sensitive; // are logins case sensitive ?
bool use_md5_passwds; // work with password hashes instead of plaintext passwords?
// bool login_gm_read; // should the login server handle info about gm accounts?
int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect
bool online_check; // reject incoming players that are already registered as online ?
bool check_client_version; // check the clientversion set in the clientinfo ?
int client_version_to_connect; // the client version needed to connect (if checking is enabled)
// bool ipban; // perform IP blocking (via contents of `ipbanlist`) ?
// bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ?
// unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures
// unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban
// unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban
bool use_dnsbl; // dns blacklist blocking ?
char dnsbl_servs[1024]; // comma-separated list of dnsbl servers
};
struct mmo_account {
int account_id;
char sex;
char userid[24];
char pass[32+1]; // 23+1 for normal, 32+1 for md5-ed passwords
char lastlogin[24];
int logincount;
uint32 state; // packet 0x006a value + 1 (0: compte OK)
char email[40]; // e-mail (by default: a@a.com)
char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a)
time_t unban_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban)
time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
char last_ip[16]; // save of last IP of connection
char memo[255]; // a memo field
int account_reg2_num;
struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
};
#endif /* _LOGIN_H_ */