Skip to content
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

Refactor Configuration and Connection Handling for Consistency #268

Open
wants to merge 6 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
101 changes: 101 additions & 0 deletions src/common/Ini.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "StdAfx.h"
#include "Ini.h"

CIni::CIni() {
m_Ini.SetUnicode();
IniFileSet(fs::mktemp_file("config", ".ini"));
m_bWriteDefaults = true;
}

CIni::CIni(const fs::path & fsFile, bool bWriteDefaults /* = true */) {
m_Ini.SetUnicode();
IniFileSet(fsFile);
m_bWriteDefaults = bWriteDefaults;
}

void CIni::IniFileSet(const fs::path & fsFile) {
m_fsFile = fsFile.is_absolute() ? fsFile : (n3std::get_app_dir() / fsFile);
ReloadFile();
}

void CIni::ReloadFile() const {
if (!fs::exists(m_fsFile)) {
return;
}

std::unique_lock lock(m_mtxIni);

// Check both last write timestamp and interval to avoid excessive reloads.
// Defaults written by the app updates the file timestamp, so we also ensure
// a minimum time interval before reloading.
auto tpCurrentWriteTime = fs::last_write_time(m_fsFile);
auto tpNow = std::chrono::steady_clock::now();
auto tpElapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(tpNow - m_tpLastReload);
bool bNeedsReload = tpCurrentWriteTime != m_tpLastWriteTime && tpElapsedSeconds >= m_dReloadIntervalSeconds;
if (!bNeedsReload) {
return;
}

m_Ini.Reset();
m_Ini.LoadFile(m_fsFile.c_str());
m_tpLastReload = tpNow;
m_tpLastWriteTime = tpCurrentWriteTime;
}

void CIni::SetBool(std::string_view szSection, std::string_view szKey, bool bDefault) const {
SetString(szSection, szKey, bDefault ? "1" : "0");
}

void CIni::SetInt(std::string_view szSection, std::string_view szKey, int iDefault) const {
SetString(szSection, szKey, std::to_string(iDefault));
}

void CIni::SetFloat(std::string_view szSection, std::string_view szKey, float fDefault) const {
SetString(szSection, szKey, std::format("{:.04f}", fDefault));
}

void CIni::SetString(std::string_view szSection, std::string_view szKey, std::string_view szDefault) const {
std::unique_lock lock(m_mtxIni);
m_Ini.SetValue(szSection.data(), szKey.data(), szDefault.data());
m_Ini.SaveFile(m_fsFile.c_str());
}

bool CIni::GetBool(std::string_view szSection, std::string_view szKey, bool bDefault) const {
return GetInt(szSection, szKey, bDefault ? 1 : 0) ? true : false;
}

int CIni::GetInt(std::string_view szSection, std::string_view szKey, int iDefault) const {
std::string szValue = GetString(szSection, szKey, std::to_string(iDefault));

int iValue = iDefault;
auto errConv = std::from_chars(szValue.data(), szValue.data() + szValue.size(), iValue);
if (errConv.ec == std::errc::invalid_argument || errConv.ec == std::errc::result_out_of_range) {
return iDefault;
}

return iValue;
}

float CIni::GetFloat(std::string_view szSection, std::string_view szKey, float fDefault) const {
std::string szValue = GetString(szSection, szKey, std::format("{:.04f}", fDefault));

float fValue = fDefault;
auto errConv = std::from_chars(szValue.data(), szValue.data() + szValue.size(), fValue);
if (errConv.ec == std::errc::invalid_argument || errConv.ec == std::errc::result_out_of_range) {
return fDefault;
}

return fValue;
}

std::string CIni::GetString(std::string_view szSection, std::string_view szKey, std::string_view szDefault) const {
ReloadFile();
if (m_bWriteDefaults && !m_Ini.KeyExists(szSection.data(), szKey.data())) {
SetString(szSection, szKey, szDefault);
return std::string(szDefault);
}

std::shared_lock lock(m_mtxIni);
const char * szValue = m_Ini.GetValue(szSection.data(), szKey.data(), szDefault.data());
return szValue ? std::string(szValue) : std::string(szDefault);
}
41 changes: 41 additions & 0 deletions src/common/Ini.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "N3Utils.h"

#include <simpleini/SimpleIni.h>
#include <shared_mutex>

class CIni {
public:
CIni();
CIni(const fs::path & fsFile, bool bWriteDefaults = true);

const fs::path & IniFile() const { return m_fsFile; }
void IniFileSet(const fs::path & fsFile);

void SetBool(std::string_view szSection, std::string_view szKey, bool bDefault) const;
void SetInt(std::string_view szSection, std::string_view szKey, int iDefault) const;
void SetFloat(std::string_view szSection, std::string_view szKey, float fDefault) const;
void SetString(std::string_view szSection, std::string_view szKey, std::string_view szDefault) const;

bool GetBool(std::string_view szSection, std::string_view szKey, bool bDefault) const;
int GetInt(std::string_view szSection, std::string_view szKey, int iDefault) const;
float GetFloat(std::string_view szSection, std::string_view szKey, float fDefault) const;
std::string GetString(std::string_view szSection, std::string_view szKey, std::string_view szDefault) const;

private:
void ReloadFile() const;

public:
bool m_bWriteDefaults; // Writes defaults if a requested key does not exists.

private:
fs::path m_fsFile;

mutable CSimpleIniA m_Ini;
mutable std::shared_mutex m_mtxIni;

mutable fs::file_time_type m_tpLastWriteTime;
mutable std::chrono::steady_clock::time_point m_tpLastReload; // Last reload timestamp
const std::chrono::seconds m_dReloadIntervalSeconds{3}; // Hot reload interval
};
21 changes: 11 additions & 10 deletions src/game/GameProcLogIn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "N3Base/N3SndObjStream.h"
#include "N3Base/N3SndMgr.h"

#include "Ini.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -120,24 +122,23 @@ void CGameProcLogIn::Init() {
s_pUIMgr->SetFocusedUI((CN3UIBase *)m_pUILogIn);

// Socket connection..
std::string fsIniFile = (CN3Base::PathGet() / "Server.ini").string();
const char * pszIniFile = fsIniFile.c_str();
CIni ini(CN3Base::PathGet() / "Server.ini", false);

int iServerCount = GetPrivateProfileInt("Server", "Count", 0, pszIniFile);
int iServerCount = ini.GetInt("Server", "Count", 0);

char szIPs[256][32]{};
std::vector<std::string> vIpAddrs(iServerCount, "");
for (int i = 0; i < iServerCount; i++) {
std::string szKey = std::format("IP{:d}", i);
GetPrivateProfileString("Server", szKey.c_str(), "", szIPs[i], sizeof(szIPs[i]), pszIniFile);
vIpAddrs[i] = ini.GetString("Server", std::format("IP{:d}", i), "");
}
int iServer = -1;

std::string szServerIpAddr;
if (iServerCount > 0) {
iServer = rand() % iServerCount;
szServerIpAddr = vIpAddrs[rand() % iServerCount];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add srand(static_cast<unsigned>(time(0))); before this line to get a different value every time?

}

if (iServer >= 0 && lstrlen(szIPs[iServer])) {
if (!szServerIpAddr.empty()) {
s_bNeedReportConnectionClosed = false; // 서버접속이 끊어진걸 보고해야 하는지..
int iErr = s_pSocket->Connect(s_hWndBase, szIPs[iServer], SOCKET_PORT_LOGIN);
int iErr = s_pSocket->Connect(s_hWndBase, szServerIpAddr.c_str(), SOCKET_PORT_LOGIN);
s_bNeedReportConnectionClosed = true; // 서버접속이 끊어진걸 보고해야 하는지..
if (iErr) {
this->ReportServerConnectionFailed("LogIn Server", iErr, true);
Expand Down
6 changes: 4 additions & 2 deletions src/game/KnightOnLine.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdAfx.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_N3GAME;N3LOG_ENABLE_SPDLOG;_CRT_SECURE_NO_WARNINGS;DIRECTINPUT_VERSION=0x0800;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)res;$(SrcDir)\common;$(SrcDir)\engine;$(VendorDir)\imgui\include;$(VendorDir)\spdlog\include;$(VendorDir)\jpeglib\include;$(WindowsSDK_IncludePath);$(VendorDir)\dxsdk9\Include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)res;$(SrcDir)\common;$(SrcDir)\engine;$(VendorDir)\simpleini\include;$(VendorDir)\imgui\include;$(VendorDir)\spdlog\include;$(VendorDir)\jpeglib\include;$(WindowsSDK_IncludePath);$(VendorDir)\dxsdk9\Include</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 /wd4018 /wd4091 /wd4244 /wd4267 /wd4477 /wd4838 /wd6031 /wd26495 /wd4102 %(AdditionalOptions)</AdditionalOptions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
Expand Down Expand Up @@ -97,7 +97,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>StdAfx.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_N3GAME;_CRT_SECURE_NO_WARNINGS;DIRECTINPUT_VERSION=0x0800;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)res;$(SrcDir)\common;$(SrcDir)\engine;$(VendorDir)\imgui\include;$(VendorDir)\spdlog\include;$(VendorDir)\jpeglib\include;$(WindowsSDK_IncludePath);$(VendorDir)\dxsdk9\Include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)res;$(SrcDir)\common;$(SrcDir)\engine;$(VendorDir)\simpleini\include;$(VendorDir)\imgui\include;$(VendorDir)\spdlog\include;$(VendorDir)\jpeglib\include;$(WindowsSDK_IncludePath);$(VendorDir)\dxsdk9\Include</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 /wd4018 /wd4091 /wd4244 /wd4267 /wd4477 /wd4838 /wd6031 /wd26495 /wd4102 %(AdditionalOptions)</AdditionalOptions>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FunctionLevelLinking>true</FunctionLevelLinking>
Expand Down Expand Up @@ -126,6 +126,7 @@
<ClInclude Include="$(SrcDir)\common\Implode.h" />
<ClInclude Include="$(SrcDir)\common\JvCryption.h" />
<ClInclude Include="$(SrcDir)\common\N3Utils.h" />
<ClInclude Include="$(SrcDir)\common\Ini.h" />
<ClInclude Include="$(SrcDir)\engine\N3Base\JpegFile.h" />
<ClInclude Include="$(SrcDir)\engine\N3Base\BitMapFile.h" />
<ClInclude Include="$(SrcDir)\engine\N3Base\DFont.h" />
Expand Down Expand Up @@ -314,6 +315,7 @@
<ItemGroup>
<ClCompile Include="$(SrcDir)\common\Implode.cpp" />
<ClCompile Include="$(SrcDir)\common\JvCryption.cpp" />
<ClCompile Include="$(SrcDir)\common\Ini.cpp" />
<ClCompile Include="$(SrcDir)\engine\N3Base\JpegFile.cpp" />
<ClCompile Include="$(SrcDir)\engine\N3Base\BitMapFile.cpp" />
<ClCompile Include="$(SrcDir)\engine\N3Base\DFont.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions src/game/KnightOnLine.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,9 @@
<ClInclude Include="$(SrcDir)\common\N3Utils.h">
<Filter>N3Base\Core</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)\common\Ini.h">
<Filter>N3Base\Core</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(SrcDir)\engine\N3Base\N3UIBase.cpp">
Expand Down Expand Up @@ -1137,6 +1140,9 @@
<ClCompile Include="$(SrcDir)\common\Implode.cpp">
<Filter>Network</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)\common\Ini.cpp">
<Filter>N3Base\Core</Filter>
</ClCompile>
<ClCompile Include="UIRookieTip.cpp">
<Filter>Procedure - Main\UI</Filter>
</ClCompile>
Expand Down
40 changes: 17 additions & 23 deletions src/game/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "N3Base/N3SndMgr.h"
#include "N3Base/N3UIEdit.h"

#include "Ini.h"

#ifdef _DEBUG
#include "N3UIDebug.h"
#endif
Expand Down Expand Up @@ -316,38 +318,37 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi

CN3Base::PathSet(fs::current_path());

// 세팅 읽기..
std::string szIniFile = (CN3Base::PathGet() / "Options.ini").string();
const char * pszIniFile = szIniFile.c_str();
// Configuration file
CIni ini(CN3Base::PathGet() / "Option.ini", false);

CN3Base::s_Options.iTexLOD_Chr = GetPrivateProfileInt("Texture", "LOD_Chr", 0, pszIniFile);
CN3Base::s_Options.iTexLOD_Chr = ini.GetInt("Texture", "LOD_Chr", 0);
if (CN3Base::s_Options.iTexLOD_Chr < 0) {
CN3Base::s_Options.iTexLOD_Chr = 0;
}
if (CN3Base::s_Options.iTexLOD_Chr >= 2) {
CN3Base::s_Options.iTexLOD_Chr = 1;
}

CN3Base::s_Options.iTexLOD_Shape = GetPrivateProfileInt("Texture", "LOD_Shape", 0, pszIniFile);
CN3Base::s_Options.iTexLOD_Shape = ini.GetInt("Texture", "LOD_Shape", 0);
if (CN3Base::s_Options.iTexLOD_Shape < 0) {
CN3Base::s_Options.iTexLOD_Shape = 0;
}
if (CN3Base::s_Options.iTexLOD_Shape >= 2) {
CN3Base::s_Options.iTexLOD_Shape = 1;
}

CN3Base::s_Options.iTexLOD_Terrain = GetPrivateProfileInt("Texture", "LOD_Terrain", 0, pszIniFile);
CN3Base::s_Options.iTexLOD_Terrain = ini.GetInt("Texture", "LOD_Terrain", 0);
if (CN3Base::s_Options.iTexLOD_Terrain < 0) {
CN3Base::s_Options.iTexLOD_Terrain = 0;
}
if (CN3Base::s_Options.iTexLOD_Terrain >= 2) {
CN3Base::s_Options.iTexLOD_Terrain = 1;
}

CN3Base::s_Options.iUseShadow = GetPrivateProfileInt("Shadow", "Use", 1, pszIniFile);
CN3Base::s_Options.iUseShadow = ini.GetInt("Shadow", "Use", 1);

CN3Base::s_Options.iViewWidth = GetPrivateProfileInt("ViewPort", "Width", 1024, pszIniFile);
CN3Base::s_Options.iViewHeight = GetPrivateProfileInt("ViewPort", "Height", 768, pszIniFile);
CN3Base::s_Options.iViewWidth = ini.GetInt("ViewPort", "Width", 1024);
CN3Base::s_Options.iViewHeight = ini.GetInt("ViewPort", "Height", 768);
if (1024 == CN3Base::s_Options.iViewWidth) {
CN3Base::s_Options.iViewHeight = 768;
} else if (1280 == CN3Base::s_Options.iViewWidth) {
Expand All @@ -359,37 +360,30 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
CN3Base::s_Options.iViewHeight = 768;
}

CN3Base::s_Options.iViewColorDepth = GetPrivateProfileInt("ViewPort", "ColorDepth", 16, pszIniFile);
CN3Base::s_Options.iViewColorDepth = ini.GetInt("ViewPort", "ColorDepth", 16);
if (CN3Base::s_Options.iViewColorDepth != 16 && CN3Base::s_Options.iViewColorDepth != 32) {
CN3Base::s_Options.iViewColorDepth = 16;
}
CN3Base::s_Options.iViewDist = GetPrivateProfileInt("ViewPort", "Distance", 512, pszIniFile);
CN3Base::s_Options.iViewDist = ini.GetInt("ViewPort", "Distance", 512);
if (CN3Base::s_Options.iViewDist < 256) {
CN3Base::s_Options.iViewDist = 256;
}
if (CN3Base::s_Options.iViewDist > 512) {
CN3Base::s_Options.iViewDist = 512;
}

CN3Base::s_Options.iEffectSndDist = GetPrivateProfileInt("Sound", "Distance", 48, pszIniFile);
CN3Base::s_Options.iEffectSndDist = ini.GetInt("Sound", "Distance", 48);
if (CN3Base::s_Options.iEffectSndDist < 20) {
CN3Base::s_Options.iEffectSndDist = 20;
}
if (CN3Base::s_Options.iEffectSndDist > 48) {
CN3Base::s_Options.iEffectSndDist = 48;
}

int iSndEnable = GetPrivateProfileInt("Sound", "Enable", 1, pszIniFile);
CN3Base::s_Options.bSndEnable = (iSndEnable) ? true : false; // 사운드...

int iSndDuplicate = GetPrivateProfileInt("Sound", "Duplicate", 0, pszIniFile);
CN3Base::s_Options.bSndDuplicated = (iSndDuplicate) ? true : false; // 사운드...

int iWindowCursor = GetPrivateProfileInt("Cursor", "WindowCursor", 1, pszIniFile);
CN3Base::s_Options.bWindowCursor = (iWindowCursor) ? true : false; // cursor...

int iWindowMode = GetPrivateProfileInt("Screen", "WindowMode", 0, pszIniFile);
CGameProcedure::s_bWindowed = iWindowMode ? true : false;
CN3Base::s_Options.bSndEnable = ini.GetBool("Sound", "Enable", true);
CN3Base::s_Options.bSndDuplicated = ini.GetBool("Sound", "Duplicate", false);
CN3Base::s_Options.bWindowCursor = ini.GetBool("Cursor", "WindowCursor", true);
CGameProcedure::s_bWindowed = ini.GetBool("Screen", "WindowMode", false);
#if _DEBUG
CGameProcedure::s_bWindowed = true;
#endif // #if _DEBUG
Expand Down
11 changes: 5 additions & 6 deletions src/game/UILogin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "N3Base/N3UIList.h"
#include "UIMessageBoxManager.h"

#include "Ini.h"

#include <algorithm>

//////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -67,12 +69,9 @@ bool CUILogIn::ReceiveMessage(CN3UIBase * pSender, DWORD dwMsg) {
::_LoadStringFromResource(IDS_CONFIRM_EXECUTE_OPTION, szMsg);
CGameProcedure::MessageBoxPost(szMsg, "", MB_YESNO, BEHAVIOR_EXECUTE_OPTION);
} else if (pSender == m_pBtn_Join) {
char szRegistrationSite[2000]{};
std::string szIniFile = (CN3Base::PathGet() / "Server.ini").string();
const char * szDefaultSite = "https://github.com/ko4life-net/ko";
GetPrivateProfileString("Join", "Registration site", szDefaultSite, szRegistrationSite,
sizeof(szRegistrationSite), szIniFile.c_str());
ShellExecute(NULL, "open", szRegistrationSite, NULL, NULL, SW_NORMAL);
CIni ini(CN3Base::PathGet() / "Server.ini", false);
std::string szSite = ini.GetString("Join", "Registration site", "https://github.com/ko4life-net/ko");
ShellExecute(NULL, "open", szSite.c_str(), NULL, NULL, SW_NORMAL);
PostQuitMessage(0);
return true;
}
Expand Down
Loading