OYUN GÜNDEMİ

Metin2 Maksimum Level Artırma ve BYTE Yerine INT Kullanımı

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.

image-404 Metin2 Maksimum Level Artırma ve BYTE Yerine INT Kullanımı

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ş :

Bu Kategoriden

Metin2 Cinsiyet Değiştirme Quest Sistemi: Sorunsuz Çalışan Güncel Kod 09.05.2026 Metin2 sistem ekleme aracı ile source dosyalarına otomatik kod uygulama ve patch sürecini gösteren arayüz görseli. Metin2 Sistem Ekleme Aracı: Kodları Otomatik Uygulayan Yardımcı Program 09.05.2026 Metin2 ruh taşı scripti ile Grand Master beceri geliştirme sistemini anlatan Seungryong Vadisi görseli. Metin2 Ruh Taşı Scripti: Tek Seferde Çoklu Grand Master Eğitimi 06.05.2026 Metin2 Shader Sistemi: Grafik Kodlarında Tam Temizlik ve Stabilizasyon Süreci 06.05.2026
Okuma Önerisi

Benzer rehberlere ve güncel oyun içeriklerine göz atabilirsin.

Okumaya Devam Et

Subnautica 2'de derin deniz keşiflerini mümkün kılan Modification Station ve araç modüllerinin üretim paneli. Subnautica 2 Modification Station Rehberi: Araç Yükseltmeleri ve Celestine Tarımı 19.05.2026 Subnautica 2 Biomod yetenek listesindeki en güçlü siber-biyolojik gen mutasyonları ve hücre paneli gösterimi. Subnautica 2 En İyi Yetenekler Tier List: En Güçlü Biomod Seçimleri 19.05.2026 Subnautica 2 Feedback Resonator yükseltmesini açmak için Root Canyon biyomunda taranması gereken antik laboratuvar kalıntıları. Subnautica 2 Feedback Resonator Nasıl Alınır? Root Canyon ve Tarama Rehberi 19.05.2026 Subnautica 2 Power Center ana salonunda yer alan ve dördüncü Angel Comb ile kilitleri açılan devasa uzaylı türbini. Subnautica 2 Power Center Türbini Nasıl Çalıştırılır? Alien Ruins Bulmaca Rehberi 19.05.2026

Hızlı Geçiş

Rehber Haber Önizleme Mobil Oyun