Bu düzenleme ile Metin2 source içinde level değişkenlerini BYTE yerine int tipine çeviriyoruz. Normalde BYTE kullanıldığı için level değeri düşük aralıkta kalıyor. Daha yüksek maksimum level kullanmak isteyen serverlarda bu alanların genişletilmesi gerekiyor.

Ben burada int kullanmayı daha mantıklı buluyorum. Çünkü karakter hasarı, party hesaplamaları ve bazı sistemlerde level zaten farklı yerlerde int gibi davranıyor. Ayrıca int maksimum değer olarak fazlasıyla yeterli.
game/src
char.cpp
Şunu bul:
void CHARACTER::SetLevel(BYTE level)
Bununla değiştir:
void CHARACTER::SetLevel(int level)
char.h
Şunu bul:
void SetLevel(BYTE level);
Bununla değiştir:
void SetLevel(int level);
Aynı dosyada şunu bul:
BYTE level;
Bu satır genelde şu yapının altında olur:
typedef struct character_point
Bununla değiştir:
int level;
party.cpp
Şunu bul:
void CParty::P2PSetMemberLevel(DWORD pid, BYTE level)
Bununla değiştir:
void CParty::P2PSetMemberLevel(DWORD pid, int level)
Şunu bul:
BYTE CParty::GetMemberMaxLevel()
{
BYTE bMax = 0;
Bununla değiştir:
int CParty::GetMemberMaxLevel()
{
int bMax = 0;
Şunu bul:
BYTE CParty::GetMemberMinLevel()
{
BYTE bMin = PLAYER_MAX_LEVEL_CONST;
Bununla değiştir:
int CParty::GetMemberMinLevel()
{
int bMin = PLAYER_MAX_LEVEL_CONST;
Şunu bul:
void CParty::RequestSetMemberLevel(DWORD pid, BYTE level)
Bununla değiştir:
void CParty::RequestSetMemberLevel(DWORD pid, int level)
party.h
Şunu bul:
BYTE bLevel;
Bu satır genelde şu yapının altında olur:
typedef struct SMember
Bununla değiştir:
int bLevel;
Şunları bul:
BYTE GetMemberMaxLevel();
BYTE GetMemberMinLevel();
Bunlarla değiştir:
int GetMemberMaxLevel();
int GetMemberMinLevel();
Şunları bul:
void RequestSetMemberLevel(DWORD pid, BYTE level);
void P2PSetMemberLevel(DWORD pid, BYTE level);
Bunlarla değiştir:
void RequestSetMemberLevel(DWORD pid, int level);
void P2PSetMemberLevel(DWORD pid, int level);
char_battle.cpp
Şunu bul:
struct FPartyTotaler
{
int total;
Bununla değiştir:
struct FPartyTotaler
{
long total;
Sonra şunu bul:
struct FPartyDistributor
{
int total;
LPCHARACTER c;
int x, y;
DWORD _iExp;
int m_iMode;
int m_iMemberCount; FPartyDistributor(LPCHARACTER center, int member_count, int total, DWORD iExp, int iMode)
Bununla değiştir:
struct FPartyDistributor
{
long total;
LPCHARACTER c;
int x, y;
DWORD _iExp;
int m_iMode;
int m_iMemberCount; FPartyDistributor(LPCHARACTER center, int member_count, long total, DWORD iExp, int iMode)
Burada total değerini long yapmak daha güvenli olur. Özellikle level ve exp tabloları büyüdüğünde hesaplama tarafında taşma yaşanmasını azaltır.
config.h
Şunu bul:
extern BYTE PK_PROTECT_LEVEL;
Bununla değiştir:
extern int PK_PROTECT_LEVEL;
locale_service.cpp
Şunu bul:
BYTE PK_PROTECT_LEVEL
Bununla değiştir:
int PK_PROTECT_LEVEL
constants.cpp
Burada maksimum level değerine göre tabloları genişletmen gerekiyor.
Örneğin maksimum leveli 300 yapmak istiyorsan, bu tablolarda da 300 levele karşılık gelecek kadar kayıt olmalı.
Kontrol edilmesi gereken tablolar:
const DWORD exp_table_euckr[PLAYER_EXP_TABLE_MAX + 1]
const DWORD exp_table_common[PLAYER_EXP_TABLE_MAX + 1]
const DWORD exp_table_newcibn[PLAYER_EXP_TABLE_MAX + 1]
const DWORD party_exp_distribute_table[PLAYER_MAX_LEVEL_CONST + 1]
const int aiExpLossPercents[PLAYER_EXP_TABLE_MAX + 1]
Burayı atlamayın. Sadece değişken tipini int yapmak yetmez. Exp tabloları kısa kalırsa oyun belirli levelden sonra hatalı hesaplama yapabilir ya da crash verebilir.
log.h
Şunu bul:
void LoginLog(bool isLogin, DWORD dwAccountID, DWORD dwPID, BYTE bLevel, BYTE bJob, DWORD dwPlayTime);
Bununla değiştir:
void LoginLog(bool isLogin, DWORD dwAccountID, DWORD dwPID, int bLevel, BYTE bJob, DWORD dwPlayTime);
log.cpp
Şunu bul:
void LogManager::LoginLog(bool isLogin, DWORD dwAccountID, DWORD dwPID, BYTE bLevel, BYTE bJob, DWORD dwPlayTime)
Bununla değiştir:
void LogManager::LoginLog(bool isLogin, DWORD dwAccountID, DWORD dwPID, int bLevel, BYTE bJob, DWORD dwPlayTime)
Guild Düzenlemeleri
guild.h
Şu yapıyı bul:
typedef struct SGuildMemberPacketData
{
DWORD pid;
BYTE grade;
BYTE is_general;
BYTE job;
BYTE level;
DWORD offer;
BYTE name_flag;
char name[CHARACTER_NAME_MAX_LEN+1];
} TGuildMemberPacketData;
Bununla değiştir:
typedef struct SGuildMemberPacketData
{
DWORD pid;
BYTE byGrade;
BYTE byIsGeneral;
BYTE byJob;
int byLevel;
DWORD dwOffer;
BYTE byNameFlag;
} TGuildMemberPacketData;
Şunu bul:
void ChangeMemberData(DWORD pid, DWORD offer, BYTE level, BYTE grade);
Bununla değiştir:
void ChangeMemberData(DWORD pid, DWORD offer, int level, BYTE grade);
Şunu bul:
SGuildMember(DWORD pid, BYTE grade, BYTE is_general, BYTE job, BYTE level, DWORD offer_exp, char* name);
Bununla değiştir:
SGuildMember(DWORD pid, BYTE grade, BYTE is_general, BYTE job, int level, DWORD offer_exp, char* name);
Şunu bul:
DWORD pid;
BYTE grade;
BYTE is_general;
BYTE job;
BYTE level;
DWORD offer_exp;
BYTE _dummy;
Bununla değiştir:
DWORD pid;
BYTE grade;
BYTE is_general;
BYTE job;
int level;
DWORD offer_exp;
BYTE _dummy;
Şunu bul:
void LevelChange(DWORD pid, BYTE level);
Bununla değiştir:
void LevelChange(DWORD pid, int level);
guild.cpp
Şunu bul:
BYTE level = (BYTE)strtoul(row[4], (char**) NULL, 10);
Bununla değiştir:
int level = (int)strtoul(row[4], (char**) NULL, 10);
Şunu bul:
sys_log(0, "GUILD: AddMember PID %u, grade %u, job %u, level %u, offer %u, name %s ptr %p",
Bununla değiştir:
sys_log(0, "GUILD: AddMember PID %u, grade %u, job %u, level %d, offer %u, name %s ptr %p",
ChangeMemberData fonksiyonu
Şunu bul:
void CGuild::ChangeMemberData(DWORD pid, DWORD offer, BYTE level, BYTE grade)
Tam fonksiyonu bununla değiştir:
void CGuild::ChangeMemberData(DWORD pid, DWORD offer, int level, BYTE grade)
{
TGuildMemberContainer::iterator cit = m_member.find(pid); if (cit == m_member.end())
return; cit->second.offer_exp = offer;
cit->second.level = level;
cit->second.grade = grade;
cit->second._dummy = 0; TPacketGCGuild pack;
TGuildMemberPacketData mbData; pack.header = HEADER_GC_GUILD;
pack.subheader = GUILD_SUBHEADER_GC_LIST;
pack.size = sizeof(TPacketGCGuild);
pack.size += sizeof(TGuildMemberPacketData); for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it)
{
LPDESC d = (*it)->GetDesc(); if (d)
{
TEMP_BUFFER buf; buf.write(&pack, sizeof(pack)); mbData.byNameFlag = 0;
mbData.byGrade = cit->second.grade;
mbData.byIsGeneral = cit->second.is_general;
mbData.byJob = cit->second.job;
mbData.byLevel = cit->second.level;
mbData.dwOffer = cit->second.offer_exp;
mbData.pid = cit->second.pid; buf.write(&mbData, sizeof(TGuildMemberPacketData)); d->Packet(buf.read_peek(), buf.size());
}
}
}
LevelChange fonksiyonu
Şunu bul:
void CGuild::LevelChange(DWORD pid, BYTE level)
Tam fonksiyonu bununla değiştir:
void CGuild::LevelChange(DWORD pid, int level)
{
TGuildMemberContainer::iterator cit = m_member.find(pid); if (cit == m_member.end())
return; cit->second.level = level; TPacketGuildChangeMemberData gd_guild; gd_guild.guild_id = GetID();
gd_guild.pid = pid;
gd_guild.offer = cit->second.offer_exp;
gd_guild.grade = cit->second.grade;
gd_guild.level = level; db_clientdesc->DBPacket(
HEADER_GD_GUILD_CHANGE_MEMBER_DATA,
0,
&gd_guild,
sizeof(gd_guild)
); TPacketGCGuild pack;
TGuildMemberPacketData mbData; pack.header = HEADER_GC_GUILD;
pack.subheader = GUILD_SUBHEADER_GC_LIST;
pack.size = sizeof(TPacketGCGuild);
pack.size += sizeof(TGuildMemberPacketData); cit->second._dummy = 0; for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it)
{
LPDESC d = (*it)->GetDesc(); if (d)
{
TEMP_BUFFER buf; buf.write(&pack, sizeof(pack)); mbData.byNameFlag = 0;
mbData.byGrade = cit->second.grade;
mbData.byIsGeneral = cit->second.is_general;
mbData.byJob = cit->second.job;
mbData.byLevel = cit->second.level;
mbData.dwOffer = cit->second.offer_exp;
mbData.pid = cit->second.pid; buf.write(&mbData, sizeof(TGuildMemberPacketData)); d->Packet(buf.read_peek(), buf.size());
}
}
}
OfferExp fonksiyonu
Şunu bul:
bool CGuild::OfferExp(LPCHARACTER ch, int amount)
Tam fonksiyonu bununla değiştir:
bool CGuild::OfferExp(LPCHARACTER ch, int amount)
{
TGuildMemberContainer::iterator cit = m_member.find(ch->GetPlayerID()); if (cit == m_member.end())
return false; if (m_data.exp + amount < m_data.exp)
return false; if (amount < 0)
return false; if (ch->GetExp() < (DWORD) amount)
{
ch->ChatPacket(
CHAT_TYPE_INFO,
LC_TEXT("<±ćµĺ> Á¦°řÇϰíŔÚ ÇĎ´Â °ćÇčġ°ˇ ł˛Ŕş °ćÇčġş¸´Ů ¸ą˝Ŕ´Ď´Ů.")
);
return false;
} if (ch->GetExp() - (DWORD) amount > ch->GetExp())
{
sys_err(
"Wrong guild offer amount %d by %s[%u]",
amount,
ch->GetName(),
ch->GetPlayerID()
);
return false;
} ch->PointChange(POINT_EXP, -amount); TPacketGuildExpUpdate guild_exp;
guild_exp.guild_id = GetID();
guild_exp.amount = amount / 100; db_clientdesc->DBPacket(
HEADER_GD_GUILD_EXP_UPDATE,
0,
&guild_exp,
sizeof(guild_exp)
); GuildPointChange(POINT_EXP, amount / 100, true); cit->second.offer_exp += amount / 100;
cit->second._dummy = 0; TPacketGCGuild pack;
TGuildMemberPacketData mbData; pack.header = HEADER_GC_GUILD;
pack.subheader = GUILD_SUBHEADER_GC_LIST;
pack.size = sizeof(TPacketGCGuild);
pack.size += sizeof(TGuildMemberPacketData); for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it)
{
LPDESC d = (*it)->GetDesc(); if (d)
{
TEMP_BUFFER buf; buf.write(&pack, sizeof(pack)); mbData.byNameFlag = 0;
mbData.byGrade = cit->second.grade;
mbData.byIsGeneral = cit->second.is_general;
mbData.byJob = cit->second.job;
mbData.byLevel = cit->second.level;
mbData.dwOffer = cit->second.offer_exp;
mbData.pid = cit->second.pid; buf.write(&mbData, sizeof(TGuildMemberPacketData)); d->Packet(buf.read_peek(), buf.size());
}
} SaveMember(ch->GetPlayerID()); TPacketGuildChangeMemberData gd_guild; gd_guild.guild_id = GetID();
gd_guild.pid = ch->GetPlayerID();
gd_guild.offer = cit->second.offer_exp;
gd_guild.level = ch->GetLevel();
gd_guild.grade = cit->second.grade; db_clientdesc->DBPacket(
HEADER_GD_GUILD_CHANGE_MEMBER_DATA,
0,
&gd_guild,
sizeof(gd_guild)
); return true;
}
SendListPacket fonksiyonu
Şunu bul:
void CGuild::SendListPacket(LPCHARACTER ch)
Tam fonksiyonu bununla değiştir:
void CGuild::SendListPacket(LPCHARACTER ch)
{
LPDESC d; if (!(d = ch->GetDesc()))
return; TPacketGCGuild pack; pack.header = HEADER_GC_GUILD;
pack.size = sizeof(TPacketGCGuild);
pack.subheader = GUILD_SUBHEADER_GC_LIST; pack.size += sizeof(TGuildMemberPacketData) * m_member.size();
pack.size += (CHARACTER_NAME_MAX_LEN + 1) * m_member.size(); TEMP_BUFFER buf;
TGuildMemberPacketData mbData; buf.write(&pack, sizeof(pack)); char c[CHARACTER_NAME_MAX_LEN + 1]; for (TGuildMemberContainer::iterator it = m_member.begin(); it != m_member.end(); ++it)
{
it->second._dummy = 1; mbData.byNameFlag = 1;
mbData.byGrade = it->second.grade;
mbData.byIsGeneral = it->second.is_general;
mbData.byJob = it->second.job;
mbData.byLevel = it->second.level;
mbData.dwOffer = it->second.offer_exp;
mbData.pid = it->second.pid; buf.write(&mbData, sizeof(TGuildMemberPacketData)); strlcpy(
c,
it->second.name.c_str(),
MIN(sizeof(c), it->second.name.length() + 1)
); buf.write(c, CHARACTER_NAME_MAX_LEN + 1); if (test_server)
sys_log(0, "name %s job %d", it->second.name.c_str(), it->second.job);
} d->Packet(buf.read_peek(), buf.size()); for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it)
{
SendLoginPacket(ch, *it);
} for (TGuildMemberP2POnlineContainer::iterator it = m_memberP2POnline.begin(); it != m_memberP2POnline.end(); ++it)
{
SendLoginPacket(ch, *it);
}
}
SendListOneToAll fonksiyonu
Şunu bul:
void CGuild::SendListOneToAll(DWORD pid)
Tam fonksiyonu bununla değiştir:
void CGuild::SendListOneToAll(DWORD pid)
{
TPacketGCGuild pack; pack.header = HEADER_GC_GUILD;
pack.size = sizeof(TPacketGCGuild);
pack.subheader = GUILD_SUBHEADER_GC_LIST; pack.size += sizeof(TGuildMemberPacketData); TGuildMemberPacketData mbData; char c[CHARACTER_NAME_MAX_LEN + 1];
memset(c, 0, sizeof(c)); TGuildMemberContainer::iterator cit = m_member.find(pid); if (cit == m_member.end())
return; for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it)
{
LPDESC d = (*it)->GetDesc(); if (!d)
continue; TEMP_BUFFER buf; buf.write(&pack, sizeof(pack)); cit->second._dummy = 1; mbData.byNameFlag = 1;
mbData.byGrade = cit->second.grade;
mbData.byIsGeneral = cit->second.is_general;
mbData.byJob = cit->second.job;
mbData.byLevel = cit->second.level;
mbData.dwOffer = cit->second.offer_exp;
mbData.pid = cit->second.pid; buf.write(&mbData, sizeof(TGuildMemberPacketData));
buf.write(cit->second.name.c_str(), cit->second.name.length());
buf.write(c, CHARACTER_NAME_MAX_LEN + 1 - cit->second.name.length()); d->Packet(buf.read_peek(), buf.size());
}
}
SGuildMember constructor
Şunu bul:
SGuildMember::SGuildMember(DWORD pid, BYTE grade, BYTE is_general, BYTE job, BYTE level, DWORD offer_exp, char* name)
Bununla değiştir:
SGuildMember::SGuildMember(DWORD pid, BYTE grade, BYTE is_general, BYTE job, int level, DWORD offer_exp, char* name)
common
tables.h
Şunu bul:
BYTE byLevel;
Bununla değiştir:
int byLevel;
Şunu bul:
BYTE level;
Bununla değiştir:
int level;
Şunu bul:
BYTE level;
Bununla değiştir:
int level;
Şunu bul:
BYTE bLevel;
Bu satır şu yapının altında olur:
typedef struct SPacketPartySetMemberLevel
Bununla değiştir:
int bLevel;
Sonra tekrar şunu bul:
BYTE bLevel;
Bu satır şu yapının altında olur:
typedef struct SPacketDGGuildMember
Bununla değiştir:
int bLevel;
length.h
Burada maksimum level değerini belirle.
Örneğin 300 level yapmak istiyorsan:
PLAYER_EXP_TABLE_MAX = 300,
PLAYER_MAX_LEVEL_CONST = 300,
Varsayılan örnek genelde şöyle olur:
PLAYER_EXP_TABLE_MAX = 120,
PLAYER_MAX_LEVEL_CONST = 120,
Buradaki değerleri yükseltirken constants.cpp içindeki exp tablolarını da aynı seviyeye göre genişletmeyi unutma.
db/src
ClientManager.h
Şunu bul:
struct TPartyInfo
{
BYTE bRole;
BYTE bLevel;
Bununla değiştir:
struct TPartyInfo
{
BYTE bRole;
int bLevel;
ClientManager.cpp
Şunu bul:
pkPeer->Encode(&it_member->second.bLevel, sizeof(BYTE));
Bu satır genelde şu fonksiyonun içinde olur:
void CClientManager::SendPartyOnSetup(CPeer* pkPeer)
Bununla değiştir:
pkPeer->Encode(&it_member->second.bLevel, sizeof(int));
ClientManagerPlayer.cpp
Şunu bul:
"PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d"
Bununla değiştir:
"PLAYER_DELETE FAILED LEVEL %d >= DELETE LIMIT %d"
Aynı satırdan dosyada 2 tane olabilir. İkisini de değiştir.
client
packet.h
Şunu bul:
BYTE byLevel;
Bununla değiştir:
int byLevel;
Şunu da bul:
BYTE byLevel;
Bununla değiştir:
int byLevel;
PythonGuild.h
Şunu bul:
BYTE byLevel;
Bununla değiştir:
int byLevel;
Database Düzenlemesi
Son olarak player database içinde player tablosundaki level kolonunu da değiştirmen gerekiyor.
Varsayılan olarak genelde tinyint olur. Bunu maksimum leveline göre smallint veya int yapabilirsin.
Örnek SQL:
ALTER TABLE player.player
MODIFY COLUMN level SMALLINT UNSIGNED NOT NULL DEFAULT 1;
Daha yüksek level planlıyorsan:
ALTER TABLE player.player
MODIFY COLUMN level INT UNSIGNED NOT NULL DEFAULT 1;
Ben çoğu server için SMALLINT UNSIGNED yeterli görürüm. Ama 1000+ gibi yüksek level planı varsa direkt INT UNSIGNED kullanmak daha rahat olur.
Dikkat Edilmesi Gerekenler
Bu işlem sadece birkaç BYTE satırını int yapmak değil. Game, db, common ve client tarafında aynı paket yapılarının tutarlı olması gerekiyor. Bir tarafta BYTE, diğer tarafta int kalırsa paket boyutu uyuşmaz ve guild, party ya da karakter bilgileri bozulabilir.
Özellikle şu kısımları kontrol et:
SetLevel
Party member level
Guild member level
Packet level fields
Database level column
Exp tables
En çok hata genelde tables.h, packet.h ve database kolonunda unutulan eski BYTE alanlarından çıkıyor.
Kısa Özet
Bu düzenleme ile karakter level değeri BYTE sınırından çıkarılıp int yapılıyor. Böylece 120, 127, 255 gibi eski limitlere takılmadan daha yüksek maksimum level sistemi kurulabiliyor. Ama düzgün çalışması için game, db, common, client ve database tarafındaki bütün level alanlarının aynı tipte güncellenmesi şart.
Paylaş :








