Skip to content
Draft
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,5 @@ generated
docs/html

#imgui.ini file
imgui.ini
imgui.ini
third_party/
16 changes: 15 additions & 1 deletion client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,21 @@ set(SOURCES

list(TRANSFORM SOURCES PREPEND ${CMAKE_CURRENT_LIST_DIR}/src/)

add_executable(${PROJECT_NAME} ${SOURCES})
# Create macOS app bundle on Apple platforms
if(APPLE)
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SOURCES})

# Set bundle properties
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "Rehti MMORPG Client"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.rehti.mmorpg.client"
MACOSX_BUNDLE_BUNDLE_VERSION "1.0"
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
)
else()
add_executable(${PROJECT_NAME} ${SOURCES})
endif()

add_subdirectory(../rehtiLib/graphics ${CMAKE_CURRENT_LIST_DIR}/build/graphics)
add_subdirectory(../rehtiLib/network ${CMAKE_CURRENT_LIST_DIR}/build/network)
Expand Down
30 changes: 30 additions & 0 deletions client/Info.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.rehti.mmorpg.client</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion client/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def requirements(self):
self.requires("spirv-tools/1.3.239.0", override=True)
self.requires("glfw/3.3.8")
self.requires("vulkan-memory-allocator/3.0.1")
self.requires("stb/cci.20220909")
self.requires("stb/cci.20240531", override=True) # updated to latest version
self.requires("glm/cci.20230113")
self.requires("vulkan-headers/1.3.239.0", override=True)
self.requires("imgui/cci.20230105+1.89.2.docking")
Expand Down
64 changes: 44 additions & 20 deletions client/src/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <boost/asio/ip/tcp.hpp>
#include <iostream>
#include <memory>
#include <thread>

#include "Client.hpp"
#include "RehtiReader.hpp"
Expand All @@ -19,30 +20,34 @@ Client::Client(std::string ip, std::string port)
Connection::owner::client, ioContextM, std::move(boost::asio::ip::tcp::socket(ioContextM)), messagesM)),
audioLibM{}
{
graphicsThreadM = std::thread([this]()
{ startGraphics(); });

// On macOS, GLFW/graphics must run on the main thread
// So we start IO and other work on background threads instead
ioThreadM = std::thread([this]()
{ ioContextM.run(); });
};

void Client::start()
{
// Wait for graphics library to be ready
if (!graphLibReadyFlagM)
{
std::unique_lock ul(graphLibMutexM);
graphLibReadyM.wait(ul);
}
// Start network and message processing on background threads
connectionThreadM = std::thread([this]()
{ boost::asio::co_spawn(ioContextM, connect(), boost::asio::detached); });

std::thread messageThread([this]()
{ processMessages(); });
// Cleanup after graphics thread has exited
graphicsThreadM.join();

// Run graphics on the main thread (required for macOS)
// This will block until the window is closed
startGraphics();

// Cleanup after graphics has exited
connectionM->disconnect();
ioContextM.stop();

// Wait for background threads to finish
if (connectionThreadM.joinable())
connectionThreadM.join();
if (messageThread.joinable())
messageThread.join();
}

boost::asio::awaitable<bool> Client::login()
Expand Down Expand Up @@ -437,13 +442,19 @@ void Client::handleMouseClick(const Hit& hit)

void Client::startGraphics()
{
try
{
std::cout << "[DEBUG] Starting graphics initialization..." << std::endl;

// Load assets to memory
assetCacheM.loadAssets();
// init graphics library
pGraphLibM = new RehtiGraphics();
// Load assets to memory
assetCacheM.loadAssets();

// Create map bounding box
std::cout << "[DEBUG] Creating RehtiGraphics instance..." << std::endl;
// init graphics library
pGraphLibM = new RehtiGraphics();
std::cout << "[DEBUG] RehtiGraphics instance created successfully!" << std::endl;

// Create map bounding box
std::vector<std::vector<int>> heightMatrix = fetchHeightMatrix();
std::vector<std::vector<std::string>> areaMatrix = fetchAreaMatrix();

Expand Down Expand Up @@ -488,9 +499,22 @@ void Client::startGraphics()
pGraphLibM->getGui()->addEquipmentItemClickCallback([this](const int itemInstanceId)
{ boost::asio::co_spawn(ioContextM, unequipItem(itemInstanceId), boost::asio::detached); });

std::cout << "Graphics library ready" << std::endl;
std::cout << "Graphics library ready" << std::endl;

graphLibReadyFlagM = true;
graphLibReadyM.notify_one();
pGraphLibM->startMainLoop();
graphLibReadyFlagM = true;
graphLibReadyM.notify_one();
pGraphLibM->startMainLoop();
}
catch (const std::exception& e)
{
std::cerr << "[ERROR] Exception in startGraphics: " << e.what() << std::endl;
std::cerr << "[ERROR] Graphics initialization failed!" << std::endl;
throw;
}
catch (...)
{
std::cerr << "[ERROR] Unknown exception in startGraphics!" << std::endl;
std::cerr << "[ERROR] Graphics initialization failed!" << std::endl;
throw;
}
}
25 changes: 19 additions & 6 deletions rehtiLib/graphics/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
add_library(rehtiGraphics "")

set(DEPENDENCY_DIR "${CMAKE_CURRENT_LIST_DIR}/../../third_party")
set(VALIDATION_LAYER_DIR "${vulkan-validationlayers_INCLUDE_DIR}/../${CMAKE_INSTALL_BINDIR}")
set($ENV{VK_LAYER_PATH} VALIDATION_LAYER_DIR)
set($ENV{VK_LOADER_LAYERS_ENABLE} "*validation")
# We *do not* set VK_LAYER_PATH here anymore.
# We'll set it in the shell/run script instead, where it actually matters at runtime.

find_package(glfw3 3.3.8 REQUIRED)
find_package(Vulkan 1.3.239.0 REQUIRED)
find_package(SPIRV-Tools 1.3.239.0 REQUIRED)
find_package(vulkan-memory-allocator 3.0.1 REQUIRED)
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
find_package(vulkan-validationlayers 1.3.239.0 REQUIRED)
find_package(stb REQUIRED)
# stb doesn't provide CMake config via Conan, manually locate and create interface library
if(NOT TARGET stb::stb)
# Try to find stb_image.h in the Conan cache
execute_process(
COMMAND bash -c "find ~/.conan2/p/stb*/p/include -name stb_image.h 2>/dev/null | head -1 | xargs dirname"
OUTPUT_VARIABLE STB_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT STB_INCLUDE_DIR)
message(FATAL_ERROR "Could not find stb include directory. Make sure stb is installed via Conan.")
endif()
message(STATUS "Found stb include directory: ${STB_INCLUDE_DIR}")
add_library(stb::stb INTERFACE IMPORTED)
target_include_directories(stb::stb INTERFACE ${STB_INCLUDE_DIR})
endif()
find_package(glm REQUIRED)
find_package(imgui REQUIRED)

Expand Down Expand Up @@ -77,7 +90,7 @@ target_link_libraries(rehtiGraphics
glfw
spirv-tools::spirv-tools
${GLSLANG_LIBS}
vulkan-memory-allocator::vulkan-memory-allocator
GPUOpen::VulkanMemoryAllocator
vulkan-validationlayers::vulkan-validationlayers
stb::stb
glm::glm
Expand Down
Loading