Skip to content

Login news #271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion src/game/GameProcLogIn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,17 @@ bool CGameProcLogIn::MsgSend_AccountLogIn(e_LogInClassification eLIC) {
return true;
}

bool CGameProcLogIn::MsgSend_NewsRequestData() {
BYTE byBuffer[4];
int iOffset = 0;

CAPISocket::MP_AddByte(byBuffer, iOffset, N3_LOGIN_NEWS_REQUEST);

s_pSocket->Send(byBuffer, iOffset);

return true;
}

void CGameProcLogIn::MsgRecv_GameServerGroupList(DataPack * pDataPack, int & iOffset) {
int iServerCount = CAPISocket::Parse_GetByte(pDataPack->m_pData, iOffset); // 서버 갯수
for (int i = 0; i < iServerCount; i++) {
Expand Down Expand Up @@ -496,10 +507,14 @@ bool CGameProcLogIn::ProcessPacket(DataPack * pDataPack, int & iOffset) {
case N3_GAMESERVER_GROUP_LIST: // 접속하면 바로 보내준다..
this->MsgRecv_GameServerGroupList(pDataPack, iOffset);
return true;

case N3_LOGIN_NEWS_REQUEST:
N3_DEBUG("N3_LOGIN_NEWS_REQUEST");
this->MsgRecv_News(pDataPack, iOffset);
return true;
case N3_ACCOUNT_LOGIN: // 계정 접속 성공..
case N3_ACCOUNT_LOGIN_MGAME: // MGame 계정 접속 성공..
this->MsgRecv_AccountLogIn(iCmd, pDataPack, iOffset);
this->MsgSend_NewsRequestData();
return true;
}

Expand All @@ -524,6 +539,64 @@ void CGameProcLogIn::ConnectToGameServer() // 고른 게임 서버에 접속
this->MsgSend_VersionCheck();
}
}
void CGameProcLogIn::MsgRecv_News(DataPack * pDataPack, int & iOffset) {
constexpr int maxNewsCount = 3;
int newsCount = 0;

int headerLen = CAPISocket::Parse_GetShort(pDataPack->m_pData, iOffset);
std::string szHeader;
if (headerLen > 0) {
CAPISocket::Parse_GetString(pDataPack->m_pData, iOffset, szHeader, headerLen);
}

int fullContentLen = CAPISocket::Parse_GetShort(pDataPack->m_pData, iOffset);
std::string fullContent;
if (fullContentLen > 0) {
CAPISocket::Parse_GetString(pDataPack->m_pData, iOffset, fullContent, fullContentLen);
}

fullContent.erase(std::remove(fullContent.begin(), fullContent.end(), '\0'), fullContent.end());

std::vector<std::string> tokens;
{
size_t start = 0;
while (true) {
size_t pos = fullContent.find('#', start);
if (pos == std::string::npos) {
std::string token = fullContent.substr(start);
tokens.push_back(token);
break;
} else {
std::string token = fullContent.substr(start, pos - start);
tokens.push_back(token);
start = pos + 1;
}
}
}

auto trim = [](const std::string & s) -> std::string {
const std::string whitespace = " \t\n\r";
size_t start = s.find_first_not_of(whitespace);
if (start == std::string::npos) {
return "";
}
size_t end = s.find_last_not_of(whitespace);
return s.substr(start, end - start + 1);
};

for (size_t i = 0; i + 1 < tokens.size() && newsCount < maxNewsCount; i += 2) {
std::string title = trim(tokens[i]);
std::string content = trim(tokens[i + 1]);

m_pUILogIn->m_loginNewsTitle[newsCount] = title;
m_pUILogIn->m_loginNewsText[newsCount] = content;
newsCount++;
}

m_pUILogIn->m_loginNewsCount = newsCount;
m_pUILogIn->LoadNewsData();
}

// By : Ecli666 ( On 2002-07-15 오후 7:35:16 )
//
/*
Expand Down
2 changes: 2 additions & 0 deletions src/game/GameProcLogIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ class CGameProcLogIn : public CGameProcedure {
void MsgRecv_AccountLogIn(int iCmd, DataPack * pDataPack, int & iOffset);
int MsgRecv_VersionCheck(DataPack * pDataPack, int & iOffset); // virtual
int MsgRecv_GameServerLogIn(DataPack * pDataPack, int & iOffset); // virtual - 국가 번호를 리턴한다.
void MsgRecv_News(DataPack * pDataPack, int & iOffset);

bool MsgSend_AccountLogIn(enum e_LogInClassification eLIC);
bool MsgSend_NewsRequestData();

void Release();
void Init();
Expand Down
1 change: 1 addition & 0 deletions src/game/PacketDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const int SOCKET_PORT_LOGIN = 15100; // 소켓이 붙을 포트 번호..
#define N3_ACCOUNT_LOGIN_MGAME 0xf4 // !!! LOGIN_REQ !!! 와 동일
#define N3_GAMESERVER_GROUP_LIST \
0xf5 // Recv - b1(ServerCount) loop( s1(IP길이), str1(IP문자열), s1(서버이름길이), str1(서버이름문자열), s1(서버접속인원) )
#define N3_LOGIN_NEWS_REQUEST 0xf6

#define N3_GAME_SERVER_LOGIN 0x01 // Game server 에 Log in..
#define N3_NEW_CHARACTER 0x02 // 캐릭터 새로 만들기..
Expand Down
37 changes: 37 additions & 0 deletions src/game/UILogin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "N3Base/N3UIEdit.h"
#include "N3Base/N3UIButton.h"
#include "N3Base/N3UIList.h"
#include "N3Base/N3UIString.h";
#include "UIMessageBoxManager.h"

#include <algorithm>
Expand All @@ -35,6 +36,10 @@ CUILogIn::CUILogIn() {
m_pImg_MGameLogo = NULL;
m_pImg_DaumLogo = NULL;

m_pGroup_Notice[1] = NULL;
m_pGroup_Notice[2] = NULL;
m_pGroup_Notice[3] = NULL;

m_pList_Server = NULL;

m_bOpenningNow = false; // 위에서 아래로 스르륵...열려야 한다면..
Expand Down Expand Up @@ -369,6 +374,38 @@ void CUILogIn::SetVisibleLogInUIs(bool bEnable) {
}
}

void CUILogIn::LoadNewsData() {
std::string szGroupNotice = "Group_Notice_";

for (size_t i = 0; i < m_loginNewsCount; ++i) {
CN3UIBase * pGroupNotice = GetChildByID(szGroupNotice + std::to_string(i + 1));
if (pGroupNotice) {
CN3UIString * pNoticeTitle = (CN3UIString *)pGroupNotice->GetChildByID("text_notice_name");
CN3UIString * pNoticeText = (CN3UIString *)pGroupNotice->GetChildByID("text_notice");

if (pNoticeTitle) {
pNoticeTitle->SetString(m_loginNewsTitle[i].c_str());
}
if (pNoticeText) {
pNoticeText->SetString(m_loginNewsText[i].c_str());
}

int x = (CN3Base::s_CameraData.vp.Width / 2) - 40;
int y = (CN3Base::s_CameraData.vp.Height / 2);

if (i == 0) {
pGroupNotice->MoveOffset(x, 30 + 170 - y);
} else if (i == 1) {
pGroupNotice->MoveOffset(x, 30 + 342 - y);
} else if (i == 2) {
pGroupNotice->MoveOffset(x, 30 + 518 - y);
}

pGroupNotice->SetVisible(true);
}
}
}

bool CUILogIn::OnKeyPress(int iKey) {
if (!m_bLogIn) {
switch (iKey) {
Expand Down
9 changes: 9 additions & 0 deletions src/game/UILogin.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class CUILogIn : public CN3UIBase {
CN3UIBase * m_pImg_MGameLogo;
CN3UIBase * m_pImg_DaumLogo;

CN3UIBase * m_pGroup_Notice[3];
CN3UIString * m_pNotice_Title[3];
CN3UIString * m_pNotice_Text[3];

CN3UIList * m_pList_Server;

std::vector<__GameServerInfo> m_ListServerInfos;
Expand All @@ -53,6 +57,10 @@ class CUILogIn : public CN3UIBase {
bool m_bLogIn; // 로그인 중복 방지..

public:
std::string m_loginNewsTitle[3];
std::string m_loginNewsText[3];
int m_loginNewsCount = 0;

void SetRequestedLogIn(bool bLogIn) { m_bLogIn = bLogIn; }
bool OnKeyPress(int iKey);
void SetVisibleLogInUIs(bool bEnable); // 계정 LogIn 에 필요한 UI 들을 숨긴다..
Expand All @@ -70,6 +78,7 @@ class CUILogIn : public CN3UIBase {
bool ServerInfoGet(int iIndex, __GameServerInfo & GSI);
bool ServerInfoGetCur(__GameServerInfo & GSI);
void ServerInfoUpdate();
void LoadNewsData();

void AccountIDGet(std::string & szID);
void AccountPWGet(std::string & szPW);
Expand Down
55 changes: 55 additions & 0 deletions src/server/LoginServer/DBProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,58 @@ BOOL CDBProcess::IsCurrentUser(const char * szAccountId, char * szServerIp, int

return retval;
}

BOOL CDBProcess::LoadNews() {
SQLHSTMT hstmt = NULL;
SQLRETURN retcode;
TCHAR szSQL[1024];

memset(szSQL, 0x00, 1024);
wsprintf(szSQL, TEXT("SELECT Title, Content, IsActive FROM NEWS WHERE IsActive = 1 AND "
"(StartsAt IS NULL OR StartsAt <= GETDATE()) AND "
"(ExpiresAt IS NULL OR ExpiresAt > GETDATE()) AND "
"NoticeType = 'login'"));

_NEWS newsItem;
memset(&newsItem, 0, sizeof(newsItem));

retcode = SQLAllocHandle(SQL_HANDLE_STMT, m_VersionDB.m_hdbc, &hstmt);
if (retcode != SQL_SUCCESS) {
return FALSE;
}

retcode = SQLExecDirect(hstmt, (unsigned char *)szSQL, 1024);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) {
if (DisplayErrorMsg(hstmt) == -1) {
m_VersionDB.Close();
if (!m_VersionDB.IsOpen()) {
ReConnectODBC(&m_VersionDB, m_pMain->m_ODBCName, m_pMain->m_ODBCLogin, m_pMain->m_ODBCPwd);
return FALSE;
}
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return FALSE;
}

while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLCHAR titleBuffer[256] = {0};
SQLCHAR contentBuffer[4096] = {0};

SQLGetData(hstmt, 1, SQL_C_CHAR, titleBuffer, sizeof(titleBuffer), NULL);
SQLGetData(hstmt, 2, SQL_C_CHAR, contentBuffer, sizeof(contentBuffer), NULL);
SQLGetData(hstmt, 3, SQL_C_BIT, &newsItem.IsActive, 0, NULL);

strncpy(newsItem.Title, reinterpret_cast<char *>(titleBuffer), sizeof(newsItem.Title) - 1);
strncpy(newsItem.Content, reinterpret_cast<char *>(contentBuffer), sizeof(newsItem.Content) - 1);

if (newsItem.IsActive) {
m_pMain->m_ServerNews.push_back(newsItem);
}
}
}

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return TRUE;
}
1 change: 1 addition & 0 deletions src/server/LoginServer/DBProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class CDBProcess {
int AccountLogin(const char * szId, const char * szPwd);
BOOL LoadVersionList();
BOOL LoadUserCountList();
BOOL LoadNews();

CDBProcess();
virtual ~CDBProcess();
Expand Down
7 changes: 7 additions & 0 deletions src/server/LoginServer/Define.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,20 @@ struct _SERVER_INFO {
};
};

struct _NEWS {
char Title[256];
char Content[4096];
bool IsActive;
};

// Packet Define...

#define LS_VERSION_REQ 0x01
#define LS_DOWNLOADINFO_REQ 0x02
#define LS_LOGIN_REQ 0xF3
#define LS_MGAME_LOGIN 0xF4
#define LS_SERVERLIST 0xF5
#define LS_NEWS 0xF6

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
Expand Down
54 changes: 54 additions & 0 deletions src/server/LoginServer/LoginServerDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ BEGIN_MESSAGE_MAP(CLoginServerDlg, CDialog)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_SETTING, OnVersionSetting)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

Expand Down Expand Up @@ -91,6 +92,12 @@ BOOL CLoginServerDlg::OnInitDialog() {
AfxPostQuitMessage(0);
return FALSE;
}
if (!m_DBProcess.LoadNews()) {
AfxMessageBox("Load News Data Fail!!");
AfxPostQuitMessage(0);
return FALSE;
}
StartNewsRefreshTimer();

m_OutputList.AddString(szConnectionString);
std::string szVersion = std::format("Latest Version : {:d}", m_nLastVersion);
Expand All @@ -105,6 +112,21 @@ BOOL CLoginServerDlg::GetInfoFromIni() {
std::string szIniFile = (n3std::get_app_dir() / "Version.ini").string();
const char * pszIniFile = szIniFile.c_str();

DWORD dwAttrib = GetFileAttributesA(pszIniFile);
if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
WritePrivateProfileString("DOWNLOAD", "URL", "ftp.your-site.net", pszIniFile);
WritePrivateProfileString("DOWNLOAD", "PATH", "/", pszIniFile);
WritePrivateProfileString("ODBC", "DSN", "kodb", pszIniFile);
WritePrivateProfileString("ODBC", "UID", "kodb_user", pszIniFile);
WritePrivateProfileString("ODBC", "PWD", "kodb_user", pszIniFile);
WritePrivateProfileString("ODBC", "TABLE", "VERSION", pszIniFile);
WritePrivateProfileString("CONFIGURATION", "DEFAULT_PATH", "", pszIniFile);
WritePrivateProfileString("CONFIGURATION", "NewsRefreshInterval", "30", pszIniFile);
WritePrivateProfileString("SERVER_LIST", "COUNT", "1", pszIniFile);
WritePrivateProfileString("SERVER_LIST", "SERVER_00", "127.0.0.1", pszIniFile);
WritePrivateProfileString("SERVER_LIST", "NAME_00", "SERVER_01", pszIniFile);
}

char szBuff[500]{};
GetPrivateProfileString("DOWNLOAD", "URL", "ftp.your-site.net", szBuff, sizeof(szBuff), pszIniFile);
m_szFtpUrl = szBuff;
Expand Down Expand Up @@ -137,6 +159,11 @@ BOOL CLoginServerDlg::GetInfoFromIni() {
return FALSE;
}

m_NewsRefreshInterval = GetPrivateProfileInt("CONFIGURATION", "NewsRefreshInterval", -1, pszIniFile);
if (m_NewsRefreshInterval <= 0) {
m_NewsRefreshInterval = 15;
}

m_ServerList.reserve(20);
for (int i = 0; i < m_nServerCount; i++) {
_SERVER_INFO * pInfo = new _SERVER_INFO;
Expand Down Expand Up @@ -216,3 +243,30 @@ void CLoginServerDlg::OnVersionSetting() {
WritePrivateProfileStringW(L"CONFIGURATION", L"DEFAULT_PATH", m_fsDefaultDir.c_str(), fsIniPath.c_str());
}
}

void CLoginServerDlg::StartNewsRefreshTimer() {
if (m_NewsRefreshTimerID != 0) {
KillTimer(m_NewsRefreshTimerID);
}

m_NewsRefreshTimerID = SetTimer(1, m_NewsRefreshInterval * 60 * 1000, NULL);
if (m_NewsRefreshTimerID == 0) {
TRACE("Timer failed to set!");
}
}

void CLoginServerDlg::RefreshNewsData() {
m_ServerNews.clear();
if (m_DBProcess.LoadNews()) {
TRACE("News Data Refreshed Successfully!");
} else {
TRACE("Failed to Refresh News Data!");
}
}

void CLoginServerDlg::OnTimer(UINT_PTR nIDEvent) {
if (nIDEvent == m_NewsRefreshTimerID) {
RefreshNewsData();
}
CDialog::OnTimer(nIDEvent);
}
Loading