This will fix that, so you can use the DNS domain name for your .ini files this is good for dynamic IP address that change, you can use a no-ip service to keep your IP and update your IP with out reconfigure your whole server, this also allows you to not have to use the zoneid field in the table zone_setting in mysql.
ADD TO MAP SERVER
Code: Select all
void CZone::LoadZoneSettings()
{
in_addr inaddr;
inaddr.S_un.S_addr = inet_addr(map_config.mysql_host);
//ShowFatalError(CL_RED"CZone:GET HOST NAME2(%u)\n" CL_RESET, inaddr);
if( inaddr.S_un.S_addr == INADDR_NONE)
{
hostent* phostent = gethostbyname(map_config.mysql_host);
//ShowFatalError(CL_RED"CZone:GET HOST NAME3(%u)\n" CL_RESET, phostent);
if( phostent == 0)
{
//ShowFatalError(CL_RED"CZone:GET HOST NAME4(%u)\n" CL_RESET, phostent);
return;
}
if( sizeof(inaddr) != phostent->h_length)
{
//ShowFatalError(CL_RED"CZone:GET HOST NAME5(%u)\n" CL_RESET, phostent);
return;
}
inaddr.S_un.S_addr = *((unsigned long*) phostent->h_addr);
}
//GetHostNameOrIP ("ffxi-a.com");
const int8* Query =
"SELECT "
"zone.name,"
"zone.zoneip,"
"zone.zoneport,"
"zone.music,"
"zone.battlesolo,"
"zone.battlemulti,"
"zone.tax,"
"zone.misc,"
"bcnm.name "
"FROM zone_settings AS zone "
"LEFT JOIN bcnm_info AS bcnm "
"USING (zoneid) "
"WHERE zoneid = %u "
"LIMIT 1";
if (Sql_Query(SqlHandle, Query, m_zoneID) != SQL_ERROR && Sql_NumRows(SqlHandle) != 0 && Sql_NextRow(SqlHandle) == SQL_SUCCESS)
{
m_zoneName.insert(0, Sql_GetData(SqlHandle,0));
string_t zonename = Sql_GetData(SqlHandle,0);
m_zoneIP = inaddr.S_un.S_addr;
//TODO ADD TO THE CONFIG FILE FOR THIS SO ALSO USE MAP SERVER THE NORMAL WAY BUT SHOULD NOT BE NEEDED.
//(uint32)Sql_GetUIntData(SqlHandle,1);
m_zonePort = (uint16)Sql_GetUIntData(SqlHandle,2);
m_zoneMusic.m_song = (uint8)Sql_GetUIntData(SqlHandle,3); // background music
m_zoneMusic.m_bSongS = (uint8)Sql_GetUIntData(SqlHandle,4); // solo battle music
m_zoneMusic.m_bSongM = (uint8)Sql_GetUIntData(SqlHandle,5); // party battle music
m_tax = (uint16)(Sql_GetFloatData(SqlHandle,6) * 100); // tax for bazaar
m_miscMask = (uint16)Sql_GetUIntData(SqlHandle,7);
if (Sql_GetData(SqlHandle,8) != NULL) // сейчас нельзя использовать bcnmid, т.к. они начинаются с нуля
{
m_InstanceHandler = new CInstanceHandler(m_zoneID);
}
if (m_miscMask & MISC_TREASURE)
{
m_TreasurePool = new CTreasurePool(TREASUREPOOL_ZONE);
}
ShowNotice(CL_GREEN"TRACER: Resolveing Zonename %s\n" CL_RESET, zonename.c_str() );
ShowNotice(CL_GREEN"TRACER: Resolveing IP %u\n" CL_RESET, inaddr.S_un.S_addr );
}
else
{
ShowFatalError(CL_RED"CZone::LoadZoneSettings: Cannot load zone settings (%u)\n" CL_RESET, m_zoneID);
}
}
Code: Select all
int32 lobbydata_parse(int32 fd)
{
login_session_data_t* sd = (login_session_data_t*)session[fd]->session_data;
if( sd == NULL )
{
if( RFIFOREST(fd) >= 5 &&
RBUFB(session[fd]->rdata,0) == 0xA1 )
{
unsigned char *buff = session[fd]->rdata;
int32 accid = RBUFL(buff,1);
sd = find_loginsd_byaccid(accid);
if( sd == NULL )
{
do_close_tcp(fd);
return -1;
}
sd->login_lobbydata_fd = fd;
session[fd]->session_data = sd;
return 0;
}
}
if( session[fd]->flag.eof )
{
do_close_lobbydata(sd,fd);
return 0;
}
if( RFIFOREST(fd) >= 1 )
{
unsigned char *buff = session[fd]->rdata;
ShowDebug("lobbydata_parse:Incoming Packet:" CL_WHITE"<%x>" CL_RESET" from ip:<%s>\n",RBUFB(buff,0),ip2str(sd->client_addr,NULL));
int32 code = RBUFB(buff,0);
switch(code)
{
case 0xA1:
{
if( RFIFOREST(fd) < 9 )
{
ShowError("lobbydata_parse:" CL_WHITE"<%s>" CL_RESET" sent less then 9 bytes\n",ip2str(session[fd]->client_addr,NULL));
do_close_lobbydata(sd,fd);
return -1;
}
char uList[300];
memset(uList,0,sizeof(uList));
sd->servip = RBUFL(buff,5);
unsigned char CharList[2500];
memset(CharList,0,sizeof(CharList));
//запись зарезервированных чисел
CharList[0] = 0xE0;CharList[1] = 0x08;
CharList[4] = 0x49;CharList[5] = 0x58;CharList[6] = 0x46;CharList[7] = 0x46;CharList[8] = 0x20;
CharList[28] = 16; // количество ячеек, доступных для создания персонажей (0-16)
const char *Query = "SELECT charid, charname, pos_zone, pos_prevzone, mjob,\
race, face, head, body, hands, legs, feet, main, sub,\
war, mnk, whm, blm, rdm, thf, pld, drk, bst, brd, rng,\
sam, nin, drg, smn, blu, cor, pup, dnc, sch \
FROM chars \
INNER JOIN char_stats USING(charid)\
INNER JOIN char_look USING(charid) \
INNER JOIN char_jobs USING(charid) \
WHERE accid = %i \
LIMIT 16;";
int32 ret = Sql_Query(SqlHandle,Query,sd->accid);
if( ret == SQL_ERROR )
{
do_close_lobbydata(sd,fd);
return -1;
}
/*int32 Content_ID = 1; //DEFAULT TO SEE IF THEY ARE NEW CREATED CHAR OR A RETURNING CHAR
Query = "SELECT content_ids FROM accounts WHERE id = '%u';";
ret = Sql_Query(SqlHandle,Query,sd->accid);
if (ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0 && Sql_NextRow(SqlHandle) == SQL_SUCCESS)
{
Content_ID = Sql_GetIntData(SqlHandle,0);
ShowDebug("GET CONTENT ID AMOUNT %u OF PLAYER %u \n" CL_RESET,Content_ID,sd->accid);
}
else
{
ShowDebug("SHOULD NEVER SEE THIS PLAYER IS NOT IN DATABASE \n" CL_RESET);
}*/
LOBBY_A1_RESERVEPACKET(ReservePacket);
//server's name that shows in lobby menu
memcpy(ReservePacket+60, login_config.servername, dsp_cap(strlen(login_config.servername), 0, 15));
//Подготовка пространства в пакете для информации о 16 игровых персонажах
for(int j = 0; j<1; ++j)
{
memcpy(CharList+32+140*j, ReservePacket+32, 140);
char ContentID[3];
memcpy(ContentID, CharList+32, sizeof(ContentID));
ContentID[2] += j;
memcpy(CharList+32+140*j, &ContentID, 3);
memcpy(uList+16*(j+1),&ContentID, 3);
}
uList[0] = 0x03;
int i = 0;
//Считывание информации о конкректном персонаже
//Загрузка всей необходимой информации о персонаже из базы
while(Sql_NextRow(SqlHandle) != SQL_NO_DATA)
{
char* strCharName = NULL;
Sql_GetData(SqlHandle,1,&strCharName,NULL);
uint32 CharID = Sql_GetIntData(SqlHandle,0);
uint8 zone = (uint8)Sql_GetIntData(SqlHandle,2);
uint8 prevzone = (uint8)Sql_GetIntData(SqlHandle,3);
uint8 MainJob = (uint8)Sql_GetIntData(SqlHandle,4);
uint8 lvlMainJob = (uint8)Sql_GetIntData(SqlHandle,13+MainJob);
WBUFL(uList,20*(i+1)) = CharID;
////////////////////////////////////////////////////
WBUFL(CharList,4+32+i*140) = CharID;
memcpy(CharList+12+32+i*140,strCharName, 15);
WBUFB(CharList,46+32+i*140) = MainJob;
WBUFB(CharList,73+32+i*140) = lvlMainJob;
WBUFB(CharList,44+32+i*140) = (uint8) Sql_GetIntData(SqlHandle, 5); // race;
WBUFB(CharList,56+32+i*140) = (uint8) Sql_GetIntData(SqlHandle, 6); // face;
WBUFW(CharList,58+32+i*140) = (uint16)Sql_GetIntData(SqlHandle, 7); // head;
WBUFW(CharList,60+32+i*140) = (uint16)Sql_GetIntData(SqlHandle, 8); // body;
WBUFW(CharList,62+32+i*140) = (uint16)Sql_GetIntData(SqlHandle, 9); // hands;
WBUFW(CharList,64+32+i*140) = (uint16)Sql_GetIntData(SqlHandle,10); // legs;
WBUFW(CharList,66+32+i*140) = (uint16)Sql_GetIntData(SqlHandle,11); // feet;
WBUFW(CharList,68+32+i*140) = (uint16)Sql_GetIntData(SqlHandle,12); // main;
WBUFW(CharList,70+32+i*140) = (uint16)Sql_GetIntData(SqlHandle,13); // sub;
WBUFB(CharList,72+32+i*140) = (zone == 0 ? prevzone : zone); // если персонаж в MogHouse
///////////////////////////////////////////////////
++i;
}
if(session[sd->login_lobbyview_fd]!=NULL){
// write into lobbydata
uList[1] = 0x10;
memcpy(session[fd]->wdata,uList,0x110);
WFIFOSET(fd,0x110);
RFIFOSKIP(fd,session[fd]->rdata_size);
RFIFOFLUSH(fd);
////////////////////////////////////////
unsigned char hash[16];
md5((unsigned char*)(CharList), hash, 2272);
memcpy(CharList+12,hash,16);
// write into lobbyview
memcpy(session[sd->login_lobbyview_fd]->wdata,CharList,2272);
WFIFOSET(sd->login_lobbyview_fd,2272);
RFIFOSKIP(sd->login_lobbyview_fd,session[sd->login_lobbyview_fd]->rdata_size);
RFIFOFLUSH(sd->login_lobbyview_fd);
}
else{ //cleanup
ShowWarning("lobbydata_parse: char:(%i) login data corrupt (0xA1). Disconnecting client.\n",sd->accid);
do_close_lobbydata(sd,fd);
return -1;
}
/////////////////////////////////////////
break;
}
case 0xA2:
{
LOBBY_A2_RESERVEPACKET(ReservePacket);
uint8 key3[20];
memset(key3,0,sizeof(key3));
memcpy(key3,buff+1,sizeof(key3));
key3[16] -= 2;
uint8 MainReservePacket[0x48];
RFIFOSKIP(fd,session[fd]->rdata_size);
RFIFOFLUSH(fd);
if(session[sd->login_lobbyview_fd]==NULL){
ShowWarning("lobbydata_parse: char:(%i) login data corrupt (0xA2). Disconnecting client.\n",sd->accid);
do_close_lobbydata(sd,fd);
return -1;
}
uint32 charid = RBUFL(session[sd->login_lobbyview_fd]->rdata,32);
in_addr inaddr;
inaddr.S_un.S_addr = inet_addr(login_config.mysql_host);
if( inaddr.S_un.S_addr == INADDR_NONE)
{
hostent* phostent = gethostbyname(login_config.mysql_host);
if( phostent == 0)
{
return 0;
}
if( sizeof(inaddr) != phostent->h_length)
{
return 0;;
}
inaddr.S_un.S_addr = *((unsigned long*) phostent->h_addr);
}
const char *fmtQuery = "SELECT zoneip, zoneport, zoneid, pos_prevzone \
FROM zone_settings, chars \
WHERE zoneid = pos_zone AND charid = %u;";
uint32 ZoneIP = inaddr.S_un.S_addr;//sd->servip;
uint16 ZonePort = 54230;
if( Sql_Query(SqlHandle,fmtQuery,charid) != SQL_ERROR &&
Sql_NumRows(SqlHandle) != 0 )
{
Sql_NextRow(SqlHandle);
if (Sql_GetIntData(SqlHandle,3) == 0) key3[16] += 6;
ZoneIP = inaddr.S_un.S_addr;//Sql_GetUIntData(SqlHandle,0);
ZonePort = (uint16)Sql_GetUIntData(SqlHandle,1);
uint8 ZoneID = (uint8)Sql_GetUIntData(SqlHandle,2);
WBUFL(ReservePacket,(0x38)) = ZoneIP;
WBUFW(ReservePacket,(0x3C)) = ZonePort;
ShowInfo("lobbydata_parse: zoneid:(%u),zoneip:(%s),zoneport:(%u) for char:(%u)\n",ZoneID,ip2str(ntohl(ZoneIP),NULL),ZonePort,charid);
}else{
ShowWarning("lobbydata_parse: zoneip:(%s) for char:(%u) is standard\n",ip2str(sd->servip,NULL),charid);
WBUFL(ReservePacket,(0x38)) = ZoneIP;
//WBUFL(ReservePacket,(0x38)) = //sd->servip; // map-server ip
//WBUFW(ReservePacket,(0x3C)) = port; // map-server port
}
WBUFL(ReservePacket,(0x40)) = ZoneIP; //sd->servip; // search-server ip
//WBUFW(ReservePacket,(0x44)) = port; // search-server port
memcpy(MainReservePacket,ReservePacket,RBUFB(ReservePacket,0));
// необходиму одалять сессию, необработанную игровым сервером
Sql_Query(SqlHandle,"DELETE FROM accounts_sessions WHERE accid = %u and client_port = 0", sd->accid);
int8 session_key[sizeof(key3)*2+1];
bin2hex(session_key,key3,sizeof(key3));
fmtQuery = "INSERT INTO accounts_sessions(accid,charid,session_key,server_addr,server_port,client_addr) VALUES(%u,%u,x'%s',%u,%u,%u)";
if( Sql_Query(SqlHandle, fmtQuery, sd->accid, charid, session_key, ZoneIP, ZonePort, sd->client_addr) == SQL_ERROR )
{
//отправляем клиенту сообщение об ошибке
LOBBBY_ERROR_MESSAGE(ReservePacket);
// устанавливаем код ошибки
// Unable to connect to world server. Specified operation failed
WBUFW(ReservePacket,32) = 305;
memcpy(MainReservePacket,ReservePacket,RBUFB(ReservePacket,0));
}
unsigned char Hash[16];
uint8 SendBuffSize = RBUFB(MainReservePacket,0);
memset(MainReservePacket+12,0,sizeof(Hash));
md5(MainReservePacket, Hash, SendBuffSize);
memcpy(MainReservePacket+12,Hash,sizeof(Hash));
memcpy(session[sd->login_lobbyview_fd]->wdata,MainReservePacket,SendBuffSize);
WFIFOSET(sd->login_lobbyview_fd,SendBuffSize);
RFIFOSKIP(sd->login_lobbyview_fd,session[sd->login_lobbyview_fd]->rdata_size);
RFIFOFLUSH(sd->login_lobbyview_fd);
if (SendBuffSize == 0x24){
// выходим в случае ошибки без разрыва соединения
return -1;
}
do_close_tcp(sd->login_lobbyview_fd);
ShowStatus("lobbydata_parse: client %s finished work with " CL_GREEN"lobbyview" CL_RESET"\n",ip2str(sd->client_addr,NULL));
break;
}
default:
break;
}
}
return 0;
};
This allows you to skip the whole process with the config your ip with the handy tool its no longer needed.
Also in the database zone setting table the zoneID is not needed either, but if it is kept so you want to use map server on another dedicated server then some one needs to add extra code in the login.config as for my self i do not need it yet, server is to small.
need to make a config setting in the map and login server.config if you get a population that can not support one map server.
then you will also have to solve how you will communicate with different players in different map servers.
This also resolved the DNS so you do not have to use a Direct IP you can us DNS ffxi-a.com for IP or any domain name.
For ffxi-boot.exe mxi.exe config.ini or ffxi-boot.ini
THIS CODE HERE IS NOT NEEDED SHOULD CLEAN IT UP
Code: Select all
/*int32 Content_ID = 1; //DEFAULT TO SEE IF THEY ARE NEW CREATED CHAR OR A RETURNING CHAR
Query = "SELECT content_ids FROM accounts WHERE id = '%u';";
ret = Sql_Query(SqlHandle,Query,sd->accid);
if (ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0 && Sql_NextRow(SqlHandle) == SQL_SUCCESS)
{
Content_ID = Sql_GetIntData(SqlHandle,0);
ShowDebug("GET CONTENT ID AMOUNT %u OF PLAYER %u \n" CL_RESET,Content_ID,sd->accid);
}
else
{
ShowDebug("SHOULD NEVER SEE THIS PLAYER IS NOT IN DATABASE \n" CL_RESET);
}*/