diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c20e8cb
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,30 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [2024-11-30] - Build System & Script Engine Fixes
+
+### Fixed
+- **Release_NoGD Configuration**: Added missing compiler settings (SSE2, OpenMP, warning suppressions) to match Release configuration
+- **Debug Build Linker Error**: Added `_USE_32BIT_TIME_T` preprocessor definition to GlobalScript Debug configuration to fix `ParsePacket::HandleUserLogin` time_t size mismatch (LNK2019)
+- **Script Execution Crash**: Implemented VirtualAlloc with PAGE_EXECUTE_READWRITE for JIT code buffer allocation to resolve DEP-related memory access violations
+- **Standalone Debugging**: Modified `_RYL_TEST` mode to automatically enable `ADMIN_L3` without requiring Login.exe
+
+### Changed
+- **Working Directory**: Set LocalDebuggerWorkingDirectory to `F:\YouxiLand\ROW` for all configurations to enable proper resource loading during debugging
+- **Server IP Handling**: Modified `GetServerInfo()` to respect command-line IP arguments even in Debug builds, falling back to `127.0.0.1` only when no IP is provided
+- **Memory Management**: Enhanced `CVirtualMachine::Destroy()` to properly detect and free VirtualAlloc-allocated memory using VirtualQuery
+
+### Added
+- **Debug Logging**: Added MCF file decryption logging (`.decrypted.log` files) for script debugging
+- **Execute State Logging**: Added comprehensive state logging to `script_execute.log` before script execution
+
+### Technical Details
+- MCF XOR encryption key: `0x82fac623 ^ 0x601f1ac4`
+- Stack reserve size increased to 8MB for Debug configuration
+- Code buffer now allocated with executable permissions for JIT execution compatibility with Windows 10/11 DEP
+
+### Notes
+- Visual Studio 2010 project
+- DirectX 8 graphics API
+- Custom JIT script engine with x86 machine code execution
diff --git a/Client/Client/RYLClient/RYLClient.vcxproj b/Client/Client/RYLClient/RYLClient.vcxproj
index de758b8..5e42065 100644
--- a/Client/Client/RYLClient/RYLClient.vcxproj
+++ b/Client/Client/RYLClient/RYLClient.vcxproj
@@ -137,7 +137,6 @@
$(OutDir)Client.pdb
Windows
8388608
- false
MachineX86
false
HighestAvailable
diff --git a/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp b/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp
index 9ce87c4..9548db1 100644
--- a/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp
+++ b/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp
@@ -602,6 +602,10 @@ USES_CONVERSION;
VOID CClientMain::GetServerInfo( HWND hWnd )
{
char *strCommandLine = GetCommandLine() ;
+
+ // 기본값으로 초기화
+ strcpy(CRYLNetworkData::m_strIP, "");
+ CRYLNetworkData::m_dwServerID = 0;
if ( hWnd )
{
@@ -612,12 +616,19 @@ VOID CClientMain::GetServerInfo( HWND hWnd )
else
{
char *pLast = strrchr( strCommandLine, '"' ) ;
- pLast += 2 ;
- sscanf( pLast,"%s %d", CRYLNetworkData::m_strIP, &CRYLNetworkData::m_dwServerID ) ;
+ if (pLast)
+ {
+ pLast += 2 ;
+ sscanf( pLast,"%s %d", CRYLNetworkData::m_strIP, &CRYLNetworkData::m_dwServerID ) ;
+ }
}
#ifdef DEBUG
- strcpy(CRYLNetworkData::m_strIP, "127.0.0.1");
+ // 명령줄에서 IP를 받지 못한 경우에만 기본값 사용
+ if (strlen(CRYLNetworkData::m_strIP) == 0 || strcmp(CRYLNetworkData::m_strIP, "") == 0)
+ {
+ strcpy(CRYLNetworkData::m_strIP, "127.0.0.1");
+ }
#endif
/*
if ( m_wAdminMode == ADMIN_L3 )
diff --git a/Client/Client/ScriptEngine/VirtualMachine.cpp b/Client/Client/ScriptEngine/VirtualMachine.cpp
index 3c545ac..0603641 100644
--- a/Client/Client/ScriptEngine/VirtualMachine.cpp
+++ b/Client/Client/ScriptEngine/VirtualMachine.cpp
@@ -10,6 +10,7 @@
#include
#include
#include "GMMemory.h"
+#include
typedef unsigned char byte;
@@ -232,7 +233,11 @@ void CVirtualMachine::Create( const void * pDataBuf, unsigned DataSize )
TotalBufferSize = GlobalVarBufferSize + StringBufferSize + m_iCodeSize;
- m_pGlobalVars = m_pBuffer = new char[TotalBufferSize];
+ // Use VirtualAlloc for executable code buffer
+ m_pGlobalVars = m_pBuffer = (char*)VirtualAlloc(NULL, TotalBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (m_pBuffer == NULL) {
+ m_pGlobalVars = m_pBuffer = new char[TotalBufferSize];
+ }
m_pStringBuffer = ((byte*)m_pGlobalVars) + GlobalVarBufferSize;
m_pCodeBuffer = ((byte*)m_pStringBuffer) + StringBufferSize;
@@ -277,7 +282,11 @@ void CVirtualMachine::Create( CIntermediateCode & IMCode, CSymbolTable & Symbo
int StringBufferSize = SymbolTable.GetStringBufferSize();
int BufSize = GlobalVarsSize + StringBufferSize + m_iCodeSize;
- m_pGlobalVars = m_pBuffer = new char[ BufSize ];
+ // Use VirtualAlloc for executable code buffer
+ m_pGlobalVars = m_pBuffer = (char*)VirtualAlloc(NULL, BufSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (m_pBuffer == NULL) {
+ m_pGlobalVars = m_pBuffer = new char[ BufSize ];
+ }
memset( m_pGlobalVars, 0, GlobalVarsSize );
@@ -329,7 +338,15 @@ void CVirtualMachine::SetSysVars()
void CVirtualMachine::Destroy()
{
- delete [] m_pBuffer;
+ // Check if buffer was allocated with VirtualAlloc (aligned to 4KB/64KB boundary typically)
+ if (m_pBuffer != NULL) {
+ MEMORY_BASIC_INFORMATION mbi;
+ if (VirtualQuery(m_pBuffer, &mbi, sizeof(mbi)) && mbi.AllocationBase == m_pBuffer) {
+ VirtualFree(m_pBuffer, 0, MEM_RELEASE);
+ } else {
+ delete [] m_pBuffer;
+ }
+ }
m_pBuffer = m_pGlobalVars = m_pStringBuffer = m_pCodeBuffer = NULL;
m_iCodeSize = 0;
m_pFunctionMap->clear();